Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Visualisierung mit Matplotlib

Matplotlib ist eine mächtige Python-Bibliothek, die viele Funktionen zur graphischen Darstellung von Daten in Form von Plots und Diagrammen bereitstellt. In diesem Kapitel lernen wir die grundlegende Funktionsweise kennen.

Erste Schritte

Ähnlich wie bei NumPy müssen wir Matplotlib zunächst installieren. Dies geschieht in einer Conda-Umgebung mit folgendem Befehl:

conda install -c conda-forge matplotlib

Anschließend können wir Matplotlib – genauer gesagt das Submodul matplotlib.pyplot – in unser Programm einbinden:

import matplotlib.pyplot as plt

Der wichtigste Befehl ist plt.plot(...). Wir können plt.plot? eingeben, um uns die Dokumentation anzeigen zu lassen.

In der einfachsten Form erwartet diese Funktion zwei Vektoren mit den xx- bzw. yy-Koordinaten einer Punktwolke. Diese Vektoren können Listen oder NumPy-Arrays sein.

Die Sinusfunktion können wir beispielsweise wie folgt plotten:

import numpy as np

x = np.linspace(0, 2*np.pi, 11)   # Erzeuge Gitter [0, 0.2*pi, 0.4*pi, ..., 2*pi])
y = np.sin(x)                     # Berechne zugehörige Funktionswerte

plt.plot(x,y)                     # Erzeuge Plot
plt.show()                        # Zeige den Plot
<Figure size 640x480 with 1 Axes>

Hier sehen wir auch eine schöne Anwendung der elementweise definierten mathematischen Funktionen aus numpy.

Gestaltung von Plots

Machen wir unseren Plot noch etwas schöner:

import numpy as np

x = np.linspace(0,4*np.pi, 1001) # Erzeuge äquidistantes Gitter für das Intervall [0, 4*pi]
y = np.sin(x)                    # Berechne zugehörige Funktionswerte für sinus
z = np.cos(x)                    # und cosinus

plt.figure(figsize=(10,5))       # Größe einstellen

plt.plot(x,y,label=r"$\sin(x)$")  # Erzeuge Plot für Sinus
plt.plot(x,z,label=r"$\cos(x)$")  # Erzeuge Plot für Cosinus

plt.title("Sinus und Cosinus")   # Titel des Plots
plt.grid()                       # Gitterlinien einschalten

plt.xlabel('x')                  # Bezeichner an x-Achse
plt.ylabel('f(x)')               # Bezeichner an y-Achse (in Latex-Code)

plt.legend()                     # Legende
plt.show()                       # Zeige den Plot
<Figure size 1000x500 with 1 Axes>

Im Prinzip hat Matplotlib unsere Punktwolke mit Koordinaten aus x und y gezeichnet und die Punkte mit Linien verbunden. Es gibt jedoch viele Möglichkeiten, das Aussehen der Linien und Marker anzupassen.

x = np.linspace(0,2,21)

y1= x-0.5*x**2
y2= 2*x-x**2
y3= 3*x-1.5*x**2 

plt.figure(figsize=(10,5))       # Größe einstellen

# Zeichne rote (r) Kreise (o) mit Verbindungslinien (-)
plt.plot(x, y1, 'ro-', linewidth=0.2, label='f1')  

# Zeichne blaue (b) Quadrate (s)
plt.plot(x, y2, 'bs', label='f1')   

# Zeichne cyane (c) Dreiecke (^) mit gestrichelten Verbindungslinien (--)
plt.plot(x, y3, 'c^--', markersize=10, label='f1')

plt.xlabel('x')
plt.ylabel('f(x)')
plt.grid()
plt.legend()
plt.show()
<Figure size 1000x500 with 1 Axes>

Die Zeichenkette ‘ro-’ gibt Farbe (r), Marker (o) und Linienstil (-) an.

Im Hilfetext plt.plot? sind noch weitere Linien- und Markertypen erklärt. Vordefinierte Farben im Submodul matplotlib.colors. Es gibt verschiedene Farbpaletten. Die Grundfarben sind:

