matplotlib Pyplot滑块未更新Jupyter Notebook中的绘图线

zdwk9cvp  于 2023-02-16  发布在  其他
关注(0)|答案(2)|浏览(119)

我尝试使用四阶龙格-库塔法来近似一阶常微分方程系统的解。我认为RK 4实现本身是正确的,如果有点不正确-它产生的图形看起来像正确的形状无论如何-但它依赖于3个常数 c,dh。我想看看当我改变这些常数时,解是如何变化的。我 * 可以 * 手动改变它们,但是我想用滑块使它具有交互性。
我希望最终有一个滑块的每一个3常数;现在,我甚至不能让一个滑动条(c 的滑动条)正常工作,它肯定是...... present,我可以来回滑动它,但是图形不会随着 c 值的变化而更新--尽管我已经为它定义了一个Slider.on_changed,并且记得用 slider 值重新调用RK 4函数并重新设置线数据:

%matplotlib notebook

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
import math

y_inits = [95, 5, 0]
c = 1
d = 5
fStepSize = 0.01
iLower = 0
iUpper = 1

tDerivatives = [
    lambda t, y1, y2, y3: -c*y1*y2,
    lambda t, y1, y2, y3: (c*y1*y2) - (d*y2),
    lambda t, y1, y2, y3: d*y2
]
   
tColors = ["blue", "red", "yellow", "green", "black", "purple"]
    
def RK4(c, d, fStepSize):
    
    tY_est = [ [y_inits[i]] for i in range(len(tDerivatives)) ]
    tT = [iLower]
    
    iRange = iUpper - iLower
    n = math.ceil(iRange / fStepSize)    
    
    for i in range(n+1)[1:]:
        
        fT_last = tT[i-1]
        fT_new = fT_last + fStepSize
        
        tK = []
        
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK1 = fStepSize * Derivative(fT_last, *[tY_est[k][i-1] for k in range(len(tY_est))])
            tK.append(["y'"+str(j+1), fK1])
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK2 = fStepSize * Derivative(fT_last + (fStepSize/2), *[tY_est[k][i-1] + (tK[k][1]/2) for k in range(len(tY_est))])
            tK[j].append(fK2)
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK3 = fStepSize * Derivative(fT_last + (fStepSize/2), *[tY_est[k][i-1] + (tK[k][2]/2) for k in range(len(tY_est))])
            tK[j].append(fK3)
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK4 = fStepSize * Derivative(fT_new, *[tY_est[k][i-1] + tK[k][3] for k in range(len(tY_est))])
            tK[j].append(fK4)    
        for j in range(len(tY_est)):
            fY_est_new = tY_est[j][i-1] + (( tK[j][1] + (2*tK[j][2]) + (2*tK[j][3]) + tK[j][4] )/6)
            tY_est[j].append(fY_est_new)
            
        tT.append(fT_new)

    return tT, tY_est 

fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)

tT_init, tY_est_init = RK4(c, d, fStepSize)
tPlots = [ ax.plot(tT_init, tY_est_init[i], marker=".", color=tColors[i]) for i in range(len(tDerivatives)) ]
plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('h = '+str(fStepSize))

axfreq = fig.add_axes([0.25, 0.1, 0.65, 0.03])
c_slider = Slider(
    ax=axfreq,
    label='c',
    valmin=0.1,
    valmax=30,
    valinit=c,
)

def Update(val):
    tT, tY_est = RK4(c_slider.val, d, fStepSize)
    for i in range(len(tPlots)):
        tPlots[i].set_data(tT, tY_est[i])
    fig.canvas.draw()

c_slider.on_changed(Update)

不会引发任何错误消息。
我应该指出,我使用this slider demo from the matplotlib site itself作为我的滑块实现的基础。* 他们的 * 代码工作得很好,即使在我的环境中,最终的绘图线也会响应滑块的变化-所以这不仅仅是“Matplotlib在Jupyter Notebook中没有交互”的问题。
我也尝试过修改Update中的fig.canvas.draw()行--也许它应该是draw_idle,或者也许我应该使用plt.draw(),或者其他一些东西,但是它们似乎都没有任何效果。
我需要做哪些更改才能使滑块响应?

**EDIT:**正如Yacine答案的注解中所讨论的,结果有两个问题。除了如何示例化这些行(参见Yacine的答案),另一个问题是上面的代码定义RK 4实际上没有将c_slider.val传递给需要它们的RK 4子例程。因此,图形 * 正在 * 更新......但每次都使用完全相同的全局 c 变量。

