Retrieving xy data from implicit plots

29 views
Skip to first unread message

jbeorse

unread,
May 25, 2010, 3:48:26 PM5/25/10
to sage-support
Hi,

I am trying to retrieve the xy coordinates of an implicit plot, but I
am having trouble. I am able to do this with regular 2d plots without
a problem like this:

p = plot(...)
for r in p:
X = numpy.array(r.xdata)
Y = numpy.array(r.ydata)
...

With an implicit plot I can retrieve the xy_data_array like this:

ip = implicit_plot(...)
for r in ip:
XY = val.xy_data_array

but I don't understand how to interpret that data. It is an nxn list
where n is the number of plot points and it seems to depend on x, y,
and the bounding box values. Is there any way I can interpret these
results? Is there any function that converts these to the simple xy
coordinates?

To give context to my question, the purpose of me getting this data is
to perform a transformation on the curve, point by point. For any
implicit function that sage can plot I can to be able to perform my
transformation and view the original and the transformation side by
side.

Thanks in advance for any help you can provide.

William Stein

unread,
Jun 2, 2010, 3:05:43 AM6/2/10
to sage-s...@googlegroups.com

Hi,

Nobody answered the above email, and I ended up talking in office
hours today with the
student who wrote it. I suggested that they just write their own
implicit plot that

(1) uses fast_float (or fast_callable) to make a quick version of
the function, then

(2) evaluates the function on a grid, and takes all points that are
within epsilon of 0.

(3) make a patch and submit it to sage later, which would *replace*
implicit_plot by something like the above.

Then at least the data can be manipulated. It seems to me that this
should be at least as good as what we already have. The student
suggested that one could even "connect the dots" using some sort of
optimization technique.

But maybe I'm totally wrong. I have a bad feeling I'm being naive. Thoughts?

--
William Stein
Professor of Mathematics
University of Washington
http://wstein.org

Mike Hansen

unread,
Jun 2, 2010, 3:18:25 AM6/2/10
to sage-s...@googlegroups.com
On Wed, Jun 2, 2010 at 12:05 AM, William Stein <wst...@gmail.com> wrote:
> Then at least the data can be manipulated.  It seems to me that this
> should be at least as good as what we already have.    The student
> suggested that one could even "connect the dots" using some sort of
> optimization technique.
>
> But maybe I'm totally wrong.  I have a bad feeling I'm being naive.  Thoughts?

I think this is worse than handing it off to matplotlib as we do now.
The data in xy_data_array is just the fast_float'd function evaluated
on a grid. The only drawback with the current approach is that it's
not immediately obvious what the points chosen are. They come from
sage.plot.misc.setup_for_eval_on_grid, but are not saved after the
plot is made since they aren't needed. The code to compute the ranges
could be easily factored out of that function and made accessible.

--Mike

William Stein

unread,
Jun 2, 2010, 3:22:14 AM6/2/10
to sage-s...@googlegroups.com

Can you elaborate? I read the above and thought.

Claim: your proposal is worse.
Proof: argument that my proposal is better.

??

> --Mike
>
> --
> To post to this group, send email to sage-s...@googlegroups.com
> To unsubscribe from this group, send email to sage-support...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/sage-support
> URL: http://www.sagemath.org

Mike Hansen

unread,
Jun 2, 2010, 3:43:58 AM6/2/10
to sage-s...@googlegroups.com
On Wed, Jun 2, 2010 at 12:22 AM, William Stein <wst...@gmail.com> wrote:
> Can you elaborate?   I read the above and thought.
>
> Claim: your proposal is worse.
> Proof: argument that my proposal is better.

We already do most of what you suggested. In contour_plot.py, we have
the following:

g, ranges = setup_for_eval_on_grid([f], [xrange, yrange],
options['plot_points'])
...
xrange,yrange=[r[:2] for r in ranges]
...
xy_data_array = [[g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)]
for y in xsrange(*ranges[1],
include_endpoint=True)]

So, all that is missing is storing the step sizes ( [r[2] for r in
ranges] ). If we have those, then one can just generate the sample
points with the xsrange command as above. (Since xsrange generates
evenly spaced points, you can just compute the step size based on the
dimensions of xy_data_array, but they may not always exactly line up
due to floating point issues.)

