注释#

注释是图形元素,通常是文本,用于解释、添加上下文或以其他方式突出显示可视化数据的某个部分。 annotate 支持多种坐标系,以便灵活地定位数据和注释,以及多种用于设置文本样式的选项。 Axes.annotate 还提供从文本到数据的可选箭头,并且此箭头可以以多种方式进行样式设置。 text 也可以用于简单的文本注释,但它在定位和样式设置方面不如 annotate 灵活。

基本标注#

在标注中,需要考虑两个点:被标注数据的xy位置和标注文本的xytext位置。这两个参数都是(x, y)元组

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(figsize=(3, 3))

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = ax.plot(t, s, lw=2)

ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5),
            arrowprops=dict(facecolor='black', shrink=0.05))
ax.set_ylim(-2, 2)
annotations

在这个例子中,xy(箭头尖端)和xytext位置(文本位置)都在数据坐标中。还有多种其他坐标系可以选择——可以使用以下字符串之一为xycoordsxytext指定坐标系(默认值为'data')

参数

坐标系

'figure points'

从图形左下角开始的点

'figure pixels'

图中左下角的像素

'图的比例'

(0, 0) 是图的左下角,(1, 1) 是右上角

'坐标轴点'

从坐标轴左下角开始的点

'坐标轴像素'

从坐标轴左下角开始的像素

'坐标轴比例'

(0, 0) 是坐标轴的左下角,(1, 1) 是右上角

'数据'

使用坐标轴数据坐标系

以下字符串也是 textcoords 的有效参数

参数

坐标系

'偏移点'

从 xy 值偏移(以点为单位)

'偏移像素'

从 xy 值偏移(以像素为单位)

对于物理坐标系(点或像素),原点是图形或坐标轴的左下角。点是 印刷点,这意味着它们是物理单位,测量值为 1/72 英寸。点和像素在 物理坐标系中的绘图 中有更详细的讨论。

对数据进行标注#

此示例将文本坐标放置在分数坐标轴坐标中

fig, ax = plt.subplots(figsize=(3, 3))

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = ax.plot(t, s, lw=2)

ax.annotate('local max', xy=(2, 1), xycoords='data',
            xytext=(0.01, .99), textcoords='axes fraction',
            va='top', ha='left',
            arrowprops=dict(facecolor='black', shrink=0.05))
ax.set_ylim(-2, 2)
annotations

对图形进行标注#

可以通过将该图形作为 xycoords 传递,将注释相对于 Artist 实例进行定位。然后 xy 被解释为图形边界框的一部分。

import matplotlib.patches as mpatches

fig, ax = plt.subplots(figsize=(3, 3))
arr = mpatches.FancyArrowPatch((1.25, 1.5), (1.75, 1.5),
                               arrowstyle='->,head_width=.15', mutation_scale=20)
ax.add_patch(arr)
ax.annotate("label", (.5, .5), xycoords=arr, ha='center', va='bottom')
ax.set(xlim=(1, 2), ylim=(1, 2))
annotations

这里,注释放置在相对于箭头左下角的 (.5,.5) 位置,并且在该位置垂直和水平对齐。垂直方向上,底部与该参考点对齐,因此标签位于线条上方。有关链接注释图形的示例,请参阅 图形部分注释的坐标系

使用箭头进行标注#

可以通过在可选关键字参数 arrowprops 中提供箭头属性的字典,启用从文本到注释点的箭头绘制。

arrowprops

描述

width

箭头宽度(以磅为单位)。

frac

箭头头部占箭头长度的比例。

headwidth

箭头头部底部的宽度(以磅为单位)。

shrink

将箭头尖端和底部从注释点和文本移动一定百分比。

**kwargs

任何matplotlib.patches.Polygon的关键字,例如facecolor

在下面的示例中,xy 点位于数据坐标系中,因为xycoords 默认值为 'data'。对于极坐标轴,它位于 (theta, radius) 空间中。此示例中的文本放置在分数图形坐标系中。matplotlib.text.Text 的关键字参数(如horizontalalignmentverticalalignmentfontsize)从annotate 传递到Text 实例。

