Einführung in die Programmierung für Studierende der Physik

(Introduction to Programming for Physicists)

Vorlesung gehalten an der J.W.Goethe-Universität in Frankfurt am Main

(Sommersemester 2022)

von Dr.phil.nat. Dr.rer.pol. Matthias Hanauske

Frankfurt am Main 01.04.2022

Visualisierung der C++ Ausgabedaten mittels der Programmiersprache Python

Im Folgenden werde ich Ihnen keine strukturierte "Einführung in die Programmiersprache Python" geben, sondern es werden nur ganz spezielle Themen der Programmiersprache Python vorstellt, die wir zur Visualisierung der mittels unserer C++ Programme erstellten Daten und zum Verständnis der Vorlesung Einführung in die Programmierung für Studierende der Physik benötigen. Strukturierte Einführungen in die Programmiersprache Python finden Sie z.B. unter den folgenden Links:

Literatur zu Python

Im Speziellen werden wir in diesem Jupyter Notebook das folgende Python-Skript (Python-Skript: PythonPlot_While_4.py) näher betrachten, welches im Unterpunkt Anwendungsbeispiel: Folgen und Reihen zur Datenvisualisierung verwendet wurde.

# Python Programm zum Plotten der berechneten Daten von (While_4.cpp)
import matplotlib.pyplot as plt                            # Python Bibliothek zum Plotten (siehe https://matplotlib.org/ )
import numpy as np                                         # Python Bibliothek fuer Mathematisches (siehe https://numpy.org/ )

data = np.genfromtxt("./While_4.dat")                      # Einlesen der berechneten Daten von While_4.cpp

plt.title(r'Approximation der Eulerschen Zahl e mittels ihrer Folgendefinition') # Titel der Abbildung
plt.ylabel(r'$e_{approx}$')                                # Beschriftung y-Achse
plt.xlabel('Index n')                                      # Beschriftung x-Achse
plt.plot(data[:,0],data[:,1], marker='+', color="blue")    # Plotten der Daten
plt.plot([data[0,0],data[-1,0]],[np.e,np.e], color="red")  # Horizontale Linie, die den exakten Wert von e markiert

plt.savefig("PythonPlot_While_4.png", bbox_inches="tight") # Speichern der Abbildung als Bild
plt.show()                                                 # Zusaetzliches Darstellen der Abbildung in einem separaten Fenster

Möchte man eine Gleichung in einem C++ Programm implementieren, muss man zunächst die in ihr enthaltenen Variablen im C++ Programm deklarieren (näheres siehe Datentypen und Variablen). Ähnlich, wie bei einer präzisen mathematischen Definition, deklariert man die Variablen in einem C++ Programm auch anhand ihrer Zahlenmengen-Zugehörigkeit. Die Programmiersprache C++ stellt hierbei eine Vielzahl von Datentypen bereit (z.B. int, double, ...).

Dies ist in der Programmiersprache Python nicht nötig und beim Initialisierungsprozess einer Variable wird, ähnlich dem C++ auto-Befehl, automatisch der Typ festgelegt.

In [1]:
zeichen = "Hallo"
zahl_1 = 3
zahl_2 = 2.45688586

Den Datentyp einer definierten Variable erhält man mit:

In [2]:
type(zeichen)
Out[2]:
str
In [3]:
type(zahl_1)
Out[3]:
int
In [4]:
type(zahl_2)
Out[4]:
float

Der Wert einer Variable ist unter ihrem Variablennamen gespeichert:

In [5]:
zahl_2
Out[5]:
2.45688586

Bei der Visualisierung von Daten, die mit unseren C++ Programmen berechnet wurden, lesen wir die Dateien dieser Datenlisten zunächst ein und visualisieren Sie danach. Eine Zahlenliste in Python wird z.B. wie folgt definiert:

In [6]:
meine_liste = [0,1,4,9,16]
In [7]:
type(meine_liste)
Out[7]:
list

Die Werte der definierten Liste sind unter ihrem Variablennamen gespeichert.

In [8]:
meine_liste
Out[8]:
[0, 1, 4, 9, 16]

Möchte man z.B. den dritten Eintrag der Liste ausgeben lassen, schreibt man

In [9]:
meine_liste[2]
Out[9]:
4

$[2]$, da der Index der Liste beginnend von Null gezählt wird. Möchte man sich einen speziellen Bereich der Listeneinträge ausgeben lassen (z.B. von 1 bis 3) schreibt man

In [10]:
meine_liste[1:4]
Out[10]:
[1, 4, 9]

Unsere Daten bestehen aber oft aus mehreren Einträgen, eine Art von Matrizen oder Listen von Listen. Wir lesen uns nun die ausgegebenen Daten 'While_4.dat' des C++ Programms While_4.cpp ein. Hierbei benutzen wir das Python-Modul numpy, welches wir zunächst einlesen (importieren) müssen. Falls Sie das NumPy Modul das erste Mal verwenden, müssen Sie es zunächst in Ihrer Python 3 Umgebung installieren (z.B. in einem Linux Terminal mit "pip3 install numpy"). Beim Importieren benennen wir das eingelesene Modul in "np" um, sodass wir bei der Verwendung von NumPy-Befehlen stets ein "np." vor den jeweiligen Befehl schreiben müssen.

NumPy ist ein Akronym für "Numerisches Python" und es stellt ein Erweiterungsmodul für Python dar, welches zum größten Teil in der Programmiersprache C geschrieben ist. NumPy ermöglicht das effiziente Rechnen mit großen Arrays und Matrizen und zusätzlich sind viele mathematische Funktionen dort definiert.

