Numerisches Programmieren I - Mathematisches Programmieren

Summary

This document is lecture notes for a course on numerical programming. The notes cover topics such as number representations (integer and floating-point), the NumPy library, and the Matplotlib library for data visualization.

Full Transcript

Numerisches Programmieren I Mathematisches Programmieren (250014 VU) Univ.-Prof. Dr. Oliver Hahn (Universität Wien) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 1 / 32 Übersicht 3....

Numerisches Programmieren I Mathematisches Programmieren (250014 VU) Univ.-Prof. Dr. Oliver Hahn (Universität Wien) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 1 / 32 Übersicht 3. Einheit: Numerisches Programmieren I 1 Zahlendarstellungen 2 Die NumPy-Bibliothek – 1. Teil 3 Die Matplotlib Bibliothek – 1. Teil Mathematisches Programmieren (Hahn) Numerisches Programmieren I 2 / 32 Zahlendarstellungen Mathematisches Programmieren (Hahn) Numerisches Programmieren I 3 / 32 Zahlendarstellungen - Integer (Ganze Zahlen) Integer Ganze Zahlen a ∈ Z (’Integer’) haben die Zifferndarstellung ±dn dn−1... d2 d1 d0 bezüglich einer Basis b ∈ N, mit 0 ≤ di < b. Die Representation stellt dabei die folgende Zahl dar Xn a=± di b i i=0 In Python können Integer prinzipiell beliebig groß sein. Zum Beispiel sind Darstellungen in binär (b = 2), oktal (b = 8), dezimal (b = 10) und hexadezimal (b = 16) möglich. Umwandlung in Python integer: int(’-12345’, 8) entspricht −123458 = −326710 Kurzformen: binär: 0b101010 oktal: 0o52 dezimal: 42 hexadezimal: 0x2a Stringkonversion zu binär: bin(42), oktal: oct(42), hexadezimal: hex(42) Für Ziffern di > 9 werden Buchstaben verwendet a= 10, b= 11, c= 12,.... Der Prozessor aktueller Computer kann 64-bit (signed) Integer direkt verarbeiten. Dies sind die Zahlen {−(263 − 1),... , 263 − 1} ⊂ Z. Dabei wird ein Bit für das Vorzeichen verwendet. Größere Integer müssen indirekt verarbeitet werden, was Berechnungen verlangsamt. Mathematisches Programmieren (Hahn) Numerisches Programmieren I 4 / 32 Zahlendarstellung - Fixkommazahlen Fixkommazahlen Die Integer können einfach auf die Fixkommadarstellung erweitert werden: ±dn dn−1... d1 d0.d−1 d−2... d−m bezüglich einer Basis b ∈ N, mit 0 ≤ di < b. Die Repräsentation stellt dabei die folgende Zahl dar Xn a=± di b i i=−m Fixkommazahlen haben allerdings folgende Nachteile: Fester Umfang: für optimale Genauigkeit müssen Zahlen skaliert werden, so dass möglichst wenige di null sind. Rundungsfehler sind absolut. Rechenaufwand: wegen des begrenzten Umfangs müssen Zahlen optimal skaliert werden, um stets gute Genauigkeit zu haben. Aus diesen Gründen werden Fixkommazahlen in modernen Computern nicht verwendet. Mathematisches Programmieren (Hahn) Numerisches Programmieren I 5 / 32 Zahlendarstellung - Float (Fließkommazahlen) IEEE-754 Fließkommazahlen Fließkommazahlen in allen modernen Computern folgen dem IEEE-754 Standard und haben die Form ±c × b q = Mantisse × BasisExponent wobei b die Basis ist (b ∈ {2, 10}), q ein Integer, und c eine Fixkommazahl mit 0.1 < c ≤ 1.0 ist, d.h. d0.d1 d2 · · · dp−1 in der Basis b. Python verwendet standardmäßig 64 bit (double precision) Fließkommazahlen als float. Aber es werden in numerischen Berechnungen oft auch 32 bit (single precision), und in machine learning auch 16 bit (half precision) verwendet. 64-bit (double precision) ▶ 11 bit Exponent (2−1022 bis 21023 ≈ 10308 ), 53 bit Mantisse (≈15.95 Dezimalstellen) 32-bit (single precision) ▶ 8 bit Exponent (2−126 bis 2127 ≈ 1038 ), 24 bit Mantisse (≈7.22 Dezimalstellen) 16-bit (half precision, nicht IEEE-754) ▶ 5 bit Exponent (2−14 bis 215 ≈ 104.5 ), 11 bit Mantisse (≈3.31 Dezimalstellen) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 6 / 32 Typische Fehler bei Fließkommazahlenberechnungen Die Fließkommaarithmetik ist nicht immer exakt, und es gibt mehrere Fehlerquellen, die bei Berechnungen mit Fließkommazahlen auftreten können. Einige der häufigsten Fehler sind: Rundungsfehler: Dies ist der Fall, wenn eine Zahl durch die nächstliegende darstellbare Zahl angenähert wird, was zu einem Verlust an Präzision führt. Cancellation: Dies tritt auf, wenn die Differenz zwischen zwei Zahlen im Vergleich zur Größe der Zahlen klein ist, was zu einem Verlust an Präzision führt. Signifikanzverlust: Dieser tritt auf, wenn zwei Zahlen mit sehr unterschiedlichen Größenordnungen addiert oder subtrahiert werden, was zu einem Verlust an Genauigkeit führt. Über-/Unterlauf: Dies tritt auf, wenn eine Zahl zu groß/klein ist, um im Fließkommaformat dargestellt zu werden, was zu einem Präzisionsverlust oder einem Über-/Unterlauffehler führt. Aufgrund dieser Fehler gelten die üblichen Kommutations und Assoziationsregeln der reellen Zahlen nicht exakt. Mathematisches Programmieren (Hahn) Numerisches Programmieren I 7 / 32 Spezielle Werte in IEEE-754 IEEE-754 enthält die Erweiterung R ∪ {−∞, +∞} sowie eine vorzeichenbehaftete Null ±0. Neben den Fließkommazahlen gibt es in IEEE-754 deshalb noch die “speziellen” Werte nan : ‘not a number’ +inf und -inf : ±∞ +0 und -0 Dabei gelten die Rechenregeln falls x ̸= 0 eine endliche IEEE-754 Fließkommazahl ist: Operation Ergebnis x / ±inf ±0 Sie sind z.B. im math Module definiert: ±inf * ±inf ±inf x / ±0 ±inf import math inf + inf inf print(math.nan) inf - inf nan print(math.inf) ±0 / ±0 nan ±inf * 0 nan nan == nan False inf == inf True Mathematisches Programmieren (Hahn) Numerisches Programmieren I 8 / 32 Rechenfehler der Fließkommazahlenarithmetik Beispiel: Rundungsfehler x = 0.1 + 0.1 + 0.1 y = 0.3 print(x) # Ausgabe: 0.30000000000000004 print(y) # Ausgabe: 0.3 print(x-y) # Ausgabe: 5.551115123125783e-17 Mathematisches Programmieren (Hahn) Numerisches Programmieren I 9 / 32 Rechenfehler der Fließkommazahlenarithmetik Beispiel: Rundungsfehler x = 0.1 + 0.1 + 0.1 y = 0.3 print(x) # Ausgabe: 0.30000000000000004 print(y) # Ausgabe: 0.3 print(x-y) # Ausgabe: 5.551115123125783e-17 Beispiel: Signifikanzverlust q = 1.0 q = 0.0 for i in range(1000000): for i in range(1000000): q += 1e-16 q += 1e-16 q += 1.0 print(q) # Ausgabe: 1.0 print(q) # Ausgabe: 1.0000000001 Mathematisches Programmieren (Hahn) Numerisches Programmieren I 9 / 32 Rechenfehler der Fließkommazahlenarithmetik Beispiel: Rundungsfehler x = 0.1 + 0.1 + 0.1 y = 0.3 print(x) # Ausgabe: 0.30000000000000004 print(y) # Ausgabe: 0.3 print(x-y) # Ausgabe: 5.551115123125783e-17 Beispiel: Signifikanzverlust q = 1.0 q = 0.0 for i in range(1000000): for i in range(1000000): q += 1e-16 q += 1e-16 q += 1.0 print(q) # Ausgabe: 1.0 print(q) # Ausgabe: 1.0000000001 Beispiel: Cancellation x = 1.0 + 2**-29 # 1.0000000018626451 y = 1.0 + 2**-30 # 1.0000000009313226 print(x**2-y**2) # Ausgabe: 1.862645149230957e-09 -- nur 8 statt 16 Stellen richtig print((x+y)*(x-y)) # Ausgabe: 1.8626451518330422e-09 Mathematisches Programmieren (Hahn) Numerisches Programmieren I 9 / 32 Rechnen mit beliebiger Genauigkeit – die Decimal-Bibliothek Die Decimal-Bibliothek erlaubt Berechnungen mit beliebiger Nachkommastellenzahl Zunächst muss die Decimal-Klasse aus dem decimal-Modul importiert werden: from decimal import Decimal Standard Python Typen können direkt dem Decimal-Konstruktor übergeben werden, Zahlen mit mehr Stellen als String two = Decimal(2) three = Decimal("3") Mittels der getcontext()-Methode kann die Genauigkeit eingestellt werden: from decimal import getcontext getcontext().prec = 100 # Genauigkeit auf 100 Stellen setzen Nun sind sehr genaue Berechnungen möglich print( two.sqrt() ) 1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534... Berechnungen sind allerdings deutlich langsamer als mit den Standardtypen. Mathematisches Programmieren (Hahn) Numerisches Programmieren I 10 / 32 Rechnen mit beliebiger Genauigkeit – die Decimal-Bibliothek Nehmen wir an, wir wollen π mittels der Bailey-Borwein-Plouffe(BBP)-Formel berechnen: ∞    X 1 4 2 1 1 π= − − − k=0 16k 8k + 1 8k + 4 8k + 5 8k + 6 Bei solchen Berechnungen verwendet man typischerweise die Methode ‘Summieren bis Saturation’ für maximale Genauigkeit. Die BBP-Formel kann auch zur unabhängigen Berechnung einzelner Ziffern von π verwendet werden! def get_BBP( k ): Konvergenz bei 30 Nachkommastellen: """Implementiert den k-ten Term der BPP Reihe """ 001 : 3.13333333333333333333333333333 002 : 3.14142246642246642246642246642 return (Decimal(1) / (16**k)) \ 003 : 3.14158739034658152305211128740 * ((Decimal(4) / (8 * k + 1)) - 004 : 3.14159245756743538183700455505 005 : 3.14159264546033631955702122244 (Decimal(2) / (8 * k + 4)) - 006 : 3.14159265322808753473437803553 (Decimal(1) / (8 * k + 5)) - 007 : 3.14159265357288082778524076189 (Decimal(1) / (8 * k + 6))) 008 : 3.14159265358897270494077776716 009 : 3.14159265358975227523617786839 010 : 3.14159265358979114638877696590 pi = Decimal(0.) # Startwert der Summe 011 : 3.14159265358979312961417056403 012 : 3.14159265358979323271129226192 k = 0 013 : 3.14159265358979323815476632249 while True: # Endlosschleife 014 : 3.14159265358979323844597750193 pinew = pi + get_BBP(k) 015 : 3.14159265358979323846173248203 016 : 3.14159265358979323846259317466 # Die Schleife wird erst unterbrochen, wenn 017 : 3.14159265358979323846264059513 # die Addition saturiert 018 : 3.14159265358979323846264322742 019 : 3.14159265358979323846264337451 if pi == pinew: break 020 : 3.14159265358979323846264338278 pi = pinew # falls nicht saturiert, weiter 021 : 3.14159265358979323846264338325 # mit neuem Wert für pi 022 : 3.14159265358979323846264338328 k += 1 Differenz zu genauerer Summe: -4.97...E-31 Mathematisches Programmieren (Hahn) Numerisches Programmieren I 11 / 32 Die NumPy-Bibliothek – 1. Teil Mathematisches Programmieren (Hahn) Numerisches Programmieren I 12 / 32 Was ist NumPy? Was it NumPy? NumPy is eine mächtige und flexible open-source Bibliothek für wissenschaftliches Rechnen in Python. Es beinhaltet mehrdimensionale Listen (’Arrays’), mathematische Funktionen, Routinen für lineare Algebra, Zufallszahlen, Fouriertransformationen, und vieles mehr Warum Numpy? NumPy is weitverbreitet Erlaubt effiziente Operationen auf großen Datensätzen Einfache Verwendung mit anderen Bibliotheken, wie SciPy und Matplotlib Das NumPy-Modul wird wie folgt geladen: import numpy as np danach sind alle Funktionen und Objekte über den np-Präfix verfügbar. Die offizielle Dokumentation (Version 1.23) ist hier: https://numpy.org/doc/1.23/ Mathematisches Programmieren (Hahn) Numerisches Programmieren I 13 / 32 NumPy Arrays sind das Herzstück der NumPy-Bibliothek. Sie sind Python Listen ähnlich, erlauben aber effizientere und kompliziertere Operationen. können über den np.array() Konstruktor als Objekt erzeugt werden, z.B. mittels Übergabe einer gewöhnlichen Python Liste als Argument: my_array = np.array([1, 2, 3, 4, 5, 6, 7, 8]) werden wie Listen indizert und erlauben auch Slicing (das Ergebnis ist wieder ein NumPy-Array) print( my_array ) # Ausgabe: 3 print( my_array[3:5] ) # Ausgabe: [4 5] print( my_array[::-1] ) # Ausgabe: [8 7 6 5 4 3 2 1] print( my_array[-3:-1] ) # Ausgabe: [6 7] Erinnerung: Slicing hat die Form [Startindex:Endindex:Inkrement], negative Indices werden vom Ende her gezählt, Endindex ist nicht enthalten. Erlauben auch mehrdimensionale Listen (Matrizen), siehe nächste Vorlesung Mathematisches Programmieren (Hahn) Numerisches Programmieren I 14 / 32 NumPy Arrays können einfach für große Längen erzeugt werden: np.zeros( N ) erzeugt ein Array mit N Nullen np.ones( N ) erzeugt ein Array mit N Einsen np.full( N, value ) erzeugt ein Array mit N Einträgen mit Wert value np.arange([start,]end[,step]) entspricht Python’s range np.linspace(start, end, steps, endpoint=True) erzeugt steps Zahlen gleichen Abstandes im Intervall [start,end], bzw. [start,end) falls endpoint=False: np.linspace(0,1,6) -> np.array([0., 0.2, 0.4, 0.6, 0.8, 1.0]) np.geomspace(start, end, steps, endpoint=True) erzeugt steps Zahlen gleichen geometrischen Abstandes im Intervall [start,end], bzw. [start,end) falls endpoint=False: np.geomspace(0.1,100,4) -> np.array([ 0.1, 1. , 10. , 100. ]) Der Datentyp kann stets explizit via dtype=... im Argument angegeben werden, z.B. np.ones( 10, dtype=np.float32 ), np.ones( 10, dtype=np.int64 ), mit u.A. int,float,complex mit 16,32,64,128 bit Genauigkeit Mathematisches Programmieren (Hahn) Numerisches Programmieren I 15 / 32 NumPy Arrays erlauben alle mathematischen Operatoren +,-,*,/,//,%,@, z.B. A = np.array([1.0, 2.0, 3.0]) B = np.array([2.0, 3.0, 4.0]) A+B # Elementweise Addition, Ergebnis ist array([3., 5., 7.]) A+10. # Elementweise Addition, Ergebnis ist array([11., 12., 13.]) A*B # Elementweise Multiplikation, Ergebnis ist array([ 2., 6., 12.]) A@B # Inneres Produkt (Skalarprodukt), Ergebnis ist float(20.) A%2.0 # Elementweise Modulodivision, Ergebnis ist array([1., 0., 1.]) # Vorsicht wegen Rundungsfehler bei Modulo von Fliesskommazahlen! erlauben die effiziente Anwendung von Funktionen auf alle Elemente ▶ Mathematische Funktionen und Konstanten, z.B. sin, cos, tanh, exp, log10,... np.cos( A * np.pi/2 ) # array([ 6.1232340e-17, -1.0000000e+00, -1.8369702e-16]) ▶ Summen, Produkte, Differenzen np.sum(A) # Summe aller Elemente -> float(6.0) np.prod(A) # Produkt aller Elemente -> float(6.0) np.cumsum(A) # Kumulative Summe -> np.array([1., 3., 6.]) np.cumprod(A) # Kumulatives Produkt -> np.array([1., 2., 6.]) np.diff(A) # Sequentielle Differenzen zw. Elementen -> np.array([1., 1.]) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 16 / 32 Performance: Vektorisierung statt Schleifen NumPy-Funktionen sind deutlich schneller als Python Schleifen oder List-Comprehensions NumPy-Funktionen verlassen sich nicht selbst auf Python, sondern verwenden im Hintergrund hocheffizienten Maschinencode import numpy as np import math # NumPy Implementierung def numpy_func( A, B ): return np.sin(A) + B # Native Python Implementierung def python_func( A, B ): return [math.sin(x)+y for x,y in zip(A,B)] # Array/Liste, Länge = 1 Million A = np.linspace(0,2*np.pi,1000000) B = np.linspace(0,1,1000000) # konvertiere nach Python-Liste Alist = A.tolist() Blist = B.tolist() Mathematisches Programmieren (Hahn) Numerisches Programmieren I 17 / 32 Performance: Vektorisierung statt Schleifen NumPy-Funktionen sind deutlich schneller als Python Schleifen oder List-Comprehensions NumPy-Funktionen verlassen sich nicht selbst auf Python, sondern verwenden im Hintergrund hocheffizienten Maschinencode import numpy as np import math Ergebnis: # NumPy Implementierung In: timeit C = numpy_func(A,B) def numpy_func( A, B ): return np.sin(A) + B 9.91 ms 53.7 µs per loop (mean std. dev. of 7 runs, 100 loops each) # Native Python Implementierung def python_func( A, B ): return [math.sin(x)+y for x,y in zip(A,B)] In: timeit Clist = python_func(Alist,Blist) # Array/Liste, Länge = 1 Million 169 ms 1.93 ms per loop (mean std. dev. of A = np.linspace(0,2*np.pi,1000000) 7 runs, 10 loops each) B = np.linspace(0,1,1000000) # konvertiere nach Python-Liste Bei diesem einfachen Beispiel ist NumPy also Alist = A.tolist() Blist = B.tolist() ca. 17 mal schneller! Mathematisches Programmieren (Hahn) Numerisches Programmieren I 17 / 32 Operationen auf NumPy Arrays Logische Bedingungen können direkt in der Array-Indizierung angegeben werden, z.B. A = np.array([1.0,2.0,3.0]) B = A > 1.0 # -> np.array([False, True, True]) C = A[ A > 1.0 ] # -> np.array([2.0, 3.0] A[ A > 1.0 ] = 4.0 # -> np.array([1.0, 4.0, 4.0]) Es gibt Funktionen und Operatoren um komplexere Prädikate zu erstellen, z.B. sind äquivalent auf Boolean-Arrays A[ (A>2.0) & (A2.0,A 2. ) # True falls wahr fuer ein Element np.all( np.array([1.,2.,3.]) > 2. ) # True falls wahr fuer alle Elemente Mathematisches Programmieren (Hahn) Numerisches Programmieren I 18 / 32 Operationen auf NumPy Arrays if-else Verzweigungen können mittels where direkt auf Arrays durchgeführt werden A = np.array([4.0, 2.0, 5.0] B = np.array([1.0, 5.0, 6.0] C = np.where( A/2 > B, A, B ) # -> array([4., 5., 6.]) die Indizes, die eine Bedingung erfüllen erhält man mit np.argwhere( A/2 > B ) # -> array([]) Maxima/Minima von Arrays und deren Index np.max( A ) # -> 5.0 np.min( A ) # -> 2.0 np.argmax( A ) # -> 2 np.argmin( A ) # -> 1 Elementweise Maxima/Minima zweier Arrays np.maximum( A, B ) # -> array([4., 5., 6.]) np.minimum( A, B ) # -> array([1., 2., 5.]) elementweise unscharfe Gleichheit zwischen Arrays mit relativer und absoluter Toleranz np.isclose( A, B, rtol=1e-05, atol=1e-08 ) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 19 / 32 Operationen auf Arrays NumPy arrays können via append aneinandergereiht werden, z.B. A = np.array([1., 2., 3., 4.]) B = np.array([5., 6.]) C = np.append( A, B ) # -> array([1., 2., 3., 4., 5., 6.]) via split aufgeteilt werden, dabei ▶ teilt split( A, N ) das Array A in N gleiche Teile wenn N eine Zahl ist ▶ teilt split( A, (i1,i2,..) ) trennt nach dem i1-ten, i2-ten,... Element wenn ein n-Tupel oder eine Liste angegeben wird: D = np.split( C, 3 ) # -> [array([1., 2.]), array([3., 4.]), array([5., 6.])] E = np.split( C, [3,5] ) # -> [array([1., 2., 3.]), array([4., 5.]), array([6.])] via tile und repeat durch Wiederholung zusammengefügt werden, z.B. F = np.tile( B, 3 ) # -> array([5., 6., 5., 6., 5., 6.]) G = np.repeat( B, 3 ) # -> array([5., 5., 5., 6., 6., 6.]) via roll periodisch verschoben werden np.roll( A, 1 ) # -> array([4., 1., 2., 3.]) np.roll( A, -2 ) # -> array([3., 4., 1., 2.]) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 20 / 32 Operationen auf Arrays NumPy arrays können mittels sort sortiert werden A = np.array([4., 2., 1., 3.]) np.sort(A) # -> array([1.,2.,3.,4.] argsort liefert die Indizes, die das Array sortieren. Damit lässt sich z.B. ein zweites Array mitsortieren A = np.array([4., 2., 1., 3.]) B = np.array([1., 2., 3., 4.]) i = np.argsort(A) # -> array([2, 1, 3, 0]) A[i] # -> array([1., 2., 3., 4.]) B[i] # -> array([3., 2., 4., 1.]) Arrays können mit save und load gespeichert werden. Damit lassen sich z.B. die Ergebnisse langer Berechnungen mit voller Genauigkeit speichern np.save( ’myfile.npy’, A ) B = np.load( ’myfile.npy’ ) Alternativ können Daten auch mittels savetxt und loadtxt in Textdateien geschrieben oder von dort gelesen werden. Dabei kann Genauigkeit verloren gehen. Mathematisches Programmieren (Hahn) Numerisches Programmieren I 21 / 32 (Pseudo-)Zufallszahlen mit NumPy np.random.uniform(low=0.0, high=1.0, size=None) erzeugt gleichförmig verteilte Zufallszahlen zwischen low und high, d.h. x ∈ [low,high) np.random.normal(loc=0.0, scale=1.0, size=None) erzeugt normalverteilte Zufallszahlen zwischen mit Mittelwert loc und Standardabweichung scale für viele wichtige Verteilungen existieren ähnliche Sampler np.random.choice(a, size=None, replace=True, p=None) wählt zufällig size Elemente aus dem Array a, mit oder ohne Zurücklegen (replace). Man kann zudem jedem Element Wahrscheinlichkeiten mitgeben (p) np.random.permutation(a) liefert eine zufällige Permutation des Arrays a, bzw. falls a ein int ist, liefert es eine Permutation von range(a) np.random.shuffle(a) mischt in-place die Elemente von a (äquivalent zu a=np.random.permutation(a))) für reproduzierbare Zufallszahlensequenzen kann die Sequenz mit np.random.seed(seedval) initialisiert werden, jedes seedval gibt eine eindeutige und reproduzierbare Sequenz Mathematisches Programmieren (Hahn) Numerisches Programmieren I 22 / 32 Die Matplotlib Bibliothek – 1. Teil Mathematisches Programmieren (Hahn) Numerisches Programmieren I 23 / 32 Plotting mit Matplotlib Laden des Plottingmoduls von Matplotlib: import matplotlib.pyplot as plt Listen oder NumPy Arrays können direkt geplottet werden # erzeuge eine neue Abbildung (fig) # mit einem einzigen Achsenobjekt (ax) fig, ax = plt.subplots() # Plotten mit Listen ax.plot([1, 2, 3, 4], [1, 4, 2, 3]); # Erzeuge NumPy Arrays x = np.linspace(0, 2*np.pi, 100) y = np.sin( x ) # Plotten mit NumPy Arrays ax.plot(x, y) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 24 / 32 Anatomie eines Matplotlib Plots Eine Abbildung (figure) kann mehrere Achsen (axes) enthalten Diese nennt man dann jeweils ’Subplots’ Jedes Achsenobjekt kann einen Titel besitzen, eine Legende, sowie Achsenbeschriftungen Die Abbildung selbst kann auch einen Titel haben Eine Abbildung kann einfach als Datei gespeichert werden, entweder interaktiv im Jupyter notebook, oder via fig.savefig(’myname.pdf’) wobei die Dateiendung das Format festlegt (z.B. PDF, JPEG, PNG) Abb. übernommen aus dem Matplotlib ‘quick start’ Tutorial Mathematisches Programmieren (Hahn) Numerisches Programmieren I 25 / 32 Komplexeres Beispiel x = np.linspace(0, 2*np.pi, 200) # Ein NumPy Array. # Eine Figure mit vorgegebener Groesse fig, ax = plt.subplots(figsize=(5, 4), layout=’constrained’) # 3 Plots mit Label f. Legende ax.plot(x, np.sin(x), label=’sin x’) ax.plot(x, np.cos(x), label=’cos x’) ax.plot(x, np.tan(x), label=’tan x’) # tan hat Singularitaeten => beschraenke y-Achse ax.set_ylim([-2,2]) # Schalte Gitter im Hintergrund an ax.grid(’on’) # Achsenbeschriftungen ax.set_xlabel(’$x$’) # verwende LaTeX ax.set_ylabel(’Funktionswert’) # Fuege Titel hinzu ax.set_title("Trigonometrische Funktionen auf $[0,2\\pi]$") # Fuege Legende hinzu ax.legend(); # Lege fest wo Ticks auf der x-Achse angezeigt werden und wie ax.set_xticks([0,np.pi/2,np.pi,3*np.pi/2,2*np.pi], \ [’0’,’$\\frac{\\pi}{2}$’,’$\\pi$’, \ ’$\\frac{3\\pi}{2}$’,’$2\\pi$’]) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 26 / 32 Verfeinerungen: Farben, Linienstile, Anmerkungen # line style: ls =’-.’ oder ’-’,’--’,’:’ # line color: c = (R,G,B) ax.plot(x, np.sin(x), ls=’-.’, c=(0.8,0.2,0.5), label=’sin x’) # line color by string: c= ’r’ (or g,b,c,m,y,k,w) # line width: lw = ax.plot(x, np.cos(x), ls=’-’, lw=5, c=’g’, label=’cos x’) # Setze Werte in der Naehe eines Pols auf inf um durchgezogene # vertikale Linien zu vermeiden ax.plot(x, np.where(np.abs(np.tan(x))>5,np.inf,np.tan(x)), \ label=’tan x’) # vertikale und horizontale Linien im Plot ax.axhline(0.0, ls=’--’, lw=1.0, c=’k’) ax.axvline(np.pi/2, ls=’:’, lw=0.5, c=’k’) ax.axvline(3*np.pi/2, ls=’:’, lw=0.5, c=’k’) # Textanmerkungen ax.text(4.0, 0.5, ’ein schraeger kleiner Text’ \ +’ $\\sum_{i=1}^n a_n$’, fontsize=7, rotation=45) # Anmerkungen mit Pfeil ax.annotate("Singularitaet von tan", \ xy=(np.pi/2, 1.8), xytext=(np.pi/2, 1.4), \ arrowprops=dict(arrowstyle="->")) # Formatierung der Legende ax.legend(loc=’lower left’,ncol=3,edgecolor=’None’) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 27 / 32 Marker und Flächen zwischen Kurven Statt Linien können auch Marker mit plot gezeichnet werden (oder beides) mögliche Marker sind: Punkt ’.’, Pixel ’,’, Kreis ’o’, Quadrat ’s’, Kreuze ’x’,’+’, Stern ’*’ u.v.m. (siehe hier) Es ist auch möglich Flächen zwischen Kurven mittels fill between auszufüllen. Mögliche Optionen sind ▶ die Füll- und die Kantenfarbe mittels facecolor und edgecolor anzueben ▶ eine Schraffierung mittels hatch anzugeben (siehe hier) theta = np.linspace( 0, 8*np.pi, 100 ) fig,ax = plt.subplots(2,1,sharex=True) # Durchgezogene Linie ax.plot( theta, np.sin(theta), ’-’, label=’sin’ ) # Keine Linie, nur Marker, mit ’-o’ bekäme man beides ax.plot( theta[::10], np.sin(theta[::10]), \ ’o’, label=’jeder 10.’ ) # Keine Linie, nur Marker ax.plot( theta[::7], np.sin(theta[::7]), \ ’x’, label=’jeder 7.’ ) ax.legend() #Linienplot mit dicker Breite ax.plot( theta, np.sin(theta), ’-’, lw=5, c=’g’, label=’sin’) # Ausgefuellte Flaeche zwischen zwei Kurven, schraffiert ax.fill_between(theta, np.sin(theta)-0.5, \\ np.sin(theta)+0.5, alpha=0.5, hatch=’||||’, label=’$\pm0.5$’) ax.legend() Mathematisches Programmieren (Hahn) Numerisches Programmieren I 28 / 32 Subplots Mit zusätzlichen Argumenten in subplots können mehrere subplots erzeugt werden: subplots(nrows=1, ncols=1, *, sharex=False, sharey=False) Die subplots werden in einer ’Tabelle’ mit nrows Zeilen und ncols Spalten angeordnet Mittels sharex und sharey kann man angeben, ob x- und/oder y-Achse geteilt werden soll Mittels figsize kann man die x- und y-Größe der Figure festlegen. Vier subplots mit geteilter y-Achse: # erstelle 2x2 subplots mit geteilter y-Achse fig, ax = plt.subplots(2,2, sharey=True, \\ figsize=(6,6), layout=’constrained’) x = np.linspace(-1.,1.,200) # Indizierung der Subplots ist [Zeile,Spalte] ax[0,0].plot( x, np.ones(200) ) ax[0,0].set_title(’konstant’) ax[0,1].plot( x, x ) ax[0,1].set_title(’linear’) ax[1,0].plot( x, x**2 ) ax[1,0].set_title(’quadratisch’) ax[1,1].plot( x, x**3 ) ax[1,1].set_title(’kubisch’) # Titel über allen Subplots (d.h. Titel der Figure) fig.suptitle(’Die ersten vier Monome’) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 29 / 32 Scatterplots – Punktdaten Beispiel: wir wollen die ersten 50 Glieder der Folge xn+1 = r xn (1 − xn ) für verschiedene 0 ≤ r ≤ 4 grafisch darstellen. Es sei x0 = 12. D.h. wir wollen für verschiedene Werte r die Punkte (r , xn ) für 0 ≤ n < 50 zeichnen. Dies geht am besten mit der Funktion scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None) x,y sind die Koordinaten-Arrays s eine Zahl oder ein Array die Größe der Symbolmarker bestimmend (d.h. Größe individuell pro Datenpunkt) c einen Farbwert oder ein Array den Farbwert bestimmend (d.h. Farbe individuell pro Datenpunkt) marker das zu zeichnende Symbol (wie schon bei plot) cmap der Name der Farbtabelle (klicke hier), die Datenwerte können mit vmin und vmax limitiert werden Mathematisches Programmieren (Hahn) Numerisches Programmieren I 30 / 32 Scatterplots – Punktdaten Beispiel: wir wollen die ersten 50 Glieder der Folge xn+1 = r xn (1 − xn ) für verschiedene 0 ≤ r ≤ 4 grafisch darstellen. Es sei x0 = 12. D.h. wir wollen für verschiedene Werte r die Punkte (r , xn ) für 0 ≤ n < 50 zeichnen. Dies geht am besten mit der Funktion scatter(x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None) x,y sind die Koordinaten-Arrays s eine Zahl oder ein Array die Größe der Symbolmarker bestimmend (d.h. Größe individuell pro Datenpunkt) c einen Farbwert oder ein Array den Farbwert bestimmend (d.h. Farbe individuell pro Datenpunkt) marker das zu zeichnende Symbol (wie schon bei plot) cmap der Name der Farbtabelle (klicke hier), die Datenwerte können mit vmin und vmax limitiert werden fig, ax = plt.subplots(figsize=(8,4)) for r in np.linspace(0,3.5,50): seq = [0.5] # Startwert der Folge for i in range(49): # Berechne 49 weitere Werte seq.append( r*seq[-1]*(1-seq[-1]) ) # scatter plot 50 Punkte (x,y) mit gleichem r als x, Folge als y # Farbe = Iteration, Punktgroesse=6 sc = ax.scatter( r*np.ones(50), seq, c=np.arange(50), s=6) cbar = plt.colorbar(sc) # Füge Farbskala hinzu cbar.set_label(’Iteration n’) # Beschriftung der Farbskala ax.text(0.0,0.53,’Startwert $x_0=\\frac{1}{2}$’) ax.set_xlabel(’$r$’) ax.set_ylabel(’$x_{n}$’) ax.set_title(’Iterationen von $x_{n+1}=r x_n (1-x_n)$’) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 30 / 32 Polygone und parametrische Kurven zeichnen Polygone und geschlossene parametrische Kurven können als Linien mittels plot Funktion dargestellt werden, oder ausgefüllt mittels der fill Funktion. Für allgemeine parametrische Kurven verwendet man einfach plot. fig, ax = plt.subplots() Parametrische Kurve: s 7→ (x(s), y (s)) # Die 4 Eckpunkte eines Quadrats x = np.array([0., 0., 1., 1., 0.]) y = np.array([0., 1., 1., 0., 0.]) # Darstellung als ausgefuelltes Polygon ax.fill(x,y) # erzeugen einer geschlossenen parametrischen Kurve theta = np.linspace( 0, 2*np.pi, 400 ) r = 1+0.1*np.cos(10*theta) xs = r * np.cos(theta) ys = r * np.sin(theta) # Darstellung als ausgefuelltes Polygon (400-Eck) # mit vorgegebener Farbe und 20% Transparenz ax.fill(xs, ys, facecolor=’lightsalmon’, \ edgecolor=’orangered’, linewidth=3, alpha=0.8) # Darstellung als Kurve (nach links verschoben) ax.plot(xs-1.,ys, ’k:’) # Erzwingen dass x:y 1:1 skaliert wird ax.axis(’equal’) Alternativ können auch patches wie im Beispielcode der Polygonklasse verwendet werden. Mathematisches Programmieren (Hahn) Numerisches Programmieren I 31 / 32 Weiterführendes Material Diese Vorlesung hat einen zweiten Teil! Mehr also nächste Woche. NumPy ▶ Die offizielle Dokumentation https://numpy.org/doc/stable/ ▶ Lev Maximovs ‘NumPy Illustrated: The Visual Guide to NumPy’ Matplotlib ▶ Die offizielle Dokumentation https://matplotlib.org/stable/tutorials https://matplotlib.org/stable/api ▶ Nicolas Rougier’s Buch ’Scientific Visualization: Python + Matplotlib’ mit viel ‘Best Practice’ Infos und Tips https://github.com/rougier/scientific-visualization-book https://hal.inria.fr/hal-03427242/document [PDF] ▶ stackoverflow (konkrete Fragen sind dort oft schon beantwortet) Mathematisches Programmieren (Hahn) Numerisches Programmieren I 32 / 32

Use Quizgecko on...
Browser
Browser