Matplotlib根据另一个滑块的更改更新一个滑块

时间:2020-10-19 03:50:02

标签: python matplotlib slider

我使用matplotlib生成带有2个滑块的简单图,这些滑块控制图上的移动点-向用户展示x或y的变化如何影响该点的位置。我需要这些滑块相互共享信息-如果其中之一发生更改,则另一个将根据更改后的值更新其值(例如,如果控制x的滑块发生了变化,那么控制y的滑块就会被更新,反之亦然)。

我已经在stackoverflow上进行了研究,并尝试实现两个解决方案(下面的代码注释掉了第一个尝试)而没有成功。我尝试的最后一次迭代似乎有效,但是过了一会儿它冻结了情节。

我的代码是:

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)
# Define x values and y function, y = f(2x**2)
x = np.arange(0.0, 11., 1.)
y = x**2
fxplot, = plt.plot(x, y, lw=2)

#define the bullet point to slide on the function
x0=2.
y0=x0**2
x0_old = x0
y0_old = y0
ptplot, = plt.plot(x0, y0, 'ko')

# Define the sliders
axcolor = 'lightgoldenrodyellow'
ax_x = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
ax_y = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)

xSlider = Slider(ax_x, 'x', 0.0, 10.0, valinit=x0, valstep=1)
ySlider = Slider(ax_y, 'y', 0.0, 10.0**2, valinit=y0, valstep=1)

# Update function; movement of one slider updates the other
# by reinitializing it
def update(val):
    global x0_old, y0_old
    x0 = xSlider.val
    y0 = ySlider.val
    
#   Detect change in y0
    if x0 == x0_old:
        print('y0 changed',y0,y0_old)
        ptplot.set_xdata(np.sqrt(y0))
        ptplot.set_ydata(y0)
        y0_old = y0
##        ax_x.clear()
##        xSlider.__init__(ax_x, 'x', 0.0, 10.0, valinit=np.sqrt(y0), valstep=1) 
        xSlider.valinit = np.sqrt(y0)
        xSlider.reset()
        
#   Detect change in x0
    if y0 == y0_old:
        print('x0 changed',x0,x0_old)
        ptplot.set_xdata(x0)
        ptplot.set_ydata(x0**2)        
        x0_old = x0
##        ax_y.clear()
##        ySlider.__init__(ax_y, 'y', 0.0, 10.0**2, valinit=y0, valstep=1)
        ySlider.valinit = x0**2
        ySlider.reset()

    print('\n')
    plt.gcf().canvas.draw_idle()

xSlider.on_changed(update)
ySlider.on_changed(update)

plt.show()

我希望这是一个简单的修复程序,但是不幸的是,我看不到它,我希望那里的人在使用能够帮助您的滑块方面有更多的经验。

谢谢。

1 个答案:

答案 0 :(得分:1)

明显的解决方法是调用Slider.set_val(),但是,由于调用set_val()会触发回调,从而调用set_val()等,因此会产生无限递归错误。

非常感谢,可以通过指示小部件不要使用the (undocumented) property Widget.eventson来调用回调函数来防止错误

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)
# Define x values and y function, y = f(2x**2)
x = np.arange(0.0, 11., 1.)
f = lambda x: x**2
g = lambda x: np.sqrt(x)
y = f(x)
fxplot, = plt.plot(x, y, lw=2)

#define the bullet point to slide on the function
x0=2.
y0=f(x0)
ptplot, = plt.plot(x0, y0, 'ko')

# Define the sliders
axcolor = 'lightgoldenrodyellow'
ax_x = plt.axes([0.25, 0.15, 0.65, 0.03], facecolor=axcolor)
ax_y = plt.axes([0.25, 0.1, 0.65, 0.03], facecolor=axcolor)

xSlider = Slider(ax_x, 'x', 0.0, 10.0, valinit=x0, valstep=1)
ySlider = Slider(ax_y, 'y', f(0.0), f(10.0), valinit=y0, valstep=1)

def update_x(x):
    y = f(x)
    ptplot.set_data(x, y)
    ySlider.eventson = False
    ySlider.set_val(y)
    fig.canvas.draw()
    ySlider.eventson = True

def update_y(y):
    x = g(y)
    ptplot.set_data(x, y)
    xSlider.eventson = False
    xSlider.set_val(x)
    fig.canvas.draw()
    xSlider.eventson = True

xSlider.on_changed(update_x)
ySlider.on_changed(update_y)

plt.show()