Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Added fplot to Axes subclass.#737

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Closed
dmcdougall wants to merge12 commits intomatplotlib:masterfromdmcdougall:fplot

Conversation

dmcdougall
Copy link
Member

Plotting functionality for Python callables, ala Matlab's 'fplot' function.

An adaptive step-size is used. Smaller step sizes are used when the gradient of the function is larger. The heavy lifting for the step size is done by the fplot function. Then x,y coordinates are created and passed directly to the plot function in the Axes subclass. As a result, all of the usual kwargs are still supported.

Only one callable is supported so far, it would be desirable to support an array/list of callables and plot them all simultaneously.

There are some unresolved problems. One is the inability to deal with the scenario when f(x) is undefined for some x.

The reason I've tried to make a start on this is to address issue#330. I'll need some help resolving some of the issues I've documented in the source code, but I'd like some feedback on this initial effort.

eps = 1e-10

tol = kwargs.pop('tol', None)
n = kwargs.pop('tol', None)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Bug right there. Also, it would be more efficient to dokwargs.pop('n', 50).

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thanks for the find. Good spot.

@pelson
Copy link
Member

On the whole, I like the idea. It would be great if the concept could be generalised to support different types of functions (parametric equations, 2d functions [for contouring and such like]), and concepts such as limiting the domain of a function (e.g.sqrt(x) where x>=0). Additionally, there is no reason to not keep hold of the function, allowing users to zoom in and get ever increasing resolution. Finally, being able to handle such functions astan(x) properly would be a bonus.

Of course, this is bread and butter stuff forsympy.

@WeatherGod
Copy link
Member

Interesting idea, but I am not convinced that this belongs here. The computational part feels like it belongs in numpy or scipy. The user could just call that, have it return the data and then feed that into what ever plotting software they may want. Having the computational part elsewhere would also allow a user to analyze the numerical results and/or save the results.

My 2 cents

@dmcdougall
Copy link
MemberAuthor

Thanks for the feedback@pelson and@WeatherGod. I can see both your points, and I have arguments in favour and against both of them. Perhaps we could decide what the best way to proceed is.

