简体   繁体   English

可拖动的Matplotlib散点图使用blitting进行动画绘制

[英]Draggable Matplotlib scatter with an animated plot using blitting

I recently asked a question about creating a draggable scatter and with the help of someone I was able to come up with a working example. 我最近问了一个有关创建可拖动散点图的问题,在我能够提出一个可行示例的帮助下。 See 'PathCollection' not iterable - creating a draggable scatter plot . 请参阅“ PathCollection”不可迭代-创建可拖动的散点图

I'm now trying to use the DraggableScatter class I created with an animated plot using blitting. 我现在正尝试使用通过blitting动画情节创建的DraggableScatter类。

I've tried to attach the DraggableScatter class in multiple places, eg, after initializing the scatter, in the init function and in the update function. 我尝试在多个位置附加DraggableScatter类,例如,在初始化分散之后,在init函数和update函数中。 In the first cases, the DraggableScatter's scatter is empty, which makes sense but obviously doesn't work. 在第一种情况下,DraggableScatter的散点为空,这是有道理的,但显然不起作用。 In the other two, the clicks seem not to be captured. 在其他两个中,似乎没有捕获到点击。

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np

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)


    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([],[])


def init():
    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)

    return scatter,

def update(frame):
    scatter = ax.scatter(np.random.rand(10), np.random.rand(10), marker ='o')
    ds = DraggableScatter(scatter)
    return scatter,

ani = FuncAnimation(fig=fig, func=update, init_func=init, blit=True, interval=5000)
plt.show()

What is the right way to do this? 什么是正确的方法?

This works with the GTK3Cairo backend. 与GTK3Cairo后端一起使用。 (It does not work using TkAgg, Qt4Agg, Qt5Agg, GTK3Agg.) (使用TkAgg,Qt4Agg,Qt5Agg,GTK3Agg无效。)

Create the DraggableScatter once, then use ds.scatter.set_offsets to change the scatter point data inside the update function: 创建一次DraggableScatter ,然后使用ds.scatter.set_offsetsupdate函数中更改散点数据:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np

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)


    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')
ds = DraggableScatter(scatter)

def init():
    ax.set_xlim(0, 1)
    ax.set_ylim(0, 1)
    return ds.scatter,

def update(frame, ds):
    x, y = np.random.rand(10), np.random.rand(10)
    ds.scatter.set_offsets(np.column_stack([x, y]))
    return ds.scatter,

ani = FuncAnimation(fig=fig, func=update, init_func=init, fargs=[ds], blit=True, 
                    interval=5000)
plt.show()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM