Saving scatterplot animations

2024/9/16 22:58:39

I've been trying to save an animated scatterplot with matplotlib, and I would prefer that it didn't require totally different code for viewing as an animated figure and for saving a copy. The figure shows all the datapoints perfectly after the save completes.

This code is a modified version of Giggi's on Animating 3d scatterplot in matplotlib, with a fix for the colors from Yann's answer on Matplotlib 3D scatter color lost after redraw (because colors will be important on my video, so I want to make sure they work).

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3DFLOOR = -10
CEILING = 10class AnimatedScatter(object):def __init__(self, numpoints=5):self.numpoints = numpointsself.stream = self.data_stream()self.angle = 0self.fig = plt.figure()self.fig.canvas.mpl_connect('draw_event',self.forceUpdate)self.ax = self.fig.add_subplot(111,projection = '3d')self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, init_func=self.setup_plot, blit=True,frames=20)def change_angle(self):self.angle = (self.angle + 1)%360def forceUpdate(self, event):self.scat.changed()def setup_plot(self):X = next(self.stream)c = ['b', 'r', 'g', 'y', 'm']self.scat = self.ax.scatter(X[:,0], X[:,1], X[:,2] , c=c, s=200, animated=True)self.ax.set_xlim3d(FLOOR, CEILING)self.ax.set_ylim3d(FLOOR, CEILING)self.ax.set_zlim3d(FLOOR, CEILING)return self.scat,def data_stream(self):data = np.zeros(( self.numpoints , 3 ))xyz = data[:,:3]while True:xyz += 2 * (np.random.random(( self.numpoints,3)) - 0.5)yield datadef update(self, i):data = next(self.stream)#data = np.transpose(data)self.scat._offsets3d = ( np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,1]) , np.ma.ravel(data[:,2]) )plt.draw()return self.scat,def show(self):plt.show()if __name__ == '__main__':a = AnimatedScatter()a.ani.save("movie.avi", codec='avi')a.show()

A perfectly valid .avi is generated by this, but it's blank for all of the four seconds except for the axes. The actual figure always shows exactly what I want to see. How can I populate the save function's plots the same way I populate a normally running animation, or is it possible in matplotlib?

EDIT: Using a scatter call in the update (without setting the bounds as in the initializer) causes the .avi to show the axes growing, showing that the data is being run each time, it's just not showing on the video itself. I am using matplotlib 1.1.1rc with Python 2.7.3.

Answer

Remove blit=True from FuncAnimation and animated=True from scatter and it works. I suspect that there is something going wrong with the logic that makes sure only the artists that need to be updated are updated/redrawn between frames (rather than just re-drawing everything).

Below is exactly what I ran and I got the expected output movie:

import matplotlib.pyplot as plt
import matplotlib.animation as animation
import numpy as np
from mpl_toolkits.mplot3d import Axes3DFLOOR = -10
CEILING = 10class AnimatedScatter(object):def __init__(self, numpoints=5):self.numpoints = numpointsself.stream = self.data_stream()self.angle = 0self.fig = plt.figure()self.fig.canvas.mpl_connect('draw_event',self.forceUpdate)self.ax = self.fig.add_subplot(111,projection = '3d')self.ani = animation.FuncAnimation(self.fig, self.update, interval=100, init_func=self.setup_plot, frames=20)def change_angle(self):self.angle = (self.angle + 1)%360def forceUpdate(self, event):self.scat.changed()def setup_plot(self):X = next(self.stream)c = ['b', 'r', 'g', 'y', 'm']self.scat = self.ax.scatter(X[:,0], X[:,1], X[:,2] , c=c, s=200)self.ax.set_xlim3d(FLOOR, CEILING)self.ax.set_ylim3d(FLOOR, CEILING)self.ax.set_zlim3d(FLOOR, CEILING)return self.scat,def data_stream(self):data = np.zeros(( self.numpoints , 3 ))xyz = data[:,:3]while True:xyz += 2 * (np.random.random(( self.numpoints,3)) - 0.5)yield datadef update(self, i):data = next(self.stream)self.scat._offsets3d = ( np.ma.ravel(data[:,0]) , np.ma.ravel(data[:,1]) , np.ma.ravel(data[:,2]) )return self.scat,def show(self):plt.show()if __name__ == '__main__':a = AnimatedScatter()a.ani.save("movie.avi", codec='avi')a.show()
https://en.xdnf.cn/q/72412.html

Related Q&A

Pandas: Bin dates into 30 minute intervals and calculate averages

I have a Pandas dataframe with two columns which are speed and time.speed date 54.72 1:33:56 49.37 1:33:59 37.03 1:34:03 24.02 7:39:58 28.02 7:40:01 24.04 7:40:04 24.02 7:40:07 25.35 …

Regular expression for UK Mobile Number - Python

I need a regular expression that only validates UK mobile numbers. A UK mobile number can be between 10-14 digits and either starts with 07, or omits the 0 and starts with 447. Importantly, if the user…

Iterate through all the rows in a table using python lxml xpath

This is the source code of the html page I want to extract data from.Webpage: http://gbgfotboll.se/information/?scr=table&ftid=51168 The table is at the bottom of the page <html><tab…

Django: Serializing a list of multiple, chained models

Given two different models, with the same parent base class. Is there any way, using either Django Rest Framework Serializers or serpy, to serialize a chained list containing instances of both the chil…

Formatting cells in Excel with Python

How do I format cells in Excel with python?In particular I need to change the font of several subsequent rows to be regular instead of bold.

What is the legality of scraping YouTube data? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.This question does not appear to be about programming within the scope defined in the help center.Cl…

Numpy: fast calculations considering items neighbors and their position inside the array

I have 4 2D numpy arrays, called a, b, c, d, each of them made of n rows and m columns. What I need to do is giving to each element of b and d a value calculated as follows (pseudo-code):min_coords = m…

How to see all the databases and Tables in Databricks

i want to list all the tables in every database in Azure Databricks. so i want the output to look somewhat like this: Database | Table_name Database1 | Table_1 Database1 | Table_2 Database1 | Table_3 D…

How to get transparent background in window with PyGTK and PyCairo?

Ive been trying really hard to create a window with no decoration and a transparent background using PyGTK. I would then draw the content of the window with Cairo. But I cant get it to work.Ive tried a…

concurrent.futures.ThreadPoolExecutor doesnt print errors

I am trying to use concurrent.futures.ThreadPoolExecutor module to run a class method in parallel, the simplified version of my code is pretty much the following: class TestClass:def __init__(self, sec…