Firstly, the issue I was trying to address (#330) was a request for Matlab'sfplot function. As far as I can tell, this doesn't support 2D parametric equations. That isn't to say it wouldn't be a great feature, it's to say the function calling signatures could potentially look very different, and users potentially expecting similar behaviour may be confused. Perhaps implementation of parametric plotting could happen in a separateAxes.fplot_parametric function? I don't know, just my initial thoughts. I do agree that 2D parametric equation plotting is a good idea.

Secondly, I completely agree that support for hairier functions liketan, or in fact, any discontinuous function. This wouldn't be hard to add to the current implementation. It's just a matter of deciding when, and where, a function is discontinuous and creating the relevantLineCollection to add to the axes. This plays against@WeatherGod's idea of implementing the numerics into NumPy or SciPy function (see my third point below).

Thirdly, the problem with having the computational part in NumPy or SciPy is: how would one then obtain the discontinuities (see my second point above)? If the NumPy function were just to return an array of points, and that was passed toAxes.plot, the discontinuities would be joined by a line, leading to an uglier plot. The plus side of having the computational part in NumPy or SciPy, as you said, is great in terms of post-processing and analysis.

So I guess we have a couple of options regarding the next steps in this:

  1. Communicate with the developers over at NumPy and SciPy to see if such an adaptive refinement function for callables, the numerical part@WeatherGod mentioned, would fit within their purview.

  2. Decide to keep it within the matplotlib package.

I'm kind of new to contributing to this library, so I'm probably not the best person to decide. Could perhaps one of you suggest what we should do?

@WeatherGod
Copy link
Member

Just some food for thought. You can plot a discontinuity with a single line2d. Just put a NaN value there and the line will be broken up.

@jdh2358
Copy link
Collaborator

Having an fplot is a long requested feature so I'm inclined to incorporate this or some version of it. I would like to see a pyplot interface function and an example along with this PR, so it will be easier to test and explore.

@fperez has done a lot of work on adaptive sampling in his former life; I don't feel well-qualified to comment on the algorithm being used here, but I am not averse to including computation in mpl if there is nothing suitable in numpy. In general, we have had a lot of success in mpl by putting out something that works in many/most cases even if it is not perfect, and over time users and domain experts will fill in the gaps. We also have the option of conditionally utilizing scipy if they have some nice adaptive sampling algorithms that we could rely on if present else fall back on our own.

I think some work improving the algorithm will be needed, addressing the comments above, eg for functions with singularities, and the speed feels pretty slow, eg there is a noticeable delay in ax.fplot(np.exp, [0, 10]) so we probably want to consider either utilizing a faster algorithm or doing some of this in extension code,

@@ -6304,6 +6305,9 @@ def quiver(self, *args, **kw):
return q
quiver.__doc__ = mquiver.Quiver.quiver_doc

def fplot(self, f, limits, *args, **kwargs):
return mfplot.fplot(self, f, limits, *args, **kwargs)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This function needs a doc string -- take a look at contour to see how we share docstrings between module helper code and the axes wrapper funcs.

Copy link
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thanks! I'll make sure to add that.

@dmcdougall
Copy link
MemberAuthor

Ok, so I have been surfing the intertubes this weekend to do some research about the best algorithm for the adaptive sampling. This comes from@jdh2358's comment on it taking a while to plotexp(x) for0 < x < 10. The explanation for the slowness may be apparent to you (especially@jdh2358) already, but I thought I would make it clear here in case there is anyone that doesn't want to fork my code and try it out but wants an answer. So the basic idea behind the algorithm is to start withn number of x-coordinates (default is 50) evenly spaced in the specified domain, then successively double the number of x-coordinates (halving the length of each partition). With each subdivision, the gradient off is computed and if it changes by less than some tolerance, stop subdividing. So there are a couple of points to note:

  1. It is a property ofexp that the gradient increases exponentially withx. So the further out in the x-direction you want it plotted, the more subdivisions you need to get withintol and the longer it will take to plot. Having said that, it is definitely too long to wait, in my opinion.

  2. For any functionf, the larger the domain you want it to be plotted on, the longer it will take (not true in all cases, but probably true for most common ones).

These issues will be the downfall of this algorithm and need to be addressed.

Now, I found athread that@jdh2358 posted to asking for advice from the SciPy/NumPy community regards adaptive sampling algorithms. Though the link in there (presumably to someone's code) didn't work for me. Interestingly, I also came acrossthis thread advising a user on plotting (adaptively) an expensive and non-analytic function. There, the advice given was to coarsely samplef and fit (polynomial) splines to it, then finely sampling the splined function. This advice would address the speed issues in 1) since less subdivision points would be needed.

Now, Matlab's approach tofplot is adaptive. I want to see how they do it, but Matlab is categorically not open source, which makes this difficult. Fortunately,Octave is an open source version of Matlab (with plotting capabilities). So I cloned the source to see how those guys did it, and they basically to it the same way I did (succussive subdivisions). Though their code is a little more vectorised, so I'm thinking I might borrow (whilst crediting) some of those ideas. One point to note is that, due to the similarities, their approach with have the same weaknesses as the one I have presented here. That is not to say we can't improve it. The two main ways to improve are:

  1. Detect singularities/discontinuities and insert aNan as per@WeatherGod's suggestion.

  2. Increasetol as a function of domain geometry to improve speed. This has the price off being less resolved, but would be fine if we did this while implementing@pelson's idea of 'zooming' to get better resolution.

External code to compute the refinements would be a great idea in terms of improving speed, but I think I should at least make some attempt at making the mpl implementation faster before doing so.

These are all just my opinions though, and I'm not the most experienced at this, so external suggestions arealways welcome.

@jdh2358
Copy link
Collaborator

Hey Damon,

regarding looking at Octave code: you have to be careful here. Octave is GPL, and matplotlib is PSF compatible, which means we cannot use GPL'd code. Seehttp://matplotlib.sourceforge.net/devel/coding_guide.html#license-discussion

I have contacted Denis Bzowy, the original author of the adaptive spline code linked on dropbox in the 2009 scipy thread you referred to that is now a stale link, to see if he can provide us a copy of the code he was working on, and perhaps collaborate with us on the current implementation of fplot. II'll respond here when I hear back.

In the meantime, please keep working on the algorithm you have to improve the performance in regular cases like exp(x) over [0, 10] and in special cases where there are singularities. Some of the performance problems can likely be solved by moving the code into C/C++, but having the right algorithm will help more.

Thanks again,
JDH

@pelson
Copy link
Member

This has the price of f being less resolved, but would be fine if we did this while implementing@pelson's idea of 'zooming' to get better resolution

I'm not sure how well known the Mandlebrot example atexamples/event_handling/viewlims.py is, but it seems pertinent to the zooming idea and well worth a look if your are not familiar with it.

In terms of implementation, it seems like it would be rather nice if the functionality offplot could be encapsulated in an object and updating the call sequence ofaxes.fplot to accept either anfplot_class_instanceor a callable.
This would then unlock the potential for future enhancements such as supporting parametric equations, and potentially provide an API for giving clues about discontinuities etc.

@dmcdougall
Copy link
MemberAuthor

Very preliminary, but when I scale the minimum step size as a function of the domain size (just linear scaling), I get a 3x-4x speed-up when plotting@jdh2358's example:exp(x) for0 < x < 10. Pretty swanky!

$time python fplottest.py# no scalingreal    0m7.573suser    0m7.260ssys 0m0.209s$time python fplottest.py# scalingreal    0m2.427suser    0m2.184ssys 0m0.203s

@jdh2358
Copy link
Collaborator

Nice performance improvements! Just wanted to let you know I have not heard yet from Denis Bzowy, the original author of the adaptive spline code.

Plotting functionality for Python callables, ala Matlab's 'fplot'function.An adaptive step-size is used. Smaller step sizes are used when thegradient of the function is larger.Only one callable is supported so far, it would be desirable to supportan array/list of callables and plot them all simultaneously.There are some unresolved problems. One is the inability to deal withthe scenario when f(x) is undefined for some x.
Reduces the amount of unnecessary computation by ignoring partitionsizes that the user won't see with longer domains.
The old method computed 'left' and 'right' gradients. These are the samefor a linear approximation, which is what Line2D is anyway.I have also stored some function values that are used later in thealgorithm. This is good if f is expensive to compute.The above changes to reduce computation time by 20%.
@dmcdougall
Copy link
MemberAuthor

Haven't pushed the updated code yet. But I've made some more performance improvements, and I've also tried to deal with singularities. Here's a picture oftan(x) for your perusal. Watch this space for some commits.

singluarity

Now we call axes.plot with stored values of f instead of calling f on x.This will improve performance when f is an expensive function.
When we find singularities, replace the function values with NaN so theyappear as separate Line2Ds on the plot
@dmcdougall
Copy link
MemberAuthor

I'm going to close this and work on@pelson's suggestion of encapsulatingfplot in a class.

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers
No reviews
Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

4 participants
@dmcdougall@pelson@WeatherGod@jdh2358

[8]ページ先頭

©2009-2025 Movatter.jp