完整的解决方案,与所有3滑块我想要的,如下所示:

%matplotlib notebook

import matplotlib.pyplot as plt
from matplotlib.widgets import Slider, Button
import math

y_inits = [95, 5, 0]
c_init = 1
d_init = 5
fStepSize = 0.01
iLower = 0
iUpper = 1

tDerivatives = [
    lambda c, d, t, y1, y2, y3: -c*y1*y2,
    lambda c, d, t, y1, y2, y3: (c*y1*y2) - (d*y2),
    lambda c, d, t, y1, y2, y3: d*y2
]
   
tColors = ["blue", "red", "yellow", "green", "black", "purple"]
    
def RK4(c, d, fStepSize):
    
    tY_est = [ [y_inits[i]] for i in range(len(tDerivatives)) ]
    tT = [iLower]
    
    iRange = iUpper - iLower
    n = math.ceil(iRange / fStepSize)    
    
    for i in range(n+1)[1:]:
        
        fT_last = tT[i-1]
        fT_new = fT_last + fStepSize
        
        tK = []
        
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK1 = fStepSize * Derivative(c, d, fT_last, *[tY_est[k][i-1] for k in range(len(tY_est))])
            tK.append(["y'"+str(j+1), fK1])
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK2 = fStepSize * Derivative(c, d, fT_last + (fStepSize/2), *[tY_est[k][i-1] + (tK[k][1]/2) for k in range(len(tY_est))])
            tK[j].append(fK2)
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK3 = fStepSize * Derivative(c, d, fT_last + (fStepSize/2), *[tY_est[k][i-1] + (tK[k][2]/2) for k in range(len(tY_est))])
            tK[j].append(fK3)
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK4 = fStepSize * Derivative(c, d, fT_new, *[tY_est[k][i-1] + tK[k][3] for k in range(len(tY_est))])
            tK[j].append(fK4)    
        for j in range(len(tY_est)):
            fY_est_new = tY_est[j][i-1] + (( tK[j][1] + (2*tK[j][2]) + (2*tK[j][3]) + tK[j][4] )/6)
            tY_est[j].append(fY_est_new)
            
        tT.append(fT_new)

    return tT, tY_est 

fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)

plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('h = '+str(fStepSize))

c_slider = Slider(
    ax=fig.add_axes([0.25, 0.1, 0.65, 0.03]),
    label='c',
    valmin=0.1,
    valmax=5,
    valinit=c_init,
)
d_slider = Slider(
    ax=fig.add_axes([0.25, 0.06, 0.65, 0.03]),
    label='d',
    valmin=0.1,
    valmax=10,
    valinit=d_init,
)
h_slider = Slider(
    ax=fig.add_axes([0.25, 0.02, 0.65, 0.03]),
    label='h',
    valmin=0.001,
    valmax=0.1,
    valinit=fStepSize,
)

tPlots = [ax.plot([], [], marker=".", color=tColors[i])[0] for i in range(len(tDerivatives))]

def Update(val):
    fStepSize = h_slider.val
    tT, tY_est = RK4(c_slider.val, d_slider.val, fStepSize)
    for i in range(len(tPlots)):
        tPlots[i].set_data(tT, tY_est[i])
    fig.canvas.draw_idle()
    ax.relim()
    ax.autoscale_view()

c_slider.on_changed(Update)
d_slider.on_changed(Update)
h_slider.on_changed(Update)

tT_init, tY_est_init = RK4(c_init, d_init, fStepSize)
for i in range(len(tPlots)):
    tPlots[i].set_data(tT_init, tY_est_init[i])
ax.relim()
ax.autoscale_view()
plt.show()
7uzetpgm

7uzetpgm1#

我认为问题在于你需要在更新函数中设置线的数据。你在RK4函数中设置初始图的数据,但是当滑块值改变时,它不会更新图。

fig, ax = plt.subplots()
plt.subplots_adjust(left=0.25, bottom=0.25)

# create empty lists for the line data
tPlots = [ax.plot([], [], marker=".", color=tColors[i])[0] for i in range(len(tDerivatives))]

def Update(val):
    tT, tY_est = RK4(c_slider.val, d, fStepSize)
    for i in range(len(tPlots)):
        # set the data for each line
        tPlots[i].set_data(tT, tY_est[i])
    ax.relim()
    ax.autoscale_view()
    fig.canvas.draw()

# set the initial data for the lines
tT_init, tY_est_init = RK4(c, d, fStepSize)
for i in range(len(tPlots)):
    tPlots[i].set_data(tT_init, tY_est_init[i])

