-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Animation of contourf becomes extremely slow #6985
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
The reason it is taking progressively longer is because the previous On Fri, Aug 26, 2016 at 12:49 PM, Erich L Foster [email protected]
|
This is what I understood, but what is the proper method to do this? |
oh, and I think there is a tiny memory leak that is fixed in master with On Fri, Aug 26, 2016 at 12:53 PM, Benjamin Root [email protected]
|
Set |
The proper way is not to do blitting. The QuadContourSet object doesn't This usually means having a global variable of some sort to store the Does that help? On Fri, Aug 26, 2016 at 5:39 PM, Elliott Sales de Andrade <
|
Seems like this would be handled better by the Animation class, but I can certainly do it the other way too. |
It's simpler to pass the artists to the update function via def init():
'''
This is where our contour is created
'''
sigma = np.random.uniform(0, 1, 4)
Z1 = mlab.bivariate_normal(X, Y, sigma[0], sigma[1], 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, sigma[2], sigma[3], 1, 1)
Z = (Z1 - Z2) * 10
norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max())
cmap = cm.PRGn
contf = plt.contourf(X, Y, Z, levels,
cmap=cm.get_cmap(cmap, len(levels) - 1),
norm=norm)
return contf
def update(frame_number, contf):
'''
This is where our contour is updated
'''
sigma = np.random.uniform(0, 1, 4)
Z1 = mlab.bivariate_normal(X, Y, sigma[0], sigma[1], 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, sigma[2], sigma[3], 1, 1)
Z = (Z1 - Z2) * 10
norm = cm.colors.Normalize(vmax=abs(Z).max(), vmin=-abs(Z).max())
cmap = cm.PRGn
contf.set_array(Z)
contf.set_cmap(cm.get_cmap(cmap, len(levels) - 1))
contf.set_norm(norm)
progress.update(frame_number)
# Construct the animation, using the update function as the animation
# director.
contf = init()
anim = FuncAnimation(fig, update, interval=n_steps, fargs=(contf, ))
anim.save("AnimContourf.mp4")
plt.close(fig)
sys.stdout.write("\n") though I'm not sure changing the cmap like that is the best idea. Depending on what you're doing, the |
Sorry, I may have been thrown by the randomness; alas, I think it doesn't update the contour. I guess the longer method is the only option until |
Correct. Just updating the Z data isn't sufficient. It still has to On Fri, Aug 26, 2016 at 6:12 PM, Elliott Sales de Andrade <
|
So how would the solution given by @QuLogic work for a contourf which uses tri=True? In this case the z data is not in matrix form. The example I gave isn't my real example, but my real example is too complicated and I use a netcdf file to fill in data. |
It wouldn't work. That's what his apology was about because the update data stuff doesn't update the entire object, and as you point out, the other contour objects don't work the same way. You would have to follow what I originally suggested, which is to keep track of the objects via a global variable (or some other specialized class that is passed in through fargs that manages the lifecycle of the contourf object). Some psuedo-code:
Something to that effect. |
With contour, just clear the axes and remake the contour plus whatever else needs to go there. I don't see any point in trying to track and remove objects associated with the contours. |
@WeatherGod When I do @efiring: In my code removing collections is about 8% faster than ax.clear(). Also, ax.clear forces me to redraw continents in basemap. In fact, the 8% slower was without even redrawing the continents. |
Hmm, that's strange. If you are not blitting at all, you can get away with On Mon, Aug 29, 2016 at 1:47 PM, Erich L Foster [email protected]
|
So what is different between self._drawn_artists.collections and ax.collections? If I go through and remove collections from ax this will of course remove my basemap continents and I lose about 10% in time, but using this method on self._drawn_artists.collections doesn't remove the continents. Right now, for efficiency, using my derived class with overloaded save is definitely the fastest. |
If you want to remove only the collections added by contourf, can't you just cycle through the list you saved in your |
I tried (before):
But,
I understand what the error is saying, but I don't understand why collection wouldn't be in gca().collections. |
No, the artist objects themselves have a remove() method. I wasn't On Mon, Aug 29, 2016 at 4:15 PM, Erich L Foster [email protected]
|
Maybe I am still confused, but using
Causes things to be as slow as if I hadn't removed the collections at all, i.e. 10x slower. So, for some reason removing the collection from gca().collections and then adding back in the coastlines is actually much faster. |
You need |
@efiring Then it says
So clearly, I must be accessing the wrong object. |
Does it really do that if you execute
That seems very strange? |
Does the following work for you?
With that, you should get a blank plot with limits from 0 to 9. As a note to self, perhaps we should augment |
After some debugging I discovered that a collection was being removed more than once. However, doing the contf.collection method results again in an extremely slow code. Anyway, I am just going to use the method of overriding save. I hope you guys consider blitting for contours. |
The time consuming step (as I understand it) with contours is actually computing the contours. Blitting only helps if you only need to re-draw a single artist and the slowest part of the process is redrawing everything else in the figure. Blitting is also only used when displaying to the screen, |
Thanks for the discussion above! Is there a way to deal with this if you're using
But otherwise it becomes painfully slow (~hours). |
I don't see how ArtistAnimation helps anything; it just puts the creation of your contours for each frame into an initial step to create the list of lists of artists. There is simply no way to get around the time taken for the contouring calculation itself. A penalty of 8% for a simpler algorithm is not worth spending a lot of programming time on. It sounds like the real problem is that you don't want to recreate the Basemap from scratch each time. The solution is to initialize the Basemap object (which includes the time-consuming step of extracting the coastlines), save it, and reuse it as the starting point for each frame. Unfortunately I don't have a simple ready-to-go example to point to, because all of my code along these lines predates the animation module (or at least my use of it), involves working with remote data sources, and uses my Basemap wrapper code. In the interest of reducing the number of open issues we have to keep scanning and checking, I am going to close this now. |
When creating an animation with FuncAnimation and contourf I have run into an issue where the more frames I have the slower things become. This is illustrated in the code below. I print a progress bar, which displays both progress and the time required for the current step. As the animation creation progresses you will see that each step takes longer and longer. I was able to mitigate this by creating a derived class MyFuncAnimation, where I overloaded the function save. In the new version of save I go through and clear all collections associated with self._drawn_artists, after writer.grab_frame, in the following way:
for collection in self._drawn_artists.collections: gca().collections.remove(collection)
I am not sure if there is a better way to do this, but it was the only way I could figure out how to address the issue.
Matplot Version = 1.5.1
Python Version = 3.5.2
Platform = MAC OS 10.11.6
Installed matplotlib through pip
Example:
The text was updated successfully, but these errors were encountered: