【问题标题】:How to use matplotlib button in conjunction with the animation function?如何结合动画功能使用matplotlib按钮?
【发布时间】:2020-12-31 20:55:40
【问题描述】:

我想编写一个代码,其中 matplotlib 中的动画函数仅在我单击 matplotlib 按钮小部件后才开始绘制。这是我的步骤:

  1. 我创建了一个空图。
  2. 我在激活点击事件的绘图上的任意位置按下鼠标,x 和 y 坐标存储在列表中。
  3. 我点击了运行动画功能的按钮。
  4. 动画函数使用存储的 x 和 y 坐标进行绘图。

我成功存储了 x 和 y 坐标,但按下按钮并没有给我所需的动画情节。这是我面临的第一个错误。

第二个错误是我的点击事件还存储了我按下按钮的坐标。我不希望在按钮按下期间坐标。我只是空地块上的坐标。

from matplotlib.widgets import Button
from matplotlib.animation import FuncAnimation

x_coord,y_coord = [],[]

fig = plt.figure()
axis = fig.add_subplot(111,xlim=(-5,15),ylim=(-5,15))
line, = axis.plot([],[],lw=3)

def init():
    line.set_data([],[])
    return line, 

def animate(i):
    x_points = [0,x_coord[i]]
    y_points = [0,y_coord[i]]
    line.set_data(x_points,y_points)
    return line, 

def onclick(event):
    print(event.xdata,event.ydata)
    x_coord.append(event.xdata)
    y_coord.append(event.ydata)


def buttonPress(pressevent):
    print('pressed')
    print(x_coord)
    ani = FuncAnimation(fig,animate,init_func=init,frames=len(x_coord),interval=100,blit=False)
    
    

cid = fig.canvas.mpl_connect('button_press_event',onclick)

axprev = plt.axes([0.5,0,0.1,0.1])
button = Button(axprev,'press')
button.on_clicked(buttonPress)

plt.show()```

【问题讨论】:

    标签: python python-3.x matplotlib


    【解决方案1】:

    第二个错误很容易修复,你可以使用event.inaxes来测试点击是在坐标区还是在坐标区之外

    动画问题是由于您在函数中创建动画对象,并且它在函数结束时立即被垃圾收集。 [FuncAnimation][2] 的文档说明:

    保持对实例对象的引用至关重要。这 动画由计时器推进(通常来自主机 GUI 框架),动画对象持有唯一的引用。如果 您没有对 Animation 对象的引用,它(因此 计时器),将被垃圾收集,这将停止动画。

    解决此问题的一种方法是将动画对象保存在全局变量中。一种更简洁的方法是将代码封装在自定义类中,并将动画存储为该类的属性。

    import matplotlib.pyplot as plt
    from matplotlib.animation import FuncAnimation
    from matplotlib.widgets import Button
    
    x_coord, y_coord = [], []
    
    fig = plt.figure()
    axis = fig.add_subplot(111, xlim=(-5, 15), ylim=(-5, 15))
    line, = axis.plot([], [], lw=3)
    ani = None
    
    
    def init():
        line.set_data([], [])
        return line,
    
    
    def animate(i):
        x_points = [0, x_coord[i]]
        y_points = [0, y_coord[i]]
        line.set_data(x_points, y_points)
        return line,
    
    
    def onclick(event):
        if event.inaxes is axis:
            print(event.xdata, event.ydata)
            x_coord.append(event.xdata)
            y_coord.append(event.ydata)
    
    
    def buttonPress(pressevent):
        global ani
        print('pressed')
        print(x_coord)
        ani = FuncAnimation(fig, animate, init_func=init, frames=len(x_coord), interval=100, blit=False)
    
    
    cid = fig.canvas.mpl_connect('button_press_event', onclick)
    
    axprev = plt.axes([0.5, 0, 0.1, 0.1])
    button = Button(axprev, 'press')
    button.on_clicked(buttonPress)
    
    plt.show()
    

    【讨论】:

    • event.inaxes 对我不起作用。同样的问题仍然存在。我有一个新问题,即动画后情节会自行清除。我想在动画后保留情节。感谢您的回答。
    • 是的,我忘记了按钮位于坐标区本身。您可以测试event.inaxes is axis 以测试点击是否在数据轴内而不是按钮轴内。我在我的代码中修复了这个问题。
    • 对于第二个问题,这取决于你想做什么。如果您只想保留最后一帧,您可以在对FuncAnimation 的调用中传递repeat=False。如果要显示所有帧,则必须更改代码,以便在到达最后一帧时绘制所有行。我确定在 SO 上有与此相关的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多