0

I want to write a code where the animation function in matplotlib starts plotting only after the matplotlib button widget is clicked by me. Here are my steps:

  1. I create a empty plot.
  2. I press my mouse anywhere on the plot which activates click events and the x and y coordinates are stored in a list.
  3. I click on press button which runs the animation function.
  4. The animation function plots by using the stored x and y coordinates.

I got successful in the storing the x and y coordinates but the press button doesn't give me the animated plot that I need. This is the first error I am facing.

The second error is my click event also stores the coordinates of where I press the button. I don't want coordinates during button press. I just the coordinates on the empty plot.

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()```

1 Answer 1

1

The second error is easy to fix, you can test whether the click was in or out of the axes region by using event.inaxes

The animation issue is due to the fact that you are creating the animation object in a function, and that it is immediately garbage-collected at the end of the function. The [documentation for FuncAnimation][2] states:

it is critical to keep a reference to the instance object. The animation is advanced by a timer (typically from the host GUI framework) which the Animation object holds the only reference to. If you do not hold a reference to the Animation object, it (and hence the timers), will be garbage collected which will stop the animation.

One way to get around that is to keep the animation object in a global variable. A cleaner way would be to encapsulate your code in a custom class and store the animation as a property of that class.

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()
Sign up to request clarification or add additional context in comments.

3 Comments

event.inaxes doesn't work for me. The same problem persists. I have a new problem which is the plot clears itself after animation. I want to retain the plot after animation. Thanks for the answer.
Yes, I forgot that the button is located in axes itself. You can test event.inaxes is axis to test that the click is inside the data axes and not the button axes. I fixed that in my code.
for the second question, it depends what you want to do. You can pass repeat=False in the call to FuncAnimation if you just want to keep the last frame. If you want to show all frames, then you will have to change your code so that it draws all the lines when it gets to the last frame. I'm sure there are questions related to this on SO

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.