Виджеты ползунка Matplotlib (сгенерированные пользователем) не запускают пересчет и обновление графика - PullRequest
0 голосов
/ 09 июля 2019

Вот основная абстракция программы и модуля.Виджеты ползунка Matplotlib должны вызывать пересчет экземпляров Data, а затем обновлять график.

Каждый раз, когда обновляется ползунок, он должен передавать свое новое значение соответствующему методу, определенному во время создания ползунка.Например, перемещение первого ползунка должно отправить его значение в d1.set_a(), что вызывает пересчет этих данных, а затем должно вызвать P.offsets() (см. МОДУЛЬ) для обновления графика.

Вопрос: Как я могу получить эти пользовательские, сгенерированные скриптом ползунки для запуска объектов данных и графика для обновления?Разве экземпляры Slider Widgets предлагают более удобные методы, чем то, как я это делаю здесь?

ОСНОВНАЯ программа:

import numpy as np
from MODULE import Data, Plot

x0 = np.linspace(0, 10., 11)
y1, y2 = [0.5 * (1.0 + f(x0)) for f in (np.cos, np.sin)]

d1, d2 = Data('hey', x0, y1), Data('wow', x0, y2) # data generating objects

p = Plot('hey')    # plot object

p.add_slider(d1, 'set_a', d1.a, (0.2, 1.0))
p.add_slider(d1, 'set_p', d1.p, (0.5, 2.0))
p.add_slider(d2, 'set_a', d2.a, (0.2, 1.0))
p.add_slider(d2, 'set_p', d2.p, (0.5, 2.0))

p.plotme((d1, d2))

Текущий результат, ползунки перемещаются, но не запускают пересчет / повторное построение:

slider test

МОДУЛЬ:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider

class Plot(object):
    def __init__(self, name):
        self.name = name
        self.sliders = []
        self.axcolor = 'lightgoldenrodyellow'
        self.fig = plt.figure()

    def sliderfunc(self, value):
        print('sliderfunc')       # currently not getting here
        for (obj, P) in self.OPs:
            P.set_offsets(obj.xy.T)
        self.fig.canvas.draw_idle()

    def add_slider(self, obj, method, nominal, limits):
        ybot = 0.03 * (len(self.sliders) + 1)
        name = obj.name + '.' + method 
        ax_slider   = plt.axes([0.25, ybot, 0.50, 0.02], facecolor=self.axcolor)
        slider      = Slider(ax_slider, name, limits[0], limits[1],
                             valinit=nominal)
        slider.on_changed(getattr(obj, method)) # this may not be right
        self.sliders.append(slider)
        return slider

    def plotme(self, objs):
        ybot = 0.03 * (len(self.sliders) + 3)
        A = plt.axes([0.15, ybot, 0.65, 0.50])
        self.OPs = []
        for obj in objs:
            P = A.scatter(obj.x, obj.y)
            self.OPs.append((obj, P))
        plt.show()

class Data(object):
    def __init__(self, name, x0, y0):
        self.name = name
        self.a = 1.0
        self.p = 1.0
        self.x0, self.y0 = x0, y0
        self.setstuff(a=1.0, p=1.0)
    def setstuff(self, a=None, p=None):
        if a != None:
            self.set_a(a)
        if p != None:
            self.set_p(p)
    def set_a(self, a):
        self.a = a
        self.x = self.a * self.x0
        self.y = self.y0**self.p
        self.xy = np.vstack((self.x, self.y))
    def set_p(self, p):
        self.p = p
        self.x = self.a * self.x0
        self.y = self.y0**self.p
        self.xy = np.vstack((self.x, self.y))

1 Ответ

1 голос
/ 09 июля 2019

Отдельные ползунки должны выполнять разные действия, поэтому каждый ползунок требует своего обратного вызова.Внутри него вы, конечно, можете затем вызвать ту же функцию (sliderfunc) для обновления графика.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider


class Plot(object):
    def __init__(self, name):
        self.name = name
        self.sliders = []
        self.fig = plt.figure()

    def sliderfunc(self):
        for (obj, P) in self.OPs:
            P.set_offsets(obj.xy.T)
        self.fig.canvas.draw_idle()

    def add_slider(self, obj, method, nominal, limits):
        ybot = 0.03 * (len(self.sliders) + 1)
        name = obj.name + '.' + method 
        ax_slider   = plt.axes([0.25, ybot, 0.50, 0.02], facecolor="w")
        slider      = Slider(ax_slider, name, limits[0], limits[1],
                             valinit=nominal)

        def callback(val):
            getattr(obj, method)(val)
            self.sliderfunc()

        slider.on_changed(callback)
        self.sliders.append(slider)
        return slider

    def plotme(self, objs):
        ybot = 0.03 * (len(self.sliders) + 3)
        A = plt.axes([0.15, ybot, 0.65, 0.50])
        self.OPs = []
        for obj in objs:
            P = A.scatter(obj.x, obj.y)
            self.OPs.append((obj, P))
        plt.show()

class Data(object):
    def __init__(self, name, x0, y0):
        self.name = name
        self.a = 1.0
        self.p = 1.0
        self.x0, self.y0 = x0, y0
        self.update()

    def update(self):
        self.x = self.a * self.x0
        self.y = self.y0**self.p
        self.xy = np.vstack((self.x, self.y))

    def set_a(self, val):
        self.a = val
        self.update()

    def set_p(self, val):
        self.p = val
        self.update()


x0 = np.linspace(0, 10., 11)
y1, y2 = [0.5 * (1.0 + f(x0)) for f in (np.cos, np.sin)]

d1, d2 = Data('hey', x0, y1), Data('wow', x0, y2) # data generating objects

p = Plot('hey')    # plot object

p.add_slider(d1, 'set_a', d1.a, (0.2, 1.0))
p.add_slider(d1, 'set_p', d1.p, (0.5, 2.0))
p.add_slider(d2, 'set_a', d2.a, (0.2, 1.0))
p.add_slider(d2, 'set_p', d2.p, (0.5, 2.0))

p.plotme((d1, d2))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...