import matplotlib.colors as mcolors
mcolors.BASE_COLORS
{'b': (0, 0, 1), 'g': (0, 0.5, 0), 'r': (1, 0, 0), 'c': (0, 0.75, 0.75), 'm': (0.75, 0, 0.75), 'y': (0.75, 0.75, 0), 'k': (0, 0, 0), 'w': (1, 1, 1)}

Darüber hinaus gibt es die Farbpalette Tableau, welche häufig für Diagramme verwendet wird:

mcolors.TABLEAU_COLORS
{'tab:blue': '#1f77b4', 'tab:orange': '#ff7f0e', 'tab:green': '#2ca02c', 'tab:red': '#d62728', 'tab:purple': '#9467bd', 'tab:brown': '#8c564b', 'tab:pink': '#e377c2', 'tab:gray': '#7f7f7f', 'tab:olive': '#bcbd22', 'tab:cyan': '#17becf'}

Außerdem stehen noch viele CSS-Farben zur Verfügung:

mcolors.CSS4_COLORS
{'aliceblue': '#F0F8FF', 'antiquewhite': '#FAEBD7', 'aqua': '#00FFFF', 'aquamarine': '#7FFFD4', 'azure': '#F0FFFF', 'beige': '#F5F5DC', 'bisque': '#FFE4C4', 'black': '#000000', 'blanchedalmond': '#FFEBCD', 'blue': '#0000FF', 'blueviolet': '#8A2BE2', 'brown': '#A52A2A', 'burlywood': '#DEB887', 'cadetblue': '#5F9EA0', 'chartreuse': '#7FFF00', 'chocolate': '#D2691E', 'coral': '#FF7F50', 'cornflowerblue': '#6495ED', 'cornsilk': '#FFF8DC', 'crimson': '#DC143C', 'cyan': '#00FFFF', 'darkblue': '#00008B', 'darkcyan': '#008B8B', 'darkgoldenrod': '#B8860B', 'darkgray': '#A9A9A9', 'darkgreen': '#006400', 'darkgrey': '#A9A9A9', 'darkkhaki': '#BDB76B', 'darkmagenta': '#8B008B', 'darkolivegreen': '#556B2F', 'darkorange': '#FF8C00', 'darkorchid': '#9932CC', 'darkred': '#8B0000', 'darksalmon': '#E9967A', 'darkseagreen': '#8FBC8F', 'darkslateblue': '#483D8B', 'darkslategray': '#2F4F4F', 'darkslategrey': '#2F4F4F', 'darkturquoise': '#00CED1', 'darkviolet': '#9400D3', 'deeppink': '#FF1493', 'deepskyblue': '#00BFFF', 'dimgray': '#696969', 'dimgrey': '#696969', 'dodgerblue': '#1E90FF', 'firebrick': '#B22222', 'floralwhite': '#FFFAF0', 'forestgreen': '#228B22', 'fuchsia': '#FF00FF', 'gainsboro': '#DCDCDC', 'ghostwhite': '#F8F8FF', 'gold': '#FFD700', 'goldenrod': '#DAA520', 'gray': '#808080', 'green': '#008000', 'greenyellow': '#ADFF2F', 'grey': '#808080', 'honeydew': '#F0FFF0', 'hotpink': '#FF69B4', 'indianred': '#CD5C5C', 'indigo': '#4B0082', 'ivory': '#FFFFF0', 'khaki': '#F0E68C', 'lavender': '#E6E6FA', 'lavenderblush': '#FFF0F5', 'lawngreen': '#7CFC00', 'lemonchiffon': '#FFFACD', 'lightblue': '#ADD8E6', 'lightcoral': '#F08080', 'lightcyan': '#E0FFFF', 'lightgoldenrodyellow': '#FAFAD2', 'lightgray': '#D3D3D3', 'lightgreen': '#90EE90', 'lightgrey': '#D3D3D3', 'lightpink': '#FFB6C1', 'lightsalmon': '#FFA07A', 'lightseagreen': '#20B2AA', 'lightskyblue': '#87CEFA', 'lightslategray': '#778899', 'lightslategrey': '#778899', 'lightsteelblue': '#B0C4DE', 'lightyellow': '#FFFFE0', 'lime': '#00FF00', 'limegreen': '#32CD32', 'linen': '#FAF0E6', 'magenta': '#FF00FF', 'maroon': '#800000', 'mediumaquamarine': '#66CDAA', 'mediumblue': '#0000CD', 'mediumorchid': '#BA55D3', 'mediumpurple': '#9370DB', 'mediumseagreen': '#3CB371', 'mediumslateblue': '#7B68EE', 'mediumspringgreen': '#00FA9A', 'mediumturquoise': '#48D1CC', 'mediumvioletred': '#C71585', 'midnightblue': '#191970', 'mintcream': '#F5FFFA', 'mistyrose': '#FFE4E1', 'moccasin': '#FFE4B5', 'navajowhite': '#FFDEAD', 'navy': '#000080', 'oldlace': '#FDF5E6', 'olive': '#808000', 'olivedrab': '#6B8E23', 'orange': '#FFA500', 'orangered': '#FF4500', 'orchid': '#DA70D6', 'palegoldenrod': '#EEE8AA', 'palegreen': '#98FB98', 'paleturquoise': '#AFEEEE', 'palevioletred': '#DB7093', 'papayawhip': '#FFEFD5', 'peachpuff': '#FFDAB9', 'peru': '#CD853F', 'pink': '#FFC0CB', 'plum': '#DDA0DD', 'powderblue': '#B0E0E6', 'purple': '#800080', 'rebeccapurple': '#663399', 'red': '#FF0000', 'rosybrown': '#BC8F8F', 'royalblue': '#4169E1', 'saddlebrown': '#8B4513', 'salmon': '#FA8072', 'sandybrown': '#F4A460', 'seagreen': '#2E8B57', 'seashell': '#FFF5EE', 'sienna': '#A0522D', 'silver': '#C0C0C0', 'skyblue': '#87CEEB', 'slateblue': '#6A5ACD', 'slategray': '#708090', 'slategrey': '#708090', 'snow': '#FFFAFA', 'springgreen': '#00FF7F', 'steelblue': '#4682B4', 'tan': '#D2B48C', 'teal': '#008080', 'thistle': '#D8BFD8', 'tomato': '#FF6347', 'turquoise': '#40E0D0', 'violet': '#EE82EE', 'wheat': '#F5DEB3', 'white': '#FFFFFF', 'whitesmoke': '#F5F5F5', 'yellow': '#FFFF00', 'yellowgreen': '#9ACD32'}

