I made a 'plotter(x)' function that reads a timeseries in a pd.DataFrame
and returns a figure (return fig
) made of two axes. One is a pyplot.figure.add_subplot(111)
, in which I add descartes.PolygonPatch(shapely.Polygon(y))
-es. The second one is a pyplot.figure.add_axes
, which includes a colorbar with a customized colormap.
I need a second function to produce a movie showing plots for each of the time-steps in the time-series at a rate of 2 fps. I did this:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def video_plotter(rain_series):
fig = plt.figure()
ims = []
for i in (range(len(rain_series.columns)-1)):
fig = plotter(rain_series[[rain_series.columns[i], rain_series.columns[-1]]])
ims.append([fig])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True,repeat_delay=1000)
writer = animation.MencoderFileWriter(fps=2)
ani.save('demo.mp4',writer=writer,dpi=100)
Question 1: What should I do to make this work?
I know an option is to loop over the time-series applying the function I already have to create a series of .png-s, and then use mencoder directly in the unix terminal to create an .avi. However the colorbar, and most of the values of shapely polygons being mapped, do not change over time, and consume a lot computation each time they need to be drawn. Additionally, I need to add a mpl_toolkits.basemap.Basemap
that does not change either. This makes this '.png-series' approach inconvenient. I also can not use sys
imports: I need to do everything within Python.
I need to use blit=True
in matplotlib.animation to avoid redrawing features if they are the same in the precedent frame. Does it also apply for basemaps?
Question 2: How can I integrate a static basemap in the video?
It seems that you will have to arrange your code differently to make it work. The general layout of animation code consits of two parts:
1. Creating of the static content of the plot
In this step you create the figure, add the subplots, draw all static content (for example the basemap) and usually add either the first data set or some compatible dummy data.
2. Updating each frame
For each animation frame you just update the dynamic data usually without creating any new objects. If you have, say, an image, you have created it in step 1 by using
imobj = ax.imshow(img)
. In this update step you do not create a new image, but just update the image data byimobj.set_array(newdata)
. (This being said, it is possible to create new objects, but you will need to remember to delete the unwanted objects.)Of course, this is not limited to images, yuo may change the data behind a plotted line, surface, patches, etc.
Blitting does not have anything to do with this, it is there just to make things faster (and does not work on all backends). If you do not need to show the animation in real time, it may be safer to just leave the blitting off.
My suggestion is that you rewrite your
plotter
with the above in mind.Just an example of how to create an animation:
This gives an animation with semi-transparent image changing in the foreground and a static image in the back. (If you have problems trying it, you may leave the
codec
andextra_args
keywords out, as they need you to have libx264 installed.)The last frame of the flick: