Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | Blog RSS

Stand: 2024-04-30
mit vielen Formulierungen von ChatGPT 4

Datenvisualisierung mit Matplotlib

Was ist Matplotlib?

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 es Benutzern, 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 Figuren und Achsen, auf denen Benutzer ihre Daten visualisieren können. Die Bibliothek benutzt eine objektorientierte API, die es ermöglicht, komplexe Plots auf eine kontrollierbare und präzise Weise zu gestalten. Für schnelle und einfache Visualisierungen bietet Matplotlib auch eine prozedurale Schnittstelle, bekannt als Pyplot, die das Erstellen von Visualisierungen mit weniger Codezeilen unterstützt und dabei an die Funktionsweise von MATLAB® angelehnt ist.

Ein großer Vorteil von Matplotlib ist seine Erweiterbarkeit und Anpassbarkeit. Nutzer können das Aussehen von Graphen vollständig anpassen, indem sie Titel, Achsenbeschriftungen, Legenden und andere Stilelemente modifizieren, siehe die Beispiele auf den Cheatsheets und Handouts. Darüber hinaus können sie mit zusätzlichen Paketen wie Seaborn, das auf Matplotlib aufbaut, weiterführende statistische Visualisierungen 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.

Beispiel für ein 2D-Diagramm

Es soll ein xy-Datensatz als Streudiagramm geplottet werden, dazu die Regressionsgerade samt deren Gleichung.

Bibliothek und Daten

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 plt

Nun 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]

Scatterplot

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.)

Regressionsgerade

Um nun noch eine Regressionsgerade durch den Scatterplot zu legen, verwenden wir die Funktion linregress der Bibliothek SciPy. Beachte, dass diese eine Funktion hier fünf Werte zurückliefert, 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')

Deutsche Schreibweise für Dezimalzahlen

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.

Fehlerbalken

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.

Beispiel für ein 3D-Diagramm

Wir lassen die Umrisse der Kontinente auf einer per Maus drehbaren Kugel zeichnen.

Daten und Bibliotheken

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

Plotten der Kontinente

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)

plt.show()

Nun können wir 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')

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.

Plotten der Erdkugel

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', alpha=0.2)