Durch Setzen des Parameters color im Plot-Befehl kann eine Farbe aus einer dieser Farbpaletten gewählt werden:

x = np.linspace(0,1,10)

plt.plot(x,0.5*x*(1-x),'o-',color='g')         # Grundfarbe
plt.plot(x,x*(1-x),'d-',color='tab:olive')     # Tableau-Farbe
plt.plot(x,1.5*x*(1-x),'s-',color='firebrick') # CSS-Farbe

plt.show()
<Figure size 640x480 with 1 Axes>

Die Farben können entweder über Kurzbezeichnungen ('r', 'g', 'b'), über Tableau-Namen ('tab:blue', 'tab:orange', ...) oder über CSS-Farbnamen ('firebrick', 'gold', 'navy', ...) angegeben werden.

Folgende Tabelle enthält eine vollständige Auflistung aller vordefinierter Farben:

Source
from matplotlib.patches import Rectangle
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors


def plot_colortable(colors, title, sort_colors=True, emptycols=0):

    cell_width = 212
    cell_height = 22
    swatch_width = 48
    margin = 12
    topmargin = 40

    # Sort colors by hue, saturation, value and name.
    if sort_colors is True:
        by_hsv = sorted((tuple(mcolors.rgb_to_hsv(mcolors.to_rgb(color))),
                         name)
                        for name, color in colors.items())
        names = [name for hsv, name in by_hsv]
    else:
        names = list(colors)

    n = len(names)
    ncols = 4 - emptycols
    nrows = n // ncols + int(n % ncols > 0)

    width = cell_width * 4 + 2 * margin
    height = cell_height * nrows + margin + topmargin
    dpi = 72

    fig, ax = plt.subplots(figsize=(width / dpi, height / dpi), dpi=dpi)
    fig.subplots_adjust(margin/width, margin/height,
                        (width-margin)/width, (height-topmargin)/height)
    ax.set_xlim(0, cell_width * 4)
    ax.set_ylim(cell_height * (nrows-0.5), -cell_height/2.)
    ax.yaxis.set_visible(False)
    ax.xaxis.set_visible(False)
    ax.set_axis_off()
    ax.set_title(title, fontsize=24, loc="left", pad=10)

    for i, name in enumerate(names):
        row = i % nrows
        col = i // nrows
        y = row * cell_height

        swatch_start_x = cell_width * col
        text_pos_x = cell_width * col + swatch_width + 7

        ax.text(text_pos_x, y, name, fontsize=14,
                horizontalalignment='left',
                verticalalignment='center')

        ax.add_patch(
            Rectangle(xy=(swatch_start_x, y-9), width=swatch_width,
                      height=18, facecolor=colors[name], edgecolor='0.7')
        )

    return fig

