Ask Your Question
1

get_minmax_data on implicit_plot

asked 2011-02-04 13:21:09 +0200

updated 2015-01-22 22:05:12 +0200

FrédéricC gravatar image

This is a sequel of my question about plotting level set.

In the following, G is a circle :

sage: f(x,y)=x**2+y**2  
sage: G=implicit_plot(f==1,(x,-2,2),(y,-3,3))
sage: G.get_minmax_data()
{'xmin': -2.0, 'ymin': -3.0, 'ymax': 3.0, 'xmax': 2.0}

The "correct" get_minmax_data sould be

{'xmin': -1.0, 'ymin': -1.0, 'ymax': 1.0, 'xmax': 1.0}

As far as I understood the code (and the thread "Retrieving xy data from implicit plots" on Sage-support), the following is the relevant part :

xy_data_arrays = numpy.asarray([[[func(x, y) for x in xsrange(*ranges[0],include_endpoint=True)]
                                 for y in xsrange(*ranges[1], include_endpoint=True)]
                                for func in g],dtype=float)

in ../plot/contour_plot.py

My questions are :

  1. can I retrieve that xy_data_array ?

  2. If I analyse xy_data_array, I suppose that extracting the point with lowest x-component such that the value is positive will provide me the "correct" xmin of the plot. I'm wrong ?

edit retag flag offensive close merge delete

2 Answers

Sort by » oldest newest most voted
2

answered 2011-02-06 09:58:55 +0200

DSM gravatar image

updated 2011-02-06 10:17:05 +0200

Following up on the comment discussion about which points are actually used in a plot, here's a revised version of the original answer I gave before kcrisman pointed out g.xy_data_array and I deleted mine as stupid by comparison. This is pretty ugly:


import matplotlib

def get_paths_from_plot(p):
    # untested!
    m = p.matplotlib()
    sp = m.get_children()[1]
    for c in sp.get_children():
        # not sure if I need to test for both or not? don't understand
        # matplotlib internals well enough to know if every Line2D
        # will be in some LineCollection and so this is pure duplication (probably)
        if isinstance(c, matplotlib.lines.Line2D):
            yield c.get_path()
        elif isinstance(c, matplotlib.collections.LineCollection):
            for path in c.get_paths():
                yield path

def get_bounds_from_implicit_plot(P):
    # untested!
    xx = []
    yy = []
    for path in get_paths_from_plot(P):
        xx += list(path.vertices[:,0])
        yy += list(path.vertices[:,1])
    print 'xx:', sorted(xx)[:10]
    print 'yy:', sorted(yy)[:10]
    d = {'xmin': min(xx), 'xmax': max(xx),
         'ymin': min(yy), 'ymax': max(yy)}
    return d
sage: f(x,y)=x**2+y**2  
sage: G=implicit_plot(f==1,(x,-2,2),(y,-3,3))
sage: get_bounds_from_implicit_plot(G)
xx: [-0.99972791583529708, -0.99972791583529708, -0.99972791583529697, -0.99972791583529697, -0.99809541084708742, -0.99809541084708742, 
-0.99809541084708719, -0.99809541084708719, -0.9948304008706681, -0.9948304008706681]
yy: [-0.99973154362416372, -0.99973154362416372, -0.99973154362416361, -0.99973154362416361, -0.99901565995525998, -0.99901565995525998, 
-0.99901565995525976, -0.99901565995525976, -0.99758389261745239, -0.99758389261745239]
{'xmin': -0.99972791583529708, 'ymin': -0.99973154362416372, 
'ymax': 0.99973154362415995, 'xmax': 0.99972791583530107}
edit flag offensive delete link more

Comments

Thanks a lot ! I'm going to test that on my favourites examples. For informations, I need these xmin,xmax,ymin,ymax in order to automatically determine the bounding box in a pspicture (LaTeX). See [here](http://student.ulb.ac.be/~lclaesse/phystricks-doc.pdf) in the section "Implicit curves"

