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()
############################################################

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&gt;
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&gt;
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

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

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