How to Animate a Scatter Plot

Animate scatter plot with colorbar using matplotlib

I'm not sure if you were indicating this from your post, but I couldn't get your code to run as is. However, I believe the main issue relates to the first point you mention: "After each animation step, the old points should be removed." You do need to be explicit about this when drawing the animation. Currently, your code is repeatedly creating a scatter for the same Axes. Just as if you were to do this outside of an animation, this will result in multiple sets of data being drawn over each other.

I have seen 2 major ways people do this: either using some set_... methods of the plot to update the data (seen here for scatter plots or here in general) or clearing the Axes or Figure each iteration in order to plot new data. I find the latter easier/more universal (if lazier). Here is an approach for your example doing so (I've edited this code to remove calls to plt.grid and plt.label, as those were not functional):

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

time_steps = 50
N_nodes = 100

positions = []
solutions = []
for i in range(time_steps):
positions.append(np.random.rand(2, N_nodes))
solutions.append(np.random.random(N_nodes))

fig, ax = plt.subplots()
marker_size = 5 #upped this to make points more visible

def animate(i):
""" Perform animation step. """
#important - the figure is cleared and new axes are added
fig.clear()
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, xlim=(0, 1), ylim=(0, 1))
#the new axes must be re-formatted
ax.set_xlim(0,1)
ax.set_ylim(0,1)
ax.grid(b=None)
ax.set_xlabel('x [m]')
ax.set_ylabel('y [m]')
# and the elements for this frame are added
ax.text(0.02, 0.95, 'Time step = %d' % i, transform=ax.transAxes)
s = ax.scatter(positions[i][0], positions[i][1], s = marker_size, c = solutions[i], cmap = "RdBu_r", marker = ".", edgecolor = None)
fig.colorbar(s)

ani = animation.FuncAnimation(fig, animate, interval=100, frames=range(time_steps))

ani.save('animation.gif', writer='pillow')

Producing the following GIF:

Sample Image

Here, I use fig.clear() to clear the colorbar each frame; otherwise, many of them will be drawn. This means you have to re-add the Axes and the formatting each time. In other cases, using ax.clear() can be fine and save the step of add_subplot.

There is another way to do this however, following here. If you have the handle for the colorbar Axes, you can just clear them (rather than clearing the entire Figure), similar to the scatter plot axes:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np

time_steps = 50
N_nodes = 100

positions = []
solutions = []
for i in range(time_steps):
positions.append(np.random.rand(2, N_nodes))
solutions.append(np.random.random(N_nodes))

# init the figure, so the colorbar can be initially placed somewhere
marker_size = 5
fig = plt.figure()
ax = fig.add_subplot(111, aspect='equal', autoscale_on=False, xlim=(0, 1), ylim=(0, 1))
s = ax.scatter(positions[0][0], positions[0][1], s = marker_size, c = solutions[0], cmap = "RdBu_r", marker = ".", edgecolor = None)
cb = fig.colorbar(s)

# get the axis for the colobar
cax = cb.ax

def animate(i):
""" Perform animation step. """
# clear both plotting axis and colorbar axis
ax.clear()
cax.cla()
#the new axes must be re-formatted
ax.set_xlim(0,1)
ax.set_ylim(0,1)
ax.grid(b=None)
ax.set_xlabel('x [m]')
ax.set_ylabel('y [m]')
# and the elements for this frame are added
ax.text(0.02, 0.95, 'Time step = %d' % i, transform=ax.transAxes)
s = ax.scatter(positions[i][0], positions[i][1], s = marker_size, c = solutions[i], cmap = "RdBu_r", marker = ".", edgecolor = None)
fig.colorbar(s, cax=cax)

ani = animation.FuncAnimation(fig, animate, interval=100, frames=range(time_steps))

ani.save('animation2.gif', writer='pillow')

Producing the same figure.

Animate scatter points and line in matplotlib

I added simple condition to sc_2.

    if i == len(x):
sc_2.set_offsets([x_end, y_end])

Code that I tested:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation

fig, ax = plt.subplots()

x_start, y_start = (0, 0)
x_end, y_end = (90, 90)

x_1, y_1 = 0, 0
x_2, y_2 = 90, 90

plt.xlim((0, 100))
plt.ylim((0,100))