Laurent Claessens gravatar imageLaurent Claessens ( 2011-02-06 10:29:17 +0200 )edit

For what it's worth I expect it to fail. :^) I was lazy and hard-coded the [1], so if the AxesSubplot isn't there it'll break, etc., etc. But the information should be in the Paths, so we can probably get at it if we need to. (There might also be some coordinate transformations we need to do, depending.) Hopefully the matplotlib guys can explain the One True Way(tm) to do the above!

DSM gravatar imageDSM ( 2011-02-06 10:34:35 +0200 )edit
3

answered 2011-02-04 14:15:33 +0200

kcrisman gravatar image

Actually, the correct data is given. You specified implicit_plot(f==1,(x,-2,2),(y,-3,3)), so it gave you exactly those bounds. If you had done

sage: G=implicit_plot(f==1,(x,-1,1),(y,-1,1))
sage: G.get_minmax_data()
{'xmin': -1.0, 'ymin': -1.0, 'ymax': 1.0, 'xmax': 1.0}

you'd get what you expect.

What is going on here is that implicit_plot just creates a contour plot of the equation with only one contour level.

sage: G=contour_plot(f==1,(x,-1,1),(y,-1,1),contours=[0],fill=False); G

As to your question, this is the attribute (not method)

sage: g = G[0]
sage: g.xy_data_array

Which is large, as it's the values of the function at EVERY data point! Only the 'right' points are connected, using matplotlib's contour functionality. See this as well:

sage: sage.plot.contour_plot.ContourPlot??
class ContourPlot(GraphicPrimitive):
    """
    Primitive class for the contour plot graphics type.  See 
    ``contour_plot?`` for help actually doing contour plots.

    INPUT:

    - ``xy_data_array`` - list of lists giving evaluated values of the function on the grid

I hope this helps! By the way, as long as you are in the Sage interpreter or notebook (or a .sage file), you can do f(x,y)=x^2+y^2; you only need ** if you are writing a Python file.

edit flag offensive delete link more

Comments

+1 for a much better solution! I must have tried xy_data_array on G rather than on G[0] and gave up too soon. On the bright side, I got to search deep in matplotlib's data structures. :-p

DSM gravatar imageDSM ( 2011-02-04 20:34:08 +0200 )edit

Thank for the answer, kcrisman. I did the mistake DSM said :) Using G[0].xy_data_array and digging in "by hand", I obtain my result: the xmin,xmax,ymin,ymax of points that are actually plotted. Obviously I would be happier using the matplotlib's functionality ... but I got lost in the code of matplotlib/contour.py ... where can I get the list of "right" points ?

Laurent Claessens gravatar imageLaurent Claessens ( 2011-02-05 06:06:45 +0200 )edit

Yes, the Graphics objects are lists - so it's annoying when trying to access the stuff, but great when (as usually is the case) you want them to 'just work'. I have no answer for the matplotlib question. Why not ask on their support list? If we can give easy access to it, that would be useful to do.

kcrisman gravatar imagekcrisman ( 2011-02-05 21:28:48 +0200 )edit

The "right" points are buried pretty deeply. G.matplotlib().get_children()[1] gives the lines etc. that make up the image, and Line2D (and LineCollection?) instances there have a method .get_path() (.get_paths()), and those Path objects returned have an attribute ".vertices" which lists the information.

DSM gravatar imageDSM ( 2011-02-05 21:35:33 +0200 )edit

G.matplotlib().get_children() returns [<matplotlib.patches.rectangle object="" at="" 0xc144e4c="">, <matplotlib.axes.axessubplot object="" at="" 0xc14472c="">] Is the data in the Rectiangle ? In the Axes ? I sent the question to the matplotlib's support list.

Laurent Claessens gravatar imageLaurent Claessens ( 2011-02-06 08:29:32 +0200 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

Stats

Asked: 2011-02-04 13:21:09 +0200

Seen: 756 times

Last updated: Feb 06 '11