Neues in Matplotlib 3.9.0 (15. Mai 2024)#

Eine Liste aller Issues und Pull Requests seit der letzten Überarbeitung finden Sie in der GitHub-Statistik für 3.9.0 (15. Mai 2024).

Verbesserungen beim Plotten und Annotieren#

Axes.inset_axes ist nicht mehr experimentell#

Axes.inset_axes gilt nun als stabil für die Verwendung.

Legendenunterstützung für Boxplot#

Boxplots unterstützen nun einen label-Parameter zur Erstellung von Legendeneinträgen. Legendenbeschriftungen können als Liste von Zeichenketten übergeben werden, um mehrere Boxen in einem einzigen Axes.boxplot-Aufruf zu beschriften.

np.random.seed(19680801)
fruit_weights = [
    np.random.normal(130, 10, size=100),
    np.random.normal(125, 20, size=100),
    np.random.normal(120, 30, size=100),
]
labels = ['peaches', 'oranges', 'tomatoes']
colors = ['peachpuff', 'orange', 'tomato']

fig, ax = plt.subplots()
ax.set_ylabel('fruit weight (g)')

bplot = ax.boxplot(fruit_weights,
                   patch_artist=True,  # fill with color
                   label=labels)

# fill with colors
for patch, color in zip(bplot['boxes'], colors):
    patch.set_facecolor(color)

ax.set_xticks([])
ax.legend()

(Quellcode, 2x.png, png)

Example of creating 3 boxplots and assigning legend labels as a sequence.

Oder als einzelne Zeichenkette für jeden einzelnen Axes.boxplot-Aufruf

fig, ax = plt.subplots()

data_A = np.random.random((100, 3))
data_B = np.random.random((100, 3)) + 0.2
pos = np.arange(3)

ax.boxplot(data_A, positions=pos - 0.2, patch_artist=True, label='Box A',
           boxprops={'facecolor': 'steelblue'})
ax.boxplot(data_B, positions=pos + 0.2, patch_artist=True, label='Box B',
           boxprops={'facecolor': 'lightblue'})

ax.legend()

(Quellcode, 2x.png, png)

Example of creating 2 boxplots and assigning each legend label as a string.

Prozentzeichen in Tortendiagramm-Beschriftungen werden mit usetex=True automatisch maskiert#

Es ist üblich, bei Axes.pie Beschriftungen anzugeben, die ein Prozentzeichen (%) enthalten, was für LaTeX einen Kommentar darstellt. Beim Aktivieren von LaTeX mit rcParams["text.usetex"] (Standard: False) oder dem Übergeben von textprops={"usetex": True}, führte dies früher dazu, dass das Prozentzeichen verschwand.

Nun wird das Prozentzeichen automatisch maskiert (durch Hinzufügen eines vorangestellten Backslashes), sodass es unabhängig von der usetex-Einstellung angezeigt wird. Wenn Sie das Prozentzeichen bereits maskiert haben, wird dies erkannt und bleibt unverändert.

hatch-Parameter für Stackplot#

Der hatch-Parameter von stackplot akzeptiert nun eine Liste von Zeichenketten, die Schrafierungsstile beschreiben, welche sequenziell auf die Schichten im Stapel angewendet werden.

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10,5))

cols = 10
rows = 4
data = (
np.reshape(np.arange(0, cols, 1), (1, -1)) ** 2
+ np.reshape(np.arange(0, rows), (-1, 1))
+ np.random.random((rows, cols))*5
)
x = range(data.shape[1])
ax1.stackplot(x, data, hatch="x")
ax2.stackplot(x, data, hatch=["//","\\","x","o"])

ax1.set_title("hatch='x'")
ax2.set_title("hatch=['//','\\\\','x','o']")

plt.show()

(Quellcode, 2x.png, png)

Two charts, identified as ax1 and ax2, showing "stackplots", i.e. one-dimensional distributions of data stacked on top of one another. The first plot, ax1 has cross-hatching on all slices, having been given a single string as the "hatch" argument. The second plot, ax2 has different styles of hatching on each slice - diagonal hatching in opposite directions on the first two slices, cross-hatching on the third slice, and open circles on the fourth.

Option zum Plotten nur einer Hälfte eines Violinplots hinzugefügt#

Durch Setzen des Parameters side auf 'low' oder 'high' kann nur eine Hälfte des Axes.violinplot geplottet werden.

# Fake data with reproducible random state.
np.random.seed(19680801)
data = np.random.normal(0, 8, size=100)

fig, ax = plt.subplots()

ax.violinplot(data, [0], showmeans=True, showextrema=True)
ax.violinplot(data, [1], showmeans=True, showextrema=True, side='low')
ax.violinplot(data, [2], showmeans=True, showextrema=True, side='high')

ax.set_title('Violin Sides Example')
ax.set_xticks([0, 1, 2], ['Default', 'side="low"', 'side="high"'])
ax.set_yticklabels([])

(Quellcode, 2x.png, png)

