简体   繁体   中英

matplotlib - Add sliders to a figure dynamically

Based on this and that examples, I am trying to add sliders to a figure dynamically (in function of the object that is plotted).

The sliders are created and added inside a for-loop, and a new update() function is created every time.

Problems: The sliders do not respond to any mouse inputs!

Any idea how to solve this?

图形

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

class Plotter:
    def __init__(self):
        self.fig, self.ax = plt.subplots()

    def plot(self, obj):
        self.obj = obj
        self.l = plt.plot(obj.t,obj.series())
        vars = obj.get_variables()
        plt.subplots_adjust(bottom=0.03*(len(vars)+2))
        for i,var in enumerate(vars):
            self.add_slider(i*0.03, var[0], var[1], var[2])
        plt.show()

    def add_slider(self, pos, name, min, max):
        ax = plt.axes([0.1, 0.02+pos, 0.8, 0.02], axisbg='lightgoldenrodyellow')
        slider = Slider(ax, name, min, max, valinit=getattr(self.obj, name))
        def update(val):
            setattr(self.obj, name, val)
            self.l.set_ydata(self.obj.series())
            self.fig.canvas.draw_idle()
        slider.on_changed(update)

class SinFunction:
    def __init__(self):
        self.freq = 1.0
        self.amp = 0.5
        self.t = np.arange(0.0, 1.0, 0.001)

    def series(self):
        return self.amp*np.sin(2*np.pi*self.freq*self.t)

    def get_variables(self):
        return [
            ('freq', 0.1, 10),
            ('amp', 0.1, 1)
        ]

Plotter().plot(SinFunction())

In the plot method of the Plotter class you are obtaining all the series of the plot in this way self.l = plt.plot(obj.t,obj.series()) so in self.l you have a list of objects and not the object itself. You could have more than one line.

In the add_slider method you should change the line self.l.set_ydata(self.obj.series()) with self.l[0].set_ydata(self.obj.series()) to use the method of the object. In this case there is only one object in self.l but you could have more. Please, take this into account.

Also, to make sliders work accordingly (see comments below) it seems they need to be in the same scope. To have sliders in the same scope you could create a sliders attribute

The final code should be:

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

class Plotter:
    def __init__(self):
        self.fig, self.ax = plt.subplots()

    def plot(self, obj):
        self.obj = obj
        self.l = plt.plot(obj.t,obj.series())
        _vars = obj.get_variables()
        plt.subplots_adjust(bottom=0.03*(len(_vars)+2))
        self.sliders = []
        for i,var in enumerate(_vars):
            self.add_slider(i*0.03, var[0], var[1], var[2])
        plt.show()

    def add_slider(self, pos, name, min, max):
        ax = plt.axes([0.1, 0.02+pos, 0.8, 0.02], axisbg='lightgoldenrodyellow')
        slider = Slider(ax, name, min, max, valinit=getattr(self.obj, name))
        self.sliders.append(slider)
        def update(val):
            setattr(self.obj, name, val)
            self.l[0].set_ydata(self.obj.series())
            self.fig.canvas.draw_idle()
        slider.on_changed(update)

class SinFunction:
    def __init__(self):
        self.freq = 1.0
        self.amp = 0.5
        self.t = np.arange(0.0, 1.0, 0.001)

    def series(self):
        return self.amp*np.sin(2*np.pi*self.freq*self.t)

    def get_variables(self):
        return [
            ('freq', 0.1, 10),
            ('amp', 0.1, 1)
        ]

k = Plotter()
k.plot(SinFunction())

This version is working for me on Python 2 and Python 3.

PD: I saw different behaviour on Python 2 when compared with Python 3. I don't know if it is something related with Python or with Matplotlib... ¿?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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