plot_colortable(mcolors.BASE_COLORS, "Grundfarben",
                sort_colors=False, emptycols=1)
plot_colortable(mcolors.TABLEAU_COLORS, "Tableau-Palette",
                sort_colors=False, emptycols=2)

plot_colortable(mcolors.CSS4_COLORS, "CSS-Farben")

# Optionally plot the XKCD colors (Caution: will produce large figure)
# xkcd_fig = plot_colortable(mcolors.XKCD_COLORS, "XKCD Colors")
# xkcd_fig.savefig("XKCD_Colors.png")

plt.show()
<Figure size 872x118 with 1 Axes>
<Figure size 872x162 with 1 Axes>
<Figure size 872x866 with 1 Axes>

Bei der Fehleranalyse sind oft logarithmische Achsen von Interesse.
Angenommen, wir analysieren einen iterativen Algorithmus und messen die Entfernung errn\text{err}_n zwischen der exakten Lösung und der berechneten Näherungslösung nach nn Iterationen.

Man sagt, das Verfahren konvergiert

  • Q-linear, falls

    errnCerrn1,C(0,1)\text{err}_n \le C\,\text{err}_{n-1}, \qquad C\in(0,1)
  • Q-superlinear, falls

    errnεnerrn1\text{err}_n \le \varepsilon_n\,\text{err}_{n-1}

    mit einer Nullfolge εn0\varepsilon_n \searrow 0

  • Q-quadratisch, falls

    errnCerrn12,C>0\text{err}_n \le C\,\text{err}_{n-1}^2, \qquad C>0

Stellen wir den Fehlerverlauf einmal in einem gewöhnlichen kartesischen Koordinatensystem und einmal in einem Koordinatensystem mit logarithmischer yy-Achse dar:

import math 

n = np.array(range(1,6), dtype='float64')
err_p1 = (0.8)**n
err_p2 = [1./math.factorial(int(i)) for i in n]
err_p3 = (0.8)**(2**n)

plt.figure(figsize=(10,5))

def generate_plot():
    plt.plot(n, err_p1, 'ro-', label='Q-linear')
    plt.plot(n, err_p2, 'bo-', label='Q-superlinear')
    plt.plot(n, err_p3, 'co-', label='Q-quadratisch')
    plt.grid()

# Plot in kartesischen Koordinatensystem
plt.subplot(1,2,1)
generate_plot()
plt.legend(loc='upper right')
    
# Plot in Koordinatensystem mit logarithmischer y-Achse
plt.subplot(1,2,2)
generate_plot()
plt.semilogy()
plt.legend(loc='lower left')
    
plt.show()
<Figure size 1000x500 with 2 Axes>

Wir sehen, dass eine Q-linear konvergente Folge im Plot mit logarithmischer yy-Achse als lineare Funktion erscheint.

Analog dazu kann auch die xx-Achse mit plt.semilogx() logarithmisch skaliert werden.
Für die oben betrachtete Anwendung ist dies allerdings wenig sinnvoll.