Three copies of a vertical violin plot; first in blue showing the default of both sides, followed by an orange copy that only shows the "low" (or left, in this case) side, and finally a green copy that only shows the "high" (or right) side.

axhline und axhspan auf polaren Achsen#

... zeichnen nun Kreise und Kreisbögen (axhline) oder Ringe und Keile (axhspan).

fig = plt.figure()
ax = fig.add_subplot(projection="polar")
ax.set_rlim(0, 1.2)

ax.axhline(1, c="C0", alpha=.5)
ax.axhspan(.8, .9, fc="C1", alpha=.5)
ax.axhspan(.6, .7, .8, .9, fc="C2", alpha=.5)

(Quellcode, 2x.png, png)

A sample polar plot, that contains an axhline at radius 1, an axhspan annulus between radius 0.8 and 0.9, and an axhspan wedge between radius 0.6 and 0.7 and 288° and 324°.

Unterüberschriften können jetzt automatisch ausgerichtet werden#

Unterüberschriften von Achsen können vertikal falsch ausgerichtet sein, wenn Tick-Beschriftungen oder x-Achsen-Beschriftungen am oberen Rand eines Unterplots platziert sind. Die neue Methode align_titles für die Figure-Klasse richtet die Titel nun vertikal aus.

fig, axs = plt.subplots(1, 2, layout='constrained')

axs[0].plot(np.arange(0, 1e6, 1000))
axs[0].set_title('Title 0')
axs[0].set_xlabel('XLabel 0')

axs[1].plot(np.arange(1, 0, -0.1) * 2000, np.arange(1, 0, -0.1))
axs[1].set_title('Title 1')
axs[1].set_xlabel('XLabel 1')
axs[1].xaxis.tick_top()
axs[1].tick_params(axis='x', rotation=55)

(Quellcode, 2x.png, png)

A figure with two Axes side-by-side, the second of which with ticks on top. The Axes titles and x-labels appear unaligned with each other due to these ticks.
fig, axs = plt.subplots(1, 2, layout='constrained')

axs[0].plot(np.arange(0, 1e6, 1000))
axs[0].set_title('Title 0')
axs[0].set_xlabel('XLabel 0')

axs[1].plot(np.arange(1, 0, -0.1) * 2000, np.arange(1, 0, -0.1))
axs[1].set_title('Title 1')
axs[1].set_xlabel('XLabel 1')
axs[1].xaxis.tick_top()
axs[1].tick_params(axis='x', rotation=55)

fig.align_labels()
fig.align_titles()

(Quellcode, 2x.png, png)

A figure with two Axes side-by-side, the second of which with ticks on top. Unlike the previous figure, the Axes titles and x-labels appear aligned.

axisartist kann jetzt zusammen mit Standard-Formatters verwendet werden#

... anstatt auf Achsenkünstler-spezifische beschränkt zu sein.

Minorticks auf Achse umschalten#

Minorticks auf einer Axis können mit minorticks_on und minorticks_off angezeigt oder entfernt werden; z.B. ax.xaxis.minorticks_on(). Siehe auch minorticks_on.

StrMethodFormatter berücksichtigt jetzt axes.unicode_minus#

Beim Formatieren negativer Werte verwendet StrMethodFormatter nun Unicode-Minuszeichen, wenn rcParams["axes.unicode_minus"] (Standard: True) gesetzt ist.

>>> from matplotlib.ticker import StrMethodFormatter
>>> with plt.rc_context({'axes.unicode_minus': False}):
...     formatter = StrMethodFormatter('{x}')
...     print(formatter.format_data(-10))
-10
>>> with plt.rc_context({'axes.unicode_minus': True}):
...     formatter = StrMethodFormatter('{x}')
...     print(formatter.format_data(-10))
−10

Layout für Figuren, Achsen und Legenden#

Subfiguren haben jetzt steuerbare Z-Ordern#

Zuvor hatte das Setzen der Z-Order einer Subfigur keine Auswirkung, und diese wurden über allen künstlichen Elementen auf Figurenebene (z.B. über Legenden auf Figurenebene) gezeichnet. Nun verhalten sich Subfiguren wie andere künstliche Elemente, und ihre Z-Order kann gesteuert werden, mit einer Standard-Z-Order von 0.

x = np.linspace(1, 10, 10)
y1, y2 = x, -x
fig = plt.figure(constrained_layout=True)
subfigs = fig.subfigures(nrows=1, ncols=2)
for subfig in subfigs:
    axarr = subfig.subplots(2, 1)
    for ax in axarr.flatten():
        (l1,) = ax.plot(x, y1, label="line1")
        (l2,) = ax.plot(x, y2, label="line2")
subfigs[0].set_zorder(6)
l = fig.legend(handles=[l1, l2], loc="upper center", ncol=2)

(Quellcode, 2x.png, png)

Example on controlling the zorder of a subfigure

Getter für xmargin, ymargin und zmargin#

