Skip to content

DOC: Emphasize artist as annotation in AnnotationBbox demo and add to annotation guide #29374

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 87 additions & 50 deletions galleries/examples/text_labels_and_annotations/demo_annotation_box.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""
===================
AnnotationBbox demo
===================

`.AnnotationBbox` creates an annotation using an `.OffsetBox`, and
provides more fine-grained control than `.Axes.annotate`. This example
demonstrates the use of AnnotationBbox together with three different
OffsetBoxes: `.TextArea`, `.DrawingArea`, and `.OffsetImage`.
======================
Artists as annotations
======================

`.AnnotationBbox` facilitates annotating parts of the figure or axes using arbitrary
artists, such as texts, images, and `matplotlib.patches`. `.AnnotationBbox` supports
these artists via inputs that are subclasses of `.OffsetBox`, which is a class of
container artists for positioning an artist relative to a parent artist.
"""

import matplotlib.pyplot as plt
Expand All @@ -15,57 +15,60 @@
from matplotlib.cbook import get_sample_data
from matplotlib.offsetbox import (AnnotationBbox, DrawingArea, OffsetImage,
TextArea)
from matplotlib.patches import Circle
from matplotlib.patches import Annulus, Circle, ConnectionPatch

fig, ax = plt.subplots()
# %%%%
# Text
# ====
#
# `.AnnotationBbox` supports positioning annotations relative to data, Artists, and
# callables, as described in :ref:`annotations`. The `.TextArea` is used to create a
# textbox that is not explicitly attached to an axes, which allows it to be used for
# annotating figure objects. The `.annotate` method should be used when annotating an
# axes element (such as a plot) with text.
#
fig, axd = plt.subplot_mosaic([['t1', '.', 't2']], layout='compressed')

# Define a 1st position to annotate (display it with a marker)
xy = (0.5, 0.7)
ax.plot(xy[0], xy[1], ".r")

# Annotate the 1st position with a text box ('Test 1')
xy1 = (.25, .75)
xy2 = (.75, .25)
axd['t1'].plot(*xy1, ".r")
axd['t2'].plot(*xy2, ".r")
axd['t1'].set(xlim=(0, 1), ylim=(0, 1), aspect='equal')
axd['t2'].set(xlim=(0, 1), ylim=(0, 1), aspect='equal')
# Draw an arrow between the points

c = ConnectionPatch(xyA=xy1, xyB=xy2,
coordsA=axd['t1'].transData, coordsB=axd['t2'].transData,
arrowstyle='->')
fig.add_artist(c)

# Annotate the ConnectionPatch position ('Test 1')
offsetbox = TextArea("Test 1")

ab = AnnotationBbox(offsetbox, xy,
xybox=(-20, 40),
xycoords='data',
boxcoords="offset points",
arrowprops=dict(arrowstyle="->"),
bboxprops=dict(boxstyle="sawtooth"))
ax.add_artist(ab)
ab1 = AnnotationBbox(offsetbox, (.5, .5),
xybox=(0, 0),
xycoords=c,
boxcoords="offset points",
arrowprops=dict(arrowstyle="->"),
bboxprops=dict(boxstyle="sawtooth"))
fig.add_artist(ab1)

# Annotate the 1st position with another text box ('Test')
offsetbox = TextArea("Test")
# %%%%
# Images
# ======
# The `.OffsetImage` container supports plotting images. `.OffsetImage` accepts many of
# the same parameters as other image plotting methods, such as *cmap*, *norm*, and
# *interpolation*.

ab = AnnotationBbox(offsetbox, xy,
xybox=(1.02, xy[1]),
xycoords='data',
boxcoords=("axes fraction", "data"),
box_alignment=(0., 0.5),
arrowprops=dict(arrowstyle="->"))
ax.add_artist(ab)

# Define a 2nd position to annotate (don't display with a marker this time)
fig, ax = plt.subplots()
# Define a position to annotate (don't display with a marker)
xy = [0.3, 0.55]

# Annotate the 2nd position with a circle patch
da = DrawingArea(20, 20, 0, 0)
p = Circle((10, 10), 10)
da.add_artist(p)

ab = AnnotationBbox(da, xy,
xybox=(1., xy[1]),
xycoords='data',
boxcoords=("axes fraction", "data"),
box_alignment=(0.2, 0.5),
arrowprops=dict(arrowstyle="->"),
bboxprops=dict(alpha=0.5))

ax.add_artist(ab)

# Annotate the 2nd position with an image (a generated array of pixels)
# Annotate a position with an image generated from an array of pixels
arr = np.arange(100).reshape((10, 10))
im = OffsetImage(arr, zoom=2)
im = OffsetImage(arr, zoom=2, cmap='viridis')
im.image.axes = ax

ab = AnnotationBbox(im, xy,
Expand All @@ -74,10 +77,9 @@
boxcoords="offset points",
pad=0.3,
arrowprops=dict(arrowstyle="->"))

ax.add_artist(ab)

# Annotate the 2nd position with another image (a Grace Hopper portrait)
# Annotate the position with another image (a Grace Hopper portrait)
with get_sample_data("grace_hopper.jpg") as file:
arr_img = plt.imread(file)

Expand All @@ -102,6 +104,38 @@

plt.show()

# %%%%
# Arbitrary Artists
# ================
#
# Multiple and arbitrary artists can be placed inside a `.DrawingArea`.


fig, ax = plt.subplots()
# Define a position to annotate (don't display with a marker)
xy = [0.3, 0.55]

# Annotate the position with a circle and annulus
da = DrawingArea(30, 30, 0, 0)
p = Circle((10, 10), 10, color='C0')
da.add_artist(p)
q = Annulus((20, 20), 10, 5, color='C1')
da.add_artist(q)


# Use the drawing area as an annotation
ab = AnnotationBbox(da, xy,
xybox=(.75, xy[1]),
xycoords='data',
boxcoords=("axes fraction", "data"),
box_alignment=(0.2, 0.5),
arrowprops=dict(arrowstyle="->"),
bboxprops=dict(alpha=0.5))

ax.add_artist(ab)
plt.show()
#

# %%
#
# .. admonition:: References
Expand All @@ -117,3 +151,6 @@
# - `matplotlib.cbook.get_sample_data`
# - `matplotlib.pyplot.subplots`
# - `matplotlib.pyplot.imread`
#
# .. tags::
# component: annotation, styling: position
45 changes: 44 additions & 1 deletion galleries/users_explain/text/annotations.py
Original file line number Diff line number Diff line change
Expand Up @@ -691,11 +691,54 @@ def __call__(self, x0, y0, width, height, mutation_size):

ax.add_artist(anchored_box)
fig.subplots_adjust(top=0.8)

# %%
# Note that, unlike in `.Legend`, the ``bbox_transform`` is set to
# `.IdentityTransform` by default
#
# .. _annotations-bbox:
#
# Using an Artist as an annotation
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# `.AnnotationBbox` uses `.OffsetBox` artists as the annotations and supports
# positioning these annotations in the same was the other annotation methods.
# For more examples, see
# :doc:`/gallery/text_labels_and_annotations/demo_annotation_box`

from matplotlib.offsetbox import AnnotationBbox, DrawingArea, OffsetImage
from matplotlib.patches import Annulus

fig, ax = plt.subplots()

text = ax.text(.2, .8, "Green!", color='green')

da = DrawingArea(20, 20, 0, 0)
annulus = Annulus((10, 10), 10, 5, color='tab:green')
da.add_artist(annulus)

# position annulus relative to text
ab1 = AnnotationBbox(da, (.5, 0),
xybox=(.5, .25),
xycoords=text,
boxcoords=(text, "data"),
arrowprops=dict(arrowstyle="->"),
bboxprops=dict(alpha=0.5))
ax.add_artist(ab1)

N = 25
arr = np.repeat(np.linspace(0, 1, N), N).reshape(N, N)
im = OffsetImage(arr, cmap='Greens')
im.image.axes = ax

# position gradient relative to text and annulus
ab2 = AnnotationBbox(im, xy=(.5, 0),
xybox=(.75, 0),
xycoords=text,
boxcoords=('data', annulus),
arrowprops=dict(arrowstyle="->"),
bboxprops=dict(alpha=0.5))
ax.add_artist(ab2)

# %%%%
# .. _annotating_coordinate_systems:
#
# Coordinate systems for annotations
Expand Down
Loading