fig = plt.figure()
ax = fig.add_subplot(projection='polar')
r = np.arange(0, 1, 0.001)
theta = 2 * 2*np.pi * r
line, = ax.plot(theta, r, color='#ee8d18', lw=3)

ind = 800
thisr, thistheta = r[ind], theta[ind]
ax.plot([thistheta], [thisr], 'o')
ax.annotate('a polar annotation',
            xy=(thistheta, thisr),  # theta, radius
            xytext=(0.05, 0.05),    # fraction, fraction
            textcoords='figure fraction',
            arrowprops=dict(facecolor='black', shrink=0.05),
            horizontalalignment='left',
            verticalalignment='bottom')
annotations

有关使用箭头绘图的更多信息,请参见自定义注释箭头

将文本注释放置在数据相对位置#

通过将textcoords 关键字参数设置为'offset points''offset pixels',可以将注释放置在相对于注释的xy 输入的相对偏移处。

fig, ax = plt.subplots(figsize=(3, 3))
x = [1, 3, 5, 7, 9]
y = [2, 4, 6, 8, 10]
annotations = ["A", "B", "C", "D", "E"]
ax.scatter(x, y, s=20)

for xi, yi, text in zip(x, y, annotations):
    ax.annotate(text,
                xy=(xi, yi), xycoords='data',
                xytext=(1.5, 1.5), textcoords='offset points')
annotations

注释从xy 值偏移 1.5 个点(1.5*1/72 英寸)。

高级注释#

建议在阅读本节之前阅读基本注释text()annotate()

使用方框文本进行标注#

text 接受一个 bbox 关键字参数,它会在文本周围绘制一个方框。

fig, ax = plt.subplots(figsize=(5, 5))
t = ax.text(0.5, 0.5, "Direction",
            ha="center", va="center", rotation=45, size=15,
            bbox=dict(boxstyle="rarrow,pad=0.3",
                      fc="lightblue", ec="steelblue", lw=2))
annotations

参数是方框样式的名称,以及其属性作为关键字参数。目前,已实现以下方框样式:

名称

属性

圆形

circle

pad=0.3

D箭头

darrow

pad=0.3

椭圆形

ellipse

pad=0.3

L箭头

larrow

pad=0.3

R箭头

rarrow

pad=0.3

圆角

round

pad=0.3,rounding_size=None

圆角4

round4

pad=0.3,rounding_size=None

圆齿

roundtooth

pad=0.3,tooth_size=None

锯齿

sawtooth

pad=0.3,tooth_size=None

方形

square

pad=0.3

../../../_images/sphx_glr_fancybox_demo_001.png

与文本关联的补丁对象(方框)可以使用以下方法访问:

bb = t.get_bbox_patch()

返回值是一个 FancyBboxPatch;补丁属性(facecolor、edgewidth 等)可以像往常一样访问和修改。 FancyBboxPatch.set_boxstyle 设置方框形状。

bb.set_boxstyle("rarrow", pad=0.6)

属性参数也可以在样式名称中用逗号分隔。

bb.set_boxstyle("rarrow, pad=0.6")

定义自定义方框样式#

您可以使用自定义方框样式。 boxstyle 的值可以是以下形式的可调用对象。

from matplotlib.path import Path


def custom_box_style(x0, y0, width, height, mutation_size):
    """
    Given the location and size of the box, return the path of the box around
    it. Rotation is automatically taken care of.

    Parameters
    ----------
    x0, y0, width, height : float
       Box location and size.
    mutation_size : float
    Mutation reference scale, typically the text font size.
    """
    # padding
    mypad = 0.3
    pad = mutation_size * mypad
    # width and height with padding added.
    width = width + 2 * pad
    height = height + 2 * pad
    # boundary of the padded box
    x0, y0 = x0 - pad, y0 - pad
    x1, y1 = x0 + width, y0 + height
    # return the new path
    return Path([(x0, y0), (x1, y0), (x1, y1), (x0, y1),
                 (x0-pad, (y0+y1)/2), (x0, y0), (x0, y0)],
                closed=True)

