Einführung
In diesem Lab führen wir Sie durch ein Beispiel einer cross-GUI-Anwendung, bei der Matplotlib-Ereignisbehandlung verwendet wird, um mit Objekten auf der Leinwand zu interagieren und zu modifizieren. Sie werden lernen, wie Sie einen Pfad auf einem Graphen bearbeiten, indem Sie Marker mit der Maus ziehen und deren Sichtbarkeit umschalten.
Tipps für die VM
Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu öffnen.
Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook vollständig geladen ist. Die Validierung von Vorgängen kann aufgrund von Einschränkungen in Jupyter Notebook nicht automatisiert werden.
Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.
Bibliotheken importieren
In diesem Schritt importieren wir die erforderlichen Bibliotheken für das Lab. Wir verwenden Matplotlib, um den Graphen zu erstellen und Ereignisse zu verarbeiten.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backend_bases import MouseButton
from matplotlib.patches import PathPatch
from matplotlib.path import Path
Den Graphen erstellen
In diesem Schritt erstellen wir einen Graphen mit einem grünen Pfad und gelben Kanten, indem wir die bereitgestellten Pfaddaten verwenden. Anschließend fügen wir ein PathPatch-Objekt zum Graphen hinzu, das den Pfad darstellt.
fig, ax = plt.subplots()
pathdata = [
(Path.MOVETO, (1.58, -2.57)),
(Path.CURVE4, (0.35, -1.1)),
(Path.CURVE4, (-1.75, 2.0)),
(Path.CURVE4, (0.375, 2.0)),
(Path.LINETO, (0.85, 1.15)),
(Path.CURVE4, (2.2, 3.2)),
(Path.CURVE4, (3, 0.05)),
(Path.CURVE4, (2.0, -0.5)),
(Path.CLOSEPOLY, (1.58, -2.57)),
]
codes, verts = zip(*pathdata)
path = Path(verts, codes)
patch = PathPatch(
path, facecolor='green', edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)
Die PathInteractor-Klasse erstellen
In diesem Schritt erstellen wir die PathInteractor-Klasse, die die Ereignisrufe für das Pfadobjekt behandelt. Diese Klasse ermöglicht es uns, den Pfad interaktiv zu bearbeiten, indem wir Marker auf dem Graphen ziehen.
class PathInteractor:
"""
Ein Pfad-Editor.
Drücken Sie 't', um die Eckmarkierungen an- und auszuschalten. Wenn die Eckmarkierungen aktiviert sind,
können Sie sie mit der Maus ziehen.
"""
showverts = True
epsilon = 5 ## maximale Pixelabstand, um als Eckpunkt-Treffer zu gelten
def __init__(self, pathpatch):
self.ax = pathpatch.axes
canvas = self.ax.figure.canvas
self.pathpatch = pathpatch
self.pathpatch.set_animated(True)
x, y = zip(*self.pathpatch.get_path().vertices)
self.line, = ax.plot(
x, y, marker='o', markerfacecolor='r', animated=True)
self._ind = None ## der aktive Eckpunkt
canvas.mpl_connect('draw_event', self.on_draw)
canvas.mpl_connect('button_press_event', self.on_button_press)
canvas.mpl_connect('key_press_event', self.on_key_press)
canvas.mpl_connect('button_release_event', self.on_button_release)
canvas.mpl_connect('motion_notify_event', self.on_mouse_move)
self.canvas = canvas
def get_ind_under_point(self, event):
"""
Gibt den Index des Punkts zurück, der am nächsten an der Ereignisposition liegt, oder *None*,
wenn kein Punkt innerhalb von ``self.epsilon`` zur Ereignisposition liegt.
"""
xy = self.pathpatch.get_path().vertices
xyt = self.pathpatch.get_transform().transform(xy) ## in die Anzeige-Koordinaten
xt, yt = xyt[:, 0], xyt[:, 1]
d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
ind = d.argmin()
return ind if d[ind] < self.epsilon else None
def on_draw(self, event):
"""Ruf für Zeichnungen."""
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
self.ax.draw_artist(self.pathpatch)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
def on_button_press(self, event):
"""Ruf für Mausklick-Ereignisse."""
if (event.inaxes is None
or event.button!= MouseButton.LEFT
or not self.showverts):
return
self._ind = self.get_ind_under_point(event)
def on_button_release(self, event):
"""Ruf für Maus loslassen-Ereignisse."""
if (event.button!= MouseButton.LEFT
or not self.showverts):
return
self._ind = None
def on_key_press(self, event):
"""Ruf für Tastendrücke."""
if not event.inaxes:
return
if event.key == 't':
self.showverts = not self.showverts
self.line.set_visible(self.showverts)
if not self.showverts:
self._ind = None
self.canvas.draw()
def on_mouse_move(self, event):
"""Ruf für Mausbewegungen."""
if (self._ind is None
or event.inaxes is None
or event.button!= MouseButton.LEFT
or not self.showverts):
return
vertices = self.pathpatch.get_path().vertices
vertices[self._ind] = event.xdata, event.ydata
self.line.set_data(zip(*vertices))
self.canvas.restore_region(self.background)
self.ax.draw_artist(self.pathpatch)
self.ax.draw_artist(self.line)
self.canvas.blit(self.ax.bbox)
Den Pfad-Interaktor erstellen
In diesem Schritt erstellen wir eine Instanz der PathInteractor-Klasse und übergeben das zuvor erstellte PathPatch-Objekt.
interactor = PathInteractor(patch)
Diagrammeigenschaften festlegen
In diesem Schritt legen wir den Titel und die Achsengrenzen für das Diagramm fest.
ax.set_title('drag vertices to update path')
ax.set_xlim(-3, 4)
ax.set_ylim(-3, 4)
Zeige das Diagramm an
In diesem Schritt zeigen wir das Diagramm auf dem Bildschirm an.
plt.show()
Zusammenfassung
In diesem Lab haben wir gelernt, wie man ein interaktives Diagramm erstellt, das es uns ermöglicht, einen Pfad durch Ziehen von Markern auf dem Diagramm zu bearbeiten. Wir haben die Matplotlib-Bibliothek verwendet, um das Diagramm zu erstellen und Ereignisse zu behandeln, und eine benutzerdefinierte Klasse erstellt, um die Ereignisrufe zu behandeln. Indem Sie diese Schritte befolgen, können Sie Ihre eigenen interaktiven Diagramme mit Matplotlib erstellen.