0

Following the Slider Demo of Matplotlib https://matplotlib.org/gallery/widgets/slider_demo.html, I would like to update the Slider ranges, so that every time I change the slider values, those are re-centred in the Slider.

I have tried to define the Sliders as

sfreq = Slider(axfreq, 'Freq', freq-10, freq+10, valinit=freq)
samp = Slider(axamp, 'Amp', amp-5, amp+5, valinit=amp)

but since the update() function does not return anything, that does not work. I also tried making these variables global inside the function, which also did not work. I finally tried defining the Sliders inside the update function,

def update(val):
    amp = samp.val
    freq = sfreq.val
    l.set_ydata(amp*np.sin(2*np.pi*freq*t))
    fig.canvas.draw_idle()
    Slider(axfreq, 'Freq', freq-10, freq+10, valinit=freq)
    Slider(axamp, 'Amp', amp-5, amp+5, valinit=amp)

but that overlays more and more Sliders as I change the values. Any suggestions?

dani reta
  • 69
  • 8
  • You probably want to change the `Slider` object attributes in the `update` function. Something like `sfreq.valmin = amp - 5`. – busybear Nov 12 '18 at 14:36
  • I do not see how that would help me. Could you please elaborate more? How would I define the sfreq and samp then? – dani reta Nov 12 '18 at 14:56
  • I cannot currently imagine how that is supposed to work. Imagine you move your slider to the right, then while draging it, the slider moves back to the center. At this point your mouse is far away from the slider and will not touch it any more. Moving the mouse further would then repeat the above, such that a minimal drag with the mouse amplifies the effect by a lot. I don't think this would produce useful results at all. – ImportanceOfBeingErnest Nov 12 '18 at 15:26
  • The reason why I want to do this is because I am writing a program to fit some data that varies largely from experiment to experiment. These fits need to have good starting guesses and there is no way of guessing that a priori. I am using the sliders to visually investigate the parameters space, and once the model function is relatively close to the experimental data, the user would proceed to fit the data. I need to recenter the Slider values to narrow down the options. – dani reta Nov 12 '18 at 15:39
  • I think I understand what you want, but as described above I cannot currently imagine how such slider work concerning mouse interactions, independent of matplotlib. Maybe by not allowing for draggin, but only clicking? – ImportanceOfBeingErnest Nov 12 '18 at 16:23
  • I think I did not explain my self. I used the Slider Demo as a simplification of my actual problem. I do not want to drag the mouse or anything like it. I would only use the mouse to indicate specific values in the slider range. Once I have changed that value, I want it to be the centre in the Slider again. The only reason to do that is not to end up in a situation in which the user cannot continue investigating the parameter space because of the initial definitions of valmin and valmax. – dani reta Nov 12 '18 at 16:40
  • I agree with the point @ImportanceOfBeingErnest is making. But if you have your reasons to continue with this approach, then setting the `Slider` attributes should work (as mentioned before). In fact, @ImportanceOfBeingErnest has an answer that should help: https://stackoverflow.com/a/47537705/6942527 – busybear Nov 12 '18 at 19:01
  • As mentioned before, could you please elaborate more and not just say "it should work"? I do not know how to define the slider attributes inside the update function to make it work. Do you have a specific recommendation? – dani reta Nov 13 '18 at 09:58

1 Answers1

0

So I just decided to make the range of the slider cover several orders of magnitude of the parameter, and display the values in a logarithmic scale. In case anyone wonders, and following the matplotlib demo:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button, RadioButtons

fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)
t = np.arange(0.0, 1.0, 0.001)
a0 = 5
f0 = 10
delta_f = 5.0
s = a0*np.sin(2*np.pi*f0*t)
l, = plt.plot(t, s, lw=2, color='red')
plt.axis([0, 1, -10, 10])

axcolor = 'lightgoldenrodyellow'
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
axamp = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)

sfreq = Slider(axfreq, 'Freq', np.log(1), np.log10(1000), valinit=np.log10(f0), valfmt='%4.2E')
samp = Slider(axamp, 'Amp', a0-5, a0+5, valinit=a0)

def update(val):
    amp = samp.val
    freq = sfreq.val
    sfreq.valtext.set_text('{:4.2E}'.format(10**freq))
    l.set_ydata(amp*np.sin(2*np.pi*10**freq*t))
    fig.canvas.draw_idle()
sfreq.on_changed(update)
samp.on_changed(update)

resetax = plt.axes([0.8, 0.025, 0.1, 0.04] )
button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975')

def reset(event):
    sfreq.reset()
    samp.reset()
button.on_clicked(reset)

rax = plt.axes([0.025, 0.5, 0.15, 0.15], facecolor=axcolor)
radio = RadioButtons(rax, ('red', 'blue', 'green'), active=0)

def colorfunc(label):
    l.set_color(label)
    fig.canvas.draw_idle()
radio.on_clicked(colorfunc)

plt.show()
dani reta
  • 69
  • 8