fig, ax = plt.subplots(figsize=(3, 3))
ax.text(0.5, 0.5, "Test", size=30, va="center", ha="center", rotation=30,
        bbox=dict(boxstyle=custom_box_style, alpha=0.2))
annotations

另请参阅 自定义方框样式。类似地,您可以定义自定义 ConnectionStyle 和自定义 ArrowStyle。查看 patches 中的源代码,了解每个类的定义方式。

自定义注释箭头#

通过指定 arrowprops 参数,可以选择绘制连接 xyxytext 的箭头。要只绘制箭头,请使用空字符串作为第一个参数

fig, ax = plt.subplots(figsize=(3, 3))
ax.annotate("",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            arrowprops=dict(arrowstyle="->", connectionstyle="arc3"))
annotations

箭头的绘制方式如下

  1. 根据 connectionstyle 参数创建连接两点的路径。

  2. 如果设置了 patchApatchB,则路径会被裁剪以避免与这两个补丁重叠。

  3. 路径还会根据 shrinkAshrinkB(以像素为单位)进行缩小。

  4. 路径会根据 arrowstyle 参数转换为箭头补丁。

../../../_images/sphx_glr_annotate_explain_001.png

连接两点之间路径的创建由 connectionstyle 键控制,并提供以下样式

名称

属性

angle

angleA=90,angleB=0,rad=0.0

angle3

angleA=90,angleB=0

arc

angleA=0,angleB=0,armA=None,armB=None,rad=0.0

arc3

rad=0.0

bar

armA=0.0,armB=0.0,fraction=0.3,angle=None

请注意,angle3arc3 中的“3”表示生成的路径是二次样条曲线段(三个控制点)。正如将在下面讨论的那样,一些箭头样式选项只能在连接路径为二次样条曲线时使用。

下面的示例演示了每种连接样式的行为(有限制)。(警告:bar 样式的当前行为尚未明确定义,将来可能会更改)。

../../../_images/sphx_glr_connectionstyle_demo_001.png

然后,连接路径(在裁剪和缩小后)会根据给定的 arrowstyle 转换为箭头补丁

名称

属性

-

None

->

head_length=0.4,head_width=0.2

