Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | ![]()
Stand: 2025-04-02
weitgehend formuliert von ChatGPT 4, verbessert von Claude 3.7 Sonnet,
redigiert/korrigiert von Jörn Loviscach
Matplotlib ist eine umfangreiche Bibliothek für die Erstellung von statischen, animierten und interaktiven Visualisierungen in Python. Sie bietet eine Vielzahl von Plot-Typen und -Stilen und ist aufgrund ihrer Effizienz und Flexibilität besonders beliebt in der wissenschaftlichen und technischen Datenvisualisierung. Matplotlib ermöglicht, hochwertige Graphen, Charts und Figuren in verschiedenen Formaten zu erzeugen, und ist kompatibel mit einer breiten Palette von Betriebssystemen und Grafik-Backends.
Die Kernfunktionalität von Matplotlib basiert auf dem Erstellen von
Diagrammen (Figure
) und Koordinatensystemen (Axis
);
letzteren werden die Daten zugeordnet. Matplotlib benutzt hauptsächlich
eine objektorientierte Programmierschnittstelle, für schnelle und
einfache Visualisierungen aber auch eine prozedurale Schnittstelle,
bekannt als Pyplot, die an die Funktionsweise von MATLAB® angelehnt
ist.
Ein großer Vorteil von Matplotlib ist seine Erweiterbarkeit und Anpassbarkeit. Das Aussehen von Graphen lässt sich weitgehend anpassen, indem man Titel, Achsenbeschriftungen, Legenden und andere Stilelemente modifiziert, siehe die Beispiele auf den Cheatsheets und Handouts. Darüber hinaus gibt es zusätzliche Pakete wie Seaborn, das auf Matplotlib aufbaut, um weiterführende statistische Visualisierungen zu erstellen. Diese Flexibilität macht Matplotlib zu einem unverzichtbaren Werkzeug für die Datenanalyse und -visualisierung in Python.
Natürlich muss Matplotlib vor der Arbeit damit in das virtuelle Environment installiert werden.
Es soll ein xy-Datensatz als Streudiagramm geplottet werden, dazu die Regressionsgerade samt deren Gleichung.
Zunächst importieren wir die benötigte Bibliothek. Hier wird das
Plot-Modul von matplotlib unter dem kurzen Namen
plt eingebunden, so dass seine Funktionen usw. Namen wie
plt.tu_was() erhalten (Details später im Semester):
import matplotlib.pyplot as pltNun definieren wir eine Liste von x-Werten und eine Liste von y-Werten. Im wahren Leben kämen diese Daten aus einer Datei, aus einer Datenbank, aus dem Netz oder von Sensoren:
x = [3.8, 3.9, 4.0, 4.2, 4.3]
y = [1.9, 3.5, 3.1, 4.6, 6.3]Als nächstes erstellen wir einen Scatterplot dieser Daten:
plt.scatter(x, y)Nun fügen wir dem Diagramm einen Titel und Achsenbeschriftungen
hinzu; innerhalb der $...$ stehen mathematische Zeichen und
Formeln im LaTeX-Format:
plt.title('Scatterplot mit Regressionsgerade')
plt.xlabel('Was auch immer $x$ ist')
plt.ylabel('Was auch immer $y$ ist')Zuletzt zeigen wir das Diagramm an:
plt.show()Das Program bleibt in diesem plt.show() hängen, bis man
das Fensterchen mit dem Diagramm schließt. (Es gibt auch einen Weg,
Matplotlib sofort weiterarbeiten zu lassen, statt dass es auf das
Schließen des Fensters wartet.)
Um nun noch eine Regressionsgerade durch den Scatterplot zu legen,
verwenden wir die Funktion linregress der Bibliothek SciPy.
Diese eine Funktion liefert fünf Werte zurück, von denen wir
nur die ersten beiden speichern:
# an den Anfang des Programms:
import scipy.stats as stats
# vor dem show():
steigung, achsenabschnitt, _, _, _ = stats.linregress(x, y)Diese Linie können wir dann über den Scatterplot zeichnen. Die
Funktion plot erwartet eine Liste an x-Werten (hier sind es nur zwei
Stück) und eine Liste dazugehöriger y-Werte. Einer der vielen weiteren
Parameter dieser Funktion, die man per Namen angeben kann, ist
color:
# vor dem show():
plt.plot([3.8, 4.3], [steigung * 3.8 + achsenabschnitt, steigung * 4.3 + achsenabschnitt], color='red')Aufgabe: Schreiben Sie die obige Zeile klarer und robuster, indem Sie die x-Werte aus den Daten gewinnen und die y-Werte mit einer selbstdefinierten Funktionen daraus erzeugen!
Und nun setzen wir noch mittels LaTeX in einem f-String die Gleichung der Regressionsgerade in das Diagramm:
# vor dem show():
plt.text(4.05, 3.5, f'$y = {steigung:.2f}x + {achsenabschnitt:.2f}$', fontsize=12, color='red')Dies ist eine Ergänzung für Hartgesottene.
Schöner ist das Ganze, wenn die Zahlen in deutscher statt amerikanischer Schreibweise erscheinen (Dezimalkomma statt Dezimalpunkt, Tausender usw. mit Punkt statt mit Komma). Das geht so:
# am Anfang des Programms
import locale
# vor dem ersten Plot-Befehl
plt.rcParams['axes.formatter.use_locale'] = 'True'
# unten im Programm
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
plt.text(4.05, 3.5, f'$y = {steigung:.2n}x {"+" if achsenabschnitt >= 0 else "-"}{abs(achsenabschnitt):.2n}$'.replace(',', '{,}'), fontsize=12, color='red')Das Einstellen von axes.formatter.use_locale bewirkt,
dass für die Zahlen an den Koordinatenachsen die locale,
also die regionale Einstellung, berücksichtigt wird. Das n
in der Formatangabe im f-String macht Entsprechendes für die Umwandlung
von Zahlen in Zeichenketten. Außerdem sorgen wir noch dafür, dass ein
negativer achsenabschnitt nicht mit Pluszeichen (wörtlich
im f-String angegeben) und Minuszeichen (von der Zahl)
erscheint.
Normalerweise ruft man setlocale ganz am Anfang des
Programms auf; allerdings setzt Matplotlib diese Einstellung zurück. Und
noch ein weiterer Trick: LaTeX interpretiert Zahlen mit Dezimalkomma
darin als Listen von Zahlen und lässt deshalb nach dem Komma eine Lücke.
Um das zu verhindern, folgt dem f-String noch ein replace,
das das Komma durch {,} ersetzt, wie es in LaTeX üblich
ist.
Angenommen, wir haben noch Angaben zu den Unsicherheiten der y-Werte:
y_error = [1.2, 0.7, 1.4, 0.9, 0.8]Dann können wir passende Fehlerbalken zeichnen lassen, indem wir
statt plot.scatter dies aufrufen:
plt.errorbar(x, y, yerr=y_error, fmt='o', capsize=5)Nun müsste man noch die unterschiedlichen Fehlerbalken bei der Berechnung der Regressionsgeraden berücksichtigen und statt einer einzigen Regressionsgeraden ein Konfidenzband zeichnen. Fragen Sie die KI, wie das geht.
Ein Easter Egg: Wenn man den Zeichencode in
with plt.xkcd(): einbettet, entstehen skizzenhafte
Diagramme im Stil der xkcd-Cartoons von
Randall Munroe. Im Zweifelsfall muss noch der richtige
Font installiert werden und die Fontliste
fontlist-v....json von Matplotlib gelöscht werden, damit es
die auffrischt.
Wir lassen die Umrisse der Kontinente auf einer per Maus drehbaren Kugel zeichnen.
Laden Sie dazu die Daten von Natural
Earth und legen Sie die Dateien ne_110m_land.shp und
ne_110m_land.shx aus dem heruntergeladenen Zip-Archiv an
eine Stelle, wo Sie sie wiederfinden.
Um solche Shapefile-Dateien zu lesen, ist noch die Bibliothek Geopandas zu installieren. Wir benötigen auch die Bibliothek NumPy (Numerical Python), die effizient mit großen Mengen an Zahlen (Vektoren, Matrizen usw.) umgeht. Numpy ist aber schon automatisch mit Matplotlib installiert worden.
Der Anfang des Programms ist damit:
import geopandas as gpd
import matplotlib.pyplot as plt
import numpy as np
import locale
plt.rcParams["axes.formatter.use_locale"] = "True" # fur Dezimalkommas usw.Wir erzeugen zum Test ein Diagramm mit einem 3D-Plot eines Dreiecks. Die Eckpunkte sind (0, 0, 0), (1, 0, 0) und (0, 1, 0). Um alle drei Linien zu zeichnen, ist der erste Eckpunkt wiederholt:
fig = plt.figure()
ax = fig.add_subplot(projection='3d')
x = [0, 1, 0, 0]
y = [0, 0, 1, 0]
z = [0, 0, 0, 0]
ax.plot(x, y, z)
ax.set_aspect('equal')
locale.setlocale(locale.LC_ALL, 'de_DE.UTF-8')
plt.show()Nun können wir stattdessen die Datei mit den Geodaten einlesen und die Umrisse der Kontinente plotten:
# Hier den Pfad zur Ihrer shp-Datei nehmen:
kontinente = gpd.read_file('ne_110m_land.shp')
for poly in kontinente.geometry:
if poly.geom_type == 'Polygon':
längengrade, breitengrade = poly.exterior.coords.xy
phis = np.radians(längengrade)
thetas = 0.5 * np.pi - np.radians(breitengrade)
x = np.sin(thetas) * np.cos(phis)
y = np.sin(thetas) * np.sin(phis)
z = np.cos(thetas)
ax.plot(x, y, z, color='k', linewidth=2)Hier wird der Effizenz halber immer mit allen Eckpunkten eines
Polygons auf einmal gerechnet. Die Variablen im if sind
dazu allesamt Arrays (wirklich Arrays und nicht die grundlegenden Listen
von Python). Die Längengrad-Angaben aller Punkte eines Polygons werden
auf einen Schlag von Winkelgrad nach Radiant umgerechnet, von allen
Winkeln ϕ wird auf einen
Schlag der Cosinus genommen, die jeweiligen Werte von sin (θ) und cos (ϕ) werden für alle Punkte auf
einen Schlag multipliziert usw. Sehen Sie sich im Debugger die Werte
von längengrade usw. an.
Nun fehlt noch die Kugel. Sie wird nicht mit Linien gezeichnet, sondern mit gefüllten Vierecken. Hier ein Beispiel für ein einziges Viereck:
x = np.array([[1, 2], [3, 4]])
y = np.array([[2, 2], [4, 5]])
z = np.array([[0, 0], [0, 0]])
ax.plot_surface(x, y, z)Die Funktion plot_surface verlangt die Koordinaten im
Raster über die gesamte Fläche. Also müssen x,
y und z jeweils zweidimensionale Arrays sein.
Das Array für y im Beispiel oben ist dieses:
| 2 | 2 |
| 4 | 5 |
Für die Erdkugel gehen wir den Winkel ϕ ∈ [0, 2π] und den Winkel
θ ∈ [0, π] der
sphärischen Koordinaten jeweils in (zum Beispiel) 100 Schritten durch.
Dazu dient die Funktion linspace. Daraus bildet
meshgrid zweidimensionale Arrays, die die Fläche im Raster
durchlaufen. Diese Arrays werden dann von den sphärischen Koordinaten
auf kartesische Koordinaten x,
y und z umgerechnet:
phis = np.linspace(0, 2*np.pi, 100)
thetas = np.linspace(0, np.pi, 100)
phis_all, thetas_all = np.meshgrid(phis, thetas)
x = np.cos(phis_all) * np.sin(thetas_all)
y = np.sin(phis_all) * np.sin(thetas_all)
z = np.cos(thetas_all)
ax.plot_surface(x, y, z, color='b', rstride=1, cstride=1, alpha=0.2, edgecolor='none')