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)
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()
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()
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.
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()
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()
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()
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.Colorizerkapselt 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'
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'
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')
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'])
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#
Die Klasse
matplotlib.ticker.ScalarFormatterhat einen neuen Instanziierungsparameterusetexerhalten.Das Erstellen einer Achse ist jetzt aufgrund interner Optimierungen 20-25% schneller.
Die API von
Figure.subfiguresundSubFiguregelten jetzt als stabil.