-[

widthB=1.0,lengthB=0.2,angleB=None

|-|

widthA=1.0,widthB=1.0

-|>

head_length=0.4,head_width=0.2

<-

head_length=0.4,head_width=0.2

<->

head_length=0.4,head_width=0.2

<|-

head_length=0.4,head_width=0.2

<|-|>

head_length=0.4,head_width=0.2

fancy

head_length=0.4,head_width=0.4,tail_width=0.4

simple

head_length=0.5,head_width=0.5,tail_width=0.2

wedge

tail_width=0.3,shrink_factor=0.5

../../../_images/sphx_glr_fancyarrow_demo_001.png

一些箭头样式只适用于生成二次样条曲线段的连接样式。它们是 fancysimplewedge。对于这些箭头样式,您必须使用“angle3”或“arc3”连接样式。

如果给出了注释字符串,则补丁默认设置为文本的 bbox 补丁。

fig, ax = plt.subplots(figsize=(3, 3))

ax.annotate("Test",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            size=20, va="center", ha="center",
            arrowprops=dict(arrowstyle="simple",
                            connectionstyle="arc3,rad=-0.2"))
annotations

text 一样,可以使用 bbox 参数在文本周围绘制一个框。

fig, ax = plt.subplots(figsize=(3, 3))

ann = ax.annotate("Test",
                  xy=(0.2, 0.2), xycoords='data',
                  xytext=(0.8, 0.8), textcoords='data',
                  size=20, va="center", ha="center",
                  bbox=dict(boxstyle="round4", fc="w"),
                  arrowprops=dict(arrowstyle="-|>",
                                  connectionstyle="arc3,rad=-0.2",
                                  fc="w"))
annotations

默认情况下,起点设置为文本范围的中心。这可以通过 relpos 键值进行调整。这些值被归一化为文本的范围。例如,(0, 0) 表示左下角,(1, 1) 表示右上角。

fig, ax = plt.subplots(figsize=(3, 3))

ann = ax.annotate("Test",
                  xy=(0.2, 0.2), xycoords='data',
                  xytext=(0.8, 0.8), textcoords='data',
                  size=20, va="center", ha="center",
                  bbox=dict(boxstyle="round4", fc="w"),
                  arrowprops=dict(arrowstyle="-|>",
                                  connectionstyle="arc3,rad=0.2",
                                  relpos=(0., 0.),
                                  fc="w"))

ann = ax.annotate("Test",
                  xy=(0.2, 0.2), xycoords='data',
                  xytext=(0.8, 0.8), textcoords='data',
                  size=20, va="center", ha="center",
                  bbox=dict(boxstyle="round4", fc="w"),
                  arrowprops=dict(arrowstyle="-|>",
                                  connectionstyle="arc3,rad=-0.2",
                                  relpos=(1., 0.),
                                  fc="w"))
annotations

将艺术家放置在锚定坐标轴位置#

有一些艺术家类可以放置在坐标轴的锚定位置。一个常见的例子是图例。这种类型的艺术家可以使用 OffsetBox 类创建。在 matplotlib.offsetboxmpl_toolkits.axes_grid1.anchored_artists 中提供了一些预定义的类。

from matplotlib.offsetbox import AnchoredText

fig, ax = plt.subplots(figsize=(3, 3))
at = AnchoredText("Figure 1a",
                  prop=dict(size=15), frameon=True, loc='upper left')
at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2")
ax.add_artist(at)
annotations

loc 关键字与图例命令中的含义相同。

一个简单的应用是在创建时知道艺术家(或艺术家集合)的大小(以像素为单位)。例如,如果你想绘制一个固定大小为 20 像素 x 20 像素(半径 = 10 像素)的圆,你可以使用 AnchoredDrawingArea。该实例使用绘图区域的大小(以像素为单位)创建,并且可以将任意艺术家添加到绘图区域。请注意,添加到绘图区域的艺术家的范围与绘图区域本身的放置无关。只有初始大小很重要。

添加到绘图区域的艺术家不应该设置变换(它将被覆盖),并且这些艺术家的尺寸被解释为像素坐标,即上面示例中圆的半径分别为 10 像素和 5 像素。

from matplotlib.patches import Circle
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredDrawingArea

fig, ax = plt.subplots(figsize=(3, 3))
ada = AnchoredDrawingArea(40, 20, 0, 0,
                          loc='upper right', pad=0., frameon=False)
p1 = Circle((10, 10), 10)
ada.drawing_area.add_artist(p1)
p2 = Circle((30, 10), 5, fc="r")
ada.drawing_area.add_artist(p2)
ax.add_artist(ada)
annotations

有时,您希望您的艺术家与数据坐标(或除画布像素以外的坐标)一起缩放。您可以使用 AnchoredAuxTransformBox 类。这类似于 AnchoredDrawingArea,只是艺术家的范围在绘制时根据指定的变换确定。

下面示例中的椭圆将具有对应于数据坐标中 0.1 和 0.4 的宽度和高度,并且当 Axes 的视图限制发生变化时会自动缩放。

from matplotlib.patches import Ellipse
from mpl_toolkits.axes_grid1.anchored_artists import AnchoredAuxTransformBox

fig, ax = plt.subplots(figsize=(3, 3))
box = AnchoredAuxTransformBox(ax.transData, loc='upper left')
el = Ellipse((0, 0), width=0.1, height=0.4, angle=30)  # in data coordinates!
box.drawing_area.add_artist(el)
ax.add_artist(box)
annotations

另一种将艺术家相对于父 Axes 或锚点进行锚定的方法是通过 AnchoredOffsetboxbbox_to_anchor 参数。然后可以使用 HPackerVPacker 将此艺术家自动定位到另一个艺术家。

from matplotlib.offsetbox import (AnchoredOffsetbox, DrawingArea, HPacker,
                                  TextArea)

fig, ax = plt.subplots(figsize=(3, 3))

box1 = TextArea(" Test: ", textprops=dict(color="k"))
box2 = DrawingArea(60, 20, 0, 0)

el1 = Ellipse((10, 10), width=16, height=5, angle=30, fc="r")
el2 = Ellipse((30, 10), width=16, height=5, angle=170, fc="g")
el3 = Ellipse((50, 10), width=16, height=5, angle=230, fc="b")
box2.add_artist(el1)
box2.add_artist(el2)
box2.add_artist(el3)

box = HPacker(children=[box1, box2],
              align="center",
              pad=0, sep=5)

anchored_box = AnchoredOffsetbox(loc='lower left',
                                 child=box, pad=0.,
                                 frameon=True,
                                 bbox_to_anchor=(0., 1.02),
                                 bbox_transform=ax.transAxes,
                                 borderpad=0.,)

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

请注意,与 Legend 不同,bbox_transform 默认情况下设置为 IdentityTransform

注释的坐标系#

Matplotlib 注释支持多种类型的坐标系。 基本注释 中的示例使用了 data 坐标系;一些其他更高级的选项是

Transform 实例#

将地图坐标转换为不同的坐标系,通常是显示坐标系。有关详细说明,请参见 变换教程。这里,Transform 对象用于识别相应点的坐标系。例如,Axes.transAxes 变换将注释相对于 Axes 坐标定位;因此,使用它等同于将坐标系设置为“axes fraction”。

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3))
ax1.annotate("Test", xy=(0.2, 0.2), xycoords=ax1.transAxes)
ax2.annotate("Test", xy=(0.2, 0.2), xycoords="axes fraction")
annotations

