diff --git a/environment.yml b/environment.yml index ed9f4ad6..5cede6d2 100644 --- a/environment.yml +++ b/environment.yml @@ -18,5 +18,6 @@ dependencies: - nbstripout - black - black-jupyter + - pooch - pip: - ./pygments_style diff --git a/python/data/sin_fit.txt b/python/data/sin_fit.txt new file mode 100644 index 00000000..5b9036c0 --- /dev/null +++ b/python/data/sin_fit.txt @@ -0,0 +1,11 @@ +# x y +0.000000000000000000e+00 2.621434772918542211e-01 +6.981317007977317912e-01 4.271280014348138643e+00 +1.396263401595463582e+00 7.545732202022269242e+00 +2.094395102393195263e+00 6.220187521589215507e+00 +2.792526803190927165e+00 3.941252392172557517e+00 +3.490658503988659067e+00 -1.676311649957553440e+00 +4.188790204786390525e+00 -6.600078564315179364e+00 +4.886921905584122428e+00 -7.537592236437750337e+00 +5.585053606381854330e+00 -4.851500755032368772e+00 +6.283185307179586232e+00 -6.476681314000437562e-01 diff --git a/python/matplotlib.ipynb b/python/matplotlib.ipynb index c01570c4..bef99c0d 100644 --- a/python/matplotlib.ipynb +++ b/python/matplotlib.ipynb @@ -17,6 +17,22 @@ "Damit wir nicht so viel tippen müssen, geben wir ihr den kürzeren Namen `plt`." ] }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Folgende Zeilen sind nur hier wichtig und sollen **nicht** übernommen werden." + ] + }, { "cell_type": "code", "execution_count": null, @@ -27,8 +43,6 @@ "source": [ "from IPython.display import Image\n", "\n", - "import matplotlib.pyplot as plt\n", - "\n", "plt.rcParams[\"figure.figsize\"] = (10, 8)\n", "plt.rcParams[\"font.size\"] = 16\n", "plt.rcParams[\"lines.linewidth\"] = 2" @@ -58,7 +72,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Zu erst ein einfaches Beispiel mit $f(x)=x^2$.\n", + "Zuerst ein einfaches Beispiel mit $f(x)=x^2$.\n", "Um den Text-Output in diesem Notebook zu unterdrücken, schreiben wir manchmal ein `;` hinter die letzte Zeile.\n", "\n", "Im Folgenden verwenden wir die objekt-orientierte Schreibweise von `matplotlib`, die mehr Möglichkeiten und Freiheiten bietet.\n", @@ -112,8 +126,15 @@ }, "outputs": [], "source": [ - "fig2, ax2 = plt.subplots()\n", - "ax2.plot(t, np.sin(t), \"r--\");" + "fig, ax = plt.subplots()\n", + "ax.plot(t, np.sin(t), \"r--\");" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Mit `ax.cla()` entfernen wir alles, was wir vorher in das Achsenobjekt geschrieben haben." ] }, { @@ -163,7 +184,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Neue Grenzen mit `set_xlim(a, b)` und `set_ylim(a, b)`" + "Neue Grenzen setzen mit `set_xlim(a, b)` und `set_ylim(a, b)`" ] }, { @@ -179,15 +200,6 @@ "fig" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "fig2" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -209,6 +221,7 @@ "cell_type": "code", "execution_count": null, "metadata": { + "scrolled": true, "tags": [] }, "outputs": [], @@ -228,9 +241,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Einheiten in Achsenbeschriftungen werden wegdividiert:\n", - "\n", - "Achsen-Beschriftungen können mit LaTeX-Code erstellt werden → LaTeX-Kurs in der nächsten Woche." + "## Einheiten in Achsenbeschriftungen werden weg dividiert:\n", + "Achsenbeschriftungen können mit LaTeX-Code erstellt werden → LaTeX-Kurs in der nächsten Woche." ] }, { @@ -258,7 +270,7 @@ "source": [ "Mehr zu Einheiten gibt es im LaTeX-Kurs.\n", "\n", - "Als eine alternative Schreibweise für die verschiedenen settings der `axes` kann man auch" + "Als eine alternative Schreibweise für die verschiedenen Einstellungen der `axes` kann man auch" ] }, { @@ -288,8 +300,7 @@ "metadata": {}, "source": [ "## Legende\n", - "\n", - "Legenden für Objekte die ein `label` tragen" + "Legenden für Objekte, die ein `label` tragen." ] }, { @@ -316,7 +327,7 @@ "source": [ "Seit matplotlib 2.0.2 ist `loc=best` standardmäßig eingestellt.\n", "\n", - "Andere möglche Orte für die Legende findest du [in der Dokumentation](https://matplotlib.org/stable/api/legend_api.html)." + "Andere mögliche Orte für die Legende findest du [in der Dokumentation](https://matplotlib.org/stable/api/legend_api.html)." ] }, { @@ -324,11 +335,10 @@ "metadata": {}, "source": [ "### Gitter\n", - "\n", "Mit `grid()` wird ein Gitter erstellt:\n", "\n", "Hier wird auch der Vorteil der objekt-orientierten Schreibweise deutlich. Wir müssen keinen neuen plot erstellen, sondern können dem in `fig` hinterlegten neue Eigenschaften hinzufügen.\n", - "Andere möglche Orte für die Legende findest du hier:\n", + "Andere mögliche Orte für die Legende findest du hier:\n", "https://matplotlib.org/api/legend_api.html." ] }, @@ -543,7 +553,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Dies führt manchmal zu Spacing-Problemen und Teilen die sich überschneiden." + "Dies führt manchmal zu Spacing-Problemen und Teilen, die sich überschneiden." ] }, { @@ -668,7 +678,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Polar-Plot\n", + "### Polarplot\n", "Manchmal braucht man einfach einen Polarplot:" ] }, @@ -785,9 +795,9 @@ "source": [ "# Nicht-Objektorientiertes Plotten\n", "Bis jetzt haben wir die ausführliche, objektorientierte Variante von matplotlib benutzt.\n", - "Es git auch die \"schnelle\" Variante mit der einfacheren `pyplot`-Syntax. Wenn man viele Plots anlegt, ist der objekt-orientierte Ansatz für matplotlib allerdings meist besser geeignet.\n", + "Es gibt auch die \"schnelle\" Variante mit der einfacheren `pyplot`-Syntax. Wenn man viele Plots anlegt, ist der objekt-orientierte Ansatz für matplotlib allerdings meist besser geeignet.\n", "\n", - "Die Schreibweise `plt.plot` zeigen wir hier einmal der Vollständig halber und damit auf Stack Overflow oder ähnlichen Seiten keine Verwirrung entsteht.\n", + "Die Schreibweise `plt.plot` zeigen wir hier einmal, der Vollständig halber und damit auf Stack Overflow oder ähnlichen Seiten keine Verwirrung entsteht.\n", "Es besteht eigentlich kein wirklicher Grund, diese Schreibweise aktiv zu nutzen." ] }, @@ -862,7 +872,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Manchmal möchte man komplexere Layouts für Plots haben. Hierbei ist `plt.subplots()` insofern eingeschränkt, dass die Subplots nur auf einem $(N\\times M)$-Gitter angeordnet werden können, bei dem jede Position auf dem Gitter mit einem einzelnen Plot besetzt wird. Hier beispielsweise $(2\\times 3)$:" + "Manchmal möchte man komplexere Layouts für Plots haben. Hierbei ist `plt.subplots()` insofern eingeschränkt, als dass die Subplots nur auf einem $(N\\times M)$-Gitter angeordnet werden können, bei dem jede Position auf dem Gitter mit einem einzelnen Plot besetzt wird. Hier beispielsweise $(2\\times 3)$:" ] }, { @@ -993,7 +1003,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Bisher haben wir immer nur das $(2\\times 3)$-Layout nachgebaut, welches wir auch einfach mit `plt.subplots()` erzeugen können. Der Vorteil von `plt.subplot_mosaic()` liegt nun darin, dass wir Subplots auch über mehrere Zeilen oder Spalten ziehen können. Hierzu werden Benachbarte Gitterpositionen einfach gleich benannt:" + "Bisher haben wir immer nur das $(2\\times 3)$-Layout nachgebaut, welches wir auch einfach mit `plt.subplots()` erzeugen können. Der Vorteil von `plt.subplot_mosaic()` liegt nun darin, dass wir Subplots auch über mehrere Zeilen oder Spalten ziehen können. Hierzu werden benachbarte Gitterpositionen einfach gleich benannt:" ] }, { @@ -1081,7 +1091,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Hierbei nutzen wir die `ax.get_label()` Methode um in der `ax.annotate()` Methode einen Text (unser Label) mit Ausrichtung oben (\"vertical alignment\", `va=\"top\"`) an die Relativkoordinate $(0.05, 0.95)$ der Achse zu setzen. Die Zeile `anchor = ax.get_window_extent()` zusammen mit dem Keyword-Argument `xycoords=anchor` in `ax.annotate()` sorgt dafür, dass wir uns im Koordinatensystem der Achse befinden und nicht im Koordinatensystem des etwaigen Plotinhalts selbst." + "Hierbei nutzen wir die `ax.get_label()` Methode, um in der `ax.annotate()` Methode einen Text (unser Label) mit Ausrichtung oben (\"vertical alignment\", `va=\"top\"`) an die Relativkoordinate $(0.05, 0.95)$ der Achse zu setzen. Die Zeile `anchor = ax.get_window_extent()` zusammen mit dem Keyword-Argument `xycoords=anchor` in `ax.annotate()` sorgt dafür, dass wir uns im Koordinatensystem der Achse befinden und nicht im Koordinatensystem des etwaigen Plotinhalts selbst." ] }, { diff --git a/python/numeric-python.ipynb b/python/numeric-python.ipynb index 293219c0..bae81be9 100644 --- a/python/numeric-python.ipynb +++ b/python/numeric-python.ipynb @@ -170,10 +170,8 @@ "outputs": [], "source": [ "import math\n", - "\n", "# This doesn't work\n", - "\n", - "# math.cos(x_arr)" + "math.cos(x_arr)" ] }, { @@ -238,7 +236,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Das erlaubt es einem unter anderem, sehr leicht physikalische Formeln auf seine Datenpunkte anzuwenden.\n", + "Das erlaubt es einem unter anderem sehr leicht physikalische Formeln auf seine Datenpunkte anzuwenden.\n", "\n", "Arrays können beliebige Dimension haben:" ] @@ -317,7 +315,7 @@ "\n", "Die Gesamtzahl der Elemente in einem Array können mit der `size`-Funktion abgefragt werden.\n", "\n", - "Der Datentyp eines Arrays muss innerhalb des Arrays der gleiche sein. Um den Datentyp eines Arrays abzufragen gibt es die `dtype`-Funktion." + "Der Datentyp eines Arrays muss innerhalb des Arrays der gleiche sein. Um den Datentyp eines Arrays abzufragen, gibt es die `dtype`-Funktion." ] }, { @@ -652,7 +650,6 @@ "metadata": {}, "source": [ "# Reduzieren von Arrays\n", - "\n", "Viele Rechenoperationen reduzieren ein Array auf einen einzelnen Wert." ] }, @@ -785,7 +782,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Um die Differenzen zwischen benachbarten Elementen herauszufinden kann die Funktion `np.diff()` genutzt werden." + "Um die Differenzen zwischen benachbarten Elementen herauszufinden, kann die Funktion `np.diff()` genutzt werden." ] }, { @@ -805,7 +802,6 @@ "metadata": {}, "source": [ "# Input / Output\n", - "\n", "Um Datenpunkte aus einer Textdatei einzulesen wird die Funktion `np.genfromtxt()` genutzt.\n", "Sie gibt den Inhalt einer Textdatei als Array zurück.\n", "\n", @@ -935,7 +931,7 @@ "metadata": {}, "source": [ "Das resultierende Array `data` ist besonders, da es ein sogenanntes `structured array` ist.\n", - "Dies ist ein NumPy Array in dem quasi mehrere Arrays in einem abgespeichert sind. Die einzelnen Arrays werden in der Dokumentation `fields` genannt und haben jeweils einen zugeordneten Namen und einen Datentyp." + "Dies ist ein NumPy Array, in dem quasi mehrere Arrays in einem abgespeichert sind. Die einzelnen Arrays werden in der Dokumentation `fields` genannt und haben jeweils einen zugeordneten Namen und einen Datentyp." ] }, { @@ -981,7 +977,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.12.6" } }, "nbformat": 4, diff --git a/python/python.ipynb b/python/python.ipynb index 923b19e9..e06d1124 100644 --- a/python/python.ipynb +++ b/python/python.ipynb @@ -114,11 +114,11 @@ "metadata": {}, "outputs": [], "source": [ - "# We start the workshop with the traditional first program\n", - "print(\"Hello, World!\")\n", "\"\"\"\n", - "This example is chosen to show the basic functionalities of python.\n", - "\"\"\"" + "We start the workshop with the traditional first program.\n", + "\"\"\"\n", + "print(\"Hello, World!\")\n", + "# This example is chosen to show the basic functionalities of python. " ] }, { @@ -1760,9 +1760,9 @@ "metadata": {}, "source": [ "## Allgemeiner Syntax-Fehler: `SyntaxError`\n", - "Zeile in der der Fehler auftritt: `line 6` \n", - "Grund für den Fehler: `SyntaxError: invalid syntax` \n", - "Hier sogar mit Hinweis auf das fehlerhafte/fehlende Zeichen.\n" + "Zeile, in der der Fehler auftritt: `line 6` \n", + "Grund für den Fehler: `SyntaxError: expected ':'` \n", + "Hier sogar mit Hinweis auf das fehlerhafte/fehlende Zeichen." ] }, { @@ -1789,15 +1789,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Ein zu Anfang verwirrender Fehler\n", - "\n", - "Die Fehlermeldung ist hier im ersten Moment nicht besonders hilfreich: \n", - "Zeile in der der Fehler auftritt: `line 11` \n", - "Grund für den Fehler: `SyntaxError: invalid syntax` \n", - "\n", - "Stimmt nur zum Teil, denn in Zeile 11 ist alles in Ordnung und der eigentliche Fehler ist in Zeile 10. \n", - "In komplexeren Programmen ist das nicht mehr so einfach zu sehen wie hier,\n", - "deswegen ist es gut, wenn man dieses Verhalten schon mal gesehen hat." + "## Klammerfehler\n", + "Zeile, in der der Fehler auftritt: `line 10` \n", + "Grund für den Fehler: `SyntaxError: '(' was never closed` \n", + "Hier sogar mit Hinweis auf die Klammer, die keinen Partner hat." ] }, { @@ -1907,9 +1902,9 @@ "gibt die Fehlermeldung einen *Traceback* aus.\n", "Dieser Fall ist eher die Regel, vor allem, wenn Module verwendet werden.\n", "Der *Traceback* zeigt die Reihenfolge aller Funktionsaufrufe, die\n", - "am Ende zu dem Fehler geführt haben mit dem letzten Aufruf ganz unten *(most recent call last)*.\n", + "am Ende zu dem Fehler geführt haben, mit dem letzten Aufruf ganz unten *(most recent call last)*.\n", "\n", - "Zeilen die zum Auftreten des Fehlers führen: \n", + "Zeilen, die zum Auftreten des Fehlers führen: \n", "Funktionsaufruf in Zeile 13: \n", "`---> 13 add_one_to_inverse_difference(x,y)` \n", "Ergebnis des Funktionsaufrufs ist das `return` in Zeile 5 mit neuem Funktionsaufruf: \n", @@ -2285,7 +2280,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.10" + "version": "3.12.6" } }, "nbformat": 4, diff --git a/python/scientific-python.ipynb b/python/scientific-python.ipynb index 2de5ac66..767eb280 100644 --- a/python/scientific-python.ipynb +++ b/python/scientific-python.ipynb @@ -11,7 +11,7 @@ "- Kann numerisch integrieren, DGLs lösen, optimieren, minimieren, …\n", "- Enthält auch physikalische Konstanten und wichtige mathematische Funktionen\n", "\n", - "Überblick über (fast) alles weitere was SciPy kann gibt es hier:\n", + "Überblick über (fast) alles Weitere, was SciPy kann, gibt es hier:\n", "\n", "- https://github.com/MaxNoe/scientific_python_notebooks/blob/master/scipy.ipynb" ] @@ -112,14 +112,14 @@ "Für Funktionen, die eine Linearkombination von Einzelfunktionen sind, also\n", "\n", "$$\n", - "f(x) = \\sum_i^N a_i \\cdot f_i(x)\n", + "f(x) = \\sum_i^N a_i \\cdot f_i(x),\n", "$$\n", "\n", "existiert eine analytische Lösung. Deswegen sollten in solchen Fällen (z.B. alle Polynome) entsprechende Funktionen genutzt werden (z.B. `np.polyfit`).\n", "\n", "### Lineare Regression bzw. Regression von Polynomen\n", "\n", - "Im folgenden wird eine lineare Regression mit `np.polyfit` durchgeführt:\n", + "Im Folgenden wird eine lineare Regression mit `np.polyfit` durchgeführt:\n", "\n", "$$\n", "f(x) = a + b \\cdot x\n", @@ -157,10 +157,10 @@ "# Fit a polynomial of degree 1, return covariance matrix\n", "params, covariance_matrix = np.polyfit(x, y, deg=1, cov=True)\n", "\n", - "errors = np.sqrt(np.diag(covariance_matrix))\n", + "uncertainties = np.sqrt(np.diag(covariance_matrix))\n", "\n", - "for name, value, error in zip(\"ab\", params, errors):\n", - " print(f\"{name} = {value:.3f} ± {error:.3f}\")" + "for name, value, uncertainty in zip(\"ab\", params, uncertainties):\n", + " print(f\"{name} = {value:.3f} ± {uncertainty:.3f}\")" ] }, { @@ -188,6 +188,7 @@ { "cell_type": "markdown", "metadata": { + "collapsed": true, "jupyter": { "outputs_hidden": true } @@ -197,10 +198,99 @@ "\n", "Wenn eine Funktion nicht linear bezüglich der freien Parameter ist, muss die Lösung numerisch gefunden werden.\n", "\n", - "Hierbei kann es sein, dass der Minimierungsalgorithmus in lokale Maxima hineinläuft und unsinnige Ergebnisse liefert,\n", + "Als erstes Beispiel dafür schauen wir uns folgende Daten an:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x, y = np.genfromtxt(\"data/sin_fit.txt\", unpack=True)\n", + "\n", + "ax.cla()\n", + "\n", + "ax.plot(x, y, \"o\", label=\"Messwerte\")\n", + "ax.set(xlabel=r\"$t$ / s\", ylabel=r\"$U$ / V\")\n", + "ax.legend()\n", + "fig" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Diese Daten sollen an in der Theorie eine Sinus-Kurve beschreiben. Wir schreiben den Sinus allgemein als\n", + "$$U(t) = a \\cdot \\sin(b \\cdot t) + c~.$$\n", + "und definieren uns die entsprechende Funktion im Code." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def sinus(x, a, b, c):\n", + " return a * np.sin(b * x) + c" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Für das fitten nutzen wir jetzt `curve_fit` und bekommen wieder die Parameter und Kovarianz-Matrix als Rückgabewerte.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.optimize import curve_fit\n", + "\n", + "params, covariance_matrix = curve_fit(sinus, x, y)\n", + "\n", + "uncertainties = np.sqrt(np.diag(covariance_matrix))\n", + "\n", + "for name, value, uncertainty in zip(\"abc\", params, uncertainties):\n", + " print(f\"{name} = {value:.3f} ± {uncertainty:.3f}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Jetzt können wir die gefittete Funktion in den Plot der Messwerte hinzufügen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ax.cla()\n", + "\n", + "x_sin_fit = np.linspace(0, 2 * np.pi)\n", + "\n", + "ax.plot(x, y, \"o\", label=\"Messwerte\")\n", + "ax.plot(x_sin_fit, sinus(x_sin_fit, *params), label=\"Sinus Fit\")\n", + "ax.set(xlabel=r\"$t$ / s\", ylabel=r\"$U$ / V\")\n", + "ax.legend()\n", + "fig" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bei dieser Variante des Fits kann es passieren, dass der Minimierungsalgorithmus in lokale Maxima hineinläuft und unsinnige Ergebnisse liefert,\n", "dies kann mit guten Startwerten meistens vermieden werden.\n", "\n", - "Als Beispiel einer komplexeren Funktion wird im Folgenden die `Sigmoidfunktion` verwendet (Ähnlich zum `tanh`):\n", + "Als Beispiel einer komplexeren Funktion wird im Folgenden die `Sigmoidfunktion` verwendet (ähnlich zum `tanh`):\n", "\n", "$$ f(x; a, b, c) = \\frac{a}{1 + \\exp(-(x-b))} + c$$" ] @@ -247,8 +337,6 @@ "ax.cla()\n", "ax.plot(x, y, \"o\", label=r\"Messwerte\")\n", "\n", - "ax.set_xlabel(\"Temperatur / °C\")\n", - "ax.set_ylabel(\"$GP$\")\n", "ax.set(xlabel=r\"Temperatur / °C\", ylabel=r\"$GP$\")\n", "fig" ] @@ -266,8 +354,6 @@ "metadata": {}, "outputs": [], "source": [ - "from scipy.optimize import curve_fit\n", - "\n", "params, covariance_matrix = curve_fit(sigmoid, x, y)\n", "\n", "uncertainties = np.sqrt(np.diag(covariance_matrix))\n", @@ -539,7 +625,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.12.6" } }, "nbformat": 4, diff --git a/python/uncertainties.ipynb b/python/uncertainties.ipynb index 0282f8df..14b88dfc 100644 --- a/python/uncertainties.ipynb +++ b/python/uncertainties.ipynb @@ -100,7 +100,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Man muss daran denken, jetzt die Funktionen aus unumpy zu benutzen (`exp`, `cos`, etc.)" + "Man muss daran denken, jetzt die Funktionen aus unumpy zu benutzen (`exp`, `cos`, etc.)." ] }, { @@ -467,7 +467,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.6" + "version": "3.12.6" } }, "nbformat": 4,