diff --git a/Kapitel_2._Das_Auge_plottet_mit_und_das_Einlesen_von_Daten__Zusatz_.ipynb b/Kapitel_2._Das_Auge_plottet_mit_und_das_Einlesen_von_Daten__Zusatz_.ipynb new file mode 100644 index 0000000..7c0a62a --- /dev/null +++ b/Kapitel_2._Das_Auge_plottet_mit_und_das_Einlesen_von_Daten__Zusatz_.ipynb @@ -0,0 +1,781 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Das Einlesen von Messdaten:\n", + "\n", + "Im PGP-2 ist es in verschiedenen Versuchen nötig Messdaten von txt-Dateien einzulesen. Hierfür könnt ihr verschiedene Methoden verwenden. Dies ist oft in Python der Fall, das mehrere Wege ans Ziel führen. Im folgen möchten wir euch zwei Methoden etwas näher bringen.\n", + "\n", + "### Mit Hilfe von numpy:\n", + "\n", + "Eine weitere nützliche `numpy`-Funktion verwenden. Gucken wir uns jedoch zunächst einmal einen typischen Beispieldatensatz (*BeispielDatenPGP2.txt*) an: \n", + "\n", + "``` \n", + "Messwertnummer\tHallspannung UH\tProbenspannung Up\tProbenstrom Ip\tProbentemperatur Tp\tFlussdichte B\n", + "n/#\tUH/mV\tUp/V\tIp/mA\tTp/°C\tB/T\n", + "\n", + "1\t-9,9\t-2,73\t-53\t24,0\t-0,006864\n", + "2\t-6,6\t-2,03\t-40\t24,0\t-0,006927\n", + "3\t-4,7\t-1,51\t-29\t24,1\t-0,006867\n", + "4\t-3,4\t-1,09\t-21\t24,1\t-0,006842\n", + "5\t-1,8\t-0,57\t-11\t23,8\t-0,006892\n", + "6\t-0,2\t-0,04\t-1\t24,1\t-0,006860\n", + "7\t0,9\t0,52\t10\t24,0\t-0,006849\n", + "8\t2,2\t1,09\t22\t24,0\t-0,006892\n", + "9\t3,3\t1,62\t32\t24,1\t-0,006869\n", + "10\t4,3\t2,15\t42\t24,2\t-0,006851\n", + "11\t6,3\t2,55\t50\t24,3\t-0,006860\n", + "```\n", + "\n", + "Wie ihr sehen könnt besteht diese Datei aus mehreren bei Leerzeichen getrennten Spalten und durch Umbrüche getrennte Zeilen. Allgemein unterscheidet man bei solchen Datensätzen zwischen zwei Informationskategorien: \n", + "\n", + "1. Der Kopfzeile (*Header*) \n", + "2. Den Messwerten selbst\n", + " \n", + "Der Header enthält allegemeine Informationen über unsere Daten. In unserem obigen Beispiel ist dies z.B. der Name der einzelnen Messwerte wie *Hallspannung UH* und dessen Einheiten *mV*. Gefolgt ist der Header von unseren tatsächlichen Messwerten, welche wir für unsere Analyse brauchen. Was für uns einfach lesbar und verständlich ist, bedeutet im allgemeinen nicht, dass das gleiche auch für unseren Computer gilt. Probieren wir doch erstmal diesen Datensatz mit Hilfe von `np.genfromtxt` einzulesen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-03T10:04:09.176914Z", + "start_time": "2019-10-03T10:04:08.956145Z" + } + }, + "outputs": [], + "source": [ + "import numpy as np" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-03T10:05:45.212389Z", + "start_time": "2019-10-03T10:05:45.000440Z" + } + }, + "outputs": [], + "source": [ + "pfad = 'BeispielDatenPGP2.txt' # <-- Pfad zur Datei, sofern sich die Datei am selben Ort wie euer\n", + " # Notebook befindet reicht es den Dateinamen anzuegebn. Ansonsten\n", + " # müsst ihr den gesamten Pfad angeben. \n", + "np.genfromtxt(pfad) # <-- Einlesen der txt-Datei" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wie ihr seht bekommen wir eine etwas längliche Fehlermeldung, welche so viel sagt wie: *Hey du ich verstehe deine Datei nicht, mal hast du mehr Spalten mal weniger*. Das Problem hier ist, dass unser *Header* scheinbar eine andere Spaltenanzahl als unser Messdaten aufweist. Dies Problem können wir relative einfach mit dem Paramter `skip_header` umgehen: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-03T10:28:02.193780Z", + "start_time": "2019-10-03T10:28:02.162533Z" + } + }, + "outputs": [], + "source": [ + "data = np.genfromtxt(pfad, \n", + " skip_header=3 # <-- Überspringt die ersten 3 Zeilen unserer Files\n", + " )\n", + "data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wie ihr sehen könnt ist uns hier schonmal ein Teilerfolg gelungen. Unsere Messwerte wurden eingelesen und wurden als ein `numpy.array` gespeichert. Ein `numpy.array` ist eine etwas bessere Form einer Liste wie ihr sie bereits kennt (denkt euch einfach das array() weg, dann sieht es genauso aus wie eine Liste. Guckt euch auch gerne mal in eurer Freizeit an wie numpy arrays funktionieren (z.B. auf youtube) arrays nehmen euch viel Arbeit ab). Des Weiteren seht ihr aber auch, dass Python nicht all unsere Messwerte richtig einglesen hat. Lasst uns nochmal die Messdaten der ersten Zeile mit unseren eingelesenen Daten vergleichen:\n", + "\n", + "Messdaten:\n", + "\n", + "```\n", + "1 -9,9 -2,73 -53 24,0 -0,006864\n", + "```\n", + "\n", + "Eingelesen in Python:\n", + "\n", + "```\n", + "[ 1., nan, nan, -53., nan, nan]\n", + "``` \n", + "\n", + "Tja dumm gelaufen \"leider\" studiert ihr in Deutschland. In Deutschland (aber auch in anderen Ländern) ist es üblich ein Dezimalkomma **\",\"** zu verwenden, wohingegen in den USA der Punkt **\".\"** das übliche Trennungszeichen ist. Sprich Python versteht nicht wie er die Zahl -9,9 in eine Float-Zahl umwandeln soll. Aus diesem Grund bekommt ihr den Wert **nan** (not a number) zurück. Aber keine Sorge auch dieses Problem lässt sich relativ einfach mit Hilfe des `converters` parameter lösen. \n", + "\n", + "Der Paramter `converts` benötigt ein sogenanntes python dictionary als Eingabe. Keine Sorge es klingt kompliziert ist aber relativ einfach. Bei einem dictionary wird einem Schlüsselbegriff (key) ein Wert (value) zu gewiesen. Dies sieht wie folgt aus:\n", + "\n", + "```python\n", + "{key1: value1, key2: value2, key3: value3}\n", + "```\n", + "\n", + "Für unseren Parameter `converts` müssen wir ein dictionary erstellen welches einer gewissen Spalte eine Funktion zuordnet. In unserem Fall muss diese Funktion das Komma durch einen Punkt ersetzen. Dies ist relativ einfach und sieht dann so aus:\n", + "\n", + "```python\n", + "{1: lambda v1: float(v1.replace(b',', b'.'))}\n", + "```\n", + "\n", + "Hierbei steht der **key** 1 für die 1. Spalte (nicht vergessen in Python starten wir bei der 0 mit dem Zählen). Als **value** wurde hier eine sogenannte `lambda`-Funktion verwendet. Eine `lambda`-Funktion ist lediglich eine mini-Funktion welche in den meisten Fällen nicht gespeichter werden soll. Unsere `lambda`-Funktion nimmt einen paramter genannt v1, was unserem Messwert entspricht und ersetzt bei diesem Wert das Komma durch ein Punkt. (Nebenbemerkung: Das kleine b vor dem String bedeutet das wir den String als bit-codiertes Wort lesen.) Es sieht sehr kompliziert aus, ist aber in der Anwendung sehr einfach. Gucken wir uns dieses Beispiel doch einfach einmal an:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-03T10:39:26.259305Z", + "start_time": "2019-10-03T10:39:26.223312Z" + } + }, + "outputs": [], + "source": [ + "np.genfromtxt(pfad, \n", + " skip_header=3, \n", + " converters={1: lambda v1: float(v1.replace(b',', b'.'))}\n", + " )" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Wie ihr seht haben wir für Spalte 1. erfolgreich die Messwerte einlesen können. Um dies nun auch mit unseren anderen Spalten machen zu können müssen wir nur unser dictionary entsprechend erweitern:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-03T10:59:09.375845Z", + "start_time": "2019-10-03T10:59:09.314951Z" + } + }, + "outputs": [], + "source": [ + "data = np.genfromtxt(pfad,\n", + " skip_header=3, \n", + " converters={1: lambda v1: float(v1.replace(b',', b'.')),\n", + " 2: lambda v1: float(v1.replace(b',', b'.')),\n", + " 4: lambda v1: float(v1.replace(b',', b'.')),\n", + " 5: lambda v1: float(v1.replace(b',', b'.'))}\n", + " )\n", + "data" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ihr könnt sehen wir haben alle Messwerte erfolgreich eingelesen auch wenn diese hier etwas gewöhnungsbedürftig in einer scientific-Schreibweise angegeben sind. Bei dieser Schreibweise steht z.B. 3.2e+01 für $3.2 \\cdot 10^1$. Jetzt können wir wie gewohnt damit Arbeiten:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-03T11:08:26.231136Z", + "start_time": "2019-10-03T11:08:26.215482Z" + } + }, + "outputs": [], + "source": [ + "zeile1 = data[0] # <-- Erste Zeile von Messdaten\n", + "Messwertnummer = data.T[0] # <-- Erste Saplte von Messdaten mit der Messwertnummer \n", + "Hallspannung = data.T[1] # <-- Zweite Spalte mit der Hallspannung \n", + "\n", + "# Nebenbemerkung:\n", + "# Arrays verhalten sich eher wie mathematische Vektoren bzw. Matritzen\n", + "# Mit dem Befehl .T transponiert ihr im obigen Beispiel eine \"Matrix\"\n", + "# wordurch ihr die jweiligen Spalten als Zeilen bekommt." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mit Hilfe des CSV-package:\n", + "\n", + "Eine weitere Methode welche zum Einlesen von Datein verwendet werden kann kommt mit dem CSV-Package. txt- oder csv-Dateien nutzen zur Trennung von Spalten Trennzeichen (separator), wie z.B. ‘,‘ ,‘;‘ oder auch ein Leerzeichen. Aus diesem Grund werden Dateien dieser Variante als CSV-Datei, das für comma separated variable steht, genannt. Wie im obigen Beispiel bereit gezeigt ist im deutschsprachigen Raum zu beachten, dass Kommas als Dezimaltrennzeichen benutzt werden, und daher nicht als Spaltentrennzeichen verwendet werden sollte.\n", + "\n", + "Für das Einlesen solcher CSV-Dateien hält Python das csv-Modul bereit. Hierbei ist zu beachten, dass die eingelesenen Werte zunächst vom Typ str sind und vor der Weiterverwendung in Rechnungen entsprechend umgewandelt werden müssen. Folgendes Beispiel demonstriert die notwendigen Schritte:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T09:14:53.935626Z", + "start_time": "2019-10-06T09:14:53.910827Z" + } + }, + "outputs": [], + "source": [ + "import csv\n", + "Messwertnummer = [] # Liste zur Speicherung der Spannungswerte\n", + "Hallspannung = [] # Liste zur Speicherung der Stromwerte\n", + "\n", + "pfad = 'BeispielDatenPGP2.txt'\n", + "\n", + "with open(pfad) as csvfile:\n", + " # Initialisieren des CSV-Readers und Festlegen des Trennzeichens, \n", + " # optionale Parameter müssen explizit benannt werden\n", + " readCSV = csv.reader(csvfile, delimiter='\\t')\n", + " \n", + " # alle Zeilen der Textdatei nacheinander einlesen\n", + " for row in readCSV: \n", + " # Erste Spalte enthält die Messwertnummber (Die Werte werden in Fließkommazahlen umgewandelt)\n", + " messwertnummer = float(row[0])\n", + " # Zweite Spalte enthält die Hallspannung\n", + " hallspannung = float(row[1].replace(',', '.')) # <-- Hier müssen wir wieder das Komma erstzen\n", + " # die Werte werden in die entsprechenden Listen eingefügt\n", + " Messwertnummer.append(messwertnummer)\n", + " Hallspannung.append(hallspannung)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Leider gibt uns auch dieser Ansatz erstmal eine Fehlermeldung, da wir wieder unseren Header überspringen müssen. Hierzu können wir das Konzept eines `if`-Statements verwenden. Eine `if`-Statement evaluiert ob eine Aussage *Wahr* oder *Falsch* und führt passierende auf dem Ergebnis eine Aktion durch. \n", + "\n", + "\n", + "Um hieraus nutzen ziehen zu können müssen wir den obigen Code wie folgt modifizieren:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T09:14:47.437191Z", + "start_time": "2019-10-06T09:14:47.422617Z" + } + }, + "outputs": [], + "source": [ + "import csv\n", + "Messwertnummer = [] # Liste zur Speicherung der Spannungswerte\n", + "Hallspannung = [] # Liste zur Speicherung der Stromwerte\n", + "\n", + "pfad = 'BeispielDatenPGP2.txt'\n", + "\n", + "with open(pfad) as csvfile:\n", + " readCSV = csv.reader(csvfile, delimiter='\\t')\n", + " \n", + " for ind, row in enumerate(readCSV): # <-- enumerate ordnet jeder eingelesenen Zeile einen index zu\n", + " \n", + " if ind < 3: # <-- Solang der Index kleiner als 3 ist befinden wir uns noch im Header\n", + " continue # <-- Deshlab wollen wir, dass nichts passiert. Dies erreichen wir mit\n", + " # continue \n", + " \n", + " messwertnummer = float(row[0])\n", + " hallspannung = float(row[1].replace(',', '.')) \n", + " Messwertnummer.append(messwertnummer)\n", + " Hallspannung.append(hallspannung)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Das Auge plottet mit:\n", + "\n", + "In diesem Notebook möchte ich noch ein paar weitere nützlichen Befehle rund ums Thema **Plotten** zeigen. Hierbei handelt es sich nur um verschiedene Beispiele wie ihr eure Plots noch etwas weiter ausschmücken könnt. Nehmen wir hierfür wieder unseren Spannungsplot aus Kapitel 1.:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:32.872223Z", + "start_time": "2019-10-06T12:31:31.934942Z" + } + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "# ------------\n", + "# \"Messwerte\":\n", + "# ------------\n", + "spannung = [0.9, 2.0, 3.0, 4.1, 4.9, 6.2] # [V]\n", + "strom = [105, 204, 298, 391, 506, 601] # [mA]\n", + "spannung_error = [0.3]*len(spannung) \n", + "strom_error = [14, 9, 12, 8, 7, 11]\n", + "\n", + "# Spannungsfunktion:\n", + "Spannung = lambda I,R: I*R # <--- Eine lambda-Funktion ist eine andere Variante um kleine \n", + " # Funktionen zu definieren.\n", + "\n", + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "plt.show" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Plotgröße ändern\n", + "\n", + "Als erstes kann es nützlich sein die Größe unseres Plottes zu erhöhen. Die können wir über `plt.figure()` erreichen. Je nach dem solltet ihr auch die fontsize eurer Beschriftung entsprechend anpassen." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:33.247151Z", + "start_time": "2019-10-06T12:31:32.872223Z" + } + }, + "outputs": [], + "source": [ + "plt.figure(figsize=(7,5), # <-- figsize gibt die Seitenlänge des Plots in\n", + " # Zoll (1 Zoll = 2.54 cm) wieder. (7,5) ist ein gutes Format für A4\n", + " dpi=150) # Auflösung des Plots\n", + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "plt.show() " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "ExecuteTime": { + "end_time": "2019-09-30T10:13:03.757411Z", + "start_time": "2019-09-30T10:13:03.316577Z" + } + }, + "source": [ + "### Linien in allen Arten und Farben:\n", + "\n", + "Das zweite nützliche Feature sind verschiedene Arten von Hilfslinien welche wir zu unserem Plot hinzufügen können. Fangen wir mit einem einfachen Gitternetz an dies könnt über `plt.grid` zu eurem Plot hinzufügen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:33.590804Z", + "start_time": "2019-10-06T12:31:33.247151Z" + } + }, + "outputs": [], + "source": [ + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "\n", + "plt.grid() # <-- Dieser Befehl fügt das Gitternet hinzu.\n", + "\n", + "plt.show" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Natürlich können wir auch für das Gitternet verschiedene Optionen spezifizieren:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:33.887611Z", + "start_time": "2019-10-06T12:31:33.590804Z" + } + }, + "outputs": [], + "source": [ + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "\n", + "\n", + "plt.grid(color='k', # Farbe \n", + " ls='dashed', # Linientyp\n", + " axis='x') # Axe\n", + "\n", + "\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In kombination mit `plt.minorticks_on()` kann der Plot sehr detailreich gestaltet werden:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:34.418733Z", + "start_time": "2019-10-06T12:31:33.887611Z" + } + }, + "outputs": [], + "source": [ + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "\n", + "\n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "\n", + "plt.minorticks_on() # Aktiviert Unterskalenteile \n", + "plt.grid(which='minor', # <-- Grid für die kleinen Ticks \n", + " color='gray',\n", + " ls='dashed'\n", + " )\n", + "plt.grid(which='major',\n", + " color='gray',\n", + " ls='solid')\n", + "\n", + "plt.show()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Manchmal ist es ebenfalls sinnvoll besondere Linien einzuführen um Dinge hervorzuheben. Hierzu könnt ihr die Funktionen `plt.hlines` and `plt.vlines` für horizontale und vertikale Linien verwenden." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:35.026277Z", + "start_time": "2019-10-06T12:31:34.513883Z" + }, + "scrolled": true + }, + "outputs": [], + "source": [ + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "\n", + "\n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "\n", + "plt.minorticks_on() \n", + "plt.grid(which='minor', \n", + " color='gray',\n", + " ls='dashed'\n", + " )\n", + "plt.grid(which='major',\n", + " color='gray',\n", + " ls='solid')\n", + "\n", + "plt.vlines(400, # <-- Position für die vertikale Linie\n", + " 2, # <-- Start y-Wert\n", + " 4, # <-- End y-Wert\n", + " label='Line',\n", + " color='red',\n", + " ls='dashed'\n", + " )\n", + "\n", + "plt.hlines([2.2,3.4], # <-- Ihr könnt auch mehrere Linien plotten\n", + " 200, \n", + " 400, \n", + " label='horizontale Linen',\n", + " color='blue',\n", + " ls='dashed'\n", + " )\n", + "\n", + "plt.legend()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Mehr Text ist manchmal mehr Information:\n", + "\n", + "Als letztes möchte ich euch noch zeigen wir ihr auf zwei unterschiedliche Arten und weisen Texte zu eurem Plot hinzufügen könnt. Dies kann nützlich sein um besondere Messwerte hervorzuheben oder einfach zusätzliche Informationen unter zu bringen.\n", + "\n", + "Fangen wir mit `plt.annotate` an. Mit dieser Funktion können wir einen beschrifteten Pfeil in unseren Plot einfügen. Dies könnte zum Beispiel so aussehen:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:31:35.914992Z", + "start_time": "2019-10-06T12:31:35.387045Z" + } + }, + "outputs": [], + "source": [ + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2 \n", + " ) \n", + "\n", + "\n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "\n", + "plt.minorticks_on() \n", + "plt.grid(which='minor', \n", + " color='gray',\n", + " ls='dashed'\n", + " )\n", + "plt.grid(which='major',\n", + " color='gray',\n", + " ls='solid')\n", + "\n", + "plt.annotate(f\"Messwertnummer {3 + 1}\", # Beschriftung des Pfeils\n", + " xy = (strom[3], spannung[3]), # Position der Pfeilspitze\n", + " xytext = (strom[3]-300, spannung[3] + 1), # Position des Textes (und des Pfeilendes)\n", + " arrowprops = {'arrowstyle': '->'}, # Style des Pfeils\n", + " fontsize=14)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Eine andere nützliche Art Beschriftungen in einen Plot hinzuzufügen stellt die Methode `plt.text` dar. Diese Methode ist insbesondere nützlich um Fitdaten in einen Plot zu zeigen. Führen wir zunächst wie in Kapitel 1. gezeigt einen Fit unsere Messdate durch:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:36:18.690010Z", + "start_time": "2019-10-06T12:36:17.672149Z" + } + }, + "outputs": [], + "source": [ + "from scipy.optimize import curve_fit" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:48:03.095908Z", + "start_time": "2019-10-06T12:48:03.080287Z" + } + }, + "outputs": [], + "source": [ + "para, pcov = curve_fit(Spannung, \n", + " strom, \n", + " spannung,\n", + " sigma=spannung_error, # <-- Diesesmal mit Fehler\n", + " absolute_sigma=True # <-- Diesen Option müssen wir auf Wahr setzen, da \n", + " # wir in der Regel absolute und keine relativen \n", + " # Unsicherheiten messen.\n", + " )\n", + "\n", + "chi2 = sum([ (Spannung(I,para[0]) - U)**2/dU**2 for I, U, dU in zip(strom, spannung, spannung_error)])\n", + "ndof = len(spannung) - len(para)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-06T12:48:38.876540Z", + "start_time": "2019-10-06T12:48:38.345426Z" + } + }, + "outputs": [], + "source": [ + "plt.figure(figsize=(7,5))\n", + "plt.errorbar(strom, \n", + " spannung,\n", + " xerr=strom_error,\n", + " yerr=spannung_error, \n", + " ls='', \n", + " marker='d', \n", + " mfc='orange', \n", + " mec='k', \n", + " ms=7,\n", + " ecolor='k', \n", + " elinewidth=2, \n", + " capsize=5, \n", + " capthick=2,\n", + " label='Messwerte'\n", + " ) \n", + "\n", + "plt.plot(strom, \n", + " Spannung(strom, para),\n", + " color='Orange',\n", + " label='$U(I)=R \\cdot I$' )\n", + "\n", + "\n", + "\n", + "plt.ylabel('Spannung [V]')\n", + "plt.xlabel('Strom [mA]')\n", + "\n", + "plt.minorticks_on() \n", + "plt.grid(which='minor', \n", + " color='gray',\n", + " ls='dashed'\n", + " )\n", + "plt.grid(which='major',\n", + " color='gray',\n", + " ls='solid')\n", + "\n", + "\n", + "R = para[0] * 1000 # Widerstand in Ohm\n", + "deltaR = pcov[0][0]**(1/2)* 1000 # Fehler des Widerstands in hm\n", + "\n", + "plt.text(100, # <-- X-Position des Textes\n", + " 4.5, # <-- Y-Position des Textes\n", + " f'R: ({R:.2f} +/- {deltaR:.2f}) Ohm\\n$\\chi^2$/ndof: {chi2:.2f}/{ndof}', \n", + " fontsize=14\n", + " )\n", + "plt.legend()\n", + "plt.show()" + ] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}