Reputation: 3745
Here is a highly abstracted main program and module. Matplotlib slider widgets should cause the Data
instances to recalculate and the plot should then update.
Each time a slider is updated, it should pass its new value to the appropriate method defined during the slider's instantiation. For example, moving the first slider should send it's value to d1.set_a()
which triggers a recalculation of that data, and should then trigger P.offsets()
(see MODULE) to update the plot.
Question: How can I get these user-defined, script-generated Sliders to trigger the data objects and the plot to update? Do the Slider Widgets instances offer more convenient methods than the way I'm doing it here?
MAIN Program:
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))
Current result, sliders move but don't trigger recalculation/replotting:
MODULE:
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))
Upvotes: 0
Views: 382
Reputation: 339062
The individual sliders need to perform different actions, so each slider needs its own callback. Inside of it you may of course then call the same function (sliderfunc
) to update the plot.
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))
Upvotes: 1