Torus Surface Plot mit Matplotlib
English version below.
Ein Torus ist ein geometrischer Rotationskörper, der einem Donut ähnelt. Dieses Objekt entsteht durch das „Rollen“ einer Fläche um eine Achse und dem anschließenden „Verkleben“ der freien Enden. Eine beispielhafte Anwendung von Tori (plural von Torus) in der Technik findet sich in der Form des erzeugten Magnetfeldes eines Tokamak Fusionsreaktors. Das Plasma, welches in dieser Torusform eingeschlossen ist, kann somit auf über 100 Millionen °C erhitzt werden, ohne dass die Reaktorwände schaden nehmen. In dieser Anleitung soll die Oberfläche von Tori anhand einer, über den wulstartigen Körper berechneten „Colormap“ verdeutlicht werden. Diese Visualisierung geschieht mittels der Bibliothek Matplotlib in der Programmiersprache Python 3. Ein ähnlicher Artiker beschreibt die Form über ein Netz: Torus Netz Plot mit Matplotlib.
Dieser Plot auf sämtlichen Produkten bei redbubble | ||
---|---|---|
|
|
|
Implementierung in Python 3 |
Zunächst werden alle erforderlichen Bibliotheken importiert
import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D
Damit die Plots direkt im Jupyter Notebook ausgegeben werden können, muss Matplotlib über einen so genannten Built-in Magic Command aktiviet werden:
%matplotlib inline
Anschließend erstellen wir einen Container fig
, in welchem die Plots deponiert werden. In unserem Fall ist es nur ein Plot. Als Parameter wird das Seitenverhältnis 1:1 mit figsize=plt.figaspect(1)
und desweiteren eine Auflösung von 700 dpi (dpi=700
) übergeben.
fig = plt.figure(figsize=plt.figaspect(1), dpi=700)
Torus Koordinaten |
Ein Torus ist hat die Form eines Reifens bzw. Donuts. Dafür ist es zweckmäßig ein eigenes Koordinatensystem zu definieren (siehe untere Abbildung), ähnlich wie ein Sphärenkoordinatensystem für Kugeln. Dabei liegt der Koordinatenursprung in der Mitte des Torus. Der Radius R
reicht von dort aus bis in die Mitte der „Wulst“, welche ihrerseits durch den Radius r
definiert ist. Mit dem Winkel φ
(Phi) wird die Ausprägung des Radius R
gegeben (bei φ=2π
wird die Wulst um einen vollen Kreisring abgebildet). Der Winkel ϑ
(Theta) gibt an, um welches Ausmaß die Wulst mit dem Radius r
gebildet ist.
φ
(Phi) und ϑ
(Theta) sind in Bogenmaß (rad
) gegeben. Ein Winkel von 2π
entspricht dabei 360°
. Die Umrechnung im Allgemeinen lautet:
Bogenmaß → Gradmaß
Gradmaß → Bogenmaß
Nun werden die Koordinatenpunkte generiert, über welche folgend das „Wireframe“ gelegt wird. Diese ergeben sich aus den Winkeln φ
(Phi) und ϑ
(Theta) und werden jeweils um einen Vollkreis gespannt. Dies erreichen wir mit der Funktion linspace()
der Bibliothek numpy. Als Parameter übergeben wird die Startkoordinate 0
; gefolgt von der Endkoordinate 2π
(verwendet wird Pi der numpy-Bibliothek), Mit endpoint=True
stellen wir sicher, dass sich jeweils ein Koordinatenpunkt bei 0
und bei 2π
befindet. Schließlich wird in dieser Funktion die Anzahl der Unterteilungen mit num=75
übergeben.
phi = np.linspace(0, 2 * np.pi, endpoint=True, num=75) theta = np.linspace(0, 2 * np.pi, endpoint=True, num=75)
Bis jetzt existieren jedoch nur zwei Kreise. Einmal der für φ
(in der Graik pink dargestellt) und ϑ
(in der Graik rot dargestellt). Somit werden alle weiteren Koordinaten benötigt, die entstehen, wenn der rote Kreis entlang von φ
um den pinken „fährt“.
meshgrid
.
phi, theta = np.meshgrid(phi, theta)
Für die Radien R
und r
erstellen wir nun jeweils eine Variable und weisen numerische Werte hinzu:
R=1.5 r=1
Da Matplotlib keine Toruskoordinaten beherrscht, müssen diese in kartesische (standard) Koordinaten umgerechnet werden:
x = np.cos(theta) * (R + r * np.cos(phi)) y = np.sin(theta) * (R + r * np.cos(phi)) z = r * np.sin(phi)
Zurück zu Matplotlib: Für die Darstellung von Text (hier nur der Titel des Plots) ändern wir diese vom Standard zu der Schriftart der Auszeichnungssprache LaTeX, welche auch auf dieser Website für die Darstellung von Gleichungen genutzt wird.
plt.rc('text', usetex=True) plt.rc('font', family='serif')
Erstellung des Plots |
Plots werden als subplot
dem Container (figure) zugeordnet. Dabei erhalten die Subplots eine Nummer in Form eines Zahlentupels. Der Tupel besteht aus den Elementen (zeile, spalte, plot)
. Dabei ergibt sich das letzte Element, also die Nummer des Plots, aus, wie in einem Dokument gelesenen Reihenfolge.
Dem Container (figrue) wird nun ein Plot an der Stelle 1,1,1 hinzugefügt.
ax = fig.add_subplot(1, 1, 1, projection='3d') # 1 zeile, 1 spalte, plot 1 (gelesen wie in Dokument)
Color Map |
Die Auswahl einer Colormap kann in der Methode plot_surface()
mit dem Parameter cmap=
festgelegt werden.
Eine vollständige Auflistung der Parametern findet sich in der Matplotlib Dokumentation.
Der „Psychedelic Plot“
ax.plot_surface(x, y, z, cmap=plt.cm.prism, antialiased=True, rstride=2, cstride=2)
Der „Emerald Water Plot“
ax.plot_surface(x, y, z, cmap=plt.cm.winter, antialiased=True, rstride=2, cstride=2)
Plot ausgeben |
Im folgenden wird ein quadratischer Ausschnitt der Größe lim
generiert. Die Kantenlängen dieses Quadrats entsprechen des betragsmäßig höchsten Maximums bzw. Minimums aus allen Koordinatenrichtungen x
und y
.
# Skalierung der gezeigten Funktion lim = (max(abs(max(np.max(x), np.max(y), np.max(z))), abs(min(np.min(x), np.min(y), np.min(z))))) # Axenlimits setzen ax.set_xlim(-lim, lim) ax.set_ylim(-lim, lim) ax.set_zlim(-lim, lim)
Zu guter Letzt wird der Plot abgespeichert und – falls im Jupyter Notebook ausgeführt, direkt angezeigt.
# deactivae coordinate axis rendering plt.axis('off') # Plot unter "psychedelic_torus.png" abspeichern plt.savefig("psychedelic_torus.png", bbox_inches='tight') # Ausgabe im Jupyter Notebook plt.show()
English Version |
You can varify the color set via the parameter cmap=
The Emerald Water Plot
ax.plot_surface(x, y, z, cmap=plt.cm.winter, antialiased=True, rstride=2, cstride=2)
The Psychedelic Plot
ax.plot_surface(x, y, z, cmap=plt.cm.prism, antialiased=True, rstride=2, cstride=2)
#!/usr/bin/env python print("This will maybe take a while, depending on the figure dpi you have chosen and your system performance") # import necessary libarys import numpy as np import matplotlib.pyplot as plt import matplotlib as mpl from mpl_toolkits.mplot3d import Axes3D from matplotlib import rc # activare the output into the jupyter notebook %matplotlib inline # container "fig" for the plot(s, it's actually one^^) # for more info: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.figure.html fig = plt.figure(figsize=plt.figaspect(1), dpi=700) # toroidal coordinate sytem with angle phi to the x-axis and theta to the z-axis # see also: http://inspirehep.net/record/1324991/files/torus_compel.png phi = np.linspace(0, 2 * np.pi, endpoint=True, num=1000) # 1000 phi proportions of the coordinate system theta = np.linspace(0, 2 * np.pi, endpoint=True, num=1000) # 1000 theta proportions of the coordinate system phi, theta = np.meshgrid(phi, theta) # phi and theta matrices with elements for every point wich will be rendered R=1.5 # radius from the coordinate origin r=1 # radius from the "pipe" # coordinate transformation from toroidal to cartesian (the standart one) # for more info: https://en.wikipedia.org/wiki/Torus#Geometry x = np.cos(theta) * (R + r * np.cos(phi)) y = np.sin(theta) * (R + r * np.cos(phi)) z = r * np.sin(phi) # activate LaTeX(-Font) plt.rc('text', usetex=True) plt.rc('font', family='serif') # Add a plot to the container (figure) ax = fig.add_subplot(1, 1, 1, projection='3d') # 1 row, 1 colomn, plot 1 (read like a document) ax.plot_surface(x, y, z, cmap=plt.cm.prism, antialiased=True, rstride=2, cstride=2) ax.set_title(' ') # scaling of the shown function lim = (max(abs(max(np.max(x), np.max(y), np.max(z))), abs(min(np.min(x), np.min(y), np.min(z))))) # find the absolute maximum of the function # Set the axis limits ax.set_xlim(-lim, lim) ax.set_ylim(-lim, lim) ax.set_zlim(-lim, lim) # deactivae coordinate axis rendering plt.axis('off') # save the plot to the file "psychedelic_torus.png" plt.savefig("psychedelic_torus.png", bbox_inches='tight') # output plt.show()
Bildquellen |
[1] | . |
[2] | Krishnavedala. (14. April 2014). Torus. Von Wikipedia, the free encyclopedia: https://en.wikipedia.org/wiki/Torus#/media/File:Torus_cycles.svg abgerufen |
[3] | Hunter, J., Dale, D., Firing, E., & Droettboom, M. (28. Ferbrar 2019). Matplotlib Documentation 3.0.3. Von Matplotlib: https://matplotlib.org/Matplotlib.pdf abgerufen |