After the grid is computed, we hand it off to matplotlib which figures
out the curves to draw. You had seemed to be suggesting doing this
part with our own code (connect the dots, etc.) which seems silly
compared to just using what matplotlib already provides.

--Mike

Jason Grout

unread,
Jun 2, 2010, 10:05:11 AM6/2/10
to sage-s...@googlegroups.com
On 06/02/2010 02:43 AM, Mike Hansen wrote:

> After the grid is computed, we hand it off to matplotlib which figures
> out the curves to draw. You had seemed to be suggesting doing this
> part with our own code (connect the dots, etc.) which seems silly
> compared to just using what matplotlib already provides.
>

I agree. As I understand it, matplotlib has some nice nontrivial
contour plotting routines (but I don't know---I haven't looked at the
code). It would be interesting to compare them to a naive contour
routine like you suggest, but my guess is that you wouldn't get any
better and probably would be worse. But hey, if you have the time, it's
probably interesting to try, even just for the educational experience.
And if it's better, I'd suggest contributing it to matplotlib.

But writing your own contour plotting routine is completely beside the
point of solving the original problem.

Is the data not stored somewhere inside of the matplotlib contour plot
object? Of course there is *something* stored inside there.

Jason

Jason Grout

unread,
Jun 2, 2010, 11:18:52 AM6/2/10
to sage-s...@googlegroups.com
On 05/25/2010 02:48 PM, jbeorse wrote:
> Hi,
>
> I am trying to retrieve the xy coordinates of an implicit plot, but I
> am having trouble. I am able to do this with regular 2d plots without
> a problem like this:
>
> p = plot(...)
> for r in p:
> X = numpy.array(r.xdata)
> Y = numpy.array(r.ydata)
> ...
>
> With an implicit plot I can retrieve the xy_data_array like this:
>
> ip = implicit_plot(...)
> for r in ip:
> XY = val.xy_data_array
>
> but I don't understand how to interpret that data. It is an nxn list
> where n is the number of plot points and it seems to depend on x, y,
> and the bounding box values. Is there any way I can interpret these
> results?

First, see below for what I think is a much better and more useful way
to approach this problem.

To answer your direct question, yes. Looking at the source code in
plot/contour_plot.py, an implicit plot of f(x,y) is merely a contour
plot of the level curve f(x,y)=0. Looking in the contour plot code, the
following statement generates the xy_data_array variable:

xy_data_array = [[g(x, y) for x in xsrange(*ranges[0],
include_endpoint=True)] for y in xsrange(*ranges[1], include_endpoint=True)]

So it looks like the implicit plot points are the points in the above
array that are close to zero. And it looks like

[[g(x, y) for x in xsrange(*ranges[0], include_endpoint=True)] for y in
xsrange(*ranges[1], include_endpoint=True)]

gives you the x,y coordinate pairs.

Is there any function that converts these to the simple xy
> coordinates?

How about something like:

xy_points=[[(x, y) for x in xsrange(*ranges[0], include_endpoint=True)]

for y in xsrange(*ranges[1], include_endpoint=True)]

num_x=len(xy_points)
num_y=len(xy_points[0])

eps=.001

[xy_points[i][j] for i in range(num_x) for j in range(num_y) if
abs(xy_data_array[i][j])<eps]


> To give context to my question, the purpose of me getting this data is
> to perform a transformation on the curve, point by point. For any
> implicit function that sage can plot I can to be able to perform my
> transformation and view the original and the transformation side by
> side.

I think it would be cool to tap into the matplotlib transform framework
here, instead of manipulating points. It would be cool to be able to do:

transform(any_sage_plot_object)

which would just tack on a matplotlib transform command in the plotting.
This would be much more general than transforming just an implicit
plot, and would be extremely useful, I think.

See http://matplotlib.sourceforge.net/users/transforms_tutorial.html for
a tutorial on using the matplotlib transformation framework.

Jason


Reply all
Reply to author
Forward
0 new messages