»Schuld« an diesem Tutorial besitzt das (schon mehrfach lobend erwähnte) Buch »Mathematische Algorithmen mit Python« von Veit Steinkamp. Darin wird nämich (auf den Seiten 243 ff) eine Eigenschaft der Matplotlib vorgestellt, die ich bis dahin noch nicht kannte: Die Matplotlib kann nämlich GUI-Elemente (Widgets) erzeugen und die Werte aus diesen Widgets dynamisch während der Laufzeit an das Programm (und damit auch an die Graphen der Matplotlib) übergeben.
Demonstriert wird das an dem Beispiel dreier Schieberegler (Slider), deren Werte die Darstellung einer Parabel definieren (siehe Screenshot unten):
Der Screenshot wurde mit diesem Programm erzeugt (Quellcode) auch auf GitHub):
# parabel.py
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
def f(a, b, c):
return(a*(x - b)**2 + c)
# Plot und Plotausrichtung
fig, ax = plt.subplots(figsize = (5, 5))
plt.title("Parabel")
plt.subplots_adjust(left = 0.15, bottom = 0.25)
plt.xlim(-5.5, 5.5)
plt.ylim(-10, 10)
plt.xlabel("x")
plt.ylabel("y", rotation = 0)
# Berechnung
x = np.arange(-5.5, 5.5, 0.001)
y, = plt.plot(x, f(1, 0, -10), lw = 2)
# Slider Pos
xyA = plt.axes([0.1, 0.12, 0.8, 0.03])
xyB = plt.axes([0.1, 0.07, 0.8, 0.03])
xyC = plt.axes([0.1, 0.02, 0.8, 0.03])
# Slider Objeekte erzeugen
sldA = Slider(xyA, "a", -2.0, 2.0, valinit = 1, valstep = 0.01)
sldB = Slider(xyB, "b", -5.0, 5.0, valinit = 0, valstep = 0.01)
sldC = Slider(xyC, "a", -10.0, 10.0, valinit = -10, valstep = 0.01)
def update(val):
a = sldA.val
b = sldB.val
c = sldC.val
y.set_data(x, f(a, b, c))
fig.canvas.draw_idle()
# Änderungen abfragen
sldA.on_changed(update)
sldB.on_changed(update)
sldC.on_changed(update)
ax.grid(True)
plt.show()
# print("I did it, Babe!")
Diese Entdeckung hat mich natürlich elektrisiert. Wie schon mehrfach erwähnt, plane ich die Implementierung einiger grundlegender numerischer Algorithmen ohne zuhilfenahme entsprechender Bibliotheken in TigerJython, um das Verständnis für numerische Probleme zu wecken. Und da kommen mir solche GUI-Elemente gerade recht. Schwach erinnerte ich mich, daß auch TigerJython solche GUI-Elemente besitzt. Und ein Stöbern in der Dokumentation brachte die Erleuchtung. 🤓
Das Programm (Quellcode auf GitLab) unterscheidet sich nur unwesentlich von der Python-3/Matplotlib-Version oben:
# Slider-Demo
from gpanel import *
WIDTH = 600
HEIGTH = 600
def f(x, a, b, c):
return(a*(x - b)**2 + c)
def doIt():
clear()
setColor(230, 226, 204)
fillRectangle(-5, -10, 5, 10)
drawGrid(-5, 5, -10, 10, 4, 4, "darkgrey")
a = sldA.getValue()
b = sldB.getValue()
c = sldC.getValue()
setColor("blue")
x = -5
candraw = False
lineWidth(2)
while x < 5:
y = f(x, a, b, c)
if x == -5 or abs(y) >= 9.9:
move(x, y)
else:
if abs(y) < 10:
draw(x, y)
x += 0.01
status.setValue("Drücke »Go« für neue Berechnung")
makeGPanel(Size(WIDTH, HEIGTH))
window(-6.5, 5.5, -12, 11)
windowPosition(1400, 80)
bgColor(240, 245, 248)
title("Slider Demo")
setColor(230, 226, 204)
fillRectangle(-5, -10, 5, 10)
drawGrid(-5, 5, -10, 10, 4, 4, "darkgrey")
sldA = SliderEntry(-2, 2, 1, 1, 0) # (min, max, init, Abstand Hauptticks, Abstand Zwischenticks)
pane1 = EntryPane("a", sldA)
sldB = SliderEntry(-5, 5, 1, 2, 1)
pane2 = EntryPane("b", sldB)
sldC= SliderEntry(-10, 10, -10, 5, 1)
pane3 = EntryPane("c", sldC)
status = StringEntry("")
pane4 = EntryPane("Status", status)
startBtn = ButtonEntry("Go")
pane5 = EntryPane(startBtn)
dlg = EntryDialog(2000, 80,
pane1, pane2, pane3, pane4, pane5)
status.setValue("Drücke »Go« für den Start")
while not dlg.isDisposed():
if isDisposed():
dlg.dispose()
break
if startBtn.isTouched():
doIt()
print("I did it, Babe!")
dispose()
doIt()
Einige Besonderheiten gibt es aber zu beachten: sliderEntry()
besitzt fünf Parameter, die der Reihe nach bedeuten: minimaler Wert, maximaler Wert, Initialisierungsposition des Schiebereglers, Abstand der Hauptticks, Abstand der Nebenticks. Die Parameter müssen anscheinend zwingend Integer-Werte sein, obwohl die ausgelesenen Werte durchaus Fließkommazahlen sein können (sonst wäre solch ein Slider auch meistens sinnlos).
Alle Widgets (zum Beispiel Slider, Statusbar, Button) müssen mit entryPane()
einem Panel zugeordnet werden. Die Parameter sind Bezeichner (String) und der Variablenname für das Widget. Bei Bedarf können auch mehrere Widgets einem Panel zugeordnet werden.
TigerJython besitzt noch weitere Widgets, zum Beispiel Eingabefelder (separat für Integer, Float und String), Radiobutton oder Checkboxen. Näheres könnt Ihr der Dokumentation entnehmen.
Alle Panels werden mit entryDialog()
in einem eigenen Dialogfenster angezeigt. Die ersten beiden Paramter sind die Bildschirmkoordinaten des Fensters, danach folgen die Panele in der Reihenfolge ihrer Anordnung im Fenster. Mit dlg.setAlwaysOnTop(True)
kann verhindert werden, daß das Dialogfenster von anderen Programmfenstern verdeckt wird.
Das Befehlszeile while not dlg.isDisposed()
führt die while
-Schleife solange aus, wie das Dialogfenster offen ist, ifDisposed()
schließt das Dialogfenster, wenn auch das Programmfenster geschlossen wird. Und dispose()
schließt das Programmfenster (vorher kann man noch ein paar abschließende Befehle ausführen lassen – im Programm oben print("I did it, Babe!")
🤡).
TigerJythons Bibliotheken greifen oft an Jython vorbei auf die darunterliegende (Swing-) Java-Implementierung zu, daher verstehen sie in vielen Fällen auch deutsche Umlaute (ist ein nicht dokumentiertes Feature, daher vor Gebrauch unbedingt testen).
Swing und macOS haben machmal unterschiedliche Vorstellung von der Geometrie. So klebt zum Beispiel in der Mac-Version das Panel mit Statuszeile ohne Zwischenraum am unteren Rand (Screenshot). Das scheint konzeptionell bedingt zu sein, daher sollte man bei der Platzierung der einzelnen Widgets vorher entsprechende Überlegungen anstellen.
Das Programm habe ich ohne Änderungen sowohl auf meinem Chromebook (siehe Banner oben) wie auch auf meinem MacBook Pro (mit Catalina) zum Laufen bekommen.
Die Widgets und auch die GUI-Elemente aus TigerJythons javax.swing
-Bibliothek funktionieren mit der Desktop-Version von TigerJython mindestens mit Turtle- und GPanel-Fenstern (von mir getestet). Prinzipiell sehe ich allerdings keinen Grund, warum sie nicht – wenn sinnvoll – auch mit den Robotik-Modulen und der Spielebibliothek GameGrid funktionieren sollten. Beides kann für Simulationen durchaus spannend sein, muß ich daher unbedingt noch testen. Still digging!
Über …
Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter Rentner, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!
Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.
Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.
Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes
von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.
Werbung
Diese Spalte wurde absichtlich leergelassen!