From: Alan G I. <ai...@am...> - 2008-07-18 20:51:25
|
The example at http://pyx.sourceforge.net/gallery/graphs/integral.html includes the following code:: p = d.path # the path is available after the graph is finished pa = g.xgridpath(a) pb = g.xgridpath(b) (splita,), (splitpa,) = p.intersect(pa) (splitb,), (splitpb,) = p.intersect(pb) area = (pa.split([splitpa])[0] << p.split([splita, splitb])[1] << pb.split([splitpb])[0].reversed()) Might someone be so kind as to provide a line by line explanation (and perhaps add this to the example). I get the basic idea, but I'd like more than a basic understanding. Thank you, Alan Isaac |
From: Joerg L. <jo...@us...> - 2008-07-19 11:06:18
|
Alan, Here comes a rather detailed explanation in the hope that we might add this to the example code. Maybe you can polish the formulation a bit. On 18.07.08, Alan G Isaac wrote: > The example at > http://pyx.sourceforge.net/gallery/graphs/integral.html > includes the following code:: > > > p = d.path # the path is available after the graph is finished This line gives you the path of the curve drawn in the graph. > > pa = g.xgridpath(a) > pb = g.xgridpath(b) The graph method xgridpath returs a path along a line of constant x in the plot area of the graph. In the present case, these paths are used for construction the two straight line segments forming the left and right boundary of the grey area. > (splita,), (splitpa,) = p.intersect(pa) > (splitb,), (splitpb,) = p.intersect(pb) Here, the top-left and top-right corners of the grey area are determined by intersecting the curve's path with the left and right grid lines, respectively. The intersect method returns a tuple of two lists of equal length, where each lists contains the parameter values corresponding to the intersection point. Here, the first list contains the result for the path p and the second list the one for the paths pa and pb, respectively. > area = (pa.split([splitpa])[0] << > p.split([splita, splitb])[1] << > pb.split([splitpb])[0].reversed()) Now the various paths are split at the intersection points and the right segments are selected from the resulting list of paths. Then, these segments are joined (using the << operator) to a single sub path. For doing so, the last segment has to be reversed. Best, Jörg |
From: Alan G I. <ai...@am...> - 2008-07-19 13:09:09
|
Hi Michael and Joerg, Your explanations were complementary and helpful. Let me respond in more detail later. But first: Where in the docs is there as clear a statement about xgridpath as this one (offered by Joerg)? "The graph method xgridpath returns a path along a line of constant x in the plot area of the graph." This is basically what I'd guessed from the example, of course, but pins down some important details. Here is how a user (e.g., me) might look. >>> help(pyx.graph.graphxy.xgridpath) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: class graphxy has no attribute 'xgridpath' >>> g=pyx.graph.graphxy(width=3) >>> help(g.xgridpath) Help on method gridpath in module pyx.graph.axis.axis: gridpath(self, x) method of pyx.graph.axis.axis.anchoredaxis instance >>> help(pyx.graph.axis.axis.anchoredaxis.gridpath) Help on method gridpath in module pyx.graph.axis.axis: gridpath(self, x) unbound pyx.graph.axis.axis.anchoredaxis method Ouch. OK, try looking here: <URL:http://pyx.sourceforge.net/manual/module-graph.graph.html> and find: Further geometry information is available by the axes instance variable, with is a dictionary mapping axis names to anchoredaxis instances. Shortcuts to the anchoredaxis positioner methods for the x- and y-axis become available after dolayout() as graphxy methods Xbasepath, Xvbasepath, Xgridpath, Xvgridpath, Xtickpoint, Xvtickpoint, Xtickdirection, and Xvtickdirection where the prefix X stands for x and y. Hmmm, OK, but what *are* those things individually? Some are pretty obvious, but not xgridpath (despite its name; I do not want to just guess based on that). OK, look here: <URL:http://pyx.sourceforge.net/manual/module-graph.axis.axis.html> and find: gridpath(x) Returns a path instance for the grid path at position x. Might return None when no grid path is available. OK, but what is a "grid path"? I'm still guessing. Dead end. Give up and write list. ;-) Hope that clarifies some points where additional help would be useful. Cheers, Alan |
From: Alan G I. <ai...@am...> - 2008-07-19 16:34:48
|
OK, here is a first pass at adding what I consider to be needed documentation of the example. However you will find six questions (marked as Q\d) interspersed. Cheers, Alan ############################################################ """ Next use the command ``g.plot`` to return a "plot-object" ``d``, which contains some information on the plotted data, including the title and the path which is plotted. We want access to the path ``p``, which comprises 100 short lines (concatenated to look like a curve). Comment: the path is just a path instance, completely independent of the graph. (This allows us, if we wish, to stroke the same path on a completely different canvas.) However, we cannot access this path until we do the graph layout. """ #plot some data on the graph d = g.plot(graph.data.function("y(x)=(x-3)*(x-5)*(x-7)")) #the path is not accessible until the layout is done g.finish() #Q1: would dolayout() be adequate here? # now we have access to the path, so get a handle to it p = d.path """ Next we want to create a path bounding the shaded area. Eventually we will do this by joining gridpath lines to part of the function plot path. Note: ``xgridpath`` is a graph method that returns a path along a line of constant 'x' within the plot area of the graph. As an alternative, we could have asked for the position of the values a and b and then created the path ourselves. E.g., :: x = g.pos(a, 0.0)[0] pa = path.line(0, x, 10, x) However this requires that we know something about the y-range (0.0 has to be a reasonable value) and that we know something about the position and size of the graph (0 should be below the x-axis, and 10 above the graph of the function). Instead, ``xgridpath`` does all that automatically for us. Q2: How do we know the "direction" of this path? From lesser to higher values? """ #get path for left boundary of the shaded area pa = g.xgridpath(a) #get path for right boundary of the shaded area pb = g.xgridpath(b) """ Next we generate an intersection between ``p`` and ``pa``. Note that ``intersect`` is a path method that returns a *2-tuple* containing two lists characterizing the points of intersection of the path with its argument (the other path). The two lists are of equal length. Each list contains parameter values corresponding to intersection points: the first list has the values for the intersecting path (``p``), and the secon list has the values for the intersected path (``pa``), A "parameter value" is a ``normpathparam`` object, which is a normalized way of characterizing a point along the path. Q3: Am I saying this correctly? Comment: Here we know that ``p`` and ``pa`` have a single intersection. Therefore, the two lists have length 1. In general, there may be many intersection points, and the following command would fail if there were more than one. :see: http://pyx.sourceforge.net/manual/module-path.html """ (splita,), (splitpa,) = p.intersect(pa) # Determine the top right conrner in the same fashion. (splitb,), (splitpb,) = p.intersect(pb) """ Like a path, a normpath can be split into pieces if we provide to the ``split`` mathod a list of parameter values at which to split. We now use this split method to produce pieces of the path around the shaded area. Remember, we always have to provide a *list* of parameters, and correspondingly we receive a list of pieces of the original path. We have to choose the correct piece. (E.g., here we specify the index [0] or [1]). Q4: Again we need to know the direction of the path ``pa``. How? :see: http://pyx.sourceforge.net/manual/node12.html """ #create a normpath as the part of ``pa`` from axis to intersection # (note: we split the path in two, and we want the first piece) leftbound = pa.split([splitpa])[0] #create a normpath as the part of ``p`` from left intersection to right intersection topbound = p.split([splita, splitb])[1] #create a normpath as the part of ``pb`` from intersection to axis # (note that we need to reverse the direction of ``rightbound``) rightbound = pb.split([splitpb])[0].reversed() """ We will us the ``<<`` operator to "glue" the path pieces together. Comment: The ``<<`` operator throws away any ``path.moveto`` at the beginning of the pieces. (Contrast with adding the paths together with the ``+`` operator, which keeps any ``moveto``.) Q5: is the << operator for *normpath* documented somewhere?? (Ex post, I understand you could say this is just another method.) """ #use the ``<<`` operator to join the three boundary paths into a single path area = (leftbound << topbound << rightbound) #an *open* path #Finally, close up the path. # Q6: Wouldn't area.append(closepath()) be more natural? # Is this different? If so, how? # Oh ... I think I see, ``area`` contains a *normpath* ... # I'll make some changes above to reflect this ... # # But ... is it needed? The fill will close automatically, right? # And restroking the axis is really not necessary. area[-1].close() ############################################################ |
From: Alan G I. <ai...@am...> - 2008-07-21 04:34:41
|
On Sat, 19 Jul 2008, Alan G Isaac apparently wrote: > g.finish() #Q1: would dolayout() be adequate here? OK, I see that ``finish`` is required to get access to the path of the plot. Cheers, Alan |
From: Alan G I. <ai...@am...> - 2008-07-21 17:05:21
|
OK, I take it my post was long enough to get its reading post-poned. So, below are the questions in summary. Thanks, Alan Q1. Why do we need g.finish() and not just g.dolayout() to get access to the path of a plotitem? Q2: How do we know the "direction" of an xgridpath? Is it always from lesser to higher values? Q3: When considering the result of a path intersection, is it correct to say that the "parameter values" in the returned lists are ``normpathparam`` object, and that these are a normalized way of characterizing a point along the path. Q4: Is there a good reason to ``close`` the area, or is that just for completeness? (I'm going to guess that without the close, half of the axis line will be covered by the gray area.) Q5: might it be worth it in the documentation to explicitly mention the ``<<`` operator for normpath? (Ex post, I understand you could say this is just another method.) Q6. Once I have the answers, should I revise the write up? (I.e., do you want to use it as part of the posted example?) |
From: Joerg L. <jo...@us...> - 2008-07-21 17:56:15
|
Hello Alan, On 21.07.08, Alan G Isaac wrote: > OK, I take it my post was long enough to get its > reading post-poned. So, below are the questions > in summary. It's on my internal TODO list and I'm glad that you pushed me a bit so I can get rid of it... > Q1. Why do we need g.finish() and not just g.dolayout() > to get access to the path of a plotitem? At least you need to do doplot, otherwise the path is not defined. > Q2: How do we know the "direction" of an xgridpath? > Is it always from lesser to higher values? Sorry, only André can answer that precisely. > Q3: When considering the result of a path intersection, > is it correct to say that the "parameter values" in the > returned lists are ``normpathparam`` object, and that these > are a normalized way of characterizing a point along the > path. Indeed, you get a normpathparam. Normpathparams are used internally instead of arc lengths in order to properly support the case of discontinous paths, i.e., ones consisting of more than one normsubpath. But all that inner guts should be pretty much hidden to the user. At least, when we introduced this change a couple of releases ago, nobody noticed (read: complained). > Q4: Is there a good reason to ``close`` the area, or is > that just for completeness? (I'm going to guess that without > the close, half of the axis line will be covered by the gray > area.) When filling an area, PostScript (and hence PyX) always implicitly closes all sub-paths. So it wouldn't make a difference here. > Q5: might it be worth it in the documentation to explicitly > mention the ``<<`` operator for normpath? > (Ex post, I understand you could say this is just another > method.) Yes, this part of the documentation still needs to be written. There's a long-standing TODO list item in the CHANGES file... But Michael described it very clearly. > Q6. Once I have the answers, should I revise the write up? > (I.e., do you want to use it as part of the posted example?) It would be nice to have it somewhere. In the example it will be rather long, especially if you compare it to the other gallery examples. On the other hand, it's better to have more documentation than less... In the optimal case, we would have a new section in the tutorial styles examples, say: "Graph methods". There one could explain using more simpler examples various concepts like the do...-methods, gridpaths, etc. The format is quite simple, have a look in the source distribution. Basically it's one Python file for the drawing and a text file with some simple markup rules for the explanation. Additionally, there's an INDEX file in every directory which defines the order of the examples. So to summarize: If you could extend the example (in that case, please use the standard comment prefix # instead of the text strings), it's would be already very helpful. If you could split it in "orthogonal" sub-examples for the tutorial section, it would be optimal. Our hope always was that we get some user help for this part. Best, Jörg |
From: Alan G I. <ai...@am...> - 2008-07-24 18:30:15
|
>> Q2: How do we know the "direction" of an xgridpath? >> Is it always from lesser to higher values? On Mon, 21 Jul 2008, Joerg Lehmann apparently wrote: > Sorry, only André can answer that precisely. Still hoping for an answer ... Cheers, Alan |
From: Alan G I. <ai...@am...> - 2008-08-04 16:47:38
|
On Mon, 21 Jul 2008, Joerg Lehmann apparently wrote: > It would be nice to have it somewhere. Here it is: http://www.american.edu/econ/notes/pyx_shadedintegral.py Primary remaining question: how do we know the "direction" of an xgridpath? Thanks, Alan |
From: Christian S. <pyx...@cs...> - 2008-09-25 02:12:50
|
On Mon, Aug 04, 2008 at 12:47:40PM -0400, Alan G Isaac wrote: > On Mon, 21 Jul 2008, Joerg Lehmann apparently wrote: > > It would be nice to have it somewhere. > > > Here it is: > http://www.american.edu/econ/notes/pyx_shadedintegral.py Thanks for all your work, Alan. (Sadly, I discovered this mailing list thread only after I figured out how integral.py worked. Would have saved myself quite some time otherwise...) -- Chris Stork <> Support eff.org! <> http://www.ics.uci.edu/~cstork/ OpenPGP fingerprint: B08B 602C C806 C492 D069 021E 41F3 8C8D 50F9 CA2F |
From: Michael S. <m-s...@us...> - 2008-07-19 11:15:21
|
Hello Alan, On 18.07.08, Alan G Isaac wrote: > The example at > http://pyx.sourceforge.net/gallery/graphs/integral.html > I get the basic idea, but I'd like more than a basic > understanding. I do not know which level of understanding you want to reach -- I just start here with some explanation, you can then ask in more detail. > p = d.path # the path is available after the graph is finished The g.plot command returned the "plot-object" d which contains some information on the plotted data, such as the title and the path which is plotted. We here want the path and call it p. p consists of 100 short lines which are concatenated to give some curved impression. Note that the path is just a path instance, completely independent of the graph. This allows to stroke the same path on a completely different canvas. (the easiest way to strip all axes off a graph) > pa = g.xgridpath(a) > pb = g.xgridpath(b) We want the points where two vertical lines intersect with the path p. We here ask the graph to give us these lines. When calling xgridpath, the graph asks its "x" axis to find the position of the values a and b and returns a path parallel to the y axis. Alternatively, we could have asked for the position of the values a and b and created the path ourselves, such as x = g.pos(a, 0.0)[0] pa = path.line(0, x, 10, x) but this requires that we know something about the y-range (0.0 has to be a reasonable value) and something about the position and size of the graph (0 should be below the x-axis, and 10 above the graph of the function). the xgridpath does all that automatically > (splita,), (splitpa,) = p.intersect(pa) > (splitb,), (splitpb,) = p.intersect(pb) These two commands do the intersections of the "curved" path p with the vertical lines. The result of each intersection is a pair of parameters which tell us where to find the common point on each of the paths. As we use p.intersect(pa) the first parameter is the one for p and the second for pa. We could equally write (splitpa,), (splita,) = pa.intersect(p) The notation with the tuples is a bit peculiar, but necessary: In principle, one does not know in advance how many intersection points will be found. Therefore, we always obtain a list of parameters for each path. In this very example, we expect only one common point and give names to the two parameters received. The above command would fail if there were more than one intersection points. > area = (pa.split([splitpa])[0] << > p.split([splita, splitb])[1] << > pb.split([splitpb])[0].reversed()) Next, we take the required pieces of the three paths p, pa, pb and glue them together. The split methods gives us pieces of the paths, split at given parameters. Again, this is possible for several parameters, therefore we always have to provide a list of parameters and receive a list of pieces of the original path. We have to choose the correct piece (by saying [0] or [1]). The operator << glues the pieces together. This operator throws away possible path.moveto at the beginning of the pieces -- this is different for the adding of paths by the "+" operator, which keeps the moveto. Actually, "area" is an open path at the moment. If we want to fill it, we must rely on the convention that postscript/pdf fills the region within an open path. We could add a path.closepath() explicitly. For filling, the direction of the surrounding path pieces is important. We go up along the path pa, then right along p. To go down on the path pb we must reverse its original direction. (It is here important to know the original directions of the xgridpaths and of the path of the plotobject). Michael |