6

I have a python program that plots the data from a file as a contour plot for each line in that text file. Currently, I have 3 separate contour plots in my interface. It does not matter if I read the data from a file or I load it to the memory before executing the script I can only get ~6fps from the contour plots.

I also tried using just one contour and the rest normal plots but the speed only increased to 7fps. I don't believe that it is so computationally taxing to draw few lines. Is there a way to make it substantially faster? Ideally, it would be nice to get at least 30fps.

The way I draw the contour is that for each line of my data I remove the previous one:

for coll in my_contour[0].collections:
    coll.remove()

and add a new one

my_contour[0] = ax[0].contour(x, y, my_func, [0])

At the beginning of the code, I have plt.ion() to update the plots as I add them.

Any help would be appreciated.

Thanks

UN4
  • 587
  • 5
  • 19
  • The speed at which you can update a plot depends on two things: (a) the time it takes to compute the new data and (b) the time it takes to draw the axes. In general it's hard to say which one takes more time in your case. Unfortunately, `contour` needs to recompute the data on every iteration, so there is little gain expected. Drawing time could potentially be reduced by using blitting, but I doubt that this will bring you from 7 to 30 fps. – ImportanceOfBeingErnest Feb 22 '17 at 09:09
  • Well, adding more contours does not reduce the fps drastically. Now I tried 6 contours and I get 5.5-6.5 fps when with one I get 7-7.5fps there is something happening in matplotlib when it updates the plots that take forever to animate. Also if I reduce the mesh density for the contour plot substantially it only increases the frame rate by a fraction of fps. – UN4 Feb 22 '17 at 09:24
  • This sounds like [blitting](http://stackoverflow.com/questions/40126176/fast-live-plotting-in-matplotlib-pyplot) could indeed provide an advantage. – ImportanceOfBeingErnest Feb 22 '17 at 09:54
  • @ImportanceOfBeingErnest Unlike the link suggest, I can't use `ax[0].draw_artist(my_contour[0])` on my contour plot. It gives me an error. If I do everything else as stated there except instead of `ax[0].draw_artist(my_contour[0])` I use `fig.canvas.draw()` I get an increase of 2fps. How should I handle blitting properly with contour plot? – UN4 Feb 22 '17 at 10:43

1 Answers1

13

Here is an example on how to use a contour plot in an animation. It uses matplotlib.animation.FuncAnimation which makes it easy to turn blitting on and off. With blit=True it runs at ~64 fps on my machine, without blitting ~55 fps. Note that the interval must of course allow for the fast animation; setting it to interval=10 (milliseconds) would allow for up to 100 fps, but the drawing time limits it to something slower than that.

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

x= np.linspace(0,3*np.pi)
X,Y = np.meshgrid(x,x)
f = lambda x,y, alpha, beta :(np.sin(X+alpha)+np.sin(Y*(1+np.sin(beta)*.4)+alpha))**2
alpha=np.linspace(0, 2*np.pi, num=34)
levels= 10
cmap=plt.cm.magma


fig, ax=plt.subplots()
props = dict(boxstyle='round', facecolor='wheat')
timelabel = ax.text(0.9,0.9, "", transform=ax.transAxes, ha="right", bbox=props)
t = np.ones(10)*time.time()
p = [ax.contour(X,Y,f(X,Y,0,0), levels, cmap=cmap ) ]

def update(i):
    for tp in p[0].collections:
        tp.remove()
    p[0] = ax.contour(X,Y,f(X,Y,alpha[i],alpha[i]), levels, cmap= cmap) 
    t[1:] = t[0:-1]
    t[0] = time.time()
    timelabel.set_text("{:.3f} fps".format(-1./np.diff(t).mean()))  
    return p[0].collections+[timelabel]

ani = matplotlib.animation.FuncAnimation(fig, update, frames=len(alpha), 
                                         interval=10, blit=True, repeat=True)
plt.show()

enter image description here

Note that in the animated gif above a slower frame rate is shown, since the process of saving the images takes a little longer.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • 1
    This is amazing, all my of my 6 contours run at 50fps! Huge improvement! Thanks! – UN4 Feb 23 '17 at 07:53
  • 1
    Thanks so much for the help. It is frustrating how unintuitive these animations are -- trying to use `set_array` on the `QuadContour` object failed, trying to create all the artists then use `ArtistAnimation` failed. The only answer turns out to be to **carry out the process behind** `ArtistAnimation` **and** make this work with `FuncAnimation`. matplotlib really needs work here. – Luke Davis Nov 25 '17 at 02:30
  • @LukeDavis It's not clear to me what the problem is. I think 4 comment lines are really too short for a sufficiently clear description, so you may ask a new question about the problem you encouter. – ImportanceOfBeingErnest Nov 25 '17 at 11:57