Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c9468c1

Browse files
story645jklymaktimhoffmQuLogic
committed
added offset section and restructured annotations tutorial and reworked
AnchoredOffsetbox section also minor consistency and linking tweaks throughout Co-authored-by: Jody Klymak <[email protected]> Co-authored-by: Tim Hoffmann <[email protected]> Co-authored-by: Elliott Sales de Andrade <[email protected]>
1 parent a68f21f commit c9468c1

File tree

1 file changed

+142
-83
lines changed

1 file changed

+142
-83
lines changed

tutorials/text/annotations.py

Lines changed: 142 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -47,22 +47,46 @@
4747
# 'data' use the axes data coordinate system
4848
# ================== ========================================================
4949
#
50-
# For example to place the text coordinates in fractional axes
51-
# coordinates, one could do::
50+
# The following strings are also valid arguments for *textcoords*
5251
#
53-
# ax.annotate('local max', xy=(3, 1), xycoords='data',
54-
# xytext=(0.8, 0.95), textcoords='axes fraction',
55-
# arrowprops=dict(facecolor='black', shrink=0.05),
56-
# horizontalalignment='right', verticalalignment='top',
57-
# )
52+
# ================== ========================================================
53+
# argument coordinate system
54+
# ================== ========================================================
55+
# 'offset points' offset (in points) from the xy value
56+
# 'offset pixels' offset (in pixels) from the xy value
57+
# ================== ========================================================
5858
#
5959
# For physical coordinate systems (points or pixels) the origin is the
60-
# bottom-left of the figure or axes.
60+
# bottom-left of the figure or axes. Points are
61+
# `typographic points <https://en.wikipedia.org/wiki/Point_(typography)>`_
62+
# meaning that they are a physical unit measuring 1/72 of an inch. Points and
63+
# pixels are discussed in further detail in :ref:`transforms-fig-scale-dpi`.
6164
#
62-
# Optionally, you can enable drawing of an arrow from the text to the annotated
63-
# point by giving a dictionary of arrow properties in the optional keyword
64-
# argument *arrowprops*.
65+
# .. _annotation-data:
66+
#
67+
# Annotating data
68+
# ~~~~~~~~~~~~~~~
69+
#
70+
# For example to place the text coordinates in fractional axes
71+
# coordinates, one could do :
72+
73+
fig, ax = plt.subplots()
74+
ax.scatter(3, 1, s=20)
75+
ax.annotate('local max',
76+
xy=(3, 1), xycoords='data',
77+
xytext=(0.8, 0.95), textcoords='axes fraction',
78+
horizontalalignment='right', verticalalignment='top')
79+
80+
###################################################################
81+
#
82+
# .. _annotation-with-arrow:
83+
#
84+
# Annotating with arrows
85+
# ~~~~~~~~~~~~~~~~~~~~~~
6586
#
87+
# You can enable drawing of an arrow from the text to the annotated point
88+
# by giving a dictionary of arrow properties in the optional keyword
89+
# argument *arrowprops*.
6690
#
6791
# ==================== =====================================================
6892
# *arrowprops* key description
@@ -77,10 +101,9 @@
77101
# e.g., ``facecolor``
78102
# ==================== =====================================================
79103
#
80-
#
81-
# In the example below, the *xy* point is in native coordinates
82-
# (*xycoords* defaults to 'data'). For a polar axes, this is in
83-
# (theta, radius) space. The text in this example is placed in the
104+
# In the example below, the *xy* point is in the data coordinate system
105+
# since *xycoords* defaults to 'data'. For a polar axes, this is in
106+
# (theta, radius) space. The text in this example is placed in the
84107
# fractional figure coordinate system. :class:`matplotlib.text.Text`
85108
# keyword arguments like *horizontalalignment*, *verticalalignment* and
86109
# *fontsize* are passed from `~matplotlib.axes.Axes.annotate` to the
@@ -94,18 +117,38 @@
94117
# annotations, including fancy arrows, see :ref:`plotting-guide-annotation`
95118
# and :doc:`/gallery/text_labels_and_annotations/annotation_demo`.
96119
#
120+
# .. _annotations-offset-text:
97121
#
98-
# Do not proceed unless you have already read :ref:`annotations-tutorial`,
99-
# :func:`~matplotlib.pyplot.text` and :func:`~matplotlib.pyplot.annotate`!
100-
#
122+
# Placing text annotations relative to data
123+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
124+
# Annotations can be positioned at a relative offset to the *xy* input to
125+
# annotation by setting the *textcoords* keyword argument to 'offset points' or
126+
# 'offset pixels'.
127+
128+
fig, ax = plt.subplots()
129+
x = [1, 3, 5, 7, 9]
130+
y = [2, 4, 6, 8, 10]
131+
annotations = ["A", "B", "C", "D", "E"]
132+
ax.scatter(x, y, s=20)
133+
134+
for xi, yi, text in zip(x, y, annotations):
135+
ax.annotate(text,
136+
xy=(xi, yi), xycoords='data',
137+
xytext=(1.5, 1.5), textcoords='offset points')
138+
139+
###############################################################################
140+
# The annotations are offset 1.5 points (1.5*1/72 inches) from the *xy* values.
101141
#
102142
# .. _plotting-guide-annotation:
103143
#
104-
# Advanced Annotations
105-
# --------------------
144+
# Advanced annotation
145+
# -------------------
106146
#
107-
# Annotating with Text with Box
108-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
147+
# We recommend reading :ref:`annotations-tutorial`, :func:`~matplotlib.pyplot.text`
148+
# and :func:`~matplotlib.pyplot.annotate` before reading this section.
149+
#
150+
# Annotating with boxed text
151+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
109152
#
110153
# Let's start with a simple example.
111154
#
@@ -116,9 +159,9 @@
116159
# `~.Axes.text` takes a *bbox* keyword argument, which draws a box around the
117160
# text::
118161
#
119-
# t = ax.text(
120-
# 0, 0, "Direction", ha="center", va="center", rotation=45, size=15,
121-
# bbox=dict(boxstyle="rarrow,pad=0.3", fc="cyan", ec="b", lw=2))
162+
# t = ax.text(0, 0, "Direction",
163+
# ha="center", va="center", rotation=45, size=15,
164+
# bbox=dict(boxstyle="rarrow,pad=0.3", fc="cyan", ec="b", lw=2))
122165
#
123166
# The patch object associated with the text can be accessed by::
124167
#
@@ -155,17 +198,16 @@
155198
# name with separating comma (this form can be used as "boxstyle" value
156199
# of bbox argument when initializing the text instance) ::
157200
#
158-
# bb.set_boxstyle("rarrow,pad=0.6")
201+
# bb.set_boxstyle("rarrow, pad=0.6")
159202
#
160-
# Annotating with Arrow
161-
# ~~~~~~~~~~~~~~~~~~~~~
203+
# Customizing annotation arrows
204+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
162205
#
163206
# `~.Axes.annotate` draws an arrow connecting two points in an Axes::
164207
#
165208
# ax.annotate("Annotation",
166209
# xy=(x1, y1), xycoords='data',
167-
# xytext=(x2, y2), textcoords='offset points',
168-
# )
210+
# xytext=(x2, y2), textcoords='offset points')
169211
#
170212
# This annotates a point at *xy* in the given coordinate (*xycoords*)
171213
# with the text at *xytext* given in *textcoords*. Often, the
@@ -180,9 +222,7 @@
180222
# ax.annotate("",
181223
# xy=(0.2, 0.2), xycoords='data',
182224
# xytext=(0.8, 0.8), textcoords='data',
183-
# arrowprops=dict(arrowstyle="->",
184-
# connectionstyle="arc3"),
185-
# )
225+
# arrowprops=dict(arrowstyle="->", connectionstyle="arc3"))
186226
#
187227
# .. figure:: ../../gallery/userdemo/images/sphx_glr_annotate_simple01_001.png
188228
# :target: ../../gallery/userdemo/annotate_simple01.html
@@ -292,8 +332,8 @@
292332
from matplotlib.offsetbox import AnchoredText
293333

294334
fig, ax = plt.subplots()
295-
at = AnchoredText(
296-
"Figure 1a", prop=dict(size=15), frameon=True, loc='upper left')
335+
at = AnchoredText("Figure 1a",
336+
prop=dict(size=15), frameon=True, loc='upper left')
297337
at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
298338
ax.add_artist(at)
299339

@@ -348,19 +388,64 @@
348388
ax.add_artist(box)
349389

350390
###############################################################################
351-
# As in the legend, the bbox_to_anchor argument can be set. Using the
352-
# HPacker and VPacker, you can have an arrangement(?) of artist as in the
353-
# legend (as a matter of fact, this is how the legend is created).
391+
# Another method of anchoring an artist relative to a parent axes or anchor
392+
# point is via the *bbox_to_anchor* argument of `.AnchoredOffsetbox`. This
393+
# artist can then be automatically positioned relative to another artist using
394+
# `.HPacker` and `.VPacker`. ::
395+
#
396+
# from matplotlib.offsetbox import (AnchoredOffsetbox, DrawingArea, HPacker,
397+
# TextArea)
398+
#
399+
# box1 = TextArea(" Test: ", textprops=dict(color="k"))
400+
# box2 = DrawingArea(60, 20, 0, 0)
401+
# # see gallery example for ellipse drawing code
402+
# box = HPacker(children=[box1, box2], align="center", pad=0, sep=5)
403+
# anchored_box = AnchoredOffsetbox(loc='lower left', child=box, pad=0.,
404+
# frameon=True, borderpad=0.,
405+
# bbox_to_anchor=(0., 1.02),
406+
# bbox_transform=ax.transAxes)
354407
#
355408
# .. figure:: ../../gallery/userdemo/images/sphx_glr_anchored_box04_001.png
356409
# :target: ../../gallery/userdemo/anchored_box04.html
357410
# :align: center
358411
#
359-
# Note that unlike the legend, the ``bbox_transform`` is set
360-
# to IdentityTransform by default.
412+
# Note that, unlike in `.Legend`, the ``bbox_transform`` is set to
413+
# IdentityTransform by default. The full example can be found at
414+
# :doc:`/gallery/userdemo/anchored_box04`.
361415
#
362-
# Coordinate systems for Annotations
363-
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
416+
# Defining custom box styles
417+
# ~~~~~~~~~~~~~~~~~~~~~~~~~~
418+
#
419+
# You can use a custom box style. The value for the ``boxstyle`` can be a
420+
# callable object in the following forms. ::
421+
#
422+
# def __call__(self, x0, y0, width, height, mutation_size,
423+
# aspect_ratio=1.):
424+
# '''
425+
# Given the location and size of the box, return the path of
426+
# the box around it.
427+
#
428+
# - *x0*, *y0*, *width*, *height* : location and size of the box
429+
# - *mutation_size* : a reference scale for the mutation.
430+
# - *aspect_ratio* : aspect-ratio for the mutation.
431+
# '''
432+
# path = ...
433+
# return path
434+
#
435+
# Here is a complete example.
436+
#
437+
# .. figure:: ../../gallery/userdemo/images/sphx_glr_custom_boxstyle01_001.png
438+
# :target: ../../gallery/userdemo/custom_boxstyle01.html
439+
# :align: center
440+
#
441+
# Similarly, you can define a custom `.ConnectionStyle` and a custom
442+
# `.ArrowStyle`. View the source code at `.patches` to learn how each class
443+
# is defined.
444+
#
445+
# .. _annotating_coordinate_systems:
446+
#
447+
# Coordinate systems for annotations
448+
# ----------------------------------
364449
#
365450
# Matplotlib Annotations support several types of coordinates. Some are
366451
# described in :ref:`annotations-tutorial`; more advanced options are
@@ -376,18 +461,22 @@
376461
# This allows annotating a point in another axes::
377462
#
378463
# fig, (ax1, ax2) = plt.subplots(1, 2)
379-
# ax2.annotate("Test", xy=(0.5, 0.5), xycoords=ax1.transData,
464+
# ax2.annotate("Test",
465+
# xy=(0.5, 0.5), xycoords=ax1.transData,
380466
# xytext=(0.5, 0.5), textcoords=ax2.transData,
381467
# arrowprops=dict(arrowstyle="->"))
382468
#
383469
# 2. An `.Artist` instance. The *xy* value (or *xytext*) is interpreted as a
384470
# fractional coordinate of the bbox (return value of *get_window_extent*) of
385-
# the artist::
471+
# the artist: ::
386472
#
387-
# an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data",
473+
# an1 = ax.annotate("Test 1",
474+
# xy=(0.5, 0.5), xycoords="data",
388475
# va="center", ha="center",
389476
# bbox=dict(boxstyle="round", fc="w"))
390-
# an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1, # (1, 0.5) of the an1's bbox
477+
#
478+
# an2 = ax.annotate("Test 2",
479+
# xy=(1, 0.5), xycoords=an1, # (1, 0.5) of the an1's bbox
391480
# xytext=(30, 0), textcoords="offset points",
392481
# va="center", ha="left",
393482
# bbox=dict(boxstyle="round", fc="w"),
@@ -405,12 +494,14 @@
405494
# returns either a `.Transform` or a `.BboxBase`. The return value is then
406495
# handled as in (1), for transforms, or in (2), for bboxes. For example, ::
407496
#
408-
# an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1,
497+
# an2 = ax.annotate("Test 2",
498+
# xy=(1, 0.5), xycoords=an1,
409499
# xytext=(30, 0), textcoords="offset points")
410500
#
411501
# is identical to::
412502
#
413-
# an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1.get_window_extent,
503+
# an2 = ax.annotate("Test 2",
504+
# xy=(1, 0.5), xycoords=an1.get_window_extent,
414505
# xytext=(30, 0), textcoords="offset points")
415506
#
416507
# 4. A pair of coordinate specifications -- the first for the x-coordinate, and
@@ -434,18 +525,18 @@
434525
# :target: ../../gallery/userdemo/annotate_simple_coord03.html
435526
# :align: center
436527
#
437-
# You may take a look at this example
528+
# This example can be found at
438529
# :doc:`/gallery/text_labels_and_annotations/annotation_demo`.
439530
#
440531
# Using ConnectionPatch
441532
# ~~~~~~~~~~~~~~~~~~~~~
442533
#
443534
# ConnectionPatch is like an annotation without text. While `~.Axes.annotate`
444-
# is sufficient in most situations, ConnectionPatch is useful when you want to
535+
# is sufficient in most situations, `.ConnectionPatch` is useful when you want to
445536
# connect points in different axes. ::
446537
#
447538
# from matplotlib.patches import ConnectionPatch
448-
# xy = (0.2, 0.2)
539+
# xy = (0.3, 0.2)
449540
# con = ConnectionPatch(xyA=xy, coordsA=ax1.transData,
450541
# xyB=xy, coordsB=ax2.transData)
451542
# fig.add_artist(con)
@@ -462,9 +553,6 @@
462553
# and is also necessary if using :doc:`constrained_layout
463554
# </tutorials/intermediate/constrainedlayout_guide>` for positioning the axes.
464555
#
465-
# Advanced Topics
466-
# ---------------
467-
#
468556
# Zoom effect between Axes
469557
# ~~~~~~~~~~~~~~~~~~~~~~~~
470558
#
@@ -475,32 +563,3 @@
475563
# .. figure:: ../../gallery/subplots_axes_and_figures/images/sphx_glr_axes_zoom_effect_001.png
476564
# :target: ../../gallery/subplots_axes_and_figures/axes_zoom_effect.html
477565
# :align: center
478-
#
479-
# Define Custom BoxStyle
480-
# ~~~~~~~~~~~~~~~~~~~~~~
481-
#
482-
# You can use a custom box style. The value for the ``boxstyle`` can be a
483-
# callable object in the following forms.::
484-
#
485-
# def __call__(self, x0, y0, width, height, mutation_size,
486-
# aspect_ratio=1.):
487-
# '''
488-
# Given the location and size of the box, return the path of
489-
# the box around it.
490-
#
491-
# - *x0*, *y0*, *width*, *height* : location and size of the box
492-
# - *mutation_size* : a reference scale for the mutation.
493-
# - *aspect_ratio* : aspect-ratio for the mutation.
494-
# '''
495-
# path = ...
496-
# return path
497-
#
498-
# Here is a complete example.
499-
#
500-
# .. figure:: ../../gallery/userdemo/images/sphx_glr_custom_boxstyle01_001.png
501-
# :target: ../../gallery/userdemo/custom_boxstyle01.html
502-
# :align: center
503-
#
504-
# Similarly, you can define a custom ConnectionStyle and a custom ArrowStyle.
505-
# See the source code of ``lib/matplotlib/patches.py`` and check
506-
# how each style class is defined.

0 commit comments

Comments
 (0)