Dieses Jupyter-Notebook enthält den Quelltext für Kapitel 7 »Visualisierung« im Buch Python für Ingenieure für Dummies.
import sys
sys.path.append("../util")
from pfi_util import define_plot_params_rh, show_book, set_cmap_cycler
import matplotlib.pyplot as plt
import numpy as np
define_plot_params_rh(plt)
set_cmap_cycler(N=2)
plt.rc('figure', dpi=70*2)
three_fig_size = (2.0, 1.25)
begin intro
import numpy as np
#!import matplotlib.pyplot as plt
# Schritt 1
x = np.linspace(0, 2, 200, endpoint=False) # x-Array
w = 2 * np.pi * 1 # Kreisfrequenz
y1 = np.sin(w*x) # y-Array
# Schritt 2
#!plt.figure()
plt.figure(figsize=three_fig_size)#!
# Schritt 3
plt.plot(x, y1)
# Schritt 5
#!plt.show()
plt.tight_layout()#!
show_book('intro') #!
end
begin two_lines
plt.figure(figsize=three_fig_size)#!
y2 = np.sin(w*x) + 1/3*np.sin(3*w*x)
plt.plot(x, y1)
plt.plot(x, y2)
# Alternative: 2D-Array mit Datensatz pro Spalte
# y12 = np.c_[y1, y2]
# plt.plot(x, y12)
plt.tight_layout()#!
show_book('two_lines') #!
end
begin limits
plt.figure(figsize=three_fig_size)#!
plt.plot(x, y1)
plt.xlim(0, 1)
plt.ylim(-1, 1)
plt.tight_layout()#!
show_book('limits') #!
end
begin styling_intro
plt.figure(figsize=(4.5, 2.8)) #!
# Rechteck als Vorzeichen des Sinussignals
y_rect = np.sign(y1)
#_
plt.plot(x, y_rect, color='black', linestyle='--',
label="Rechteck")
# Abkürzung: plt.plot(x, y_rect, 'k--', label="Rechteck")
# Beschriftungen mit TeX-Formeln gehen in $$
plt.plot(x, y1, linewidth=3, label="$n=1$")
plt.plot(x, y2, linewidth=3, label="$n=2$")
#_
# Achsenabstufungen
plt.xticks([0, 0.5, 1, 1.5, 2])
plt.yticks([-1, 0, 1])
# Graues Achsengitter
plt.grid()
#_
plt.title('Approximation Rechteckfunktion durch Sinus')
plt.xlabel("$x$")
plt.ylabel("$f(x)$")
#!plt.legend() # Automatische Legende anhand "label"
plt.legend(loc="lower left")#!
plt.tight_layout()#!
show_book('styling_intro') #!
end
plt.figure(figsize=(3,1.5), edgecolor='k')
x = np.array([0, 1])
y = np.array([1, 1])
linestyles = ['-', '--', '-.', ':', ' ']
for i, ls in enumerate(linestyles):
plt.text(-0.3, -i, f"'{ls}'", family='monospace')
plt.plot(x, -y*i, c='b', ls=ls)
#xlim(-0.15, 1.1)
#ylim(-4, 1)
plt.axis('off')
plt.xticks([])
plt.yticks([])
plt.tight_layout()
plt.savefig('linestyles.pdf')
plt.show()
plt.figure(figsize=(3,1.8))
nr_marker=5
x = np.linspace(0, 1, nr_marker)
y = np.ones(nr_marker)
markers = ['.', 'o', 's', '+', 'x', 'D']
for i, marker in enumerate(markers):
plt.text(-0.3, -i, f"'{marker}'", family='monospace')
plt.plot(x, -y*i, c='b', marker=marker, ls=' ')
#xlim(-0.2, 1.1)
plt.axis('off')
plt.tight_layout()
plt.savefig('markers.pdf')
plt.show()
begin rcparams
import matplotlib
#!matplotlib.rcParams['lines.linewidth'] = 2
end
begin figsize
plt.figure(figsize=(4, 1)) # (Breite, Höhe) in Zoll
x = np.linspace(0, 10)
plt.plot(x, np.sin(x))
plt.tight_layout() #!
show_book('figsize') #!
end
begin subplot_bad_spacing
x = np.linspace(0, 5)
#_
plt.figure(figsize=(4, 2.5))#!
#!plt.figure()
#_
# 2 Zeilen, 3 Spalten, 1. Subplot
plt.subplot(2, 3, 1)
plt.plot(x, x**2, c='black')
#_
# Tupel für i erstreckt Subplot über mehrere Zellen
# 2 Zeilen, 3 Spalten, 2. & 3. Subplot
# (also Zeile 1, Spalte 2 und 3)
plt.subplot(2, 3, (2, 3))
plt.plot(x, np.sin(x), c='black', ls='--')
#_
# 4. & 5. Subplot (also Zeile 2, Spalte 1 und 2)
plt.subplot(2, 3, (4, 5))
plt.plot(x, np.cos(x), c='black', ls='-.')
#_
plt.subplot(2, 3, 6)
plt.plot(x, np.exp(x), c='grey')
show_book('subplot_bad_spacing') #!
end
x = np.linspace(0, 5)
#_
plt.figure(figsize=(4, 2.5))#!
#_
# 2 Zeilen, 3 Spalten, 1. Subplot
plt.subplot(2, 3, 1)
plt.plot(x, x**2, c='black')
#_
# Tupel für i erstreckt Subplot über mehrere Zellen
# 2 Zeilen, 3 Spalten, 2. & 3. Subplot (also Zeile 1, Spalte 2 und 3)
plt.subplot(2, 3, (2, 3))
plt.plot(x, np.sin(x), c='black', ls='--')
#_
# 4. & 5. Subplot (also Zeile 2, Spalte 1 und 2)
plt.subplot(2, 3, (4, 5))
plt.plot(x, np.cos(x), c='black', ls='-.')
#_
plt.subplot(2, 3, 6)
plt.plot(x, np.exp(x), c='grey')
#_
plt.tight_layout()
show_book('spacing_fixed') #!
begin spacing_fixed
# ...Plot-Befehle aus vorherigem Beispiel...
#!plt.tight_layout()
end
w0 = 1
D = 0.1
a2 = 1/w0**2
a1 = 2*D/w0
print('Koeffizienten:', [a2, a1, 1])
Koeffizienten: [1.0, 0.2, 1]
begin bode
# Logarithmisch verteilte Stützpunkte zwischen
# 10^(-1) und 10^1
w = np.logspace(-1, 1, 100)
s = 1j * w
# Übertragungsfunktion auswerten
G = 1/(1*s**2 + 0.2*s + 1)
#_
plt.figure(figsize=(4,3.3))#!
# Speichere Referenz auf Subplot-Achsen
ax1 = plt.subplot(211)
plt.title('Bode-Diagramm $G(s)=\\frac{1}{s^2+0.2s+1}$')
plt.xscale('log') # x-Achse logarithmisch
plt.ylabel('Verstärkung [dB]')
plt.grid()
#_
plt.plot(w, 20*np.log10(np.abs(G)))
plt.axhline(0, ls='--', c='orange') # 0-dB-Grenze
plt.axvline(1.42, ls='--', c='red')
plt.text(1.5, 1, "$\\omega_d$")
#_
# Nutze gleiche x-Achse wie in Verstärkungsdiagramm
plt.subplot(212, sharex=ax1)
plt.yticks([-180, -135, -90, -45, 0])
plt.ylabel('Phase [deg]')
plt.xlabel('$\\omega$ [rad/s]')
plt.grid()
#_
plt.plot(w, np.angle(G)/np.pi*180)
plt.axvline(1.42, ls='--', c='red')
plt.text(1, -175, '$\\Phi_R$')
plt.tight_layout() #!
show_book('bode') #!
end
durchtritt_i = 0
for i, mag in enumerate(20*np.log10(np.abs(G))):
if mag < 0:
durchtritt_i = i
break
wd = w[durchtritt_i]
phid = (np.angle(G)/np.pi*180)[durchtritt_i]
print("wd:", wd)
print("phid:", phid)
wd: 1.4174741629268055 phid: -164.30987993473843
x = np.linspace(0, 2, 200, endpoint=False) # x-Array
w = 2 * np.pi * 1 # Kreisfrequenz
y1 = np.sin(w*x) # y-Array
y2 = np.sin(w*x) + 1/3*np.sin(3*w*x)
y_rect = np.sign(y1)
begin demo_oo
import matplotlib
#_
fig = matplotlib.pyplot.figure() # matplotlib.figure.Figure
axes = fig.add_subplot() # matplotlib.axes.Axes
#_
# plot(...) gibt Liste von Linien zurück, in dem Fall nur eine
# matplotlib.lines.Line2D
line_rect, = axes.plot(x, y_rect, color='black')
# Eigenschaften nachträglich mit Methode setzen
line_rect.set_linestyle('--')
line_1, = axes.plot(x, y1, linewidth=3)
line_2, = axes.plot(x, y2, linewidth=3)
#_
xaxis = axes.get_xaxis() # matplotlib.axis.XAxis
xaxis.set_ticks([0, 0.5, 1, 1.5, 2])
xaxis.set_label_text("$x$")
#_
# Eine Abkürzung, ohne erst YAxis auszulesen
axes.set_yticks([-1, 0, 1])
axes.set_ylabel("$f(x)$")
#_
axes.set_title('Approximation Rechteckfunktion durch Sinus')
# Manuelle Zuordnung von Linien und Beschriftungen in Legende
axes.legend([line_rect, line_1, line_2],
["Rechteck", "$n=1$", "$n=2$"])
axes.grid()
plt.show() #!
end
import numpy as np
set_cmap_cycler(N=3)
begin barchart_primitive
os_names = ['Forest X', 'IronPhone', 'PlumbusOS']
#_
os_users_in_atlantis = np.array([31756415, 13431, 5037615])
os_users_in_lummerland = np.array([534143, 8172634, 2615266])
os_users_in_schlaraffenland = np.array([6574612, 26735,
10857163])
#_
xs = range(len(os_names))
plt.figure(figsize=(2.9, 1.8))#!
plt.bar(xs, os_users_in_atlantis)
show_book('barchart_primitive') #!
end
begin barchart_nice
plt.figure(figsize=(3.1, 2))#!
# Teile durch 10^6, um auf Millionen zu skalieren
plt.bar(xs, os_users_in_atlantis/1e6, label='Atlantis')
# Breite der oberen Balken verjüngt sich
# Unterseite wird um Wert des darunterliegenden Balkens
# nach oben verschoben
plt.bar(xs, os_users_in_schlaraffenland/1e6, width=0.75,
bottom=os_users_in_atlantis/1e6, label='Schlaraffenland')
plt.bar(xs, os_users_in_lummerland/1e6, width=0.7,
bottom=(os_users_in_atlantis+os_users_in_schlaraffenland)/1e6,
label='Lummerland')
#_
plt.xticks(xs, os_names)
plt.ylabel('Mio. Benutzer')
plt.legend()
plt.tight_layout()#!
show_book('barchart_nice') #!
end barchart_nice
from PIL import Image
import numpy as np
import matplotlib.patheffects as PathEffects
imshow_size = (2.6, 2.2)
begin imshow_intro
plt.figure(figsize=imshow_size) #!
# Erstelle Matrix mit 6 Zeilen und 5 Spalten
# Die Einerstelle jedes Elements enthält die Spalte,
# die Zehnerstelle die Zeile
arr = np.array([[10*y + x for x in range(5)] for y in range(6)])
#!plt.imshow(arr) # Zeichne Array als farbiges Bild
plt.imshow(arr, cmap="plasma") #!
plt.colorbar() # Zeichne Farbskala
#_
# Beschrifte Werte in Bild
for x in range(arr.shape[1]):
for y in range(arr.shape[0]):
txt = plt.text(x-0.2, y+0.1, arr[y,x], color="black") #!
txt.set_path_effects([PathEffects.Stroke(linewidth=3, foreground="w"), PathEffects.Normal()]) #!
#! plt.text(x, y, arr[y,x])
show_book('imshow_intro') #!
end imshow_intro
begin imshow_vmin_vmax
plt.figure(figsize=imshow_size) #!
#!plt.imshow(arr, vmin=20, vmax=40) # Wertebereich beschränken
plt.imshow(arr, vmin=20, vmax=40, cmap="plasma") #!
plt.colorbar()
for x in range(arr.shape[1]): #!
for y in range(arr.shape[0]): #!
txt = plt.text(x-0.2, y+0.1, arr[y,x], color="black") #!
txt.set_path_effects([PathEffects.Stroke(linewidth=3, foreground="w"), PathEffects.Normal()]) #!
show_book('imshow_vmin_vmax') #!
end
begin imshow_cmap
plt.figure(figsize=imshow_size) #!
plt.imshow(arr, cmap='Greys') # Farbskala anpassen
plt.colorbar()
show_book('imshow_cmap') #!
end
begin imshow_interpolation
plt.figure(figsize=imshow_size) #!
#!plt.imshow(arr, interpolation='bicubic') # Interpolation anpassen
plt.imshow(arr, interpolation='bicubic', cmap="plasma") #!
plt.colorbar()
show_book('imshow_interpolation') #!
end
pil_img = Image.open('hammer.png')
np_img = np.array(pil_img)
brightness = np_img[:, :, 0]/255
T_min = 18
T_max = 37
temp_arr = T_min + brightness * (T_max - T_min)
begin hammer_heat
#!temp_arr = np.load('infrared.npy')
temp_arr.shape
(300, 300)
plt.figure(figsize=(2.67, 2)) #!
plt.imshow(temp_arr, cmap='plasma')
plt.axis('off')
plt.colorbar(label='Temperatur [°C]')
show_book('hammer_heat') #!
end
begin imshow_image
# Lade Bild mit Matplotlib-Funktion imread
#!np_img = imread('ihr_foto.jpg')
# [Zeile, Spalte, RGB]
#!np_img.shape
print("(285, 240, 3)")#!
(285, 240, 3)
# Bild hat 8 Bit Farbtiefe
np_img.dtype
dtype('uint8')
#!imshow(np_img) # Zeichne RGB-Bild
end
begin sinani_setup
from matplotlib.animation import FuncAnimation
from math import sin
T_end = 5.0 # Dauer der Animation
fps = 30 # Anzahl Bilder pro Sekunde
interval_ms = 1000/fps # Intervall zwischen Bildern in ms
nr_frames = int(T_end*fps) # Gesamtzahl an Bildern
# figure-Instanz speichern, wird später benötigt
fig = plt.figure()
# Listen mit x- und y-Werten, wachsen im Laufe der Animation
x_list = []
y_list = []
# plot gibt Liste von gezeichneten Linien zurück (hier nur eine)
lines = plt.plot(x_list, y_list)
# Grenzen müssen manuell gesetzt werden
plt.xlim(0, T_end)
plt.ylim(-1.2, 1.2)
(-1.2, 1.2)
end
begin sinani_update
def update(frame_index):
t = frame_index / fps # Neuer Zeitwert
y = sin(2*3.14*t) # Neuer Funktionswert
x_list.append(t)
y_list.append(y)
# Aktualisiere gezeichnete Linie mit längeren Listen
lines[0].set_data(x_list, y_list)
return lines
end
begin sinani_final
# Definiere Animation
anim = FuncAnimation(fig, update, frames=nr_frames,
interval=interval_ms, blit=True)
# Als Datei abspeichern
#!anim.save('animation.mp4')
# Oder direkt im Notebook anzeigen
# Dafür ist etwas Jupyter-Foo nötig
from IPython.core.display import display, HTML
display(HTML(anim.to_jshtml()))
end
orig_rcParams = plt.rcParams.copy()
plt.rcParams.update({'xtick.labelsize': 8})
plt.rcParams.update({'ytick.labelsize': 8})
begin contour_intro
plt.figure(figsize=(2.8, 1.7)) #!
x = np.linspace(0.1, 0.9)
y = np.linspace(0.1, 0.9)
xx, yy = np.meshgrid(x, y)
zz = 10*np.sin(2*np.pi*xx)*np.sin(np.pi*yy)
#_
plt.contour(xx, yy, zz)
plt.tight_layout() #!
show_book('contour_intro') #!
end contour_intro
begin contour_clabel
plt.figure(figsize=(2.8, 1.7)) #!
# Setze Farbpalette und Werte der Niveaulinien
cs = plt.contour(xx, yy, zz, cmap='plasma',
levels=range(-10, 10, 2))
# clabel braucht ContourSet
# "fmt" blendet Nachkommastellen aus
plt.clabel(cs, fontsize=8, fmt='%.0f')
plt.tight_layout() #!
show_book('contour_clabel') #!
end
begin contourf
plt.figure(figsize=(4, 2.0)) #!
plt.contourf(xx, yy, zz, cmap='plasma')
plt.colorbar()
plt.tight_layout() #!
show_book('contourf') #!
end
plt.rcParams.update(orig_rcParams)
/home/ck2/miniconda3/envs/base38/lib/python3.8/_collections_abc.py:832: MatplotlibDeprecationWarning: The animation.avconv_args rcparam was deprecated in Matplotlib 3.3 and will be removed two minor releases later. self[key] = other[key] /home/ck2/miniconda3/envs/base38/lib/python3.8/_collections_abc.py:832: MatplotlibDeprecationWarning: The animation.avconv_path rcparam was deprecated in Matplotlib 3.3 and will be removed two minor releases later. self[key] = other[key] /home/ck2/miniconda3/envs/base38/lib/python3.8/_collections_abc.py:832: MatplotlibDeprecationWarning: The animation.html_args rcparam was deprecated in Matplotlib 3.3 and will be removed two minor releases later. self[key] = other[key] /home/ck2/miniconda3/envs/base38/lib/python3.8/_collections_abc.py:832: MatplotlibDeprecationWarning: The keymap.all_axes rcparam was deprecated in Matplotlib 3.3 and will be removed two minor releases later. self[key] = other[key] /home/ck2/miniconda3/envs/base38/lib/python3.8/_collections_abc.py:832: MatplotlibDeprecationWarning: The savefig.jpeg_quality rcparam was deprecated in Matplotlib 3.3 and will be removed two minor releases later. self[key] = other[key] /home/ck2/miniconda3/envs/base38/lib/python3.8/_collections_abc.py:832: MatplotlibDeprecationWarning: The text.latex.preview rcparam was deprecated in Matplotlib 3.3 and will be removed two minor releases later. self[key] = other[key]
begin 3d_intro
t = np.linspace(0, 5, num=200)
phi = 2*np.pi*t
r = 1-t/5
x = r*np.cos(phi)
y = r*np.sin(phi)
z = t
plt.figure(figsize=(2.8,2.8)) #!
ax = plt.subplot(projection='3d')
# Schlüsselwörter wie bei 2D-Plot
ax.plot(x, y, z, ls='--', lw=3)
show_book('3d_intro') #!
end
begin 3d_ortho
plt.figure(figsize=(2.8,2.8)) #!
ax = plt.subplot(projection='3d', proj_type='ortho')
ax.plot(x, y, z, ls='--', lw=3) #!
show_book('3d_ortho') #!
end
begin 3d_surface
x = np.linspace(0.1, 0.9)
y = np.linspace(0.1, 0.9)
xx, yy = np.meshgrid(x, y)
zz = 10*np.sin(2*np.pi*xx)*np.sin(np.pi*yy)
plt.figure(figsize=(2.8,2.8)) #!
ax = plt.subplot(projection='3d')
ax.plot_surface(xx, yy, zz, cmap='plasma')
show_book('3d_surface') #!
end
begin 3d_camera
plt.figure(figsize=(2.8,2.8)) #!
ax = plt.subplot(projection='3d') #!
ax.plot_surface(xx, yy, zz, cmap='plasma') #!
ax.azim = -20 # Azimut in °
ax.elev = 45 # Höhe in °
ax.dist = 8 # Distanz
show_book('3d_camera') #!
end
fig = plt.figure()
ax = plt.subplot(projection='3d') #!
# Grab some test data.
u, v = np.mgrid[0:2*np.pi:20j, 0:np.pi:10j]
x = np.cos(u)*np.sin(v)
y = np.sin(u)*np.sin(v)
z = np.cos(v)
# Plot a basic wireframe.
ax.plot_wireframe(x, y, z)
<mpl_toolkits.mplot3d.art3d.Line3DCollection at 0x7fe1728bf760>
begin 3d_wireframe
fig = plt.figure(figsize=(4, 3)) #!
ax = plt.subplot(projection='3d')
R = 1 # Donut-Radius
r = 0.35 # Ring-Radius
#_
# Generiere Gitter für Winkelkoordinaten
u = np.linspace(0, 2*np.pi, 32)
v = np.linspace(0, 2*np.pi, 16)
uu, vv = np.meshgrid(u, v)
# Torus in kartesischen Koordinaten
xx = np.cos(uu)*(R + r*np.cos(vv))
yy = np.sin(uu)*(R + r*np.cos(vv))
zz = r*np.sin(vv)
#_
# Zeichne Drahtgitter, aber mit Linien nur bei
# jedem zweiten Datenpunkt im x- und y-Array
ax.plot_wireframe(xx, yy, zz, rstride=2, cstride=2)
#_
# Definiere zu zeichnenden Wertebereich
ax.set_xlim(-1.4, 1.4)
ax.set_ylim(-1.4, 1.4)
ax.set_zlim(-0.5, 0.5)
# Skaliere Box entsprechend Wertebereich, sodass
# Darstellung nicht verzerrt ist
ax.set_box_aspect((1.4, 1.4, 0.5))
show_book('3d_wireframe') #!
end
begin savefig
plt.figure(figsize=(2.5, 2))
x = np.linspace(-1, 1)
plt.plot(x, x**2)
plt.tight_layout()
plt.savefig('my_plot.pdf')
end
plt.figure(figsize=(5, 4))
x = np.linspace(-1, 1)
plt.plot(x, x**2)
plt.tight_layout()
plt.savefig('my_plot_large.pdf')
x = np.linspace(0, 10)
fig = plt.figure(figsize=(3.5, 4), linewidth=2, edgecolor='red')
ax1 = fig.add_axes((0.2, 0.6, 0.6, 0.3))
ax1.plot(x, 3*np.sin(2*np.pi*x/5))
ax2 = fig.add_axes((0.2, 0.1, 0.6, 0.3))
ax2.plot(x, np.sin(3*(x-5))/(3*(x-5)))
ax_over = fig.add_axes((0, 0, 1.0, 1.0), fc=(1.0, 1.0, 1.0, 0.0))
ax_over.tick_params(axis='x', direction='in', pad=-22)
ax_over.tick_params(axis='y', direction='in', pad=-18)
x = np.linspace(0, 10)
fig = plt.figure(figsize=(3.5, 4))
ax1 = fig.add_subplot(211)
ax1.plot(x, 3*np.sin(2*np.pi*x/5))
plt.ylabel('$y_1$')
plt.grid()
plt.title('Überschrift')
ax2 = fig.add_subplot(212)
ax2.plot(x, np.sin(3*(x-5))/(3*(x-5)))
plt.ylabel('$y_2$')
plt.grid()
plt.xlabel('$t$ [s]')
plt.savefig('mpl_elements.svg')
begin meshgrid
# Normale 1D-Arrays für beide Achsen einzeln
x = np.arange(1, 4)
x #!
array([1, 2, 3])
y = np.arange(5, 8)
y #!
array([5, 6, 7])
xx, yy = np.meshgrid(x, y)
# Erzeugt 2D-Arrays, die für jeden 2D-Punkt jeweils
# nur einen Koordinatenwert enthalten
xx
array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])
yy
array([[5, 5, 5], [6, 6, 6], [7, 7, 7]])
# So können Funktionen z=f(x, y) geschrieben werden,
# die ein 2D-Array ergeben
zz = xx + 0.1*yy
zz #!
array([[1.5, 2.5, 3.5], [1.6, 2.6, 3.6], [1.7, 2.7, 3.7]])
end