x = np.linspace(x_1, x_2, 50)
y = np.linspace(y_1, y_2, 50)

sc_1 = ax.scatter([], [], color="green", zorder=4)
line, = ax.plot([], [], color="crimson", zorder=4)
sc_2 = ax.scatter([], [], color="gold", zorder=4)

def animate(i):
## plot scatter point
sc_1.set_offsets([x_start, y_start])

## plot line
line.set_data(x[:i], y[:i])

## plot scatter point
if i == len(x):
sc_2.set_offsets([x_end, y_end])

return sc_1, line, sc_2

ani = animation.FuncAnimation(
fig=fig, func=animate, interval=100, blit=True, save_count=50)

plt.show()

Animating a scatter plot with a stationary gap in python

Define the gap when you load the data, and do so in the x column rather than the y:

# imports

my_data = genfromtxt("sample.csv", delimiter=",", skip_header=1) # reading data
gap_loc = [19,20,21] # location of a gap
my_data[gap_loc, 0] = np.nan # creating a gap in graph

# plotting code

So now when you roll the x column, there will always be np.nan at the x values [19, 20, 21], regardless of what the y coordinate is. You can use print(my_data) within the update function to make clear what was going on each iteration.

Here is the result:

Sample Image

Also, I think you are over-plotting because you continually expand xdata and ydata using append. I ended up just removing the xdata and ydata and doing:

def update(frame):
my_data[:,0] = np.roll(my_data[:,0],1) # moving graph
line.set_data(my_data[:,0], my_data[:,1])
return line,

3D scatter plot animation

In the animation function was looped by the size of the data frame, but rewrote your code partly because the animation argument is linked to the number of frames. Please correct me if I'm wrong. You can also pass in the size with graph.set_sizes(), which you can specify there. Your size variable had a negative value, so I'm recreating it as an integer. I've used a separate library in part because of my working environment.

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.animation as animation
from IPython.display import HTML # Animation on jupyter lab
from matplotlib.animation import PillowWriter # For GIF animation
#####Data Generation####

# Space Coordinate
X = np.random.random((100,)) * 255 * 2 - 255
Y = np.random.random((100,)) * 255 * 2 - 255
Z = np.random.random((100,)) * 255 * 2 - 255

# Magnitude of each point
# M = np.random.random((100,))*-1+0.5
M = np.random.randint(1,70, size=100)
# Time
t = np.sort(np.random.random((100,))*10)

#ID each point should be color coded. Moreover, each point belongs to a cluster `ID`
ID = np.sort(np.round([np.random.random((100,))*5]))

x = []
y = []
z = []
m = []

def update_lines(i):
# for i in range (df_IS["EASTING [m]"].size):
dx = X[i]
dy = Y[i]
dz = Z[i]
dm = M[i]
# text.set_text("{:d}: [{:.0f}] Mw[{:.2f}]".format(ID[i], t[i],ID[i])) # for debugging
x.append(dx)
y.append(dy)
z.append(dz)
m.append(dm)
graph._offsets3d = (x, y, z)
graph.set_sizes(m)
return graph,

fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
graph = ax.scatter(X, Y, Z, s=M, color='orange') # s argument here
text = fig.text(0, 1, "TEXT", va='top') # for debugging

ax.set_xlim3d(X.min(), X.max())
ax.set_ylim3d(Y.min(), Y.max())
ax.set_zlim3d(Z.min(), Z.max())

# Creating the Animation object
ani = animation.FuncAnimation(fig, update_lines, frames=100, interval=500, blit=False, repeat=False)
# plt.show()
ani.save('test3Dscatter.gif', writer='pillow')
plt.close()
HTML(ani.to_html5_video())

Sample Image

Edit:

# Time
t = np.sort(np.random.random((100,))*10)

# datapoint for color
cm_name = 'jet'
cm = plt.get_cmap(cm_name, 100)
C = [cm(n) for n in range(cm.N)]

# list for colors add
x = []
y = []
z = []
m = []
c = []

# animation function update

dm = M[i]
dc = C[i] # update

m.append(dm)
c.append(dc) # update

graph._facecolor3d = c # scatter color defined
return graph,


Related Topics



Leave a reply



Submit