0

I have a df consisting of two different frames for each observation, denoted by the ending character in the variable

     name x1 y1 x2 y2
0    bob  3  2  1  4
1    amy  2  1  4  3
2    pam  6  3  3  1
3    joe  4  2  6  5

I am wondering how to create an animation consisting of two frames ([x1,y1],[x2,y2]). I have seen resources on how to create animations with line and bar charts, but I couldn't find much info on scatterplot animations.

The response to this question seems a bit complicated for my application.

Things I have tried:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

fig = plt.figure(figsize=(5,5))
scatter=ax.scatter(df["x1"], df["y1"])

def animate():
    scatter.set_data(df[['x2','y2'])

Is my dataframe set up correctly for this? I would also like to annotate these points, but I know how to do that with the adjustText package, so that isn't a problem here, right? I'm assuming I don't have to set the annotations like I have to set the data.

Any help is appreciated. Thanks!

1 Answer 1

1

The answer in the linked question mentions that in order to change the data of a scatter plot you do

scatter.set_offsets(array)

A few other things to notice from there, or from reading the docs/other resources, is that the animate function requires an argument, which is the current frame you're on. You're also supposed to return as a tuple the artists you want to animate. So at minimum it should look like the following:

def animate(i):
    scatter.set_offsets(<the respective (4, 2) array for ith frame>)
    return scatter,

If you want to include annotations in your animation, you also have to return those artists. In that case, I suggest putting everything in a tuple and accessing them by index. Here is a simple example for your two frames + the annotation of each point's respective name:

from matplotlib.animation import FuncAnimation
import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame(
     [['bob', 3, 2, 1, 4], ['amy', 2, 1, 4, 3], ['pam', 6, 3, 3, 1], ['joe', 4, 2, 6, 5]],
     columns=['name', 'x1', 'y1', 'x2', 'y2'])

def animate(i):
     columns = df.columns[1:]
     data = df[columns[2*i:2*i+2]].to_numpy()
     # You can also do `scatter.set_offsets()` and `zip(annnotations, data)`
     artists[0].set_offsets(data)
     for ann, (x, y) in zip(artists[1:], data):
          ann.set_x(x)
          ann.set_y(y)
     return artists,

fig = plt.figure(figsize=(5,5))
scatter = plt.scatter([], [])   # whatever, it'll change every frame
annotations = tuple(plt.annotate(df['name'].iloc[i], (0, 0)) for i in range(len(df)))
artists = (scatter,) + annotations
# Setting them manually here; all points in all frames should be visible
plt.xlim(0, 7)
plt.ylim(0, 7)
anim = FuncAnimation(fig, animate, frames=2)
plt.show()
Sign up to request clarification or add additional context in comments.

2 Comments

Awesome! Is there a way to do a sliding transition, rather than just cutting to the second set of data points? That is, can there be a smoother transition between the two frames somehow? @Reti43
@bismo Not that I know of with matplotlib's FuncAnimation, but it's worth asking a new question about it. If no options exist for creating smooth transitions between frames, I would simple add a lot more frames in the between and interpolate the points' movement. After all, you have a start and end point, so figuring out their line of motion and speed shouldn't be hard.

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.