Balken-, Stab- und Tortendiagramme

Schauen wir uns weitere elementare Plot-Typen an. Angenommen wir haben die Auswertung einer Umfrage vorliegen, und möchten diese graphisch aufbereiten. Unsere Beispieldaten sind:

transport = ["Auto", "Fahrrad", "Bus", "Bahn", "Zu Fuß", "Sonstiges"]
colors = ["gray", "green", "blue", "red", "orange", "purple"]

values = [35, 28, 12, 10, 11]
values.append(100 - sum(values))

Anstelle des Befehls plt.plot können auch andere Plot-Typen verwendet werden:

  • stem – Stabdiagramm

  • scatter – Streudiagramm

  • bar – Balkendiagramm

  • pie – Tortendiagramm

Im folgenden Beispiel werden diese Darstellungsformen miteinander verglichen:

plt.figure(figsize=(10,10))

plt.subplot(2,2,1)
plt.stem(transport, values)
plt.title("Plot")

plt.subplot(2,2,2)
plt.bar(transport, values, color=colors)
plt.title("Bar")

plt.subplot(2,2,3)
plt.scatter(transport, values, color=colors)
plt.title("Scatter")

plt.subplot(2,2,4)
plt.pie(values, labels=transport, explode=[0,0.2,0,0,0,0], colors=colors, autopct='%1.1f%%')
plt.title("Pie")

plt.show()
<Figure size 1000x1000 with 4 Axes>

Plots für Skalar- und Vektorfelder

Auch für die graphische Darstellung von Skalarfeldern f ⁣:R2Rf\colon \mathbb{R}^2 \to \mathbb{R} und Vektorfeldern F ⁣:R2R2\vec F\colon \mathbb{R}^2 \to \mathbb{R}^2 stellt Matplotlib verschiedene Funktionen bereit.

Viele Darstellungen von Skalarfeldern erwarten als Argument drei Matrizen: eine für die xx-Koordinaten, eine für die yy-Koordinaten und eine für den Funktionswert f(x,y)f(x,y).

Hilfreich ist hier die Funktion numpy.meshgrid, mit der wir aus zwei eindimensionalen Gittern ein zweidimensionales Tensorprodukt-Gitter erzeugen.

# 1D-Gitter für x- und y-Variable
x = np.linspace(-5,5,1001)
y = np.linspace(-4,4,1001)

# 2D-Gitter erzeugen
X,Y = np.meshgrid(x,y)

# Definiere Himmelblau-Funktion
Z = (X**2 + Y - 11)**2 + (X + Y**2 - 7)**2

Countour-Plots:

Eine mögliche Darstellung eines solchen Skalarfeldes ist ein Contour-Plot. Dabei werden die Kurven

{(x,y) ⁣:f(x,y)=ci}\{(x,y)\colon f(x,y)=c_i\}

für verschiedene Werte c1<c2<<clevelsc_1<c_2<\dots<c_{\text{levels}} eingezeichnet:

plt.contour(X,Y,Z, levels=25)
plt.colorbar()
plt.show()
<Figure size 640x480 with 2 Axes>

Colormap-Plots:

Eine weitere Möglichkeit ist ein Color-Plot, bei dem der Funktionswert an einer Stelle (x,y)(x,y) über eine Farbskala dargestellt wird:

import matplotlib.cm as cm

plt.pcolormesh(X,Y,Z, cmap=cm.coolwarm)
plt.show()
<Figure size 640x480 with 1 Axes>

3D-Darstellungen von Skalarfeldern:

Skalarfelder lassen sich auch in einem dreidimensionalen Koordinatensystem darstellen. Dabei werden die Argumente auf der xx- und yy-Achse dargestellt und der Funktionswert auf der zz-Achse. Hier müssen wir uns zunächst ein dreidimensionales Koordinatensystem erzeugen. Dazu erzeugen wir eine neue Abbildung via

fig = plt.figure()

und fügen ein 3D-Koordinatensystem hinzu

ax = fig.add_subplot(projection='3d')

