user89 user89 - 16 days ago 5
Python Question

matplotlib: how can I "predraw" an animation?

Currently, my custom animation class's

_draw_frame
function does this:


  1. get line data for timestep
    n

  2. update data of each line of interest in the axes with
    set_data
    (lets say for the sake of an example (
    ax_line1.set_data(datax, datay
    , where
    ax_line1, = ax.plot(...)
    )

  3. make a list of each line that was updated, and set
    self._drawn_artists
    to that (so in the example if two lines of interest are there, then we update them
    self._drawn_artists = [ax_line1, ax_line2]



Is there a way I can set the data in multiple copies of the line artists before
_draw_frame
is called? Then, all that
_draw_frame
has to do is fetch the predrawn lines, and update the drawn artist list with that.

That means that I set the artist data in parallel, if I have the data already, and thus produce an animation faster? I tried doing
copy.deepcopy
of the artists, but got an error telling me that I cannot do so (
TransformationNode
has to be frozen). What other options do I have?

Answer

If you want to set the data in parallel, I think your best option is to just create all of the line objects that you will need by calling the constructor that many times. Then you can iterate through them and set data as appropriate. If a lot of your lines are supposed to be identical share attributes, you can achieve this with the update_from method of matplotlib artists. You could freeze some of the line objects to allow them to be copied, but then you wouldn't be able to change the data.

That said, when you consider that you'll be needing to undraw lines as well, I'm not sure how much time this will save you. If you have a massive amount of data that you can handle in a very parallel manner, then it might be worth it.

Still, if you really want to speed this up, you should probably use blitting. The basic idea behind blitting is this:

  • Start out by drawing any background elements that will be present in all frames.
  • All other elements in your animation are represented as drawable objects of some sort (which lines conveniently are)
  • For every frame, you update any attributes of your drawables that you need to. Then you return a list of everything that you changed an attribute of.
  • Matplotlib's FuncAnimation function handles the rest with shocking efficiency.

Because all of your operations involve updating lines, this is a pretty ideal scenario in which to use blitting. Matplotlib's documentation on blitting is not incredibly clear, so, if you want more detail, I wrote this tutorial, which has example code and such.

Comments