I am using matplotlib's Slider to do a simple dynamic plot of a sine curve. I want to change the frequency using a slider. The code looks like this:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
x = np.linspace(400, 800, 400)
fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.25)
mod = 1.
lambda_plot, = ax.plot(x, np.sin(mod*x*2*np.pi/500))
ax_mod_slider = fig.add_axes([0.3, 0.1, 0.5, 0.04])
mod_slider = Slider(
ax = ax_mod_slider,
label = "modulation",
valmin = 0,
valmax = 20,
valinit = 1.,
orientation = "horizontal")
def update_mod(val):
mod = mod_slider.val
redraw()
fig.canvas.draw_idle()
def redraw():
lambda_plot.set_ydata(np.sin(mod*x*2*np.pi/500))
mod_slider.on_changed(update_mod)
plt.show()
This does only work if I put the code in redraw() directly in update_mod(), like this:
def update_mod(val):
mod = mod_slider.val
lambda_plot.set_ydata(np.sin(mod*x*2*np.pi/500))
fig.canvas.draw_idle()
Why can I not call another function for changing the plot? In this example, I could put it all into update_mod(), but as I do more complicated calculations, I thought it might be good to be able to split update_mod() into separate functions.
In the redraw()
function:
def redraw():
lambda_plot.set_ydata(np.sin(mod * x * 2 * np.pi / 500))
You're using the variable mod
, but this mod
is not defined in the local scope of redraw()
, nor is it properly declared as global or passed as an argument. So Python looks for it in the outer scope and finds the mod = 1.
you defined at the beginning of the script which never changes.
When update_mod()
changes mod
, it does so in its local scope, and that doesn't affect the mod
that redraw()
sees.
Just pass the mod
value and it should work properly:
def redraw(mod):
lambda_plot.set_ydata(np.sin(mod * x * 2 * np.pi / 500))