{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## jupyter notebook Tutorial: \n",
"# Visualisierung mit *matplotlib*\n",
" Günter Quast, Dez. 2020\n",
"---\n",
"\n",
"## Kurzanleitung zu Jupyter Notebooks\n",
"\n",
"Diese Datei vom Typ `.ipynb` enthält ein Tutorial als `jupyter notebook`.\n",
"`jupyter` bietet eine Browser-Schnittstelle mit einer (einfachen) Entwicklungsumgebung\n",
"für `python`-Code und erklärende Texte im intuitiven *markdown*-Format. Die Eingabe von Formeln im `LaTeX`-Format wird ebenfalls unterstützt. \n",
"\n",
"Eine Zusammenstellung der wichtigsten Befehle zur Verwendung von *jupyter* als\n",
"Arbeitsumgebung findet sich im Notebook\n",
"[*JupyterCheatsheet.ipynb*](JupyterCheatsheet.ipynb). \n",
"Die kurzen Abschnitte geben einen Überblick über das Notwendigste, um mit dem \n",
"Tutorial arbeiten zu können. \n",
"\n",
"In *jupyter* werden Code und Text in jeweils einzelne Zellen eingegeben. \n",
"Aktive Zellen werden durch einen blauen Balken am Rand angezeigt. Sie können sich in zwei Zuständen befinden: im Edit-Modus ist das Eingabefeld weiß, im Command-Modus ist es\n",
"ausgegraut. Durch Klicken in den Randbereich wird der Command-Modus gewählt, ein Klick \n",
"in das Textfeld einer Code-Zelle schaltet in den Edit-Modus. Die Taste `esc` kann\n",
"ebenfalls verwendet werden, um den Edit-Modus zu verlassen. \n",
"\n",
"Eingabe von `a` im Command-Modus erzeugt eine neue leere Zelle oberhalb der aktiven Zelle,\n",
"`b` eine unterhalb. Eingabe von `dd` löscht die betreffende Zelle.\n",
"\n",
"Zellen können entweder den Typ `Markdown` oder `Code` haben. Die Eingabe von `m` im Command-Modus setzt den Typ Markdown, Eingabe von `y` wählt den Typ Code.\n",
"\n",
"Prozessiert - also Text gesetzt oder Code ausgeführt - wird der Zelleninhalt durch \n",
"Eingabe von `shift+return`, oder auch `alt+return` wenn zusätzliche eine neue, leere Zelle erzeugt werden soll. \n",
"\n",
"Die hier genannten Einstellungen sowie das Einfügen, Löschen oder Ausführen von Zellen können auch über das Pull-Down-Menü am oberen Rand ausgeführt werden. \n",
"\n",
"---\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> Bei diesem Tutorial handelt es sich um einen Ansatz nach dem Prinzip \n",
"\"_learning by doing_\".\n",
"Es werden einfache Beispiele in der Sprache _Python_ verwendet, um konkrete \n",
"Anwendungen zu zeigen, die auch in eigenen Arbeiten verwendet werden können. \n",
"Es gibt andere Tutorials, die \n",
"Grundlagen der Sprache _Python_ \n",
"den Umgang mit dem Paket _numpy_ \n",
"vermitteln - siehe *PythonIntro.ipynb* oder *PythonChearsheet.ipynb*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"---\n",
"\n",
"# Grafische Darstellung mit *matplotlib*\n",
"---\n",
"\n",
"## Inhalt: \n",
"\n",
"[1. Einführung](#Sec-Intro) \n",
"[2. Ein ganz einfaches Beispiel](#Sec-Simple) \n",
"[3. Darstellungen von Datenpunkten mit Unsicherheiten](#Sec-SimpleData) \n",
"[4. Darstellung von Daten und Modell](#Sec-Data-andData) \n",
"[5. Häufigkeitsverteilungen](#Sec-Histogram) \n",
"[6. Weitere Darstellungen](#Sec-WeitereDarstellungen) \n",
"[7. Fortgeschrittene Anwendung von *matplotlib*](#Sec-Advanced) \n",
"[8. Mehrere Grafiken in der gleichen Abbildung](#Sec-MultiplePlots) \n",
"[9. Dreidimensionale Darstellungen](#Sec-3D) \n",
"[10. Anpassung von Darstellungsoptionen](#Sec-DarstellungsAnpassung)\n",
"\n",
"---\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 1. Grundsätzliches zur *matplotlib* [^](#Inhalt)\n",
"\n",
"*matplotlib* ist eine sehr mächtige, quelloffene *Python*-Bibliothek zur Erzeugung von Grafiken in Publikationsqualität. Ziel der Autoren ist es, \"einfache Dinge einfach und\n",
"schwierige Dinge möglich zu machen\". *matplotlib* enthält bereits eine Vielzahl von in der Wissenschaft üblichen Darstellungsformen, erlaubt es aber auch, durch Bereitstellung von Basisobjekten komplexe eigene Grafiken zu erstellen. Die vollständige Dokumentation auf den Projektseiten [matplotlib.org](https:matplotlib.org) enthält sowohl Tutorials als auch ein ausführliche Galerie mit Beispielen, die als Grundlage für die eigene Arbeit mit *matplotlib* dienen können. \n",
"\n",
"*matplotlib* folgt prinzipiell einem objekt-orientierten (“OO”) Ansatz mit einem entsprechenden Nutzerinterface.\n",
"Das *Figure*-Objekt ist ein Container für weitere Objekte, die eine Grafik ausmachen (Plots, Achsen, Linien usw.).\n",
"\n",
"In der Praxis und vor allem für schnelle Implementierungen einfacher ist das funktionale Interface *pyplot*, das Funktionen zur\n",
"Erzeugung *Figures* und deren Objekten bereit stellt, das eine Imitation der im wissenschaftlichen Umfeld weit verbreiteten, kommerziellen Software [*MATLAB*](https://www.mathworks.com) darstellt. \n",
"\n",
"Eine weitere, auf *matplotlib* aufsetzende Software zur Visualisierung statistischer Daten ist das Projekt\n",
"[seaborn](https://seabaron.pydata.org), mit dessen Hilfe ansprechende und den üblichen Standards der statistischen\n",
"Datenanalyse in den empirischen Wissenschaften entsprechende Darstellungsformen erzeugt werden können. \n",
"\n",
"In diesem Tutorial wollen wir uns zunächst mit dem *pylot*-Interface beschäftigen, mit dem schnell und \n",
"einfach Abbildungen erstellt werden können. Alle *pyplot*-Kommandos wirken jeweils auf die gleiche Abbildung, \n",
"die während aller aufeinader folgenden Schritte erhalten bleibt. \n",
"*pyplot*-Kommandos liefern Zeiger auf die *matplotlib*-Objekte, so dass im Bedarfsfall auch auf die komplexeren,\n",
"aber wesentlich mächtigeren Methoden des objektorientierten *matplot*-Interfaces zurückgegriffen werden kann. \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1.1 *pyplot* in *Jupyter* Notebooks [^](#Inhalt)\n",
"\n",
"Um das *matplotlib* mit *Jupyter* Notebooks, verwenden zu können, sind nur ganz wenige Zeilen notwendig, die in der\n",
"Codezelle unten gezeigt sind. Mit dem “magischen Kommando” \n",
"`%matplotlib inline` \n",
"wird erreicht, dass mit *matplotlib* erzeugte Grafiken in *Jupyter* angezeigt werden. \n",
"\n",
"Weiter wird das Paket *numpy* benötigt, das Funktionen zum effizienten Umgang mit Feldern bereitstellt. \n",
"\n",
"In der letzten Zeile wird dann *pyplot* mit dem Alias-Namen *plt* importiert, so dass *pyplot*-Funktionenvereinfacht als \n",
"`plt.` \n",
"aufgerufen werden können.\n",
" \n",
"Bevor es los geht, also bitte den Code in der folgenden Zelle durch Eingabe von `+` ausführen!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"## allgemein nützliche Einstellungen und Pakete\n",
"\n",
"# Grafiken im Notebook anzeigen\n",
"%matplotlib inline\n",
"\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## 2. Ein ganz einfaches Beispiel [^](#Inhalt)\n",
"\n",
"---\n",
"\n",
"Nun ist alles bereit, um das erste Beispiel anzuschauen. Dazu ist nur ganz wenig Code notwendig. \n",
"\n",
"Zunächst werden Daten benötigt, die dargestellt werden sollen. \n",
"Dies erledigt die *numpy*-Funktion `linspace()`. Mit deren Hilfe werden zunächst \n",
"200 Stützstellen im Bereich von -20. bis 20. für eine Funktion erzeugt: \n",
"`x = np.linspace(-20., 20., 200)` \n",
"Dann werden die Funktionswerte berechnet: \n",
"`y = np.sin(x)/x` \n",
"Die Darstellung erledigt die *pyplot*-Funktion \n",
"`plt.plot(x,y)`\n",
"\n",
"Damit existiert die gewünschte Abbildung im Speicher des Computers. Es fehlt noch eine Anweisung, die festlegt, was mit der Grafik geschehen soll - sie könnte mit der Funktion (`plt.savefig()` auf der Festplatte unter dem Namen `` gespeichert werden. Hier soll sie aber zunächst auf dem Bildschirm angezeigt werden. Das erledigt die Funktion \n",
"`plt.show()` "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# erstes Beispiel\n",
"# ---------------\n",
"\n",
"# Felder mit Datenpunkten erzeugen \n",
"x = np.linspace(-20., 20., 200)\n",
"y = np.sin(x)/x\n",
"\n",
"# Abbildung erzeugen\n",
"plt.plot(x,y)\n",
"\n",
"# Abbildung darstellen\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Darstellungen von Datenpunkten mit Unsicherheiten [^](#Inhalt)\n",
"----\n",
"\n",
"Daten in der Physik sind typischerweise Messungen mit Unsicherheiten. Zu deren Darstellung bietet *pyplot* die Funktion\n",
"*errorbar()*, die Daten nicht als Punkte, sondern als Symbole mit Fehlerbalken darstellt. \n",
"\n",
"Zunächst werden die Datenpunkte als Felder mit $x$- und $y$-Koordinaten und die entsprechenden Unsicherheiten erzeugt:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# Datenpunkte erzeugen\n",
"Dx = [1., 2., 3., 4.]\n",
"Dy = [1.1, 1.9,3.05, 4.2]\n",
"sy = [0.1, 0.15, 0.2, 0.25]\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Das Erzeugen der Abbildung und Darstellung auf dem Bildschirm erfolgen \n",
"analog zum ersten Beispiel:\n",
"```\n",
"plt.errorbar(Dx, Dy, sy)\n",
"plt.show()\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Codezeilen zum Testen hier eingeben und ausprobieren\n",
"# -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wie man sieht, ist die grafische Darstellung noch nicht sehr schön: \n",
"die Punkte sind durch eine Linie verbunden, und Symbole für die Datenpunkte fehlen. \n",
"Das lässt sich mit Formatierungsanweisungen beheben beim Aufruf der Funktion *errorbar()* \n",
"beheben, z. B. `fmt='ro'`. `r` steht für die Farbe rot (red), `o` bezeichnet den\n",
"gewünschten Marker-Typ, hier ein ausgefüllter Kreis. Andere Typen von Markern sind `.` für Punkt,\n",
"`,` für einen Pixel, `v` für ein Dreieck, `s` für Rechteck, `+` für $+$. Eine vollständige Liste\n",
"findet sich in der *matplotlib*-Dokumenation.\n",
"\n",
"Der Funktionsaufruf zur Darstellung von Datenpunkten sieht dann so aus:\n",
"\n",
"`plt.errorbar(Dx, Dy, yerr=sy, fmt='ro')`\n",
"\n",
"Da die Funktion *errorbar()* eine ganze Reihe von zusätzlichen Optionen erlaubt, ist es sinnvoll, \n",
"die Parameter als benannte Argumente zu übergeben. Im Gegensatz zum einfachen ersten Beispiel wird\n",
"also hier auch die Angabe der Unsicherheiten in $y$-Richtung als benanntes Argument angegeben. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Codezeilen zum Testen hier eingeben und ausprobieren\n",
"# -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vollständig ist die Grafik nun aber immer noch nicht, es fehlen die zwingend notwendigen \n",
"Achsenbeschriftungen und ggf. ein Titel für die Abbildung. \n",
"Dazu dienen die Funktionen\n",
"```\n",
"# Grafik beschriften\n",
"plt.xlabel('x-Werte / bel. Einheit')\n",
"plt.ylabel('y-Werte / bel. Einheit)\n",
"plt.title('Beispieldaten')\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und vervollständigen\n",
"# -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Darstellung von Daten und Modell [^](#Inhalt)\n",
"---\n",
"\n",
"In der Regel werden Daten mit einem Modell verglichen.\n",
"Dazu kann dieses Beispiel mit dem vorigen kombiniert und Datenpunkte\n",
"sowie eine Funktion in die Abbildung eingezeichnet werden.\n",
"\n",
"Die Modellfunktion wird in der folgenden Zelle definiert:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# Modellfunktion definieren\n",
"def model(x, a=1, b=0):\n",
" return a*x+b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Darstellung erfolgt genau wie im ersten Beispiel zur Darstellung einer \n",
"Funktion:\n",
"```\n",
"# Einzeichnen einer Modellfunktion \n",
"x = np.linspace(0., 5., 100)\n",
"plt.plot(x,model(x))\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und vervollständigen\n",
"# -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Eine Kleinigkeit fehlt noch, die Bedeutung der Linien und Punkte. Dazu dient die Funktion *legend()*, die die Angabe von \n",
"Bezeichnungen (Labels) für die in der Grafik eingezeichneten Objekte erlaubt. Dazu sind leichte Modifikationen beim \n",
"Zeichnen der Objekte und der Aufruf der Funktion *legend()* notwendig:\n",
"\n",
"```\n",
"plt.errorbar( ..., label=`Daten`, ...)\n",
"```\n",
"```\n",
"plt.plot(..., label='Modell', ...)\n",
"```\n",
"```\n",
"#Legende erzeugen\n",
"plt.legend()\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und vervollständigen\n",
"# -->\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mit dem nun vorhandenen Code existiert bereits ein allgemein verwendbares Gerüst für die einfache Darstellung von Datenpunkten, deren Unsicherheiten und einer Modellfunktion, wie sie in der Praxis sehr häufig vorkommt. \n",
"\n",
"Die vollständige Liste der Optionen der Funktion *errorbar()* ist\n",
"\n",
"```\n",
"errorbar(x, y, yerr=None, xerr=None, fmt='', ecolor=None, elinewidth=None, capsize=None, \n",
"barsabove=False, lolims=False, uplims=False, xlolims=False, xuplims=False, errorevery=1, \n",
"capthick=None, *, data=None, **kwargs)\n",
"```\n",
"Die Beschreibung findet sich in der Dokumentation zu *matplotlib.pyplot.errorbar()*"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.1 Beeinflussung des Grafik-Layouts [^](#Inhalt)\n",
"---\n",
"\n",
"Die Abbildung ist nun recht vollständig, die Darstellung ist aber noch nicht für alle Zwecke geeignet. \n",
"\n",
"Wenn die Daten einen großen Bereich abdecken, ist eine logarithmische Darstellung hilfreich. \n",
"Zur Beeinflussung der Skalierung der Achsen gibt es die Funktion *plt.yscale(value)*.\n",
"\n",
"Zum Ausprobieren einfach die Zeile\n",
"```\n",
"plt.yscale(\"log\")\n",
"\n",
"```\n",
"nach dem *plot()*-Befehl einfügen. Zum Zurücksetzen ```plt.yscale(\"linear\")``` verwenden.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und vervollständigen\n",
"# ->\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Es gibt auch Einstellungsmöglichkeiten für den dargestellten Bereich: \n",
"`plt.xlim(, )` Minimum und Maximum auf der x-Achse \n",
"`plt.ylim(, )` Minimum und Maximum auf der y-Achse \n",
"\n",
"Damit kann die logarithmische Darstellung durch Angabe eines passenderen Bereichs\n",
"für die x-Achse verbessert werden, wie im folgenden Codebeispiel gezeigt. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Vollständiges Codebeispiel zur Darstellung von Daten und Modellfunktion\n",
"# -----------------------------------------------------------------------\n",
"\n",
"\n",
"plt.errorbar(Dx, Dy, yerr=sy, fmt='ro', label='Daten')\n",
"\n",
"# Grafik beschriften \n",
"plt.xlabel('x-Werte / bel. Einheit')\n",
"plt.ylabel('y-Werte / bel. Einheit')\n",
"plt.title('Beispieldaten')\n",
" \n",
"# Modellfunktion einzeichnen\n",
"x = np.linspace(0., 5., 100,)\n",
"plt.plot(x,model(x), 'b-', label='Modell') \n",
"plt.yscale(\"log\")\n",
"plt.xlim(0.5,4.5)\n",
"\n",
"# Legende erzeugen\n",
"plt.legend()\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Schriftgröße und Schriftart\n",
"\n",
"Zur Verwendung in einer Präsentation hätte man vielleicht gerne die Beschriftungen größer,\n",
"und in einer Publikation möchte man eine andere Schriftart wählen. \n",
"Natürlich bietet *matplotlib* dazu eine Vielzahl an Möglichkeiten. \n",
"\n",
"Eine Möglichkeit besteht darin, zusätzliche Parameter beim Aufruf anzugeben.\n",
"*xlabel()*, *ylabel()* und *title()* kennen zur Wahl der Schriftgröße \n",
"den Parameter `size`, der die Werte \n",
"`small`, `medium`, `large`, `x-large` oder `xx-large`\n",
"annehmen kann, also z. B. \n",
"`plt.xlabel( ..., size='x-large')`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und verschiedene Schrifgrößen testen\n",
"# ->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Änderung der Schriftart ist ebenfalls möglich, hängt aber von den auf dem System verfügbaren Schriften ab. \n",
"Dazu muss ein Dictionary mit dem gewünschten Font-Namen als zusätzliche Parameter übergeben werden.\n",
"\n",
"```\n",
"# create font dictionary\n",
"csfont = {'fontname' : 'Comic Sans MS'}\n",
"\n",
"title('Beispieldaten, size='xx-large', **csfont)\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und vervollständigen\n",
"# ->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wenn die Größe der Grafik insgesamt verändert werden soll, kann man gezielt eine Abbildung erzeugen und\n",
"Parameter zur gewünschten Größe als Tuple (Breite, Höhe) in Zoll (inches) und die Auflösung in Dots/inch \n",
"angeben:\n",
"```\n",
"plt.figure(figsie=(8, 5), dpi=300)\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code aus dem vorigen Beispiel kopieren und vervollständigen\n",
"# ->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Bisweilen möchte man in einer Grafik zusätzlichen Text darstellen. Dazu dient die Funktion *text(x-Position, y-Position, text, Optionen)*.\n",
"\n",
"Hier ein Beispiel:\n",
"```\n",
"plt.text(2.8, 0.1, 'Grafik mit matplotlib')\n",
"```\n",
"\n",
"Das vollständige Codebeispiel mit Anapassung von Schriftgröße und -Font \n",
" zur Darstellung von Daten und Modellfunktion sieht nun so aus:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Vollständiges Codebeispiel mit Anapassung von Schriftgröße und -Font \n",
"# zur Darstellung von Daten und Modellfunktion\n",
"# --------------------------------------------------------------------\n",
"\n",
"# Abbildung erzeugen\n",
"plt.figure(figsize=(7.5, 6), dpi=100)\n",
"\n",
"# Daten mit Fehlerbalken zeichnen\n",
"plt.errorbar(Dx, Dy, yerr=sy, fmt='ro', label='Daten')\n",
"\n",
"# Grafik beschriften \n",
"\n",
"plt.xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"plt.ylabel('y-Werte / bel. Einheit', size='x-large')\n",
"# create font dictionary\n",
"csfont = {'fontname' : 'Comic Sans MS'}\n",
"plt.title('Beispieldaten', size='xx-large', **csfont)\n",
" \n",
"# Modellfunktion einzeichnen\n",
"x = np.linspace(0., 5., 100,)\n",
"plt.plot(x,model(x), 'b-', label='Modell') \n",
"## plt.yscale(\"log\")\n",
"## plt.xlim(0.5,4.5)\n",
"\n",
"# Legende erzeugen\n",
"plt.legend()\n",
"\n",
"# Text einfügen\n",
"plt.text(2.8, 0.1, 'Grafik mit matplotlib', color='darkgreen', size='xx-large')\n",
"\n",
"# Abbildung darstellen\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Das oben gezeigte Code-Beispiel ist nun recht flexibel und kann als allgemeine Vorlage \n",
"für die Darstellung von Daten und Modellen verwendet werden."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Häufigkeitsverteilungen [^](#Inhalt)\n",
"---\n",
"\n",
"Eine weitere, in der Physik häufig benötigte Darstellungsform von Messdaten ist die\n",
"Häufigkeitsverteilung, auch Histogramm genannt. \n",
"In *pyplot* steht dafür die Funktion *hist()* zur Verfügung, die die Häufigkeit\n",
"des Auftretens von Werten im Feld $x$ in bestimmten Intervallen als Balkendiagramm\n",
"darstellt.\n",
"\n",
"Zunächst werden gaußförmig verteilte Zufallszahlen erzeugt:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"\n",
"# Zufallsdaten erzeugen\n",
"xdata = np.random.normal(size=200)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Darstellung erfolgt mittels `plt.hist(xdata)`.\n",
"Die Methoden zur Achsenbeschriftung sind die gleichen wie schon besprochen.\n",
"\n",
"```\n",
"\"\"\"\n",
" Darstellung von Häufigkeitsverteilungen\n",
"\"\"\"\n",
"# Abbildung erzeugen\n",
"plt.figure(figsize=(7.5, 6.0), dpi=100)\n",
"#Daten als Histogram in 50 Intervallen darstellen\n",
"plt.hist(x, bins=50)\n",
"\n",
"# Achsenbeschriftung\n",
"plt.xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"plt.ylabel('Anzahl/bin', size='x-large')\n",
"plt.title('Beispieldaten', size='xx-large')\n",
"\n",
"plt.show()\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"## Code hier testen\n",
"# -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Intervalleinteilung hängt in diesem Beispiel noch von den Daten ab. Man kann sie genau festlegen, wenn man statt der\n",
"Zahl der Intervalle die Intervallgrenzen als Feld angibt, z. B. nbins=np.linspace(-3.,3.,101). \n",
"Mit der Option `density=True` kann das Histogramm als Verteilungsdichte normiert werden, d. h. \n",
"die Häufigkeit einer Beobachtung in einem Bin ergibt sich als Produkt des für das Bin angegebenen\n",
"Werts mit der Binbreite.\n",
"\n",
"Dazu notwendige Änderungen am Code sind:\n",
"\n",
"```\n",
"binedges = np.linspace(-3., 3., 51)\n",
"plt.hist(x, bins=binedges, density=True)\n",
"```\n",
"```\n",
"plt.ylabel('Verteilungsdichte', size='xx-large')\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code von oben kopieren und anpassen\n",
"# -->\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Mit der Option `density=True` kann direkt mit der Gaußverteilung verglichen werden.\n",
"\n",
"Zunächst definieren wir dazu eine Funktion zur Berechnung einer Gaußverteilung:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# define Gauss distribution)\n",
"def fGauss(x,mu=0.,sigma=1.):\n",
" return (np.exp(-(x-mu)**2/2/sigma**2)/np.sqrt(2*np.pi)/sigma)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Der Code zur Darstellung der Gaußverteilung in der gleichen Grafik ist völlig\n",
"analog zu den bereits oben eingeführten Beispielen zur Darstellung von Funktionen:\n",
"\n",
"```\n",
"# Gaußverteilug darstellen, Stützstellen in der Binmitte\n",
"xp = (binedges[:-1] + binedges[1:])/2.\n",
"plt.plot(xp, fGauss(xp))\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Vollständiges Codebeispiel zur Darstellung von Häufigkeitsverteilungen\n",
"# und Vergleich mit einer Verteilungsdichte \n",
"# --------------------------------------------------------------------\n",
"\n",
"#Daten als Histogram in 50 Intervallen darstellen\n",
"# Abbildung erzeugen\n",
"plt.figure(figsize=(7.5, 6), dpi=100)\n",
"# Histogram mit 50 Bins von [-3.,3.] (d.h. mit 51 Bingrenzen)\n",
"binedges = np.linspace(-3., 3., 51)\n",
"plt.hist(xdata, bins=binedges, density=True)\n",
"\n",
"# Achsenbeschriftung\n",
"plt.xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"plt.ylabel('Verteilungsdichte', size='x-large')\n",
"plt.title('Beispieldaten', size='xx-large')\n",
"\n",
"# Gaußverteilug darstellen, Stützstellen in der Binmitte\n",
"xp = (binedges[:-1] + binedges[1:])/2.\n",
"plt.plot(xp, fGauss(xp))\n",
"\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Berechnung statistischer Größen aus den Histogrammdaten \n",
"\n",
"Um statistische Größen wie Mittelwert oder Standardabweichung aus den Histogrammdaten\n",
"zu berechnen, muss man auf die Rückgabewerte der Funktion *hist()* zugreifen. \n",
"\n",
"```\n",
"bin_contents, bin_edges, pltobjs = plt.hist(x, bins=binedges)\n",
"```\n",
"\n",
"Das Paket [PhyPraKit](https://git.scc.kit.edu/yh5078/PhyPraKit) enhält eine Funktion *histstat(bin_contents, bin_edges)*,\n",
"die aus diesen Daten die statistischen Größen berechnet.\n",
"*Die Option density=True* sollte nicht verwendet werden, damit\n",
"die Unsicherheit auf den Mittelwert korrekt ausgegeben wird.\n",
"\n",
"Der relevante Code ist folgender: "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"def histstat(binc, bine, pr=True):\n",
" \"\"\"\n",
" calculate mean, standard deviation and uncertainty on mean \n",
" of a histogram with bin-contents `binc` and bin-edges `bine`\n",
" \n",
" Args:\n",
" * binc: array with bin content\n",
" * bine: array with bin edges\n",
"\n",
" Returns:\n",
" * float: mean, sigma and sigma on mean \n",
" \"\"\"\n",
"\n",
" bincent =(bine[1:]+bine[:-1])/2 # determine bincenters\n",
" mean = sum(binc*bincent)/sum(binc)\n",
" rms=np.sqrt(sum(binc*bincent**2)/sum(binc) - mean**2)\n",
" sigma_m = rms/np.sqrt(sum(binc))\n",
" if pr: \n",
" print('hist statistics:\\n'\\\n",
"' mean=%g, sigma=%g sigma of mean=%g\\n' %(mean,rms,sigma_m))\n",
" return mean, rms, sigma_m\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In der folgenden Zelle die Zeile mit dem Aufruf von *plt.hist()* anpassen und\n",
"*histstat()* ausprobieren:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code von oben kopieren und anpassen\n",
"# -->\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.5 Zweidimensionale Häufigkeitsverteilungen [^](#Inhalt)\n",
"---\n",
"\n",
"Bei vielen Problemstellungen sind mehr als eine Zufalls- oder Messgröße relevant. \n",
"Dann müssen multidimensionale Verteilungen untersucht werden. Wegen der auf zwei\n",
"Dimensionen beschränkten Darstellungsmöglichkeiten werden dann Paare von Größen\n",
"untersucht, um Zusammenhänge zwischen ihnen darzustellen. \n",
"*matplotlib* bietet dafür verschiedene Versionen von zweidimensionalen Darstellungen an. \n",
"\n",
"Zur Illustration benötigen wir zunächst Zufallszahlen in zwei Dimensionen. Korrelierte, gaußförming verteilte Zufallszahlen lassen sich mit folgendem Code erzeugen:\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# Definition einer zweidimensionalen Verteilungsdichte\n",
"def gen2dGauss(size=10000, mux=5., sigx=10., muy=20., sigy=3., rho=0.15 ):\n",
"# generate two arrays with pairs of correlated gaussian numbers\n",
" u=np.random.randn(size) \n",
" x = mux+sigx*u # gauss, with mean mux and sigma sigx\n",
" v = np.random.randn(size) \n",
" y = muy+sigy*(rho*u+np.sqrt(1.-rho**2)*v)\n",
" return x, y\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"#### Darstellung als Streudiagramm\n",
"\n",
"Eine ganz einfache Möglichkeit, zweidimensionale Daten darzustellen, ist das sogenannte Streudiagramm (Scatter Plot), bereitgestellt von der Funktion *plt.scatter()*. Über\n",
"die Option *s=size* wird die Symbolgröße gesetzt. Hier ein einfaches Codebeispiel:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# Daten erzeugen\n",
"x2, y2 = gen2dGauss(1000)\n",
"\n",
"# Streudiagramm erzeugen\n",
"plt.scatter(x2, y2, s=5)\n",
"\n",
"# Achsenbeschriftung\n",
"plt.xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"plt.ylabel('y-Wert/ bel. Einheit', size='x-large')\n",
"plt.title('2d-Histogram der Beispieldaten', size='xx-large')\n",
"\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Darstellung als zweidimensionales Histogramm\n",
"\n",
"Eine weitere Möglichkeit ist die Darstellung als zweidimensionale Häufigkeitsverteilung mit\n",
"Hilfe der Funktion *plt.hist2d()*, wie in der folgenden Code-Zelle gezeigt:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"# Histogramm erzeugen und darstellen\n",
"nbinsx=20\n",
"nbinsy=20\n",
"plt.hist2d(x2 ,y2, [nbinsx,nbinsy])\n",
"\n",
"# Achsenbeschriftung\n",
"plt.xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"plt.ylabel('y-Wert/ bel. Einheit', size='x-large')\n",
"plt.title('2d-Histogram der Beispieldaten', size='xx-large')\n",
"\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Diese Darstellung mit den vorgegebenen Einstellungen ist noch nicht schön. Quantitativ besser zu interpretieren als der voreingestellte Farbverlauf ist ein Helligkeitsverlauf. Dafür sollte dem Aufruf noch eine Colormap mitgegeben werden:\n",
"```\n",
"plt.hist2d(x,y,[nbinsx,nbinsy], cmap='Blues')\n",
"```\n",
" \n",
"Weitere Farbtabellen sind z. B. *Oranges', 'Greys'. Es gibt auch sehr bunte, wegen der Farbempfindlichkeit des\n",
"Auges und auch wegen der menschlichen Psyche (rot=Signalfarbe) sind bunte Farbtabellen zur quantitativen Darstellung\n",
"ungünstig; einfach mal \"rainbow\" oder \"jet\" ausprobieren!\n",
"\n",
"Um tatsächlich die Häufigkeiten ablesen zu können, wird noch eine Legende mit den Bedeutungen der Farbschattierungen\n",
"benötigt. Das erledigt der Befehl\n",
"```\n",
"plt.colorbar()\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code hier zusammenstellen und testen\n",
"# --> \n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Berechnung statistischer Größen aus den Histogrammdaten\n",
"\n",
"Zur Berechnung statistischer Größen aus dem Histogramm wird wieder eine Hilfsfunktion \n",
"*hist2dstat()* benötigt, die das Paket [PhyPraKit](https://git.scc.kit.edu/yh5078/PhyPraKit) \n",
"bereitstellt und die die von *plt.hist2d()* zurückgegeben Objekte nutzt.\n",
"\n",
"Neben der Mittelwert und Varianz der x- und y-Werte werden auch deren \n",
"Kovarianz und die Korrelation ausgegeben. Hier der Beispielcode:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"from PhyPraKit import hist2dstat\n",
"\n",
"H, xedges, yedges, p = plt.hist2d(x2, y2, [nbinsx,nbinsy], cmap='Blues')\n",
"meanx,meany,varx,vary,cov,cor = hist2dstat(H, xedges, yedges, True)\n",
"plt.colorbar()\n",
"\n",
"# Achsenbeschriftung\n",
"plt.xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"plt.ylabel('y-Wert/ bel. Einheit', size='x-large')\n",
"plt.title('2d-Histogram der Beispieldaten', size='xx-large')\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zur Untersuchung des Zusammenhangs zwischen Zufallsgrößen wird gerne auch eine sogenannte Profil-Darstellung genutzt. \n",
"Dabei wird für jedes Intervall in x-Richtung der Mittelwert und die Standarabweichung der auf die y-Achse projezierten Verteilungen berechnet und gegen den x-Wert aufgetragen. \n",
"Eine Implementierung ist die Funktion *PhyPraKit.profile2d()*, die wie im eindimensionalen Fall \n",
"die von *hist2d()* zurückgegebenen Objekte nutzt:\n",
"\n",
"```\n",
"from PhyPraKit import profile2d\n",
"\n",
"bincenters_x, means_y, sigs_y, sigmeans_y = profile2d(H, xedges, yedges)\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from PhyPraKit import profile2d\n",
"\n",
"bincenters_x, means_y, sigs_y, sigmeans_y = profile2d(H, xedges, yedges)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Weitere Darstellungen [^](#Inhalt)\n",
"---\n",
"\n",
"Es gibt eine ganze Reihe weitere Darstellungsformen, die im Folgenden als Code-Beisiele zusammengestellt sind.\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.1 Polardarstellung\n",
"\n",
"Zur Darstellung von Größen, die von Winkeln abhängen, eignet sich die Polardarstellung `plt.polar(theta, r)`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Polardarstellung einer winkelabhängigen Fuktion \n",
"# --------------------------------------------------\n",
"\n",
"def polarFunction(theta):\n",
" return np.cos(theta)**2\n",
"\n",
"theta=np.linspace(0., 2*np.pi, 100)\n",
"plt.polar(theta,polarFunction(theta))\n",
"\n",
"\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.2 Tortendiagramm\n",
"```\n",
" matplotlib.pyplot.pie(x, explode=None, labels=None, colors=None, autopct=None, \n",
" pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, radius=None, \n",
" counterclock=True, wedgeprops=None, textprops=None, center=(0, 0), frame=False, \n",
" rotatelabels=False, *, data=None)\n",
"```\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Erzeugung eines Tortendiagramms\n",
"# --------------------------------\n",
"labels = 'A', 'B', 'C', 'D', 'E'\n",
"sizes = [10, 30, 25, 15, 20]\n",
"explode=(0., 0., 0.1, 0.,0.) # \"explode 3rd slice\"\n",
"plt.pie(sizes, labels=labels, autopct='%1.1f%%', shadow=True, explode=explode)\n",
"\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.3 Balkendiagramm\n",
"\n",
"```\n",
"matplotlib.pyplot.bar(x, height, width=0.8, bottom=None, \n",
"*, align='center', data=None, **kwargs)\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Erzeugung eines Balkendiagramms\n",
"# -------------------------------\n",
"\n",
"sizes = [10, 30, 25, 15, 20]\n",
"xpos=[0.5, 1.5, 2.5, 3.5, 4.5]\n",
"labels = 'A', 'B', 'C', 'D', 'E'\n",
"plt.bar(xpos, sizes, tick_label=labels)\n",
"plt.ylabel('Wert')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Boxplot\n",
"\n",
"Boxplots sind sehr geeignet, um einen schnellen Überblick Lage und Streuung von Zufallsdaten zu gewinnen\n",
"und sind in den empirisch arbeitenden Sozial- und Geisteswissenschaften weit verbreitet, in der Physik aber\n",
"(leider) noch unüblich. \n",
"In der gängigen Variante dieser Darstellungsform werden der Median als Linie und das zentrale 50%-Quantil \n",
"als Kasten (Box) dargestellt. Die \"Antennen\" enden beim minimalen bzw. maximalen Datenpunkt, sind aber auf eine\n",
"Länge des 1.5-fachen des zentalen 50%-Quantils beschränkt. Darüber hinaus streuende Datenpunkten werden als\n",
"Punkte dargestellt.\n",
"\n",
"```\n",
" matplotlib.pyplot.boxplot(x, notch=None, sym=None, vert=None, \n",
" whis=None, positions=None, widths=None, \n",
" patch_artist=None, bootstrap=None, usermedians=None, \n",
" conf_intervals=None, meanline=None, showmeans=None, \n",
" showcaps=None, showbox=None, showfliers=None, boxprops=None, \n",
" labels=None, flierprops=None, medianprops=None, meanprops=None, \n",
" capprops=None, whiskerprops=None, manage_ticks=True, \n",
" autorange=False, zorder=None, *, data=None)\n",
"```\n",
"\n",
"Ein Beispiel für gaußförimig verteilte Gruppen von Werten ist in der Zelle unten gezeigt."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Erzeugung eines Boxplots\n",
"#-------------------------\n",
"\n",
"#Daten\n",
"r1 = np.random.normal(size=200)+0.5\n",
"r2 = 1.5*np.random.normal(size=200)-0.3\n",
"\n",
"plt.boxplot((r1,r2), showfliers=True, labels=('A', 'B') )\n",
"plt.ylabel('Größe / bel. Einheit')\n",
" \n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## 7. Fortgeschrittene Anwendung von *matplotlib* [^](#Inhalt)\n",
"\n",
"---\n",
"\n",
"Für einfache Anwendungen sind die in den bisherigen Beispielen beschriebenen Methoden völlig ausreichend,\n",
"um ansprechende Abbildungen mit minimalem Aufwand an Code zu erzeugen.\n",
"\n",
"In vielen Fällen ist es aber notwendig, mehr Kontrolle über die Grafikelemente zu erlangen.\n",
"Dann empfiehlt es sich, auf das objekt-orientierte Interface von *matplotlib* zurück zu greifen. \n",
"Damit lassen sich dann praktisch alle Grafikelemente wie Anzahl, Größe und Format der Zahlen auf\n",
"den Achsen, die Größe und Liniendicke der Tickmarks auf den Achsen und vieles andere anpassen, \n",
"wenn die Voreinstellungen nicht optimal sind. Außerdem kann man dann mehrere Grafiken in der\n",
"gleichen Abbildung erstellen, Objekte gezielt in die einzelnen Plots eintragen oder auch\n",
"mehrere Abbildungen im gleichen Code verwalten. \n",
"\n",
"Die Zahl der möglichen Optionen und Kombinationen ist dann natürlich sehr groß, und deshalb muss\n",
"in Einzelfall die vollständige *matplotlib*-Dokumentation zu Rate gezogen werden. \n",
"\n",
"Um sich diese mächtigen Möglichkeiten offen zu halten, ändert sich an unserem ersten Beispiel \n",
"zur Darstellung von Daten und Modell nicht viel, außer, dass die Rückgabe-Objekte der\n",
"aufgerufenen Fuktionen von *matplotlib.pyplot* gespeichert und die weitere Erzeugung\n",
"von Objekten über Methoden der Rückgabeobjkte realisiert werden. Ein Beispiel ist\n",
"in der Code-Zelle unten gezeigt.\n",
"\n",
"Neu ist die Fuktion *figure.add_subplot(nrows, ncolumns, index)*. \n",
"Mit $nrows=1, ncols=1, index=1$ wird in der Abbildung eine Grafik mit einem Achsenkreuz\n",
"erzeugt.\n",
"Durch wiederholten Aufruf lassen sich auch mehrere Untergrafiken erzeugen und jeweils\n",
"einem *axes*-Objekt zuweisen. Der Zugriff auf das Objekt erfolgt über Methoden, deren\n",
"Namen an die *pyplot*-Funktionen angelehnt sind, aber den Zusatz *set_* enthalten. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"\n",
"\"\"\"\n",
" Beispiel zum Vergleich eines Modells mit Daten\n",
"\"\"\"\n",
"\n",
"# Modellfunktion\n",
"def model(x, a=1, b=0):\n",
" return a*x+b\n",
"\n",
"# Datenpunkte erzeugen\n",
"Dx = [1., 2., 3., 4.]\n",
"Dy = [1.1, 1.9,3.05, 4.2]\n",
"sy = [0.1, 0.15, 0.2, 0.25]\n",
"\n",
"# Abbildung erzeugen\n",
"myfig = plt.figure(figsize=(7.5, 6.), dpi=100)\n",
"ax1 = myfig.add_subplot(1,1,1) \n",
"\n",
"ax1.errorbar(Dx, Dy, yerr=sy, fmt='ro', label='Daten')\n",
"\n",
"# Grafik beschriften \n",
"\n",
"ax1.set_xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"ax1.set_ylabel('y-Werte / bel. Einheit', size='x-large')\n",
"# create font dictionary\n",
"csfont = {'fontname' : 'Comic Sans MS'}\n",
"ax1.set_title('Beispieldaten', size='xx-large', **csfont)\n",
" \n",
"# Modellfunktion einzeichnen\n",
"x = np.linspace(0., 5., 100,)\n",
"y = x\n",
"ax1.plot(x,y, 'b-', label='Modell') \n",
"\n",
"# Legende erzeugen\n",
"ax1.legend()\n",
"\n",
"ax1.text(3.5, 0.1, 'erste Grafik mit matplotlib', color='darkgreen')\n",
"\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"\n",
"## 8. Mehrere Grafiken in der gleichen Abbildung [^](#Inhalt)\n",
"\n",
"---\n",
"\n",
"Beim Vergleich von Daten mit einem Modell ist es fast immer hilfreich, in einem zweiten Diagramm die \n",
"Differenz zwischen Daten und Modell oder auch deren Verhältnis darzustellen. Dazu benötigen wir ein\n",
"zweites Achsenkreuz mit der gleichen x-Achse, dessen y-Achse aber wegen des Bezugs der Daten zum \n",
"Modell kleiner sein kann. Zur Erzeugung beliebiger von Diagrammen unterschiedlicher Größe in einer\n",
"Abbildung stellt *matpltolib* die Funktion \n",
"`plt.subplot2grid(shape, loc, rowspan=1, colspan=1)` \n",
"zur Verfügung. Der Parameter *shape*, ein Tupel mit zwei Einträgen, definiert ein Gitter,\n",
"der Parameter *loc* gibt die Position einer Untergrafik in diesem Gitter an, und *rowspan*\n",
"bzw. *colspan* geben an, über wie viele Zeilen bzw. Spalten des Gitters sich eine Grafik\n",
"erstrecken soll. Weitere Optionen, `sharex=` bzw. `sharey=`, erlauben es eine \n",
"gemeinsame x- bzw. y-Achse zu verwenden. \n",
"Um Überlappungen der Achsenbeschriftung zu vermeiden, sollten noch ein speziell \n",
"angepasstes Layout verwendet werden, *plt.tight_layout()* mit voreingestellten Optionen\n",
"funktioniert meist akzeptabel. \n",
"\n",
"Das erweiterte Beispiel zum Vergleich von Daten mit einem Modell sieht nun so aus:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"\"\"\"\n",
" Erweitertes Beispiel zum Vergleich eines Modells mit Daten\n",
"\"\"\"\n",
"\n",
"# Modellfunktion\n",
"def model(x, a=1, b=0):\n",
" return a*x+b\n",
"\n",
"# Datenpunkte erzeugen\n",
"Dx = [1., 2., 3., 4.]\n",
"Dy = [1.1, 1.9,3.05, 4.2]\n",
"sy = [0.1, 0.15, 0.2, 0.25]\n",
"\n",
"# Abbildung und Unter-Diagramme erzeugen\n",
"myfig = plt.figure(figsize=(7.5, 9.), dpi=100)\n",
"ax1 = plt.subplot2grid( (7,1), (0,0), rowspan=5)\n",
"ax2 = plt.subplot2grid( (7,1), (5,0), rowspan=2, sharex=ax1)\n",
"plt.tight_layout()\n",
"\n",
"# Daten eintragen\n",
"ax1.errorbar(Dx, Dy, yerr=sy, fmt='ro', label='Daten')\n",
"# Daten - Modell eintragne\n",
"ax2.errorbar(Dx, Dy-model(np.array(Dx)), yerr=sy, fmt='ro', label='Daten')\n",
"ax2.axhline(0.)\n",
"\n",
"# Grafik beschriften \n",
"ax1.set_ylabel('y-Werte / bel. Einheit', size='x-large')\n",
"ax2.set_ylabel('Differenz', size='x-large')\n",
"ax2.set_xlabel('x-Werte / bel. Einheit', size='x-large')\n",
"ax1.set_title('Beispieldaten', size='xx-large')\n",
" \n",
"# Modellfunktion einzeichnen\n",
"x = np.linspace(0., 5., 100,)\n",
"y = model(x)\n",
"ax1.plot(x,y, 'b-', label='Modell') \n",
"\n",
"# Legende erzeugen\n",
"ax1.legend()\n",
"\n",
"plt.show()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Anwendung mit noch mehr Unterdiagrammen \n",
"\n",
"Als weiteres, noch etwas komplexeres Beispiel kommen wir auf die Darstellung von zweidimensionalen \n",
"Zufallsdaten zurück und kombinieren alle oben besprochenen Elemente in einer Abbildung. \n",
"Der Code ist in der Zelle unten enthalten."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"from PhyPraKit import histstat, hist2dstat, profile2d\n",
"\n",
"def gen2dGauss(size=10000, mux=5., sigx=10., muy=20., sigy=3., rho=0.15 ):\n",
"# generate two arrays with pairs of correlated gaussian numbers\n",
" u=np.random.randn(size) \n",
" x = mux+sigx*u # gauss, with mean mux and sigma sigx\n",
" v = np.random.randn(size) \n",
" y = muy+sigy*(rho*u+np.sqrt(1.-rho**2)*v)\n",
" return x, y\n",
"\n",
"\n",
"def gen2dExpGauss(size=10000, mux=5., sigx=10., muy=20., sigy=3., rho=0.15 ):\n",
"# generate two arrays with pairs of correlated gaussian numbers\n",
" u=np.random.randn(size) \n",
" x = mux+sigx*u # gauss, with mean mux and sigma sigx\n",
" v = np.random.randn(size) \n",
" y = muy+sigy*(rho*u+np.sqrt(1.-rho**2)*v)\n",
" return x, y\n",
"\n",
"\n",
"x2, y2 = gen2dGauss(10000) \n",
"nbinsx=20\n",
"nbinsy=25\n",
"\n",
"fig=plt.figure(1,figsize=(10.,10.))\n",
"\n",
"ax_y=plt.subplot(2,2,1) # y histogram and statistics\n",
"# bincont,binedge = nhist(y,nbinsy,xlabel=\"y\") # histogram data\n",
"bcy, bey, p = ax_y.hist(y2, nbinsy) # histogram data\n",
"ax_y.set_xlabel('y')\n",
"ax_y.set_ylabel('frequency')\n",
"histstat(bcy,bey)\n",
"\n",
"ax_x=plt.subplot(2,2,4) # x histogram and statistics\n",
"# bincont,binedge = nhist(x,nbinsx) # histogram data\n",
"bcx, bex, p = ax_x.hist(x2, nbinsx) # histogram data\n",
"ax_x.set_xlabel('x')\n",
"ax_x.set_ylabel('frequency')\n",
"histstat(bcx,bex)\n",
"\n",
"ax_xy=plt.subplot(2,2,2) # 2d histogram\n",
"H, xedges, yedges, p = ax_xy.hist2d(x2 ,y2, [nbinsx,nbinsy],cmap='Blues')\n",
"fig.colorbar(p, ax=ax_xy)\n",
"ax_xy.set_xlabel('x')\n",
"ax_xy.set_ylabel('y')\n",
"hist2dstat(H, xedges, yedges, True)\n",
"\n",
"# make a \"Profile Plot\" - mean y at a given x, standard deviation as error bar\n",
"ax_profile=plt.subplot(2,2,3) # profile historgram \n",
"bincenters_x, means_y, sigs_y, sigmeans_y = profile2d(H, xedges, yedges)\n",
"ax_profile.set_xlabel('x', size='x-large') \n",
"ax_profile.set_ylabel('mean of y',size='x-large') \n",
"\n",
"plt.show()\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 9. Dreidimensionale Darstellungen [^](#Inhalt)\n",
"\n",
"*matplotlib* ermöglicht auch dreidimensionale Darstellungen. Dies können Funktionen *z=f(x,y)* sein, \n",
"oder auch zweidimensionale Häufigkeitsverteilungen, bei denen die Häufigkeit als Höhe einer Säule *H(x,y)* \n",
"dargestellt wird.\n",
"Solche Darstellungen wirken zwar \"professionell\" und sehr fortschrittlich, aber das quantitative Ablesen \n",
"von Größen aus solchen Diagrammen ist wegen der notwendigen perspektivischen Darstellung nur ungenau möglich. \n",
"Es ist also in der Praxis sinnvoller, mit Projektionen oder einer Farb- oder Sättigungskodierung der *z*-Werte\n",
"zu arbeiten. \n",
"\n",
"Das folgende Beispiel zeigt, wie die 3d-Darstellung grundsätzlich funktioniert. \n",
"Am besten nutzt man eine allg. Hilfsfunktion (*get_3dfunctionData*) zur \n",
"Erzeugung der Funktionswerte auf einem zweidimensionalen Gitter. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# diese Zelle durch Eingabe von + ausführen\n",
"\n",
"from mpl_toolkits.mplot3d import Axes3D\n",
"from matplotlib import cm\n",
"\n",
"# eine Funktion z=f(x,y)\n",
"# modified rosenbrock function: f(x,y) = (x^2+y-a)^2 + (x+y^2-b)^2 + c(x+y)^2\n",
"def modified_rosenbrock_function(x,y, par=[11., 7., 0.1]):\n",
" a = par[0] # a, should be 11\n",
" b = par[1] # b, should be 7\n",
" c = par[2] # c, should be 0.1\n",
" return (x**2+y-a)**2 + (x+y**2-b)**2 + c*(x+y)**2\n",
"\n",
"\n",
"# ---helper function ---------------------------------------\n",
"def get_3Dfunction_data(xmin=1.,xmax=1.,ymin=-1.,ymax=1., \n",
" func=None, fkwargs={}, delta=0.1):\n",
" '''\n",
" get function values on 2D-grid\n",
"\n",
" Args: \n",
" float xmin: minimum x-range\n",
" float xmax: maximum x-range\n",
" float ymin: minimum y-range\n",
" float ymys: maximum y-range\n",
" funtion func: funtion f(x,y **kwargs)\n",
" dict fkwargs: prameters to pass to function\n",
" delta: resolution of grid\n",
"\n",
" Returns: \n",
" tuple X, Y, Z\n",
" ''' \n",
" x = np.arange(xmin, xmax, delta)\n",
" y = np.arange(ymin, ymax, delta)\n",
" X, Y = np.meshgrid(x, y)\n",
" Z = func(X, Y, **fkwargs)\n",
" return X, Y, Z\n",
"\n",
"\n",
"# --- main part of program ---\n",
"\n",
"# get the 3d data\n",
"f = modified_rosenbrock_function\n",
"# parameters of function as keyword arguments\n",
"kwargs = {'par': [11., 7. , 0.1]}\n",
"\n",
"X, Y, Z = get_3Dfunction_data(xmin=-4., xmax=4., ymin=-4., ymax=4.,\n",
" func = f, fkwargs=kwargs, delta=0.1)\n",
"minz = np.amin(Z) \n",
"maxz = np.amax(Z)\n",
"\n",
"# create a figure ...\n",
"fig = plt.figure(figsize=(10., 7.5))\n",
"ax = fig.add_subplot(projection = '3d')\n",
"\n",
"# ... and plot the surface.\n",
"surf = ax.plot_surface(X, Y, Z, cmap=cm.Blues,\n",
" linewidth=0, antialiased=False)\n",
"# set range for z axis.\n",
"ax.set_zlim(minz, maxz)\n",
"\n",
"# Add a color bar which maps values to colors.\n",
"fig.colorbar(surf, shrink=0.5, aspect=10)\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 10. Anpassung von Darstellungsoptionen [^](#Inhalt)\n",
"---\n",
"\n",
"Die von *matplotlib* als Voreinstellung verwendeten Parameter zur Steuerung der Darstellung, also \n",
"Linienstärken, Farben, Schriften usw.) sind einer Datei `matplotlibrc` enthalten. Davon gibt es\n",
"eine systemweit gültige Version, aber auch Versionen im *home*-Verzeichnis des Nutzers oder auch\n",
"im aktuellen Arbeitsverzeichnis. Angaben im Arbeitsverzeichnis überschreiben die Datei im \n",
"Nutzerverweichnis, die wiederum Angaben in der systemweiten Datei überschreiben. So ist es\n",
"möglich, den Stil von Grafiken perönlichen Vorlieben oder dem jeweiligen Projekt anzupassen. \n",
"Zusätzlich kann die Funktion *plt.rc()* verwendet werden, um Konfigurationsparamter\n",
"programmgesteuert anzupassen.\n",
"\n",
"Um Parameter zu ändern, werden die Kommentarzeichen vor den entsprechenden Zeilen in der Datei \n",
"auskommentiert und Parameter ggf. angepasst.\n",
"\n",
"Ein Ausschnitt aus der Datei *matplotlibrc* mit einigen wichtigen Parametern sieht wie folgt aus:\n",
"```\n",
"#### MATPLOTLIBRC FORMAT\n",
"\n",
" ...\n",
"\n",
"## information on line properties.\n",
"#lines.linewidth : 1.5 ## line width in points\n",
"#lines.linestyle : - ## solid line\n",
"#lines.color : C0 ## has no affect on plot(); see axes.prop_cycle\n",
"#lines.marker : None ## the default marker\n",
"#lines.markeredgewidth : 1.0 ## the line width around the marker symbol\n",
"#lines.markersize : 6 ## markersize, in points\n",
"\n",
" ...\n",
"\n",
"#### AXES\n",
"## default face and edge color, default tick sizes,\n",
"## default fontsizes for ticklabels, and so on. See\n",
"#axes.facecolor : w ## axes background color\n",
"#axes.edgecolor : k ## axes edge color\n",
"#axes.linewidth : 0.8 ## edge linewidth\n",
"\n",
" ... \n",
"\n",
"#axes.titlesize : large ## fontsize of the axes title\n",
"#axes.titleweight : normal ## font weight of title\n",
"#axes.titlepad : 6.0 ## pad between axes and title in points\n",
"#axes.labelsize : medium ## fontsize of the x any y labels\n",
"#axes.labelpad : 4.0 ## space between label and axis\n",
"#axes.labelweight : normal ## weight of the x and y labels\n",
"#axes.labelcolor : k\n",
"\n",
" ...\n",
"\n",
"#axes.formatter.limits : -7, 7 ## use scientific notation if log10 of the axis range is\n",
" ## smaller than the first or larger than the second\n",
"#axes.formatter.min_exponent: 0 ## minimum exponent to format in scientific notation\n",
"#axes.formatter.useoffset : True ## If True, the tick label formatter\n",
" ## will default to labeling ticks relative\n",
" ## to an offset when the data range is\n",
" ## small compared to the minimum absolute\n",
" ## value of the data.\n",
"#axes.formatter.offset_threshold : 4 ## When useoffset is True, the offset\n",
" ## will be used when it can remove\n",
" ## at least this number of significant\n",
" ## digits from tick labels.\n",
"...\n",
"\n",
"#axes.unicode_minus : True ## use unicode for the minus symbol\n",
" ## rather than hyphen. \n",
"#axes.prop_cycle : cycler('color', ['1f77b4', 'ff7f0e', '2ca02c', 'd62728', '9467bd', '8c564b', 'e377c2', '7f7f7f', 'bcbd22', '17becf'])\n",
" ## color cycle for plot lines as list of string\n",
" ## colorspecs: single letter, long name, or web-style hex\n",
" ## Note the use of string escapes here ('1f77b4', instead of 1f77b4)\n",
" ## as opposed to the rest of this filee.\n",
"#axes.autolimit_mode : data ## How to scale axes limits to the data.\n",
" ## Use \"data\" to use data limits, plus some margin\n",
" ## Use \"round_number\" move to the nearest \"round\" number\n",
"#axes.xmargin : .05 ## x margin. See `axes.Axes.margins`\n",
"#axes.ymargin : .05 ## y margin See `axes.Axes.margins`\n",
"#polaraxes.grid : True ## display grid on polar axes\n",
"#axes3d.grid : True ## display grid on 3d axes\n",
"\n",
" ... \n",
"\n",
"```\n",
"\n",
"Für wissenschaftliche Grafiken sollen einige Anpassungen vorgenommen werden, um die Klarheit der Achsenbeschriftungen\n",
"zu gewährleisten und ggf. auf die wissenschaftliche Notation der Zahlen an den Achsen umzustellen. \n",
"\n",
"```\n",
"#axes.formatter.limits : -3, 3 ## use scientific notation if log10 of the axis range is\n",
" ## smaller than the first or larger than the second\n",
"#axes.formatter.min_exponent: 2 ## minimum exponent to format in scientific notation\n",
"```\n",
"\n",
"Es ist sinnvoll, auch dem \"persönlichen Geschmack\" entsprechende Anpassungen vorzuhmemen, \n",
"um den Grafiken eine eigenen Note zu verleihen. In großen Arbeitsgruppen oder auch für\n",
"Veröffentlichungen in Zeitschriften sind häufig Stilvorgaben zu berücksichtigen, um eine\n",
"\"Corporate Identity\" zu schaffen. Auch dabei helfen die die Optionen in der *matplotlibrc*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zum Ausprobieren oder zur schnellen Anpassung ist die Funktion *plt.rc(key, value=?)* geeignet. \n",
"\n",
"Im Code in der folgenden Zelle zum einfachen Ausprobieren die entsprechenden\n",
"Parameter verändern:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Code zum Ausprobieren\n",
"\n",
"x = np.linspace(-20., 20., 200)\n",
"y = np.sin(x)/x\n",
"\n",
"# einige Parameter ändern\n",
"plt.rc('lines', linewidth=5)\n",
"plt.rc('xtick', labelsize=25)\n",
"plt.rc('ytick', labelsize=25)\n",
"\n",
"# Abbildung erzeugen\n",
"plt.plot(x,y, 'r-')\n",
"\n",
"# Abbildung darstellen\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Grafiken werden häufig in verschiedenen Kontexten benötigt - etwa für eine Präsentation oder für ein Dokument. Generell\n",
"sollten Achsenbeschriftungen und auch Liniendicken für Präsentationen größer gewählt werden. *matplotlib* unterstützt\n",
"das durch die Bereitstellung sogenannter \"Styles\". Auf dem System vorhande Style-Optionen gibt die \n",
"Funktion `plt.rc.style.available()`. Es lohnt sich, einige davon mit der Funktion `plt.style.use()`\n",
"in der Codezelle unten auszuprobieren. \n",
"Vorher sollten mit `plt.rcdefaults()` alle Änderungen zurückgesetzt werden. \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Ausprobieren von rc-styles \n",
"\n",
"print(plt.style.available)\n",
"\n",
"plt.rcdefaults() # alle Änderungen zurücksetzen\n",
"plt.style.use('classic')\n",
" \n",
"# einfache Grafik \n",
"x = np.linspace(-20., 20., 200)\n",
"y = np.sin(x)/x\n",
"plt.plot(x,y)\n",
"plt.xlabel('x-Wert')\n",
"plt.ylabel('y-Wert')\n",
"\n",
"plt.locator_params(nbins=5)\n",
"plt.show() \n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Eigene Styles\n",
"\n",
"Man kann auch sehr leicht eigene Styles anlegen. Dazu muss lediglich eine Datei mit den\n",
"entsprechenden Einträgen für geänderte Optionen angelegt werden, die Werte für einen \n",
"Schlüssel aus der *matplotlibrc* angeben. \n",
"\n",
"Hier ein für Präsentationen geeignetes Beispiel:\n",
"```\n",
"figure.figsize: 10., 8.\n",
"figure.dpi: 100 # resolution sufficient for screen\n",
"\n",
"# use scientific format for numbers <=10^-2, >=10^3\n",
"axes.formatter.limits: -2, 3\n",
"\n",
"# use latex text rendering\n",
"text.usetex: True\n",
"\n",
"# set larger titles for presentations\n",
"axes.titlesize: 24\n",
"axes.labelsize: 20\n",
"xtick.labelsize: 16\n",
"ytick.labelsize: 16\n",
"\n",
"# use larger ticks \n",
"xtick.major.width: 3\n",
"xtick.major.size: 5\n",
"xtick.minor.width: 2\n",
"xtick.minor.size: 3\n",
"\n",
"ytick.major.width: 3\n",
"ytick.major.size: 5\n",
"ytick.minor.width: 2\n",
"ytick.minor.size: 3\n",
"\n",
"# play with colors - dark-blue axes\n",
"axes.edgecolor: 'darkblue'\n",
"ytick.color: 'darkblue'\n",
"xtick.color: 'darkblue'\n",
"```\n",
"\n",
"Angewendet wird der Style-File durch Aufrufen der Funktion *plt.style.use()*, wobei sich\n",
"auch mehrere Styles kombinieren lassen:\n",
"```\n",
"plt.style.use(['.mplstyle', '.mplstyle'])\n",
"```\n",
"\n",
"Wenn man eine Datei vom Typ *.mplstyle* im Verzeichnis \n",
"*~/.config/matplotlib/stylelib* anlegt,\n",
"kann sie direkt als *matplotlib-Style* verwenden, \n",
"andernfalls muss der komplette Pfad zur *.mplstyle*-Datei angegeben werden."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Damit sind wir am Ende dieser Einführung in die Verwendung von *matlotlib* angekommen. Sie kennen nun die wesentlichen Grundlagen, auf denen Sie eigene kreative Ideen ausprobieren können. Für die schier unendliche Zahl an Mögichkeiten sind dazu ein Blick in die offizielle \n",
"[Dokumentation zu *matplotlib*](https://matplotlib.org/) oder die Suche im Internet unvermeidlich. \n",
"\n",
"Die Code-Beispiele sind zur freien Anwendung in Ihren eigenen Arbeiten gedacht und Sie können sie\n",
"hoffentlich nutzbringend einsetzen. Zum Verständnis des Codes zur Erzeugung der Grafiken in den\n",
"Tutorials \n",
"[Grundlagen der Stochastik](IntroStatistik.ipynb) und \n",
"[Fehlerrechnung im Anfängerpraktikum](Fehlerrechnung.ipynb) ist diese Einführung ebenfalls hilfreich. "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}