{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Python Einführungskurs für das Physikalische Anfängerpraktikum der Universität Heidelberg | [Startseite](index.ipynb)\n", "\n", "---" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# 202 - Plots mit Matplotlib" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- [Einfaches Plotten](#Einfaches-Plotten)\n", "- [Plots gestalten](#Plots-gestalten)\n", "- [Mehrere Plots in einer Abbildung](#Mehrere-Plots-in-einer-Abbildung)\n", "- [Plots speichern](#Plots-speichern)\n", "- [Aufgabe 1 - Temperaturen in Heidelberg visualisieren](#Aufgabe-1---Temperaturen-in-Heidelberg-visualisieren)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir können mit Numpy nun numerisch Daten auswerten, und um diese zu visualisieren können wir mit dem **Matplotlib** Modul Plots von wissenschaftlicher Qualität erstellen.\n", "\n", "Per Konvention importieren wir das PyPlot Submodul von Matplotlib unter dem Namen `plt`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Zeige Plots direkt im Jupyter Notebook an\n", "%matplotlib inline\n", "# Anschließend können wir das Modul importieren\n", "import matplotlib.pyplot as plt # Die Abkürzung `plt` ist Konvention\n", "# Numpy brauchen wir immer.\n", "import numpy as np" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Hinweis:** Matplotlib kann mit verschiedenen _Backends_ arbeiten um Plots zu speichern oder auch interaktiv anzuzeigen. Der Aufruf `%matplotlib inline` konfiguriert das Modul für die **statische Anzeige** von Plots im Jupyter Notebook und muss **vor** dem Import von PyPlot ausgeführt werden. Dabei können auch Anzeigeparameter gesetzt werden:\n", ">\n", "> ```python\n", "> %matplotlib inline\n", "> import matplotlib\n", "> # Setzte Anzeigeparameter, z.B.:\n", "> matplotlib.rcParams['figure.figsize'] = (10.0, 8.0)\n", "> import matplotlib.pyplot as plt\n", "> ```\n", ">\n", "> Folgender Aufruf konfiguriert das Jupyter Notebook alternativ für die Verwendung des **interaktiven Backends**:\n", ">\n", "> ```python\n", "> %matplotlib notebook\n", "> ```\n", ">\n", "> Versucht's mal!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Einfaches Plotten\n", "\n", "PyPlot stellt einige grundlegende Funktionen zur Verfügung, mit denen wir Daten schnell plotten können:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **`plot`** nimmt x- und y-Daten sowie eine Vielzahl von optionalen Argumenten zur Konfiguration an. Fehlen die x-Daten, werden die Indizes der y-Daten verwendet:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.plot(np.arange(100)**2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Entfernt das '`#`'-Zeichen und schaut euch die Argumente in der Dokumentation an, mit denen wir den Plot konfigurieren können:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#plt.plot?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matplotlib bietet unzählige Möglichkeiten, das Aussehen von Plots anzupassen! Ihr könnt oben einige ausprobieren, wie bspw. `color`, `linestyle` und `linewidth`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **`scatter`** plottet Datenpunkte statt einer Linie:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.scatter(np.arange(10), np.arange(10)**2)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#plt.scatter?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **`errorbar`** nimmt zusätzlich Fehler in x- und y-Richtung an und zeichnet Fehlerbalken:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.errorbar(np.arange(10), np.arange(10)**2, yerr=np.arange(10))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#plt.errorbar?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **`hist`** plottet schnell ein Histogramm:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_ = plt.hist(np.random.normal(size=100), bins=10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#plt.hist?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Hinweis:** Alternativ könnt ihr Histogramme mit `numpy.histogram` und `matplotlib.pyplot.bar` plotten. Diese Methode bietet etwas mehr Kontrolle über die Berechnung der Histogrammdaten." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- **`imshow`** visualisiert zweidimensionale Daten:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.imshow(np.random.random((64, 64)), interpolation='none')\n", "plt.colorbar()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#plt.imshow?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plots gestalten\n", "\n", "Mit Matplotlib könnt ihr jegliche Plots erstellen, die ihr euch vorstellen könnt. Überlegt euch zuerst, wie der Plot aussehen soll. Die [Gallerie](http://matplotlib.org/gallery.html) kann dabei helfen. Mit einer beherzten Websuche, die meist direkt zur [Dokumentation](http://matplotlib.org/api/pyplot_api.html) führt, findet ihr dann die Funktionen, die ihr braucht.\n", "\n", "> **Hinweis:** Plotten ist eine Kunst.\n", "\n", "> **Weiterer Hinweis:** Versucht's mal mit `plt.xkcd()`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Titel, und Achsen und Legende mit LaTeX\n", "\n", "Strings in Matplotlib wie Titel und Achsenbeschriftungen können **LaTeX-Code** enthalten. Text zwischen `$`-Zeichen wird dabei wie gewohnt im _Math-Mode_ gesetzt.\n", "\n", "> **Achtung:** Einige Zeichen wie `\\t` (``) oder `\\n` (``) werden von Python als Steuerzeichen und daher nicht als LaTeX-Code interpretiert. Markiert Strings, die LaTeX-Code enthalten, daher mit dem Prefix `r` (für _raw_), sodass Steuerzeichen ignoriert werden." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x = np.linspace(0, 2 * np.pi, 100)\n", "# Plot mit Label für Legende\n", "plt.plot(x, np.sin(x), label=r'$A \\times \\sin(\\phi)$')\n", "plt.plot(x, np.cos(x), label=r'$A \\times \\cos(\\phi)$')\n", "# Titel\n", "plt.title('Oszillation')\n", "# Achsenlimits\n", "plt.xlim(0, 2 * np.pi)\n", "plt.ylim(-1, 1)\n", "# Achsenbeschriftungen\n", "plt.xlabel(r'Winkel $\\phi \\, [\\mathrm{rad}]$')\n", "plt.ylabel(r'Auslenkung $d \\, [\\mathrm{cm}]$')\n", "# Legende\n", "plt.legend(loc='lower left')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mehrere Plots in einer Abbildung\n", "\n", "Wir können eine Abbildung in ein Gitter mit mehreren Achsen aufteilen. Funktionsaufrufe wie `plt.plot` plotten dann immer in die zuletzt erstellte Achse:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Erstelle eine Abbildung mit Titel\n", "fig = plt.figure()\n", "fig.suptitle(\"Oszillation\")\n", "\n", "# Erstelle eine Achse in einem Gitter von 2 Zeilen und 1 Spalte\n", "ax_upper = plt.subplot(211) # Abkürzung für die 1. Achse im Gitter\n", "\n", "# Funktionen plotten nun in diese Achse:\n", "x = np.linspace(0, 2 * np.pi, 100)\n", "plt.plot(x, np.sin(x), label=r'$\\sin(\\phi)$')\n", "plt.xlim(0, 2 * np.pi)\n", "plt.legend(loc='lower left')\n", "\n", "# Erstelle eine zweite Achse im gleichen Gitter, aber an 2. Position\n", "ax_lower = plt.subplot(212, sharex=ax_upper, sharey=ax_upper) # Verwende die gleichen x- und y-Limits wie oben\n", "\n", "# Funktionen plotten nun in die zweite Achse:\n", "plt.plot(x, np.cos(x), label=r'$\\cos(\\phi)$')\n", "plt.xlabel(r'Winkel $\\phi \\, [\\mathrm{rad}]$')\n", "plt.legend(loc='lower left')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Hinweis:** Matplotlib arbeitet mit _Abbildungen_ und _Achsen_. Wenn wir solche nicht explizit erstellen, wie im Beispiel oben, werden sie beim Aufrufen von Funktionen wie `plt.plot` automatisch erstellt. Du kannst sie auch jederzeit abrufen:\n", ">\n", "> ```python\n", "> fig = plt.gcf() # die aktuelle Abbildung\n", "> ax = plt.gca() # die aktuelle Achse\n", "> ```\n", "> \n", "> Wenn du genauer bestimmen willst, auf welche Achse du plotten möchtest, kannst du sie in Funktionsaufrufen auch angeben oder die Achse direkt verwenden:\n", ">\n", "> ```python\n", "> # Explizit auf Achse `ax` plotten:\n", "> plt.plot(x, y, axis=ax) # oder:\n", "> ax.plot(x, y)\n", "> ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plots speichern\n", "\n", "Mit `matplotlib.pyplot.savefig` könnt ihr einen Plot als Bilddatei speichern:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.savefig('plots/my_plot.png')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Hinweis:** Um einen Plot im **DIN A4-Format** zu speichern könnt ihr dessen Größe und Auflösung anpassen:\n", ">\n", "> ```python\n", "> fig = plt.gcf()\n", "> fig.set_size_inches(11.69, 8.27)\n", "> plt.savefig(filename, dpi=150)\n", "> ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> **Hinweis:** Um Plots in **LaTeX Dokumente** einzubinden bietet sich das [PGF Vektorformat](https://en.wikipedia.org/wiki/PGF/TikZ) statt Pixelgrafiken wie PNG an. Damit übernimmt LaTeX das Zeichnen des Plots und setzt zudem die enthaltenen Texte selbst, sodass die Fonts und Stile des Dokuments auch im Plot verwendet werden.\n", ">\n", "> Eine Beispiel-Implementierung findet ihr im [TexFig](https://github.com/knly/texfig) Repository." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Aufgabe 1 - Temperaturen in Heidelberg visualisieren\n", "\n", "Wir visualisieren nun die Temperaturdaten mit denen wir schon numerisch gearbeitet haben. Lest die Daten zunächst erneut ein:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Zelle ausführen, um Daten einzulesen\n", "data = np.loadtxt('data/temperatures.txt')\n", "date, T = data[np.abs(data[:,1]) != 99,:].transpose()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "a) Plottet den Temperaturverlauf über den gesamten Zeitraum. Vergesst nicht Titel, Achsenbeschriftungen und Legende.\n", "\n", "**Hinweis:** Ihr könnt die Temperatureinheit als `^\\circ{}\\mathrm{C}` (rendert als $^\\circ{}\\mathrm{C}$) schreiben." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": false, "grade_id": "202-1a-sol", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "plt.plot(date, T, label='Messwerte')\n", "plt.title('Temperaturverlauf in Heidelberg')\n", "plt.xlim(np.min(date), np.max(date))\n", "plt.xlabel(r'Zeitpunkt')\n", "plt.ylabel(r'Temperatur $T \\, [^\\circ{}\\mathrm{C}]$')\n", "plt.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sieht dein Plot etwa so aus?\n", "\n", "![Temperaturverlauf in Heidelberg](plots/202-1a.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Setze die Variable auf `True` wenn du mit deinem Plot zufrieden bist:\n", "plot_1a_fertig = False" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": true, "grade_id": "202-1a-test", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "from nose.tools import assert_true\n", "assert_true(plot_1a_fertig, \"Versuche dich an Aufgabe 1a, bis du mit deinem Plot zufrieden bist.\")\n", "print(\"Sieht gut aus.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "b) Plottet den kombinierten Jahres-Temperaturverlauf, also die Temperaturdaten aufgetragen über dem Zeitpunkt innerhalb des Jahres.\n", "\n", "Plottet nur die Datenpunkte und keine verbindende Linie. Vergesst nicht Titel, Achsenbeschriftungen und Legende.\n", "\n", "**Hinweis:** Den Zeitpunkt innerhalb eines Jahres erhaltet ihr wieder mit dem Modulo Operator: `date % 1`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": false, "grade_id": "202-1b-sol", "locked": false, "schema_version": 1, "solution": true } }, "outputs": [], "source": [ "plt.scatter(date % 1, T, marker='.', label='Messwerte')\n", "plt.title('Jahres-Temperaturverlauf in Heidelberg')\n", "plt.xlim(0, 1)\n", "plt.xlabel(r'Zeitpunkt innerhalb des Jahres')\n", "plt.ylabel(r'Temperatur $T \\, [^\\circ{}\\mathrm{C}]$')\n", "plt.legend()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sieht dein Plot etwa so aus?\n", "\n", "![Jahres-Temperaturverlauf in Heidelberg](plots/202-1b.png)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Setze die Variable auf `True` wenn du mit deinem Plot zufrieden bist:\n", "plot_1b_fertig = False" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "nbgrader": { "grade": true, "grade_id": "202-1b-test", "locked": true, "points": 1, "schema_version": 1, "solution": false } }, "outputs": [], "source": [ "from nose.tools import assert_true\n", "assert_true(plot_1b_fertig, \"Versuche dich an Aufgabe 1b, bis du mit deinem Plot zufrieden bist.\")\n", "print(\"🖼 Wunderschön.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "\n", "Nun kannst du Daten mit Numpy analysieren und mit Matplotlib plotten. Lerne in der nächsten Lektion wie du mit dem umfassenden wissenschaftlichen Paket _Scipy_ unter anderem Daten an Funktionen fitten kannst.\n", "\n", "[Startseite](index.ipynb) | [**>> 203 - Fits mit Scipy**](203%20-%20Fits%20mit%20Scipy.ipynb)" ] } ], "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.7.0" } }, "nbformat": 4, "nbformat_minor": 1 }