我正在使用matplotlib编写一个脚本,其中我有两个可以左右移动绘图的滑块。我想这样做,如果我移动一个滑块,另一个滑块也会更新。我以为我可以使用Slider.set_val(val)方法,但这会让我陷入无限循环。滑块的功能是沿x轴拉伸或压缩图形线。如果运行代码,您将看到一个滑块比另一个更“粗糙”,它会更多地拉伸图形,另一个允许用户进行微调。我最终需要人们能够轻松读取绝对拉伸量,这就是为什么我希望将值链接起来。我目前有以下代码:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import sys
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 = 3
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'
d0 = 0.0
c = 300000
z0 = d0/c
vmin = -300.0
vmax = 3000.0
zmin = -0.01
zmax = 2
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
axz = plt.axes([0.25, 0.15, 0.65, 0.03], axisbg=axcolor)
svlsr = Slider(axfreq, 'VLSR', vmin, vmax, valinit=d0, valfmt=u'%1.1f')
sreds = Slider(axz, 'z', zmin, zmax, valinit=z0, valfmt=u'%1.4f')
def update(val):
global d0, z0
delt = svlsr.val/c
z = sreds.val
if z!=0.0:
if z != z0:
delt = z
svlsr.set_val(z*c) #set_val causes infinite loop??
d0 = delt
z0 = z
fac = 1.0 + delt
l.set_xdata(t*fac)
fig.canvas.draw_idle()
svlsr.on_changed(update)
sreds.on_changed(update)
plt.show()
答案 0 :(得分:2)
You get the infinite recursion because when you call svlsr.set_val
in the update()
function this notifies any observer registered on svlsr
. For anyone interested the code that does that is here.
The observer is the function you specified in the call to svlsr.on_changed
and is ... update()
again. So, update()
will be called again, which will call set_val()
again, then update()
again and so on...
Based on the code you have, the top slider (sreds
) changes the value on the bottom one (svlsr
) but not vice versa. If this is the case, then the solution is relatively easy. You can have one function to deal with sreds
(e.g. updatesreds()
) which could be exactly the same as your current update()
and a different one (e.g. updatesvlsr()
) doing whatever you want when the bottom slider updates. This will work unless you want a change in svlsr
to call set_val()
on sreds
, in which case you are back in the same situation.
The code would look something like this (replacing line 33 onwards in your example):
def updatereds(val):
global d0, z0
delt = svlsr.val/c
z = sreds.val
if z!=0.0:
if z != z0:
delt = z
svlsr.set_val(z*c) #set_val causes infinite loop??
d0 = delt
z0 = z
fac = 1.0 + delt
l.set_xdata(t*fac)
fig.canvas.draw_idle()
def updatesvlsr(val):
# put any code you need to execute on direct update to svlsr here
# the only thing you can't do is set_val on sreds, otherwise again
# you will infinitely recurse
pass
svlsr.on_changed(updatesvlsr)
sreds.on_changed(updatereds)
答案 1 :(得分:0)
我发现有一个破解方法。定义一个单独的功能,例如“ donothing”功能,该功能什么也不做。然后,在设置update函数中的svlsr值之前,将svlsr绑定从update更改为donothing,以便调用donothing函数而不是'update'。在set_value之后,重新绑定svlsr滑块以更新功能。这是完整的代码:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
import sys
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 = 3
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'
d0 = 0.0
c = 300000
z0 = d0/c
vmin = -300.0
vmax = 3000.0
zmin = -0.01
zmax = 2
axfreq = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)
axz = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
svlsr = Slider(axfreq, 'VLSR', vmin, vmax, valinit=d0, valfmt=u'%1.1f')
sreds = Slider(axz, 'z', zmin, zmax, valinit=z0, valfmt=u'%1.4f')
def donothing(val): #The dummy function
pass
def update(val):
global d0, z0
delt = svlsr.val/c
z = sreds.val
svlsr.observers[svlsrcid] = donothing #Binding removed from update
if z!=0.0:
if z != z0:
delt = z
svlsr.set_val(z*c) #set_val causes infinite loop?? Now it doesn't.
svlsr.observers[svlsrcid] = update #Binded again with update
d0 = delt
z0 = z
fac = 1.0 + delt
l.set_xdata(t*fac)
fig.canvas.draw_idle()
svlsrcid = svlsr.on_changed(update) #Getting the id of the binding
sredscid = sreds.on_changed(update)
plt.show()
仅删除带有断开连接的绑定将不起作用,因为它将产生“ RuntimeError:字典在迭代期间更改大小”错误。