Die Methoden Axes.get_xmargin, Axes.get_ymargin und Axes3D.get_zmargin wurden hinzugefügt, um die durch Axes.set_xmargin, Axes.set_ymargin und Axes3D.set_zmargin gesetzten Randwerte zurückzugeben.

Verbesserungen an Mathtext#

mathtext-Dokumentationsverbesserungen#

Die Dokumentation wird aktualisiert, um Informationen direkt aus dem Parser zu beziehen. Das bedeutet, dass (fast) alle unterstützten Symbole, Operatoren usw. unter Schreiben mathematischer Ausdrücke angezeigt werden.

mathtext-Abstands Korrekturen#

Als Folge der aktualisierten Dokumentation wurden die Abstände bei einer Reihe von relationalen und operativen Symbolen korrekt klassifiziert und werden daher richtig abgesetzt.

Widget-Verbesserungen#

Check- und Radiobutton-Widgets unterstützen das Löschen#

Die Widgets CheckButtons und RadioButtons unterstützen nun das Löschen ihres Zustands durch Aufruf ihrer .clear-Methode. Beachten Sie, dass es nicht möglich ist, keine ausgewählten Radiobuttons zu haben, sodass die zum Zeitpunkt der Konstruktion ausgewählte Option ausgewählt bleibt.

Verbesserungen bei 3D-Plots#

Das Setzen von 3D-Achsenlimits setzt die Limits jetzt exakt#

Zuvor wurde beim Setzen der Limits einer 3D-Achse immer ein kleiner Rand hinzugefügt. Limits werden nun standardmäßig exakt gesetzt. Der neu eingeführte rcParam axes3d.automargin kann verwendet werden, um zum alten Verhalten zurückzukehren, bei dem automatisch ein Rand hinzugefügt wird.

fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'})

plt.rcParams['axes3d.automargin'] = True
axs[0].set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), title='Old Behavior')

plt.rcParams['axes3d.automargin'] = False  # the default in 3.9.0
axs[1].set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), title='New Behavior')

(Quellcode, 2x.png, png)

Example of the new behavior of 3D axis limits, and how setting the rcParam reverts to the old behavior.

Weitere Verbesserungen#

BackendRegistry#

Die neue Klasse BackendRegistry ist die einzige Quelle für verfügbare Backends. Die Singleton-Instanz ist matplotlib.backends.backend_registry. Sie wird intern von Matplotlib und ab IPython 8.24.0 auch von IPython (und damit Jupyter) verwendet.

Es gibt drei Quellen für Backends: integrierte (der Quellcode befindet sich im Matplotlib-Repository), explizite Syntax module://some.backend (das Backend wird durch Laden des Moduls bezogen) oder über einen Entry Point (selbstregistrierendes Backend in einem externen Paket).

Um eine Liste aller registrierten Backends zu erhalten, verwenden Sie

>>> from matplotlib.backends import backend_registry
>>> backend_registry.list_all()

Setter für widths, heights und angles zu EllipseCollection hinzugefügt#

Die Werte widths, heights und angles der EllipseCollection können nun geändert werden, nachdem die Kollektion erstellt wurde.

from matplotlib.collections import EllipseCollection

rng = np.random.default_rng(0)

widths = (2, )
heights = (3, )
angles = (45, )
offsets = rng.random((10, 2)) * 10

fig, ax = plt.subplots()

ec = EllipseCollection(
    widths=widths,
    heights=heights,
    angles=angles,
    offsets=offsets,
    units='x',
    offset_transform=ax.transData,
    )

ax.add_collection(ec)
ax.set_xlim(-2, 12)
ax.set_ylim(-2, 12)

new_widths = rng.random((10, 2)) * 2
new_heights = rng.random((10, 2)) * 3
new_angles = rng.random((10, 2)) * 180

ec.set(widths=new_widths, heights=new_heights, angles=new_angles)

(Quellcode, 2x.png, png)

image.interpolation_stage rcParam#

Dieser neue rcParam steuert, ob die Bildinterpolation im "Daten"-Raum oder im "RGBA"-Raum stattfindet.

Pfeilpatch-Position kann jetzt geändert werden#

Eine Setter-Methode wurde hinzugefügt, die es ermöglicht, die Position des patches.Arrow-Objekts zu aktualisieren, ohne dass ein vollständiges Neuzeichnen erforderlich ist.

from matplotlib import animation
from matplotlib.patches import Arrow

fig, ax = plt.subplots()
ax.set_xlim(0, 10)
ax.set_ylim(0, 10)

a = Arrow(2, 0, 0, 10)
ax.add_patch(a)


# code for modifying the arrow
def update(i):
    a.set_data(x=.5, dx=i, dy=6, width=2)


ani = animation.FuncAnimation(fig, update, frames=15, interval=90, blit=False)

plt.show()

(Quellcode, 2x.png, png)

Example of changing the position of the arrow with the new ``set_data`` method.

NonUniformImage hat jetzt Maus-Über-Unterstützung#

Beim Überfahren eines NonUniformImage mit der Maus werden nun die Datenwerte angezeigt.