Wir lesen nun die Daten ein und speichern diese unter der Variable 'data', wobei Sie bei der unten benutzten verwendeten Angabe der Datei darauf achten müssen, dass sich die Datei 'While_4.dat' in dem selben Verzeichnis befindet, wie dieses Jupyter Notebook.

In [11]:
import numpy as np
data = np.genfromtxt("./While_4.dat")

Betrachten wir zunächst den Datentyp der Datenvariable 'data':

In [12]:
type(data)
Out[12]:
numpy.ndarray

Es handelt sich um ein sogenanntes "NumPy ndarray", eine mehrdimensionales Array von Zahleneinträgen mit folgender Struktur (die Deklaration und Initialisierung von C++ Arrays werden wir in der Vorlesung erst später kennenlernen):

In [13]:
data
Out[13]:
array([[ 1.        ,  2.        ],
       [ 2.        ,  2.25      ],
       [ 3.        ,  2.37037037],
       [ 4.        ,  2.44140625],
       [ 5.        ,  2.48832   ],
       [ 6.        ,  2.52162637],
       [ 7.        ,  2.5464997 ],
       [ 8.        ,  2.56578451],
       [ 9.        ,  2.58117479],
       [10.        ,  2.59374246],
       [11.        ,  2.60419901],
       [12.        ,  2.61303529],
       [13.        ,  2.62060089],
       [14.        ,  2.62715156],
       [15.        ,  2.63287872],
       [16.        ,  2.6379285 ],
       [17.        ,  2.64241438],
       [18.        ,  2.64642582],
       [19.        ,  2.65003433],
       [20.        ,  2.65329771]])

Der Zugriff auf einzelne Zahlenelemente ist ähnlich der von Listen, jedoch gibt es kleine Unterschiede. Wir bezeichnen im Folgenden die ersten Einträge als x-Werte und die zweiten als y-Werte.

Die x-Werte erhält man mit

In [14]:
data[:,0]
Out[14]:
array([ 1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9., 10., 11., 12., 13.,
       14., 15., 16., 17., 18., 19., 20.])

, die y-Werte mit

In [15]:
data[:,1]
Out[15]:
array([2.        , 2.25      , 2.37037037, 2.44140625, 2.48832   ,
       2.52162637, 2.5464997 , 2.56578451, 2.58117479, 2.59374246,
       2.60419901, 2.61303529, 2.62060089, 2.62715156, 2.63287872,
       2.6379285 , 2.64241438, 2.64642582, 2.65003433, 2.65329771])

, wobei der Doppelpunkt bedeuted, das alle y-Werte ausgegeben werden sollen. Möchte man sich z.B. den dritten y-Wert ausgeben lassen, schreibt man

In [16]:
data[2,1]
Out[16]:
2.37037037037037

Man kann ein NumPy-Array mit dem Befehl "list(...)" in eine Liste umwandeln. Z.B. erhält man die Liste der ersten fünf y-Werte mit:

In [17]:
list(data[0:5,1])
Out[17]:
[2.0, 2.25, 2.37037037037037, 2.44140625, 2.488319999999999]

Nun möchten wir die eingelesenen Datenpunkte in einem x-y-Diagramm visualisieren. Hierbei benutzen wir das Python-Modul "matplotlib" (siehe Matplotlib: Visualization with Python), welches wir zunächst einlesen (importieren) müssen. Falls Sie das Matplotlib Modul das erste Mal verwenden, müssen Sie es zunächst in Ihrer Python 3 Umgebung installieren (z.B. in einem Linux Terminal mit "pip3 install matplotlib").

In [18]:
import matplotlib.pyplot as plt

Wir stellen die Datenpunkte mittels des Befehls 'plt.plot(...)' dar (näheres siehe matplotlib.pyplot.plot und Pyplot tutorial).

In [19]:
plt.plot(data[:,0],data[:,1], marker='+', color="blue");

Um ein schöneres Erscheinungsbild des Bildes zu erhalten und eine Titel-Überschrift, eine Beschreibungen der x- und y-Achsen zu erhalten, die Bildgröße festzulegen gibt man z.B. das Folgende ein:

In [20]:
import matplotlib
params = {
    'figure.figsize'    : [10,8],
    'axes.titlesize' : 16,
    'axes.labelsize' : 18,  
    'xtick.labelsize' : 14,
    'ytick.labelsize' : 14
}
matplotlib.rcParams.update(params) 
In [21]:
plt.title(r'Approximation der Eulerschen Zahl e mittels ihrer Folgendefinition') 
plt.ylabel(r'$e_{approx}$')
plt.xlabel('Index n')
plt.plot(data[:,0],data[:,1], marker='+', color="blue");
plt.plot([data[0,0],data[-1,0]],[np.e,np.e], color="red");

Zusätzlich wurde in dem oberen Diagramm noch eine horizontale rote Linie eingezeichnet, die den exakten Wert von e markiert. Bei dieser roten Linie erkennt man gut die unterliegende Struktur der plot(...)-Funktion. Es wird hierbei eine Linie durch die folgenden x- und y-Werte gezeichnet

In [22]:
[data[0,0],data[-1,0]],[np.e,np.e]
Out[22]:
([1.0, 20.0], [2.718281828459045, 2.718281828459045])

was ja gerade eine horizontale Linie im x-Bereich von 0 bis 20 mit einem y-Wert von 2.718281828459045 ergibt.

Das erzeugte Bild kann man schließlich mittels des folgenden Befehls speichern:

In [23]:
plt.savefig("PythonPlot_While_4.png", bbox_inches="tight")
<Figure size 720x576 with 0 Axes>