-
Notifications
You must be signed in to change notification settings - Fork 48
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
Regarding animation with SymPy #4
Comments
Thanks for reaching out, and thanks for the detailed information, that's really helpful! I'm wondering, though, what is the advantage of your approach compared to using Is it more efficient? And doesn't it loose the ability to do adaptive sampling? In the simple example with the sine wave this of course isn't a problem, but for more complicated plots I would definitely like to have adaptive sampling, as I don't really like the default look of SymPy plots, so I have always used
Yeah, I've also used this in my examples. Recently, however, I have stumbled upon a situation where Do you happen to know how to change that code for it to work in a Jupyter notebook? |
Back in the day, sympy.plotting used adaptive algorithm by default, very often producing low quality representation of functions. That behavior was changed: now it uses uniform sampling (the x-axis gets discretized with 1000 points, then function is evaluated), which produces consistent results between runs and of much better quality. You might need to use If you still want to use adaptive sampling, you'd have to specify Right now, using
I'll get back to you if I'll find the time to look at it. |
Thanks for this information, I wasn't aware of that! I will update my example notebook with that information. |
Hello Matthias,
I read the email you sent to the sympy mailing list. I'm the person who attempted to modernize the sympy plotting module. Unfortunately, that attempt failed midway through it, leaving stuffs in undesirable conditions, thought in working condition according to the test implemented on that submodule.
I took the time to look at your notebook and what you did back then was incorrect. I guess you would like the notebook to work as before, but instead I'm going to explain what was wrong and what could be improved.
Wrong approach
p
, which only serves the purpose of accessing the underlying data series withp[0]
.backend = MatplotlibBackend(p)
you constructed another object (repetitive, because it was already available withp._backend
if only it was ever documented).func
:p[0].expr = sp.sin(x - (frame / 5))
you assumed it is safe to change the expression of the data series. It is a very strong assumption: all other sympy objects operates on the concept of immutability.backend.process_series()
: you handled the process of generating numerical data and add it to the plot to thebackend
object. The main problem is that you have to clear the axes at each time frame, thus rebuilding every matplotlib renderer at each time frame. Even for a few line expressions, this would quickly become a performance bottleneck.Back in the day, I did exactly the same mistakes. Why?
Correct approach
This requires more lines of code, a lot of book-keeping with matplotlib handles, drowning yourself into matplotlib's documentation in order to find the correct update method for each handle (line, scatter, surface, contour, ...). But, it is the safest choice, and the one that always work.
Easiest way to animate sympy expressions
If you, like me, hate the repetitive process of book-keeping matplotlib's handles in order to create animations, maybe you would enjoy a simpler api. I created an improved plotting module for symbolic expression, which supports animations. This module follows the procedure illustrated in the above section Correct approach, so performance should not be an issue.
I'm going to show a few examples taken from your notebook. The above example becomes:
Note the
%matplotlib widget
command. In order to support multiple plotting libraries,spb
animations are based on ipywidgets. Without this command, the animation won't show on the screen (more likely, you will get some error). Instead, if you want to show theFuncAnimation
object:Note that I had to create a hidden animation with
show=False
. Then, I had to close the figure withplt.close(p.fig)
, otherwise there would be two figures shown on the notebook cell. Unfortunately, this is standard Jupyter Notebook behavior: it listen to a particular attribute of Matplotlib, and when a new figure is created, it immediately shows it on the screen.Another example:
Another one, reusing an existing figure/axes:
The text was updated successfully, but these errors were encountered: