Neues in Matplotlib 3.10.0 (13. Dezember 2024)#

Eine Liste aller Probleme und Pull-Anfragen seit der letzten Überarbeitung finden Sie in den GitHub-Statistiken für 3.10.3 (08. Mai 2025).

Neuer, zugänglicherer Farbzyklus#

Ein neuer Farbzyklus namens 'petroff10' wurde hinzugefügt. Dieser Zyklus wurde unter Verwendung einer Kombination aus algorithmisch erzwungenen Barrierefreiheitsbeschränkungen, einschließlich der Modellierung von Farbsehschwächen, und einem maschinellen Lern-basierten Ästhetikmodell, das aus einer Crowdsourcing-Farbpräferenzumfrage entwickelt wurde, erstellt. Er zielt darauf ab, sowohl ästhetisch gefällig als auch farbfehlsichtig zugänglich zu sein, sodass er als Standard im Sinne eines universellen Designs dienen könnte. Weitere Einzelheiten finden Sie unter Petroff, M. A.: "Accessible Color Sequences for Data Visualization" und dem zugehörigen SciPy-Talk. Eine Demonstration ist in der Referenz der Style-Sheets enthalten. Um diesen Farbzyklus anstelle des Standardzyklus zu laden

import matplotlib.pyplot as plt
plt.style.use('petroff10')

Divergierende Colormaps für den Dunkelmodus#

Drei divergierende Colormaps wurden hinzugefügt: "berlin", "managua" und "vanimo". Dies sind divergierende Colormaps für den Dunkelmodus, mit minimaler Helligkeit in der Mitte und maximaler Helligkeit an den Extremen. Diese stammen aus F. Crameris Scientific Colour Maps Version 8.0.1 (DOI: https://doi.org/10.5281/zenodo.1243862).

import numpy as np
import matplotlib.pyplot as plt

vals = np.linspace(-5, 5, 100)
x, y = np.meshgrid(vals, vals)
img = np.sin(x*y)

_, ax = plt.subplots(1, 3)
ax[0].imshow(img, cmap=plt.cm.berlin)
ax[1].imshow(img, cmap=plt.cm.managua)
ax[2].imshow(img, cmap=plt.cm.vanimo)

(Quellcode, 2x.png, png)

Example figures using "imshow" with dark-mode diverging colormaps on positive and negative data. First panel: "berlin" (blue to red with a black center); second panel: "managua" (orange to cyan with a dark purple center); third panel: "vanimo" (pink to green with a black center).

Verbesserungen bei Plotting und Annotationen#

Festlegen einer einzelnen Farbe in contour und contourf#

contour und contourf akzeptierten bisher eine einzelne Farbe, sofern sie als String angegeben wurde. Diese Einschränkung wurde nun aufgehoben, und eine einzelne Farbe in jedem im Tutorial Farben spezifizieren beschriebenen Format kann übergeben werden.

import matplotlib.pyplot as plt

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(6, 3))
z = [[0, 1], [1, 2]]

ax1.contour(z, colors=('r', 0.4))
ax2.contour(z, colors=(0.1, 0.2, 0.5))

plt.show()

(Quellcode, 2x.png, png)

Two-panel example contour plots.  The left panel has all transparent red contours.  The right panel has all dark blue contours.

Vektorisierte hist Stilparameter#

Die Parameter hatch, edgecolor, facecolor, linewidth und linestyle der hist-Methode sind jetzt vektorisiert. Das bedeutet, dass Sie einzelne Parameter für jedes Histogramm übergeben können, wenn die Eingabe x mehrere Datensätze enthält.

import matplotlib.pyplot as plt
import numpy as np
np.random.seed(19680801)

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(9, 9))

data1 = np.random.poisson(5, 1000)
data2 = np.random.poisson(7, 1000)
data3 = np.random.poisson(10, 1000)

labels = ["Data 1", "Data 2", "Data 3"]

ax1.hist([data1, data2, data3], bins=range(17), histtype="step", stacked=True,
         edgecolor=["red", "green", "blue"], linewidth=[1, 2, 3])
ax1.set_title("Different linewidths")
ax1.legend(labels)

ax2.hist([data1, data2, data3], bins=range(17), histtype="barstacked",
         hatch=["/", ".", "*"])
ax2.set_title("Different hatch patterns")
ax2.legend(labels)

ax3.hist([data1, data2, data3], bins=range(17), histtype="bar", fill=False,
         edgecolor=["red", "green", "blue"], linestyle=["--", "-.", ":"])
ax3.set_title("Different linestyles")
ax3.legend(labels)

ax4.hist([data1, data2, data3], bins=range(17), histtype="barstacked",
         facecolor=["red", "green", "blue"])
ax4.set_title("Different facecolors")
ax4.legend(labels)

plt.show()

(Quellcode, 2x.png, png)

Four charts, each displaying stacked histograms of three Poisson distributions. Each chart differentiates the histograms using various parameters: top left uses different linewidths, top right uses different hatches, bottom left uses different edgecolors, and bottom right uses different facecolors. Each histogram on the left side also has a different edgecolor.

InsetIndicator Artist#

indicate_inset und indicate_inset_zoom geben jetzt eine Instanz von InsetIndicator zurück, die die Rechteck- und Verbindungspatches enthält. Diese Patches werden jetzt automatisch aktualisiert, sodass

ax.indicate_inset_zoom(ax_inset)
ax_inset.set_xlim(new_lim)

jetzt das gleiche Ergebnis liefert wie

ax_inset.set_xlim(new_lim)
ax.indicate_inset_zoom(ax_inset)

matplotlib.ticker.EngFormatter kann jetzt Offsets berechnen#

matplotlib.ticker.EngFormatter hat die Fähigkeit erhalten, einen Offset-Text in der Nähe der Achse anzuzeigen. Unter Verwendung von Logik, die mit matplotlib.ticker.ScalarFormatter geteilt wird, kann es entscheiden, ob die Daten einen Offset rechtfertigen und diesen mit einem geeigneten SI-Einheitenpräfix und der angegebenen unit anzeigen.

Um dieses neue Verhalten zu aktivieren, übergeben Sie einfach useOffset=True, wenn Sie matplotlib.ticker.EngFormatter instanziieren. Siehe Beispiel SI-Präfix-Offsets und natürliche Größenordnungen.

(Quellcode, 2x.png, png)

Fixierung des Abstands einer einzelnen Colorbar für ImageGrid#

ImageGrid mit cbar_mode="single" fügt den axes_pad nicht mehr zwischen den Achsen und der Colorbar für cbar_location "left" und "bottom" hinzu. Falls gewünscht, fügen Sie zusätzlichen Abstand mit cbar_pad hinzu.

ax.table akzeptiert jetzt ein Pandas DataFrame#

Die table-Methode kann jetzt ein Pandas DataFrame für das Argument cellText akzeptieren.

import matplotlib.pyplot as plt
import pandas as pd

data = {
    'Letter': ['A', 'B', 'C'],
    'Number': [100, 200, 300]
}

df = pd.DataFrame(data)
fig, ax = plt.subplots()
table = ax.table(df, loc='center')  # or table = ax.table(cellText=df, loc='center')
ax.axis('off')
plt.show()

Subfigures werden jetzt in zeilenweiser Reihenfolge hinzugefügt#

Für API-Konsistenz werden Figure.subfigures jetzt in zeilenweiser Reihenfolge hinzugefügt.

import matplotlib.pyplot as plt

fig = plt.figure()
subfigs = fig.subfigures(3, 3)
x = np.linspace(0, 10, 100)

for i, sf in enumerate(fig.subfigs):
    ax = sf.subplots()
    ax.plot(x, np.sin(x + i), label=f'Subfigure {i+1}')
    sf.suptitle(f'Subfigure {i+1}')
    ax.set_xticks([])
    ax.set_yticks([])
plt.show()

(Quellcode, 2x.png, png)

Example of creating 3 by 3 subfigures.

boxplot und bxp Orientierungsparameter#

Boxplots haben einen neuen Parameter orientation: {"vertical", "horizontal"}, um die Ausrichtung des Plots zu ändern. Dieser ersetzt den veralteten Parameter vert: bool.

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
np.random.seed(19680801)
all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]

ax.boxplot(all_data, orientation='horizontal')
plt.show()

(Quellcode, 2x.png, png)

Example of creating 4 horizontal boxplots.

violinplot und violin Orientierungsparameter#

Violinplots haben einen neuen Parameter orientation: {"vertical", "horizontal"}, um die Ausrichtung des Plots zu ändern. Dies ersetzt den veralteten Parameter vert: bool.

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots()
np.random.seed(19680801)
all_data = [np.random.normal(0, std, 100) for std in range(6, 10)]

ax.violinplot(all_data, orientation='horizontal')
plt.show()

(Quellcode, 2x.png, png)

Example of creating 4 horizontal violinplots.

FillBetweenPolyCollection#

Die neue Klasse matplotlib.collections.FillBetweenPolyCollection bietet die Methode set_data, die z. B. Resampling ermöglicht (galleries/event_handling/resample.html). matplotlib.axes.Axes.fill_between() und matplotlib.axes.Axes.fill_betweenx() geben jetzt diese neue Klasse zurück.

import numpy as np
from matplotlib import pyplot as plt

t = np.linspace(0, 1)

fig, ax = plt.subplots()
coll = ax.fill_between(t, -t**2, t**2)
fig.savefig("before.png")

coll.set_data(t, -t**4, t**4)
fig.savefig("after.png")

matplotlib.colorizer.Colorizer als Container für norm und cmap#

matplotlib.colorizer.Colorizer kapselt die Daten-zu-Farbe-Pipeline. Dies erleichtert die Wiederverwendung von Colormapping, z. B. über mehrere Bilder hinweg. Plotting-Methoden, die die Schlüsselwortargumente norm und cmap unterstützen, akzeptieren jetzt auch das Schlüsselwortargument colorizer.

Im folgenden Beispiel werden Norm und cmap gleichzeitig für mehrere Plots geändert

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

x = np.linspace(-2, 2, 50)[np.newaxis, :]
y = np.linspace(-2, 2, 50)[:, np.newaxis]
im_0 = 1 * np.exp( - (x**2 + y**2 - x * y))
im_1 = 2 * np.exp( - (x**2 + y**2 + x * y))

colorizer = mpl.colorizer.Colorizer()
fig, axes = plt.subplots(1, 2, figsize=(6, 2))
cim_0 = axes[0].imshow(im_0, colorizer=colorizer)
fig.colorbar(cim_0)
cim_1 = axes[1].imshow(im_1, colorizer=colorizer)
fig.colorbar(cim_1)

colorizer.vmin = 0.5
colorizer.vmax = 2
colorizer.cmap = 'RdBu'

(Quellcode, 2x.png, png)

Example use of a matplotlib.colorizer.Colorizer object

Alle Plotting-Methoden, die eine Daten-zu-Farbe-Pipeline verwenden, erstellen jetzt ein Colorizer-Objekt, wenn keines bereitgestellt wird. Dies kann von nachfolgenden Artists wiederverwendet werden, sodass sie eine einzige Daten-zu-Farbe-Pipeline gemeinsam nutzen.

import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np

x = np.linspace(-2, 2, 50)[np.newaxis, :]
y = np.linspace(-2, 2, 50)[:, np.newaxis]
im_0 = 1 * np.exp( - (x**2 + y**2 - x * y))
im_1 = 2 * np.exp( - (x**2 + y**2 + x * y))

fig, axes = plt.subplots(1, 2, figsize=(6, 2))

cim_0 = axes[0].imshow(im_0, cmap='RdBu', vmin=0.5, vmax=2)
fig.colorbar(cim_0)
cim_1 = axes[1].imshow(im_1, colorizer=cim_0.colorizer)
fig.colorbar(cim_1)

cim_1.cmap = 'rainbow'

(Quellcode, 2x.png, png)

