Я пытаюсь создать график разметки Matplotlib с перетаскиваемыми маркерами.
Я нашел пример прямоугольного прямоугольника на сайте Matplotlib, https://matplotlib.org/users/event_handling.html. Подход, похоже, заключается в создании класса DraggableRectangle, который обрабатывает события мыши и который инициализируется и подключается для каждого прямоугольника на графике.
Я попытался сделать что-то подобное с диаграммой рассеяния, но когда я пытаюсь выполнить итерацию по маркерам, я получаю typeError: объект PathCollection не является итерируемым.
import numpy as np
import matplotlib.pyplot as plt
class DraggableMarker:
def __init__(self, marker):
self.marker = marker
def connect(self):
self.cidpress = self.rect.figure.canvas.mpl_connect(
'button_press_event', self.on_press)
self.cidrelease = self.rect.figure.canvas.mpl_connect(
'button_release_event', self.on_release)
self.cidmotion = self.rect.figure.canvas.mpl_connect(
'motion_notify_event', self.on_motion)
def on_press(self, event):
pass
def on_motion(self, event):
pass
def on_release(self, event):
pass
def disconnect(self):
self.rect.figure.canvas.mpl_disconnect(self.cidpress)
self.rect.figure.canvas.mpl_disconnect(self.cidrelease)
self.rect.figure.canvas.mpl_disconnect(self.cidmotion)
fig, ax = plt.subplots(1, 1)
markers = ax.scatter(np.random.rand(10), np.random.rand(10), marker ='o')
draggable_markers = []
for marker in markers:
draggable_marker = DraggableMarker(marker)
draggable_marker.connect()
draggable_markers.append(draggable_marker)
plt.show()
Каков правильный способ сделать это?
В случае, если кто-то другой встретит это в поисках ответа, вот перетаскиваемый разброс, основанный на ссылках, предоставленных в комментариях от ImportanceOfBeingErnes.
import numpy as np
import matplotlib.pyplot as plt
class DraggableScatter():
epsilon = 5
def __init__(self, scatter):
self.scatter = scatter
self._ind = None
self.ax = scatter.axes
self.canvas = self.ax.figure.canvas
self.canvas.mpl_connect('button_press_event', self.button_press_callback)
self.canvas.mpl_connect('button_release_event', self.button_release_callback)
self.canvas.mpl_connect('motion_notify_event', self.motion_notify_callback)
plt.show()
def get_ind_under_point(self, event):
xy = np.asarray(self.scatter.get_offsets())
xyt = self.ax.transData.transform(xy)
xt, yt = xyt[:, 0], xyt[:, 1]
d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2)
ind = d.argmin()
if d[ind] >= self.epsilon:
ind = None
return ind
def button_press_callback(self, event):
if event.inaxes is None:
return
if event.button != 1:
return
self._ind = self.get_ind_under_point(event)
def button_release_callback(self, event):
if event.button != 1:
return
self._ind = None
def motion_notify_callback(self, event):
if self._ind is None:
return
if event.inaxes is None:
return
if event.button != 1:
return
x, y = event.xdata, event.ydata
xy = np.asarray(self.scatter.get_offsets())
xy[self._ind] = np.array([x, y])
self.scatter.set_offsets(xy)
self.canvas.draw_idle()
fig, ax = plt.subplots(1, 1)
scatter = ax.scatter(np.random.rand(10), np.random.rand(10), marker='o')
DraggableScatter(scatter)
get_offsets
иset_offsets
. В целом, более полезным может быть просмотр matplotlib.org/gallery/event_handling/path_editor.html или matplotlib.org/gallery/event_handling/poly_editor.html .