Introducción
Esta práctica te guiará a través de un ejemplo de una aplicación cruzada de GUI que utiliza el control de eventos de Matplotlib para interactuar y modificar objetos en el lienzo. Aprenderás cómo editar una trayectoria en un gráfico, arrastrando marcadores con el mouse y alternando su visibilidad.
Consejos sobre la VM
Una vez finalizada la inicialización de la VM, haz clic en la esquina superior izquierda para cambiar a la pestaña Cuaderno y acceder a Jupyter Notebook para practicar.
A veces, es posible que tengas que esperar unos segundos a que Jupyter Notebook termine de cargarse. La validación de operaciones no puede automatizarse debido a las limitaciones de Jupyter Notebook.
Si tienes problemas durante el aprendizaje, no dudes en preguntar a Labby. Proporciona retroalimentación después de la sesión y resolveremos rápidamente el problema para ti.
Importar bibliotecas
En este paso, importamos las bibliotecas necesarias para la práctica. Utilizamos Matplotlib para crear el gráfico y manejar eventos.
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
Crear el gráfico
En este paso, creamos un gráfico con una trayectoria verde y bordes amarillos, utilizando los datos de la trayectoria proporcionados. Luego agregamos un objeto PathPatch al gráfico, que representa la trayectoria.
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)
Crear la clase PathInteractor
En este paso, creamos la clase PathInteractor, que maneja las devoluciones de llamada de eventos para el objeto de trayectoria. Esta clase nos permite editar interactivamente la trayectoria arrastrando marcadores en el gráfico.
class PathInteractor:
"""
Un editor de trayectorias.
Presiona 't' para alternar los marcadores de vértices encendidos y apagados. Cuando los marcadores de vértices están encendidos,
se pueden arrastrar con el mouse.
"""
showverts = True
epsilon = 5 ## distancia máxima en píxeles para considerarse un golpe en un vértice
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 ## el vértice activo
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):
"""
Devuelve el índice del punto más cercano a la posición del evento o *None*
si ningún punto está a una distancia de ``self.epsilon`` de la posición del evento.
"""
xy = self.pathpatch.get_path().vertices
xyt = self.pathpatch.get_transform().transform(xy) ## a coordenadas de visualización
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):
"""Devolución de llamada para dibujos."""
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):
"""Devolución de llamada para pulsaciones del botón del mouse."""
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):
"""Devolución de llamada para liberaciones del botón del mouse."""
if (event.button!= MouseButton.LEFT
or not self.showverts):
return
self._ind = None
def on_key_press(self, event):
"""Devolución de llamada para pulsaciones de teclas."""
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):
"""Devolución de llamada para movimientos del mouse."""
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)
Crear el interactuador de trayectoria
En este paso, creamos una instancia de la clase PathInteractor, pasando el objeto PathPatch que creamos anteriormente.
interactor = PathInteractor(patch)
Establecer propiedades del gráfico
En este paso, establecemos el título y los límites de los ejes para el gráfico.
ax.set_title('drag vertices to update path')
ax.set_xlim(-3, 4)
ax.set_ylim(-3, 4)
Mostrar el gráfico
En este paso, mostramos el gráfico en la pantalla.
plt.show()
Resumen
En este laboratorio, aprendimos cómo crear un gráfico interactivo que nos permite editar una trayectoria arrastrando marcadores en el gráfico. Utilizamos la biblioteca Matplotlib para crear el gráfico y manejar eventos, y creamos una clase personalizada para manejar las devoluciones de llamada de eventos. Siguiendo estos pasos, puedes crear tus propios gráficos interactivos con Matplotlib.