另一个常用的 Transform 实例是 Axes.transData。此变换是 Axes 中绘制数据的坐标系。在本例中,它用于在两个 Axes 中的相关数据点之间绘制箭头。我们传递了一个空文本,因为在这种情况下,注释连接数据点。

x = np.linspace(-1, 1)

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3))
ax1.plot(x, -x**3)
ax2.plot(x, -3*x**2)
ax2.annotate("",
             xy=(0, 0), xycoords=ax1.transData,
             xytext=(0, 0), textcoords=ax2.transData,
             arrowprops=dict(arrowstyle="<->"))
annotations

Artist 实例#

xy 值(或 xytext)被解释为艺术家(在本例中为 an1)的边界框 (bbox) 的分数坐标。

fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(3, 3))
an1 = ax.annotate("Test 1",
                  xy=(0.5, 0.5), xycoords="data",
                  va="center", ha="center",
                  bbox=dict(boxstyle="round", fc="w"))

an2 = ax.annotate("Test 2",
                  xy=(1, 0.5), xycoords=an1,  # (1, 0.5) of an1's bbox
                  xytext=(30, 0), textcoords="offset points",
                  va="center", ha="left",
                  bbox=dict(boxstyle="round", fc="w"),
                  arrowprops=dict(arrowstyle="->"))
annotations

请注意,您必须确保在绘制 an2 之前确定坐标艺术家 (an1 在本例中) 的范围。通常,这意味着 an2 需要在 an1 之后绘制。所有边界框的基类是 BboxBase

返回 Transform 的可调用对象 BboxBase#

一个可调用对象,它将渲染器实例作为单个参数,并返回一个 Transform 或一个 BboxBase。例如,Artist.get_window_extent 的返回值是一个 bbox,因此此方法与 (2) 传递艺术家相同。

fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(3, 3))
an1 = ax.annotate("Test 1",
                  xy=(0.5, 0.5), xycoords="data",
                  va="center", ha="center",
                  bbox=dict(boxstyle="round", fc="w"))

an2 = ax.annotate("Test 2",
                  xy=(1, 0.5), xycoords=an1.get_window_extent,
                  xytext=(30, 0), textcoords="offset points",
                  va="center", ha="left",
                  bbox=dict(boxstyle="round", fc="w"),
                  arrowprops=dict(arrowstyle="->"))
annotations

Artist.get_window_extent 是 Axes 对象的边界框,因此与将坐标系设置为轴分数相同

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3))

an1 = ax1.annotate("Test1", xy=(0.5, 0.5), xycoords="axes fraction")
an2 = ax2.annotate("Test 2", xy=(0.5, 0.5), xycoords=ax2.get_window_extent)
annotations

混合坐标规范#

一对混合的坐标规范 - 第一个用于 x 坐标,第二个用于 y 坐标。例如,x=0.5 位于数据坐标中,而 y=1 位于归一化轴坐标中

fig, ax = plt.subplots(figsize=(3, 3))
ax.annotate("Test", xy=(0.5, 1), xycoords=("data", "axes fraction"))
ax.axvline(x=.5, color='lightgray')
ax.set(xlim=(0, 2), ylim=(1, 2))
annotations

任何支持的坐标系都可以在混合规范中使用。例如,文本“锚定到 1 和 2”相对于两个 Text 艺术家

fig, ax = plt.subplots(figsize=(3, 3))

t1 = ax.text(0.05, .05, "Text 1", va='bottom', ha='left')
t2 = ax.text(0.90, .90, "Text 2", ha='right')
t3 = ax.annotate("Anchored to 1 & 2", xy=(0, 0), xycoords=(t1, t2),
                 va='bottom', color='tab:orange',)
annotations

text.OffsetFrom#

有时,您希望您的注释带有某些“偏移点”,而不是来自注释点,而是来自其他点或艺术家。 text.OffsetFrom 是此类情况的帮助程序。

from matplotlib.text import OffsetFrom

fig, ax = plt.subplots(figsize=(3, 3))
an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data",
                  va="center", ha="center",
                  bbox=dict(boxstyle="round", fc="w"))

offset_from = OffsetFrom(an1, (0.5, 0))
an2 = ax.annotate("Test 2", xy=(0.1, 0.1), xycoords="data",
                  xytext=(0, -10), textcoords=offset_from,
                  # xytext is offset points from "xy=(0.5, 0), xycoords=an1"
                  va="top", ha="center",
                  bbox=dict(boxstyle="round", fc="w"),
                  arrowprops=dict(arrowstyle="->"))
annotations

非文本注释#

使用 ConnectionPatch#

ConnectionPatch 就像没有文本的注释。虽然 annotate 在大多数情况下都足够了,但 ConnectionPatch 在您想连接不同 Axes 中的点时很有用。例如,这里我们将 ax1 的数据坐标中的点 xy 连接到 ax2 的数据坐标中的点 xy

from matplotlib.patches import ConnectionPatch

fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3))
xy = (0.3, 0.2)
con = ConnectionPatch(xyA=xy, coordsA=ax1.transData,
                      xyB=xy, coordsB=ax2.transData)

fig.add_artist(con)
annotations

这里,我们将 ConnectionPatch 添加到 figure(使用 add_artist)而不是添加到任何 Axes。这确保了 ConnectionPatch 艺术家绘制在两个 Axes 之上,并且在使用 constrained_layout 定位 Axes 时也是必需的。

Axes 之间的缩放效果#

mpl_toolkits.axes_grid1.inset_locator 定义了一些用于互连两个 Axes 的补丁类。

../../../_images/sphx_glr_axes_zoom_effect_001.png

此图形的代码位于 Axes 缩放效果,建议熟悉 变换教程

脚本的总运行时间:(0 分钟 4.488 秒)

由 Sphinx-Gallery 生成的画廊