【问题标题】:'PathCollection' not iterable - creating a draggable scatter plot'PathCollection' 不可迭代 - 创建可拖动的散点图
【发布时间】:2019-03-21 07:12:00
【问题描述】:

我正在尝试创建一个带有可拖动标记的 Matplotlib 散点图。

我在 Matplotlib 网站上找到了一个可拖动的矩形示例,https://matplotlib.org/users/event_handling.html。该方法似乎是创建一个 DraggableRectangle 类来处理鼠标事件,并为条形图中的每个矩形进行初始化和连接。

我尝试用散点图做类似的事情,但是当我尝试遍历标记时,我得到一个 typeError: 'PathCollection' object is not iterable。

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()

这样做的正确方法是什么?

【问题讨论】:

  • 一个 PathCollection 将其成员的位置存储在其中。这些可以通过get_offsetsset_offsets 访问。一般来说,查看matplotlib.org/gallery/event_handling/path_editor.htmlmatplotlib.org/gallery/event_handling/poly_editor.html 在这里可能会更有帮助。
  • @ImportanceOfBeingErnest 感谢您为我指明了正确的方向。似乎 get_offsets 根据图表的值返回 x,y 值,其中我的鼠标按钮事件正在返回基于像素的位置。所以,我需要弄清楚这一点,但我正在再次取得进展。

标签: python python-3.x matplotlib


【解决方案1】:

如果其他人在寻找答案时遇到此问题,这里有一个基于 ImportanceOfBeingErnes 在 cmets 中提供的链接的可拖动散点图。

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)

【讨论】:

    猜你喜欢
    • 2017-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-15
    相关资源
    最近更新 更多