Annotationen#

Annotationen sind grafische Elemente, oft Textstücke, die einen Teil der visualisierten Daten erklären, Kontext hinzufügen oder anderweitig hervorheben. annotate unterstützt eine Reihe von Koordinatensystemen für die flexible Positionierung von Daten und Annotationen relativ zueinander sowie eine Vielzahl von Optionen für das Styling des Textes. Axes.annotate bietet auch einen optionalen Pfeil vom Text zu den Daten, und dieser Pfeil kann auf verschiedene Weise gestylt werden. text kann auch für einfache Textannotationen verwendet werden, bietet aber nicht so viel Flexibilität bei der Positionierung und dem Styling wie annotate.

Grundlegende Annotation#

Bei einer Annotation gibt es zwei zu berücksichtigende Punkte: den Ort der annotierten Daten, *xy*, und den Ort des Annotationstextes, *xytext*. Beide Argumente sind Tupel vom Typ (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

In diesem Beispiel befinden sich sowohl der *xy*-Punkt (Pfeilspitze) als auch die *xytext*-Position (Textposition) in Datenkoordinaten. Es gibt eine Vielzahl anderer Koordinatensysteme, aus denen Sie wählen können – Sie können das Koordinatensystem von *xy* und *xytext* mit einem der folgenden Strings für *xycoords* und *textcoords* angeben (Standard ist 'data')

Argument

Koordinatensystem

'figure points'

Punkte vom linken unteren Rand der Abbildung

'figure pixels'

Pixel vom linken unteren Rand der Abbildung

'figure fraction'

(0, 0) ist unten links in der Abbildung und (1, 1) ist oben rechts

'axes points'

Punkte vom linken unteren Rand der Achsen

'axes pixels'

Pixel vom linken unteren Rand der Achsen

'axes fraction'

(0, 0) ist unten links in den Achsen und (1, 1) ist oben rechts

'data'

verwendet das Datenkoordinatensystem der Achsen

Die folgenden Strings sind auch gültige Argumente für *textcoords*

Argument

Koordinatensystem

'offset points'

Offset (in Punkten) vom xy-Wert

'offset pixels'

Offset (in Pixeln) vom xy-Wert

Für physikalische Koordinatensysteme (Punkte oder Pixel) ist der Ursprung die untere linke Ecke der Abbildung oder der Achsen. Punkte sind typografische Punkte, was bedeutet, dass sie eine physikalische Einheit von 1/72 Zoll messen. Punkte und Pixel werden im Detail diskutiert in Zeichnen in physikalischen Koordinaten.

Daten annotieren#

Dieses Beispiel platziert die Textkoordinaten in fraktionellen Achsenkoordinaten

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

Einen Künstler annotieren#

Annotationen können relativ zu einer Artist-Instanz positioniert werden, indem dieser Künstler als *xycoords* übergeben wird. Dann wird *xy* als Bruchteil der Bounding Box des Künstlers interpretiert.

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

Hier ist die Annotation am Punkt (.5,.5) relativ zur unteren linken Ecke des Pfeils positioniert und befindet sich vertikal und horizontal an dieser Position. Vertikal ist unten an diesem Referenzpunkt ausgerichtet, sodass die Beschriftung über der Linie liegt. Ein Beispiel für die Verkettung von Annotationskünstlern finden Sie im Abschnitt Künstler von Koordinatensysteme für Annotationen.

Mit Pfeilen annotieren#

Sie können das Zeichnen eines Pfeils vom Text zum annotierten Punkt aktivieren, indem Sie ein Wörterbuch mit Pfeileigenschaften im optionalen Schlüsselwortargument *arrowprops* angeben.

*arrowprops*-Schlüssel

Beschreibung

width

die Breite des Pfeils in Punkten

frac

der Anteil der Pfeillänge, der vom Kopf eingenommen wird

headwidth

die Breite der Basis des Pfeilkopfes in Punkten

shrink

verschiebt Spitze und Basis um einen bestimmten Prozentsatz vom annotierten Punkt und Text weg

**kwargs

beliebiger Schlüssel für matplotlib.patches.Polygon, z.B. facecolor

Im folgenden Beispiel befindet sich der *xy*-Punkt im Datenkoordinatensystem, da *xycoords* standardmäßig auf 'data' gesetzt ist. Für eine polare Achse ist dies im (theta, Radius)-Raum. Der Text in diesem Beispiel wird im fraktionellen Abbildungskoordinatensystem platziert. matplotlib.text.Text Schlüsselwortargumente wie *horizontalalignment*, *verticalalignment* und *fontsize* werden von annotate an die Text-Instanz übergeben.

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

Weitere Informationen zum Zeichnen mit Pfeilen finden Sie unter Benutzerdefinierte Annotation-Pfeile

Textannotationen relativ zu Daten platzieren#

Annotationen können mit einem relativen Offset zum *xy*-Eingang der Annotation platziert werden, indem das Schlüsselwortargument *textcoords* auf 'offset points' oder 'offset pixels' gesetzt wird.

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

Die Annotationen sind 1,5 Punkte (1,5 * 1/72 Zoll) von den *xy*-Werten versetzt.

Erweiterte Annotation#

Wir empfehlen, Grundlegende Annotation, text() und annotate() zu lesen, bevor Sie diesen Abschnitt lesen.

Mit annotiertem Text#

text nimmt ein Schlüsselwortargument *bbox*, das eine Box um den Text zeichnet

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

Die Argumente sind der Name des Box-Stils mit seinen Attributen als Schlüsselwortargumente. Derzeit sind die folgenden Box-Stile implementiert

Klasse

Name

Attribute

Circle

circle

pad=0.3

DArrow

darrow

pad=0.3

Ellipse

ellipse

pad=0.3

LArrow

larrow

pad=0.3

RArrow

rarrow

pad=0.3

Round

round

pad=0.3,rounding_size=None

Round4

round4

pad=0.3,rounding_size=None

Roundtooth

roundtooth

pad=0.3,tooth_size=None

Sawtooth

sawtooth

pad=0.3,tooth_size=None

Square

square

pad=0.3

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

Das Patch-Objekt (Box), das dem Text zugeordnet ist, kann über

bb = t.get_bbox_patch()

Der Rückgabewert ist ein FancyBboxPatch; Patch-Eigenschaften (facecolor, edgewidth usw.) können wie üblich abgerufen und geändert werden. FancyBboxPatch.set_boxstyle setzt die Boxform

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

Die Attributargumente können auch innerhalb des Stilnamens mit trennendem Komma angegeben werden

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

Benutzerdefinierte Box-Stile definieren#

Benutzerdefinierte Box-Stile können als Funktion implementiert werden, die Argumente entgegennimmt, die sowohl eine rechteckige Box als auch das Ausmaß der "Mutation" angeben, und den "mutierten" Pfad zurückgibt. Die spezifische Signatur ist die von custom_box_style unten.

Hier geben wir einen neuen Pfad zurück, der eine "Pfeil"-Form links von der Box hinzufügt.

Der benutzerdefinierte Box-Stil kann dann verwendet werden, indem bbox=dict(boxstyle=custom_box_style, ...) an Axes.text übergeben wird.

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

Ebenso können benutzerdefinierte Box-Stile als Klassen implementiert werden, die __call__ implementieren.

Die Klassen können dann in das Wörterbuch BoxStyle._style_list registriert werden, was die Angabe des Box-Stils als String ermöglicht: bbox=dict(boxstyle="registered_name,param=value,...", ...). Beachten Sie, dass diese Registrierung auf internen APIs beruht und daher nicht offiziell unterstützt wird.

from matplotlib.patches import BoxStyle


class MyStyle:
    """A simple box."""

    def __init__(self, pad=0.3):
        """
        The arguments must be floats and have default values.

        Parameters
        ----------
        pad : float
            amount of padding
        """
        self.pad = pad
        super().__init__()

    def __call__(self, 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
            Reference scale for the mutation, typically the text font size.
        """
        # padding
        pad = mutation_size * self.pad
        # 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)


BoxStyle._style_list["angled"] = MyStyle  # Register the custom style.

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="angled,pad=0.5", alpha=0.2))

del BoxStyle._style_list["angled"]  # Unregister it.
annotations

Ähnlich können Sie einen benutzerdefinierten ConnectionStyle und einen benutzerdefinierten ArrowStyle definieren. Sehen Sie sich den Quellcode unter patches an, um zu erfahren, wie jede Klasse definiert ist.

Annotation-Pfeile anpassen#

Ein Pfeil, der *xy* mit *xytext* verbindet, kann optional gezeichnet werden, indem das Argument *arrowprops* angegeben wird. Um nur einen Pfeil zu zeichnen, verwenden Sie einen leeren String als erstes Argument

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

Der Pfeil wird wie folgt gezeichnet

  1. Ein Pfad, der die beiden Punkte verbindet, wird erstellt, wie durch den Parameter *connectionstyle* angegeben.

  2. Der Pfad wird beschnitten, um die Patches *patchA* und *patchB* zu vermeiden, falls diese gesetzt sind.

  3. Der Pfad wird weiter um *shrinkA* und *shrinkB* (in Pixeln) geschrumpft.

  4. Der Pfad wird zu einem Pfeil-Patch transformiert, wie durch den Parameter *arrowstyle* angegeben.

(2x.png, png)

Die Erstellung des Verbindungspfades zwischen zwei Punkten wird durch den Schlüssel connectionstyle gesteuert und die folgenden Stile sind verfügbar

Name

Attribute

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

Beachten Sie, dass "3" in angle3 und arc3 bedeutet, dass der resultierende Pfad ein quadratisches Spline-Segment ist (drei Kontrollpunkte). Wie unten erläutert wird, können einige Pfeilstiloptionen nur verwendet werden, wenn der Verbindungspfad ein quadratischer Spline ist.

Das Verhalten jedes Verbindungsstils wird im folgenden Beispiel (begrenzt) demonstriert. (Warnung: Das Verhalten des bar-Stils ist derzeit nicht gut definiert und könnte in Zukunft geändert werden).

(Quellcode, 2x.png, png)

Verbindungsstile für Annotationen

Der Verbindungspfad (nach dem Beschneiden und Schrumpfen) wird dann in ein Pfeil-Patch umgewandelt, entsprechend dem angegebenen arrowstyle

Name

Attribute

-

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

Einige Pfeilstile funktionieren nur mit Verbindungsstilen, die ein quadratisches Spline-Segment erzeugen. Dies sind fancy, simple und wedge. Für diese Pfeilstile müssen Sie den Verbindungsstil "angle3" oder "arc3" verwenden.

Wenn der Annotationsstring angegeben ist, wird das Patch standardmäßig auf das Bbox-Patch des Textes gesetzt.

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

Wie bei text kann mit dem Argument *bbox* eine Box um den Text gezeichnet werden.

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

Standardmäßig ist der Startpunkt auf die Mitte der Textausdehnung gesetzt. Dies kann mit dem Schlüsselwert relpos angepasst werden. Die Werte werden auf die Ausdehnung des Textes normalisiert. Zum Beispiel bedeutet (0, 0) die untere linke Ecke und (1, 1) die obere rechte Ecke.

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

Künstler an verankerten Achsenpositionen platzieren#

Es gibt Künstlerklassen, die an einer verankerten Position in den Achsen platziert werden können. Ein gängiges Beispiel ist die Legende. Diese Art von Künstler kann durch die Verwendung der Klasse OffsetBox erstellt werden. Einige vordefinierte Klassen sind in matplotlib.offsetbox und in mpl_toolkits.axes_grid1.anchored_artists verfügbar.

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

Der Schlüssel *loc* hat die gleiche Bedeutung wie im Legendenbefehl.

Eine einfache Anwendung ist, wenn die Größe des Künstlers (oder der Sammlung von Künstlern) zum Zeitpunkt der Erstellung in Pixelgröße bekannt ist. Wenn Sie beispielsweise einen Kreis mit einer festen Größe von 20 Pixel x 20 Pixel (Radius = 10 Pixel) zeichnen möchten, können Sie AnchoredDrawingArea verwenden. Die Instanz wird mit der Größe des Zeichenbereichs (in Pixeln) erstellt, und beliebige Künstler können zum Zeichenbereich hinzugefügt werden. Beachten Sie, dass die Ausdehnungen der zum Zeichenbereich hinzugefügten Künstler nicht mit der Platzierung des Zeichenbereichs selbst zusammenhängen. Nur die Anfangsgröße zählt.

Die dem Zeichenbereich hinzugefügten Künstler sollten keinen Transformator haben (er wird überschrieben), und die Abmessungen dieser Künstler werden als Pixelkoordinaten interpretiert, d.h. die Radien der Kreise im obigen Beispiel sind 10 Pixel bzw. 5 Pixel.

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

Manchmal möchten Sie, dass Ihre Künstler mit den Datenkoordinaten (oder Koordinaten, die keine Canvas-Pixel sind) skaliert werden. Sie können die Klasse AnchoredAuxTransformBox verwenden. Dies ist ähnlich wie AnchoredDrawingArea, mit dem Unterschied, dass die Ausdehnung des Künstlers zur Zeichenzeit bestimmt wird und die angegebene Transformation berücksichtigt.

Die Ellipse im folgenden Beispiel hat eine Breite und Höhe, die 0,1 bzw. 0,4 in Datenkoordinaten entsprechen, und wird automatisch skaliert, wenn sich die Ansichtslimits der Achsen ändern.

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

Eine weitere Methode, einen Künstler relativ zu einer übergeordneten Achse oder einem Ankerpunkt zu verankern, ist über das Argument *bbox_to_anchor* von AnchoredOffsetbox. Dieser Künstler kann dann automatisch relativ zu einem anderen Künstler positioniert werden, indem HPacker und VPacker verwendet werden.

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

Beachten Sie, dass im Gegensatz zu Legend die bbox_transform standardmäßig auf IdentityTransform gesetzt ist.

Koordinatensysteme für Annotationen#

Matplotlib-Annotationen unterstützen verschiedene Arten von Koordinatensystemen. Die Beispiele in Grundlegende Annotation verwendeten das data-Koordinatensystem; einige andere fortgeschrittenere Optionen sind

Transform-Instanz#

Transformationen bilden Koordinaten in verschiedene Koordinatensysteme ab, normalerweise in das Anzeige-Koordinatensystem. Eine detaillierte Erklärung finden Sie im Transformations-Tutorial. Hier werden Transform-Objekte verwendet, um das Koordinatensystem der entsprechenden Punkte zu identifizieren. Zum Beispiel positioniert die Axes.transAxes-Transformation die Annotation relativ zu den Achsenkoordinaten; daher ist die Verwendung identisch mit dem Setzen des Koordinatensystems auf "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

Eine weitere häufig verwendete Transform-Instanz ist Axes.transData. Diese Transformation ist das Koordinatensystem der in den Achsen gezeichneten Daten. In diesem Beispiel wird sie verwendet, um einen Pfeil zwischen zusammenhängenden Datenpunkten in zwei Achsen zu zeichnen. Wir haben einen leeren Text übergeben, da in diesem Fall die Annotation Datenpunkte verbindet.

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-Instanz#

Der *xy*-Wert (oder *xytext*) wird als fraktionale Koordinate der Bounding Box (bbox) des Künstlers interpretiert.

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

Beachten Sie, dass Sie sicherstellen müssen, dass die Ausdehnung des Koordinatenkünstlers (*an1* in diesem Beispiel) bestimmt wird, bevor *an2* gezeichnet wird. Normalerweise bedeutet dies, dass *an2* nach *an1* gezeichnet werden muss. Die Basisklasse für alle Bounding Boxes ist BboxBase

Callable, die Transform von BboxBase zurückgibt#

Ein aufrufbares Objekt, das die Renderer-Instanz als einziges Argument entgegennimmt und entweder eine Transform oder eine BboxBase zurückgibt. Zum Beispiel ist der Rückgabewert von Artist.get_window_extent eine Bbox, daher ist diese Methode identisch mit (2) dem Übergeben des Künstlers.

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 ist die Bounding Box des Achsenobjekts und ist daher identisch mit dem Setzen des Koordinatensystems auf Achsen-Bruchteile.

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

Gemischte Koordinatenspezifikation#

Ein gemischtes Paar von Koordinatenspezifikationen – die erste für die x-Koordinate und die zweite für die y-Koordinate. Zum Beispiel ist x=0,5 in Datenkoordinaten und y=1 in normalisierten Achsenkoordinaten.

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

Jedes der unterstützten Koordinatensysteme kann in einer gemischten Spezifikation verwendet werden. Zum Beispiel wird der Text "Anker an 1 & 2" relativ zu den beiden Text-Künstlern positioniert.

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#

Manchmal möchten Sie Ihre Annotation mit einem "Offset in Punkten", nicht vom annotierten Punkt, sondern von einem anderen Punkt oder Künstler. text.OffsetFrom ist eine Hilfe für solche Fälle.

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

Nicht-Text-Annotationen#

Verwendung von ConnectionPatch#

ConnectionPatch ist wie eine Annotation ohne Text. Während annotate in den meisten Situationen ausreichend ist, ist ConnectionPatch nützlich, wenn Sie Punkte in verschiedenen Achsen verbinden möchten. Zum Beispiel verbinden wir hier den Punkt *xy* in den Datenkoordinaten von ax1 mit dem Punkt *xy* in den Datenkoordinaten von ax2.

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

Hier haben wir den ConnectionPatch zur *figure* (mit add_artist) hinzugefügt, anstatt zu einer der Achsen. Dies stellt sicher, dass der ConnectionPatch-Künstler über beiden Achsen gezeichnet wird, und ist auch notwendig, wenn constrained_layout für die Positionierung der Achsen verwendet wird.

Zoom-Effekt zwischen Achsen#

mpl_toolkits.axes_grid1.inset_locator definiert einige Patch-Klassen, die nützlich für die Verbindung zweier Achsen sind.

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

Der Code für diese Abbildung befindet sich unter Axes-Zoom-Effekt und Vertrautheit mit dem Transformations-Tutorial wird empfohlen.

Gesamtlaufzeit des Skripts: (0 Minuten 4,013 Sekunden)

Galerie generiert von Sphinx-Gallery