Example of how artists that share a ``colorizer`` have coupled colormaps

Verbesserungen bei 3D-Plots#

Fläche zwischen 3D-Linien füllen#

Die neue Methode Axes3D.fill_between ermöglicht das Füllen der Oberfläche zwischen zwei 3D-Linien mit Polygonen.

N = 50
theta = np.linspace(0, 2*np.pi, N)

x1 = np.cos(theta)
y1 = np.sin(theta)
z1 = 0.1 * np.sin(6 * theta)

x2 = 0.6 * np.cos(theta)
y2 = 0.6 * np.sin(theta)
z2 = 2  # Note that scalar values work in addition to length N arrays

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.fill_between(x1, y1, z1, x2, y2, z2,
                alpha=0.5, edgecolor='k')

(Quellcode, 2x.png, png)

Example of 3D fill_between

Drehen von 3D-Plots mit der Maus#

Das Drehen von dreidimensionalen Plots mit der Maus wurde intuitiver gestaltet. Der Plot reagiert jetzt auf Mausbewegungen auf die gleiche Weise, unabhängig von der aktuellen Ausrichtung; und es ist möglich, alle 3 Rotationsfreiheitsgrade (Azimut, Elevation und Rollen) zu steuern. Standardmäßig wird eine Variante von Ken Shoemakes ARCBALL verwendet [1]. Der spezifische Mausrotationsstil kann über rcParams["axes3d.mouserotationstyle"] (Standard: 'arcball') eingestellt werden. Siehe auch Rotation mit der Maus.

Um zum ursprünglichen Mausrotationsstil zurückzukehren, erstellen Sie eine Datei matplotlibrc mit folgendem Inhalt

axes3d.mouserotationstyle: azel

Um einen der verschiedenen Mausrotationsstile auszuprobieren

import matplotlib as mpl
mpl.rcParams['axes3d.mouserotationstyle'] = 'trackball'  # 'azel', 'trackball', 'sphere', or 'arcball'

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm

ax = plt.figure().add_subplot(projection='3d')

X = np.arange(-5, 5, 0.25)
Y = np.arange(-5, 5, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm,
                       linewidth=0, antialiased=False)

plt.show()

Daten in 3D-Plots können jetzt dynamisch auf die Achsenansichtslimits zugeschnitten werden#

Alle 3D-Plotting-Funktionen unterstützen jetzt das Schlüsselwortargument axlim_clip, das die Daten auf die Achsenansichtslimits zuschneidet und alle Daten außerhalb dieser Grenzen verbirgt. Dieses Zuschneiden wird in Echtzeit während des Verschiebens und Zoomens dynamisch angewendet.

Bitte beachten Sie, dass, wenn ein Eckpunkt eines Liniensegments oder eines 3D-Patches zugeschnitten wird, das gesamte Segment oder der gesamte Patch ausgeblendet wird. Das Nicht-Darstellen von teilweise abgeschnittenen Linien oder Patches, die "glatt" an den Grenzen des Ansichtsfeldes abgeschnitten sind, ist eine Einschränkung des aktuellen Renderers.

import matplotlib.pyplot as plt
import numpy as np

fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
x = np.arange(-5, 5, 0.5)
y = np.arange(-5, 5, 0.5)
X, Y = np.meshgrid(x, y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

# Note that when a line has one vertex outside the view limits, the entire
# line is hidden. The same is true for 3D patches (not shown).
# In this example, data where x < 0 or z > 0.5 is clipped.
ax.plot_wireframe(X, Y, Z, color='C0')
ax.plot_wireframe(X, Y, Z, color='C1', axlim_clip=True)
ax.set(xlim=(0, 10), ylim=(-5, 5), zlim=(-1, 0.5))
ax.legend(['axlim_clip=False (default)', 'axlim_clip=True'])

(Quellcode, 2x.png, png)

Example of default behavior (blue) and axlim_clip=True (orange)

Vorläufige Unterstützung für das freie Threading von CPython 3.13#

Matplotlib 3.10 bietet vorläufige Unterstützung für den freien Threading-Build von CPython 3.13. Weitere Einzelheiten zu freiem Threading-Python finden Sie unter https://py-free-threading.github.io, PEP 703 und den CPython 3.13 Release Notes.

Die Unterstützung für freies Threading-Python bedeutet nicht, dass Matplotlib vollständig thread-sicher ist. Wir gehen davon aus, dass die Verwendung einer Figure innerhalb eines einzelnen Threads funktioniert, und obwohl Eingabedaten normalerweise kopiert werden, kann die Änderung von Datenobjekten, die für einen Plot verwendet werden, aus einem anderen Thread in Fällen, in denen dies nicht der Fall ist, zu Inkonsistenzen führen. Die Verwendung von globalem Zustand (wie dem pyplot-Modul) wird dringend abgeraten und ist wahrscheinlich nicht konsistent. Beachten Sie auch, dass die meisten GUI-Toolkits davon ausgehen, auf dem Hauptthread zu laufen, sodass die interaktive Nutzung von anderen Threads aus eingeschränkt oder nicht unterstützt sein kann.

Wenn Sie an freiem Threading-Python interessiert sind, zum Beispiel weil Sie einen auf Multiprocessing basierenden Workflow haben, den Sie mit Python-Threads ausführen möchten, ermutigen wir Sie zu Tests und Experimenten. Wenn Sie auf Probleme stoßen, bei denen Sie vermuten, dass sie auf Matplotlib zurückzuführen sind, eröffnen Sie bitte ein Issue und prüfen Sie zunächst, ob der Fehler auch im "regulären" CPython 3.13 Build ohne freien Threading auftritt.

Weitere Verbesserungen#

svg.id rcParam#

rcParams["svg.id"] (Standard: None) ermöglicht es Ihnen, ein id-Attribut in das übergeordnete <svg>-Tag einzufügen.

z. B. rcParams["svg.id"] = "svg1" führt zu

<svg
    xmlns:xlink="http://www.w3.org/1999/xlink"
    width="50pt" height="50pt"
    viewBox="0 0 50 50"
    xmlns="http://www.w3.org/2000/svg"
    version="1.1"
    id="svg1"
></svg>

Dies ist nützlich, wenn Sie die gesamte Matplotlib-SVG-Datei innerhalb einer anderen SVG-Datei mit dem <use>-Tag verknüpfen möchten.

<svg>
<use
    width="50" height="50"
    xlink:href="mpl.svg#svg1" id="use1"
    x="0" y="0"
/></svg>

Hierbei verweist der Indikator #svg1 jetzt auf das übergeordnete <svg>-Tag und führt somit zur Einbindung der gesamten Datei.

Standardmäßig wird kein id-Tag eingefügt.

Kontrolle der Ausnahmebehandlung#

Die Ausnahme, die ausgelöst wird, wenn ein ungültiger Schlüsselwortparameter übergeben wird, enthält jetzt diesen Parameternamen als name-Eigenschaft der Ausnahme. Dies bietet mehr Kontrolle für die Ausnahmebehandlung

import matplotlib.pyplot as plt

def wobbly_plot(args, **kwargs):
    w = kwargs.pop('wobble_factor', None)

    try:
        plt.plot(args, **kwargs)
    except AttributeError as e:
        raise AttributeError(f'wobbly_plot does not take parameter {e.name}') from e


wobbly_plot([0, 1], wibble_factor=5)
AttributeError: wobbly_plot does not take parameter wibble_factor

Erhöhte Figure-Limits mit Agg-Renderer#

Figuren, die den Agg-Renderer verwenden, sind jetzt auf 2**23 Pixel in jeder Richtung beschränkt, anstatt auf 2**16. Außerdem wurden Fehler behoben, die dazu führten, dass Artists nicht über 2**15 Pixel horizontal gerendert wurden.

Beachten Sie, dass, wenn Sie ein GUI-Backend verwenden, dieses möglicherweise eigene kleinere Limits hat (die selbst von der Bildschirmgröße abhängen können).

Verschiedene Änderungen#