Skip to content

Instantly share code, notes, and snippets.

@ad-1
Last active April 13, 2023 20:56
Show Gist options
  • Select an option

  • Save ad-1/0a99017a076e491afcafc520359fdce7 to your computer and use it in GitHub Desktop.

Select an option

Save ad-1/0a99017a076e491afcafc520359fdce7 to your computer and use it in GitHub Desktop.
Code accompanying a concise article exploring how to drag a 2D vector around a figure while users receive real-time updates through dynamically updating data.
# define 2D vector coordinates
vector_coord_1 = np.random.rand(2)
vector_coord_2 = np.random.rand(2)
# plotting
fig, ax = plt.subplots()
vector_1 = ax.add_patch(mpatches.FancyArrowPatch((0, 0), vector_coord_1, mutation_scale=15))
vector_2 = ax.add_patch(mpatches.FancyArrowPatch((0, 0), vector_coord_2, mutation_scale=15))
draggable_vector_1 = DraggableVector(vector=vector_1)
draggable_vector_2 = DraggableVector(vector=vector_2)
import matplotlib.patches
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
class DraggableVector:
def __init__(self, vector: matplotlib.patches.Patch):
"""
Initialize a new instance of the DraggableVector class.
Parameters:
vector (matplotlib.patches.Patch): the vector that should be made draggable.
Returns:
None
"""
self.vector = vector
self.press = None
self.cidpress = self.vector.figure.canvas.mpl_connect(
"button_press_event", self.on_press
)
self.cidmotion = self.vector.figure.canvas.mpl_connect(
"motion_notify_event", self.on_motion
)
self.cidrelease = self.vector.figure.canvas.mpl_connect(
"button_release_event", self.on_release
)
def on_press(self, event: matplotlib.backend_bases.MouseEvent):
"""
Detect mouse click, and store the data if it is on the vector.
Parameters:
event (matplotlib.backend_bases.MouseEvent): the mouse event that triggered the callback.
Returns:
None
"""
if event.inaxes != self.vector.axes:
return
contains, attrd = self.vector.contains(event)
if not contains:
return
self.press = (0, 0), (event.xdata, event.ydata)
def on_motion(self, event: matplotlib.backend_bases.MouseEvent):
"""
Update the vector's position when the mouse is moved over the vector.
Parameters:
event (matplotlib.backend_bases.MouseEvent): the mouse event that triggered the callback.
Returns:
None
"""
if self.press is None or event.inaxes != self.vector.axes:
return
self.vector.set_positions((0, 0), (event.xdata, event.ydata))
self.vector.figure.canvas.draw()
def on_release(self, event: matplotlib.backend_bases.MouseEvent):
"""
Handle the release of the mouse button over the vector.
Parameters:
event (matplotlib.backend_bases.MouseEvent): the mouse event that triggered the callback.
Returns:
None
"""
self.press = None
self.vector.figure.canvas.draw()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
class DraggableVector:
def __init__(self, vector: matplotlib.patches.Patch):
self.vector = vector
self.press = False
self.cidpress = self.vector.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.vector.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.vector.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
def on_motion(self, event: matplotlib.backend_bases.MouseEvent):
if not self.press or event.inaxes != self.vector.axes:
return
self.vector.set_positions((0, 0), (event.xdata, event.ydata))
self.vector.figure.canvas.draw()
def on_press(self, event: matplotlib.backend_bases.MouseEvent):
if event.inaxes != self.vector.axes:
return
contains, attrd = self.vector.contains(event)
if not contains:
return
self.press = True
def on_release(self, event: matplotlib.backend_bases.MouseEvent):
self.press = False
self.vector.figure.canvas.draw()
import matplotlib.patches
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
class DraggableVector:
def __init__(self, vector: matplotlib.patches.Patch):
"""
Initialize a new instance of the DraggableVector class.
Parameters:
vector (matplotlib.patches.Patch): the vector that should be made draggable.
Returns:
None
"""
self.vector = vector
self.press = None
self.cidpress = self.vector.figure.canvas.mpl_connect(
"button_press_event", self.on_press
)
self.cidmotion = self.vector.figure.canvas.mpl_connect(
"motion_notify_event", self.on_motion
)
self.cidrelease = self.vector.figure.canvas.mpl_connect(
"button_release_event", self.on_release
)
def on_press(self, event: matplotlib.backend_bases.MouseEvent):
"""
Detect mouse click, and store the data if it is on the vector.
Parameters:
event (matplotlib.backend_bases.MouseEvent): the mouse event that triggered the callback.
Returns:
None
"""
if event.inaxes != self.vector.axes:
return
contains, attrd = self.vector.contains(event)
if not contains:
return
self.press = (0, 0), (event.xdata, event.ydata)
def on_motion(self, event: matplotlib.backend_bases.MouseEvent):
"""
Update the vector's position when the mouse is moved over the vector.
Parameters:
event (matplotlib.backend_bases.MouseEvent): the mouse event that triggered the callback.
Returns:
None
"""
if self.press is None or event.inaxes != self.vector.axes:
return
self.vector.set_positions((0, 0), (event.xdata, event.ydata))
self.vector.figure.canvas.draw()
def on_release(self, event: matplotlib.backend_bases.MouseEvent):
"""
Handle the release of the mouse button over the vector.
Parameters:
event (matplotlib.backend_bases.MouseEvent): the mouse event that triggered the callback.
Returns:
None
"""
self.press = None
self.vector.figure.canvas.draw()
# define 2D vector coordinates
vector_coord_1 = np.random.rand(2)
vector_coord_2 = np.random.rand(2)
# plotting
fig, ax = plt.subplots()
vector_1 = ax.add_patch(mpatches.FancyArrowPatch((0, 0), vector_coord_1, mutation_scale=15))
vector_2 = ax.add_patch(mpatches.FancyArrowPatch((0, 0), vector_coord_2, mutation_scale=15))
draggable_vector_1 = DraggableVector(vector=vector_1)
draggable_vector_2 = DraggableVector(vector=vector_2)
ax.set_xlabel("x-axis")
ax.set_ylabel("y-axis")
ax.grid(True)
ax.yaxis.grid(True, which="minor", linestyle="--")
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment