2

プロットを左右に移動できる2つのスライダーがある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()
4

2 に答える 2

2

svlsr.set_val関数を呼び出すと、 にupdate()登録されているオブザーバーに通知されるため、無限再帰が発生しますsvlsr。それを行うコードに興味がある人は、ここにあります。

オブザーバーは、呼び出しで指定した関数であり、svlsr.on_changedまた ... ですupdate()。そのため、再び呼び出され、再び呼び出され、次に再びupdate()呼び出されます...set_val()update()

単純なケースのソリューション

あなたが持っているコードに基づいて、上のスライダー ( sreds) は下のスライダー ( ) の値を変更しますが、svlsrその逆はありません。この場合、解決策は比較的簡単です。処理する関数sreds(例: updatesreds()) は現在のものとまったく同じでupdate()あり、別の関数 (例: )updatesvlsr()は、下のスライダーが更新されたときに何でも実行できます。でを呼び出すように変更したい場合を除き、これは機能します。その場合、同じ状況に戻ります。svlsrset_val()sreds

コードは次のようになります (例の 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)
于 2015-07-28T22:17:47.077 に答える