将两个matplotlib滑块链接到一起

2024-09-29 19:27:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在用matplotlib编写一个脚本,其中有两个滑块可以左右移动绘图。我想让它这样,如果我移动一个滑块,另一个滑块也会更新。我想我可以用滑块设置值(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()

Tags: importmatplotlibnpupdatepltvalslider滑块
2条回答

您得到无限递归,因为当您在update()函数中调用svlsr.set_val时,它会通知在svlsr上注册的任何观察者。对于任何感兴趣的人,执行此操作的代码是here。在

observer是您在调用svlsr.on_changed中指定的函数,它是。。。update()又来了。因此,update()将再次被调用,它将再次调用set_val(),然后再次调用{},依此类推。。。在

简单情况下

根据您的代码,顶部滑块(sreds)会更改底部滑块(svlsr)上的值,但反之亦然。如果是这样,那么解决方案就相对容易了。您可以有一个函数来处理sreds(例如updatesreds()),它可能与当前的update()完全相同,而另一个函数(例如updatesvlsr())在底部滑块更新时做任何你想做的事情。除非您希望在svlsr中对set_val()调用sreds上的set_val(),否则这将有效。在

代码如下所示(替换示例中的第33行):

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)

我找到了一个黑客来做这个。定义一个单独的函数,比如“donothing”函数,它什么也不做。然后,在update函数内设置svlsr的值之前,将svlsr绑定从update更改为donothing,以便调用donothing函数而不是update。设置好_值后,将svlsr滑块重新绑定到update函数。以下是完整代码:

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()

只删除带有disconnect的绑定将不起作用,因为它将给出“RuntimeError:dictionary changed size during iteration”错误。在

相关问题 更多 >

    热门问题