使用matplotlib的动画交互式绘图
问题内容:
在寻找一种使用matplotlib制作动画交互式绘图的方法时,我在堆栈溢出文档中遇到了这段代码:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.widgets import Slider
TWOPI = 2*np.pi
fig, ax = plt.subplots()
t = np.arange(0.0, TWOPI, 0.001)
initial_amp = .5
s = initial_amp*np.sin(t)
l, = plt.plot(t, s, lw=2)
ax = plt.axis([0,TWOPI,-1,1])
axamp = plt.axes([0.25, .03, 0.50, 0.02])
# Slider
samp = Slider(axamp, 'Amp', 0, 1, valinit=initial_amp)
def update(val):
# amp is the current value of the slider
amp = samp.val
# update curve
l.set_ydata(amp*np.sin(t))
# redraw canvas while idle
fig.canvas.draw_idle()
# call update function on slider value change
samp.on_changed(update)
plt.show()
这段代码几乎可以完全满足我的需求,但是我希望对绘图进行动画处理,即使滑块自动从左向右移动,例如每秒移动0.01。有没有简单的方法可以做到这一点?知道我还想将手动控件保留在滑块上(使用click事件)。
问题答案:
这是对代码的简单修改,以添加动画:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib.widgets import Slider
TWOPI = 2*np.pi
fig, ax = plt.subplots()
t = np.arange(0.0, TWOPI, 0.001)
initial_amp = .5
s = initial_amp*np.sin(t)
l, = plt.plot(t, s, lw=2)
ax = plt.axis([0,TWOPI,-1,1])
axamp = plt.axes([0.25, .03, 0.50, 0.02])
# Slider
samp = Slider(axamp, 'Amp', 0, 1, valinit=initial_amp)
# Animation controls
is_manual = False # True if user has taken control of the animation
interval = 100 # ms, time between animation frames
loop_len = 5.0 # seconds per loop
scale = interval / 1000 / loop_len
def update_slider(val):
global is_manual
is_manual=True
update(val)
def update(val):
# update curve
l.set_ydata(val*np.sin(t))
# redraw canvas while idle
fig.canvas.draw_idle()
def update_plot(num):
global is_manual
if is_manual:
return l, # don't change
val = (samp.val + scale) % samp.valmax
samp.set_val(val)
is_manual = False # the above line called update_slider, so we need to reset this
return l,
def on_click(event):
# Check where the click happened
(xm,ym),(xM,yM) = samp.label.clipbox.get_points()
if xm < event.x < xM and ym < event.y < yM:
# Event happened within the slider, ignore since it is handled in update_slider
return
else:
# user clicked somewhere else on canvas = unpause
global is_manual
is_manual=False
# call update function on slider value change
samp.on_changed(update_slider)
fig.canvas.mpl_connect('button_press_event', on_click)
ani = animation.FuncAnimation(fig, update_plot, interval=interval)
plt.show()
主要变化是update_plot
功能的添加,该功能用于FuncAnimation
在倒数第二行中添加a。动画从设置的最后一个滑块值开始递增。
该变量is_manual
跟踪用户何时单击滑块。用户单击它之后,变量将设置为True
,并且动画将不再更新绘图。
为了恢复动画,我添加了一个on_click
功能,该功能设置is_manual = False
用户何时单击画布上滑块以外的其他位置。
由于这是一个快速处理的脚本,因此我将变量保留为全局变量,但是您可以轻松地将其编写在适当的类中。
请注意,samp.set_val
隐式调用会调用该update_slider
函数,当用户直接单击滑块时也会调用该函数,因此我们必须is_manual
在该update_plot
函数中进行重置。