matplotlib FuncAnimation 不会在按钮按下小部件事件时启动



matplotlib noob。

我正在尝试创建一个正在填充的正态分布的动画(从点击按钮开始(,其中使用两个滑块窗口小部件选择分布参数(mean和std-dev(。

请帮忙。我已经在下面粘贴了我的代码

%matplotlib notebook
from pdb import set_trace as bp
import matplotlib.animation as animation
import numpy as np
from matplotlib.widgets import Slider, Button, RadioButtons

fig = plt.figure()
n = 1000
x = np.array([])
bins = np.arange(-4, 4, 0.5)
plt.hist(x, bins=bins)
plt.subplots_adjust(bottom=0.25)
def update(curr):
if curr == n: 
a.event_source.stop()
plt.cla()
plt.hist(x[:curr], bins=bins)
plt.axis([-4,4,0,500])
plt.gca().set_title('Sampling the Normal Distribution')
plt.gca().set_ylabel('Frequency')
plt.gca().set_xlabel('Value')
plt.annotate('n = {}'.format(curr), [3,480])
axcolor = 'lightgoldenrodyellow'
axmu = plt.axes([0.15, 0.1, 0.65, 0.03], facecolor=axcolor)
axstdev = plt.axes([0.15, 0.15, 0.65, 0.03], facecolor=axcolor)
muslider = Slider(axmu, 'mean', 0.1, 30.0, valinit=0)
stdevslider = Slider(axstdev, 'stdev', 0.1, 10.0, valinit=1.0)
startax = plt.axes([0.4, 0.025, 0.1, 0.04])
startbutton = Button(startax, 'Start', color=axcolor, hovercolor='0.975')
newmean = 0
newstdev = 1.0
def getnewparams(val):
global newmean
global newstdev
newmean = muslider.val
newstdev = stdevslider.val

def startanimation(event):
print(f"params now is {newmean} {newstdev}")
global x
x = np.random.normal(loc=newmean, scale=newstdev, size=n)
a = animation.FuncAnimation(fig, update, interval=100)
a.event_source.start()

muslider.on_changed(getnewparams)
stdevslider.on_changed(getnewparams)
startbutton.on_clicked(startanimation)

我的情节现在看起来怎么样

使用@jasonharper的建议,我能够自己解决这个问题。我正在下面粘贴工作代码

%matplotlib notebook
import matplotlib.pyplot as plt
from pdb import set_trace as bp
import matplotlib.animation as animation
import numpy as np
from matplotlib.widgets import Slider, Button, RadioButtons

fig = plt.figure()
n = 1000
a = None
x = np.array([])
# bins = np.arange(-4, 4, 0.5)
plt.hist(x, bins=bins)
plt.subplots_adjust(bottom=0.25)
histaxis = plt.gca()
def update(curr):
if curr == n: 
a.event_source.stop()
histaxis.cla()
histaxis.hist(x[:curr], bins=100)
# histaxis.axis([-4,4,0,500])
histaxis.set_title('Sampling the Normal Distribution')
histaxis.set_ylabel('Frequency')
histaxis.set_xlabel('Value')
histaxis.annotate('n = {}'.format(curr), [3,480])
axcolor = 'lightgoldenrodyellow'
axmu = plt.axes([0.15, 0.1, 0.65, 0.03], facecolor=axcolor)
axstdev = plt.axes([0.15, 0.15, 0.65, 0.03], facecolor=axcolor)
muslider = Slider(axmu, 'mean', 0.1, 30.0, valinit=0)
stdevslider = Slider(axstdev, 'stdev', 0.1, 10.0, valinit=1.0)
startax = plt.axes([0.4, 0.025, 0.1, 0.04])
startbutton = Button(startax, 'Start', color=axcolor, hovercolor='0.975')
newmean = 0
newstdev = 1.0
def getnewparams(val):
global newmean
global newstdev
newmean = muslider.val
newstdev = stdevslider.val

def startanimation(event):
print(f"params now is {newmean} {newstdev}")
global x
x = np.random.normal(loc=newmean, scale=newstdev, size=n)
global a
a = animation.FuncAnimation(fig, update, interval=100)
a.event_source.start()

muslider.on_changed(getnewparams)
stdevslider.on_changed(getnewparams)
startbutton.on_clicked(startanimation)

我刚刚遇到了一个类似的问题,多亏了jasonharper的评论,我才得以解决。我仍然想简要地提供一个最小的工作示例,以防其他人再次遇到这个问题。

%matplotlib widget
import numpy as np
import ipywidgets as widgets
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# Initialize global variables
global anim
anim = None
# Initialize x and y
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(2*np.pi*x)
# Create plot
fig, ax = plt.subplots()
line, = ax.plot(x, y)
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1.1, 1.1)
def update(curr, anim, T=1):
if curr == 100:
anim.pause()

# Update y
y = np.sin(2*np.pi*(x/T +  curr/100))
line.set_data((x, y))
return line

def start_animation(event):
# Generate random period
T = np.random.randint(1, 10)

# Stop existing animations
global anim
if anim is not None:
anim.pause()

# Create new animation
anim = FuncAnimation(fig, update, fargs=(anim,T), interval=100, blit=True)
fig.canvas.draw_idle()

def stop_animation(event):
global anim
if anim is not None:
# Stop animation
anim.pause()
anim = None

# Create button
start_btn = widgets.Button(description='Start')
stop_btn = widgets.Button(description='Stop')
# Link button to callback function
start_btn.on_click(start_animation)
stop_btn.on_click(stop_animation)
# Display buttons
display(start_btn, stop_btn)
# Turn off interactive mode
plt.ioff();

最新更新