Перетаскиваемый разброс Matplotlib с анимированным сюжетом с использованием блиттинга - PullRequest
0 голосов
/ 25 октября 2018

Я недавно задал вопрос о создании перетаскиваемого скаттера, и с помощью кого-то мне удалось создать рабочий пример.См. 'PathCollection', не повторяемый - создание перетаскиваемого графика рассеяния .

Я сейчас пытаюсь использовать созданный мной класс DraggableScatter с анимированным графиком с использованием блитинга.

Я пытался прикрепить класс DraggableScatter в нескольких местах, например, после инициализации scatter, в функции init и в функции update.В первых случаях разброс DraggableScatter пуст, что имеет смысл, но, очевидно, не работает.В двух других, похоже, что щелчки не фиксируются.

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

Как правильно это сделать?

1 Ответ

0 голосов
/ 25 октября 2018

Работает с бэкэндом GTK3Cairo.(Он не работает с использованием TkAgg, Qt4Agg, Qt5Agg, GTK3Agg.)

Создайте DraggableScatter один раз, затем используйте ds.scatter.set_offsets для изменения данных точки разброса внутри функции update:

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()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...