# add the slider
axfreq = fig.add_axes([0.25, 0.1, 0.65, 0.03])
c_slider = Slider(
    ax=axfreq,
    label='c',
    valmin=0.1,
    valmax=30,
    valinit=c,
)
c_slider.on_changed(Update)

plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('h = '+str(fStepSize))
plt.show()
hmmo2u0o

hmmo2u0o2#

还有一个选项是使用ipywidgets的interactive,让它处理与滑块的连接和响应,当提供所需值的元组时,它实际上会自己创建滑块,就像我下面提到的例子一样;但是,由于您需要初始设置,我在此处定义了滑块。
应该是这样的但是,我在将所有内容组合在一起以正确显示三行时遇到了一个小问题。**因此,现在,这只是演示了滑块处理,无法正确绘制(?!?!)。**它至少可以响应滑块的更改:

# PLOT ISN'T WORKING RIGHT BUT SLIDERS SEEM RESPONSIVE.
from ipywidgets import interactive
import ipywidgets as widgets
import matplotlib.pyplot as plt
import numpy as np

from matplotlib.widgets import Slider, Button
import math

y_inits = [95, 5, 0]
c = 1
d = 5
fStepSize = 0.01
iLower = 0
iUpper = 1

tDerivatives = [
    lambda t, y1, y2, y3: -c*y1*y2,
    lambda t, y1, y2, y3: (c*y1*y2) - (d*y2),
    lambda t, y1, y2, y3: d*y2
]
   
tColors = ["blue", "red", "yellow", "green", "black", "purple"]
    
def RK4(c, d, fStepSize):
    
    tY_est = [ [y_inits[i]] for i in range(len(tDerivatives)) ]
    tT = [iLower]
    
    iRange = iUpper - iLower
    n = math.ceil(iRange / fStepSize)    
    
    for i in range(n+1)[1:]:
        
        fT_last = tT[i-1]
        fT_new = fT_last + fStepSize
        
        tK = []
        
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK1 = fStepSize * Derivative(fT_last, *[tY_est[k][i-1] for k in range(len(tY_est))])
            tK.append(["y'"+str(j+1), fK1])
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK2 = fStepSize * Derivative(fT_last + (fStepSize/2), *[tY_est[k][i-1] + (tK[k][1]/2) for k in range(len(tY_est))])
            tK[j].append(fK2)
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK3 = fStepSize * Derivative(fT_last + (fStepSize/2), *[tY_est[k][i-1] + (tK[k][2]/2) for k in range(len(tY_est))])
            tK[j].append(fK3)
        for j in range(len(tDerivatives)):
            Derivative = tDerivatives[j]
            fK4 = fStepSize * Derivative(fT_new, *[tY_est[k][i-1] + tK[k][3] for k in range(len(tY_est))])
            tK[j].append(fK4)    
        for j in range(len(tY_est)):
            fY_est_new = tY_est[j][i-1] + (( tK[j][1] + (2*tK[j][2]) + (2*tK[j][3]) + tK[j][4] )/6)
            tY_est[j].append(fY_est_new)
            
        tT.append(fT_new)

    return tT, tY_est 


def f(c, d, fStepSize):
    #[l.remove() for l in ax.lines]
    fig, ax = plt.subplots()
    plt.subplots_adjust(left=0.25, bottom=0.25)
    plt.xlabel('t')
    plt.ylabel('y(t)')
    plt.title('h = '+str(fStepSize))
    tPlots = [ax.plot([], [], marker=".", color=tColors[i])[0] for i in range(len(tDerivatives))]

    tT, tY_est = RK4(c, d, fStepSize)
    for i in range(len(tPlots)):
        tPlots[i].set_data(tT, tY_est[i])
    plt.grid(True) #optional grid
    plt.show()

cc=widgets.FloatSlider(min=0.1,max=5,value=1) #Create an FloatSlider such that the range is [0.1,5] and default is 1
dc=widgets.FloatSlider(min=0.1,max=10,value=5) #Create an FloatSlider such that the range is [0.1,10] and default is 5
hc=widgets.FloatSlider(min=0.01,max=1,value=0.1) #Create an FloatSlider such that the range is [0.01,1] and default is 0.1
    
interactive_plot = interactive(f, c=cc, d=dc, fStepSize=hc)
interactive_plot

这基于herehere
如果ipywidgets的interactive真的有同样的情节,它的销售会更好,但也许最终我会看到这个问题并解决它。

相关问题