ax stellt dann die entsprechenden Plot-Befehle bereit. Hier ein Beispiel:

fig = plt.figure(figsize=(8,6))

# Surface-Plot
ax1 = fig.add_subplot(1,2,1, projection='3d')
ax1.plot_surface(X,Y,Z, cmap=cm.inferno)
ax1.set_title("Surface-Plot")

# Wireframe-Plot
ax2 = fig.add_subplot(1,2,2, projection='3d')
ax2.plot_wireframe(X, Y, Z, rcount=20, ccount=20)
ax2.set_title("Wireframe-Plot")

plt.show()
<Figure size 800x600 with 2 Axes>

Plots für Vektorfelder:

Vektorfelder F:R2R2\vec F:\mathbb{R}^2\to\mathbb{R}^2 können in Matplotlib mit sogenannten Quiver-Plots visualisiert werden. In einem Quiver-Plot wird der Funktionswert F(x)\vec F(\vec x) durch einen Pfeil beginnend im Punkt x\vec x gekennzeichnet.

Beispiel: Das Vektorfeld

f(x,y)=(y,x)\vec f(x,y) = (-y, x)^\top

lassen wir auf einem regelmäßigen Punktgitter darstellen. Optional können die Pfeile nach ihrer Länge eingefärbt werden.

x = np.linspace(-1,1, 11)
y = np.linspace(-1,1, 11)

# Punktgitter definieren
X,Y = np.meshgrid(x, y)

# Funktionswerte von F
Z1 = -Y
Z2 = X

# Optional: Färbe Pfeile nach Länge
C = np.sqrt(Z1**2 + Z2**2)

# Quiverplot erzeugen und anzeigen
plt.quiver(X, Y, Z1, Z2, C, cmap=cm.rainbow)
plt.show()
<Figure size 640x480 with 1 Axes>

Plots für Kurven

Auch Kurven lassen sich in Matplotlib zeichnen. Eine Kurve ist zunächst eine Menge an Punkten

Γ={x(t)Rn ⁣:t[ta,tb]}\Gamma = \{\vec x(t)\in \mathbb R^n\colon \quad t\in[t_a,t_b]\}

mit einer sogenannten Kurvenparametrisierung x ⁣:[ta,tb]Rn\vec x\colon[t_a,t_b]\to\mathbb{R}^n, welche als regulär vorrausgesetzt wird, d.h., x˙(t)0\dot{\vec x}(t)\ne 0 für alle t[ta,tb]t\in [t_a,t_b].

Kurven in der Ebene:

Für eine ebene Kurve (n=2n=2) können wir den normalen Plot-Befehl nutzen. Das Kleeblatt

Γ={x(t)=(cos(t)+cos(2t)sin(t)sin(2t)) ⁣:t[0,2π]}\Gamma = \{\vec x(t) = \begin{pmatrix}\cos(t)+\cos(2t) \\ \sin(t)-\sin(2t)\end{pmatrix}\colon\quad t\in [0,2\pi]\}

zeichnen wir beispielsweise mit

t = np.linspace(0,2*np.pi,100)
x = np.cos(t)+np.cos(2*t)
y = np.sin(t)-np.sin(2*t)

plt.plot(x,y,'o-')
plt.grid()
plt.show()
<Figure size 640x480 with 1 Axes>

Kurven im Raum:

Ähnlich kann man Raumkurven (n=3n=3) zeichnen, man benötigt nur vorher ein dreidimensionales Koordinatensystem. Wie wir das anlegen haben wir aber schon gesehen. Wir zeichnen hier die Schraubenlinie

Γ={(cos(t)sin(t)t) ⁣:t[0,4π]}.\Gamma = \{\begin{pmatrix}\cos(t)\\ \sin(t) \\ t\end{pmatrix}\colon t\in [0,4\pi]\}.
t = np.linspace(0,4*np.pi,100)
x = np.cos(t)
y = np.sin(t)
z = t

fig = plt.figure()

ax = fig.add_subplot(projection='3d')
ax.plot3D(x, y, z)

plt.show()
<Figure size 640x480 with 1 Axes>