Repository: matplotlib/matplotlib
File: galleries/examples/text_labels_and_annotations/demo_annotation_box.py (Python)

Code before:
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")

ab1 = AnnotationBbox(offsetbox, (.5, .5),
                     xybox=(0, 0),
                     xycoords=c,
                     boxcoords="offset points",
                     arrowprops=dict(arrowstyle="->"),
                     bboxprops=dict(boxstyle="sawtooth"))
fig.add_artist(ab1)

# %%%%
# Images
# ======
# The `.OffsetImage` container facilitates using images as annotations


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

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

ab = AnnotationBbox(im, xy,
                    xybox=(-50., 50.),
                    xycoords='data',
                    boxcoords="offset points",
                    pad=0.3,
                    arrowprops=dict(arrowstyle="->"))
ax.add_artist(ab)

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

imagebox = OffsetImage(arr_img, zoom=0.2)
imagebox.image.axes = ax


Review comment (suggestion):
Uh, this is a red herring as this arrow is not visible. And the overall example is a bit tricky: We do not annotate a coordinate location *xycoords*, but an artist, the ConnectionPatch. The annotation has no offset and is thus centered on the artist, which means the annotation arrow has length 0.

To illustrate, if we change to `xybox=(0, 20)`, we get:

<img width="642" height="215" alt="Image" src="https://github.com/user-attachments/assets/eb6ad3a4-bb5e-4b15-be79-22e8085a930f" />


The problematic parts:
- if we want to annotate an artist instead of coordinates, we should explicitly mention that *xycoords* can be an Artist to be annoated.
- annotating a connection patch may lead to confusion as the connection patch itself is an arrow and the AnnotationBox also brings its annotating arrow
- using 0 offset is a special case. Better to show a general case, or at least mention that we do not use an offset and therefore no arrow.

Code after:
fig, axd = plt.subplot_mosaic([['t1', '.', 't2']], layout='compressed')

# Define a 1st position to annotate (display it with a marker)
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 a connection patch 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")

# place the annotation above the midpoint of c
ab1 = AnnotationBbox(offsetbox,
                     xy=(.5, .5),
                     xybox=(0, 30),
                     xycoords=c,
                     boxcoords="offset points",
                     arrowprops=dict(arrowstyle="->"),
                     bboxprops=dict(boxstyle="sawtooth"))
fig.add_artist(ab1)

# %%%%
# Images
# ======
# The `.OffsetImage` container facilitates using images as annotations

fig, ax = plt.subplots()
# Define a position to annotate
xy = (0.3, 0.55)
ax.scatter(*xy, s=200, marker='X')

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

# place the image NW of xy
ab = AnnotationBbox(im, xy=xy,
                    xybox=(-50., 50.),
                    xycoords='data',
                    boxcoords="offset points",
                    pad=0.3,
                    arrowprops=dict(arrowstyle="->"))