Basic graphics¶

Introduction¶

The path module allows one to construct PostScript-like paths, which are ane of the main building blocks for the generation of drawings. A PostScript path is an capricious shape consisting of straight lines, arc segments and cubic Bézier curves. Such a path does non have to be connected but may also incorporate several asunder segments, which volition be called subpaths in the following.

Todo

example for paths and subpaths (figure)

Usually, a path is constructed by passing a list of the path primitives moveto , lineto , curveto , etc., to the constructor of the path class. The following code snippet, for case, defines a path p that consists of a straight line from the point \((0, 0)\) to the point \((1, 1)\)

                            from              pyx              import              *              p              =              path              .              path              (              path              .              moveto              (              0              ,              0              ),              path              .              lineto              (              i              ,              1              ))            

Equivalently, one can besides use the predefined path subclass line and write

                            p              =              path              .              line              (              0              ,              0              ,              1              ,              1              )            

While already some geometrical operations can be performed with this path (see side by side section), another PyX object is needed in order to actually existence able to draw the path, namely an instance of the sail course. By convention, we employ the proper name c for this case:

In club to draw the path on the sail, nosotros use the stroke() method of the sheet class, i.eastward.,

                            c              .              stroke              (              p              )              c              .              writeEPSfile              (              "line"              )            

To complete the case, we have added a writeEPSfile() call, which writes the contents of the canvas to the file line.eps . Note that an extension .eps is added automatically, if non already present in the given filename. Similarly, if you want to generate a PDF or SVG file instead, utilize

or

c.writeSVGfile("line")

As a second example, allow us ascertain a path which consists of more than one subpath:

                            cross              =              path              .              path              (              path              .              moveto              (              0              ,              0              ),              path              .              rlineto              (              1              ,              ane              ),              path              .              moveto              (              1              ,              0              ),              path              .              rlineto              (              -              ane              ,              1              ))            

The get-go subpath is over again a straight line from \((0, 0)\) to \((1, 1)\), with the but departure that we now have used the rlineto course, whose arguments count relative from the last point in the path. The second moveto example opens a new subpath starting at the point \((one, 0)\) and ending at \((0, 1)\). Note that although both lines intersect at the point \((ane/2, i/2)\), they count as disconnected subpaths. The full general rule is that each occurrence of a moveto instance opens a new subpath. This ways that if i wants to describe a rectangle, one should non use

                            rect1              =              path              .              path              (              path              .              moveto              (              0              ,              0              ),              path              .              lineto              (              0              ,              one              ),              path              .              moveto              (              0              ,              1              ),              path              .              lineto              (              ane              ,              1              ),              path              .              moveto              (              1              ,              1              ),              path              .              lineto              (              1              ,              0              ),              path              .              moveto              (              ane              ,              0              ),              path              .              lineto              (              0              ,              0              ))            

which would construct a rectangle out of four asunder subpaths (see Fig. Rectangle case a). In a better solution (see Fig. Rectangle case b), the pen is non lifted between the first and the terminal point:

_images/rects.png

Rectangle example

Rectangle consisting of (a) four separate lines, (b) i open path, and (c) i closed path. (d) Filling a path always closes it automatically.

                            rect2              =              path              .              path              (              path              .              moveto              (              0              ,              0              ),              path              .              lineto              (              0              ,              i              ),              path              .              lineto              (              1              ,              one              ),              path              .              lineto              (              1              ,              0              ),              path              .              lineto              (              0              ,              0              ))            

However, equally one tin encounter in the lower left corner of Fig. Rectangle example b, the rectangle is withal incomplete. It needs to be closed, which can exist done explicitly past using for the concluding straight line of the rectangle (from the point \((0, 1)\) back to the origin at \((0, 0)\)) the closepath directive:

                            rect3              =              path              .              path              (              path              .              moveto              (              0              ,              0              ),              path              .              lineto              (              0              ,              1              ),              path              .              lineto              (              one              ,              1              ),              path              .              lineto              (              1              ,              0              ),              path              .              closepath              ())            

The closepath directive adds a straight line from the electric current indicate to the offset betoken of the current subpath and furthermore closes the sub path, i.e., it joins the offset and the cease of the line segment. This results in the intended rectangle shown in Fig. Rectangle example c. Notation that filling the path implicitly closes every open subpath, as is shown for a single subpath in Fig. Rectangle example d), which results from

                            c              .              stroke              (              rect2              ,              [              deco              .              filled              ([              colour              .              gray              (              0.5              )])])            

Hither, nosotros supply as second argument of the stroke() method a listing which in the present example only consists of a single element, namely the then called decorator deco.filled . Equally its proper name says, this decorator specifies that the path is not merely being stroked but also filled with the given color. More information about decorators, styles and other attributes which tin be passed equally elements of the list can be institute in Sect. Attributes: Styles and Decorations. More details on the available path elements can be found in Sect. Path elements.

To conclude this section, we should not forget to mention that rectangles are, of course, predefined in PyX, so above we could have every bit well written

                            rect2              =              path              .              rect              (              0              ,              0              ,              1              ,              1              )            

Hither, the first two arguments specify the origin of the rectangle while the second two arguments define its width and height, respectively. For more details on the predefined paths, we refer the reader to Sect. Predefined paths.

Path operations¶

Oft, one wants to perform geometrical operations with a path earlier placing information technology on a canvas by stroking or filling it. For example, i might desire to intersect ane path with some other one, divide the paths at the intersection points, and and then join the segments together in a new style. PyX supports such tasks past ways of a number of path methods, which we will introduce in the following.

Suppose you want to draw the radii to the intersection points of a circle with a straight line. This task can be done using the post-obit lawmaking which results in Fig. Example: Intersection of circumvolve with line yielding two radii

                            from              pyx              import              *              c              =              sail              .              sheet              ()              circle              =              path              .              circle              (              0              ,              0              ,              2              )              line              =              path              .              line              (              -              iii              ,              1              ,              three              ,              2              )              c              .              stroke              (              circumvolve              ,              [              style              .              linewidth              .              Thick              ])              c              .              stroke              (              line              ,              [              fashion              .              linewidth              .              Thick              ])              isects_circle              ,              isects_line              =              circumvolve              .              intersect              (              line              )              for              isect              in              isects_circle              :              isectx              ,              isecty              =              circumvolve              .              at              (              isect              )              c              .              stroke              (              path              .              line              (              0              ,              0              ,              isectx              ,              isecty              ))              c              .              writePDFfile              ()            

_images/radii.png

Example: Intersection of circle with line yielding two radii

Here, the basic elements, a circumvolve around the indicate \((0, 0)\) with radius \(2\) and a straight line, are divers. Then, passing the line, to the intersect() method of circumvolve, nosotros obtain a tuple of parameter values of the intersection points. The starting time element of the tuple is a list of parameter values for the path whose intersect() method has been chosen, the 2nd element is the corresponding listing for the path passed equally argument to this method. In the nowadays case, we only need one list of parameter values, namely isects_circle. Using the at() path method to obtain the point respective to the parameter value, we depict the radii for the dissimilar intersection points.

Another powerful feature of PyX is its ability to split paths at a given set of parameters. For case, in guild to make full in the previous example the segment of the circle delimited by the direct line (cf. Fig. Case: Intersection of circle with line yielding radii and circumvolve segment), one first has to construct a path corresponding to the outline of this segment. The post-obit code snippet yields this segment

                            arc1              ,              arc2              =              circle              .              split              (              isects_circle              )              if              arc1              .              arclen              ()              <              arc2              .              arclen              ():              arc              =              arc1              else              :              arc              =              arc2              isects_line              .              sort              ()              line1              ,              line2              ,              line3              =              line              .              split up              (              isects_line              )              segment              =              line2              <<              arc            

_images/radii2.png

Instance: Intersection of circle with line yielding radii and circle segment

Here, we first split the circle using the carve up() method passing the list of parameters obtained above. Since the circle is airtight, this yields two arc segments. We so use the arclen() , which returns the arc length of the path, to discover the shorter of the 2 arcs. Before splitting the line, we have to accept into business relationship that the split up() method only accepts a sorted listing of parameters. Finally, we join the straight line and the arc segment. For this, we brand employ of the << operator, which non but adds the paths (which could be washed using line2 + arc ), merely likewise joins the concluding subpath of line2 and the first one of arc. Thus, segment consists of just a single subpath and filling works as expected.

An important issue when operating on paths is the parametrisation used. Internally, PyX uses a parametrisation which uses an interval of length \(i\) for each path element of a path. For instance, for a simple direct line, the possible parameter values range from \(0\) to \(1\), respective to the start and concluding signal, respectively, of the line. Appending another straight line, would extend this range to a maximal value of \(2\).

However, the situation becomes more complicated if more circuitous objects similar a circle are involved. Then, ane could be tempted to assume that over again the parameter value ranges from \(0\) to \(1\), because the predefined circle consists just of 1 arc together with a closepath element. Still, this is not the example: the actual range is much larger. The reason for this behaviour lies in the internal path handling of PyX: Earlier performing any non-trivial geometrical operation on a path, it will automatically be converted into an example of the normpath class (see too Sect. path.normpath ). These and so generated paths are already separated in their subpaths and only comprise straight lines and Bézier curve segments. XXX explain normpathparams and things like p.begin(), p.stop()-1,

A more geometrical manner of accessing a point on the path is to use the arc length of the path segment from the first indicate of the path to the given point. Thus, all PyX path methods that accept a parameter value also allow the user to pass an arc length. For case,

                            from              math              import              pi              r              =              2              pt1              =              path              .              circle              (              0              ,              0              ,              r              )              .              at              (              r              *              pi              )              pt2              =              path              .              circle              (              0              ,              0              ,              r              )              .              at              (              r              *              three              *              pi              /              2              )              c              .              stroke              (              path              .              path              (              path              .              moveto              (              *              pt1              ),              path              .              lineto              (              *              pt2              )))            

will draw a straight line from a point at bending \(180\) degrees (in radians \(\pi\)) to some other point at bending \(270\) degrees (in radians \(3\pi/two\)) on a circle with radius \(r=2\). Note however, that the mapping from an arc length to a point is in general discontinuous at the beginning and the end of a subpath, and thus PyX does not guarantee whatever particular effect for this boundary case.

More information on the bachelor path methods tin be plant in Sect. Course path — PostScript-similar paths.

Attributes: Styles and Decorations¶

Attributes ascertain properties of a given object when it is beingness used. Typically, at that place are different kinds of attributes which are unremarkably orthogonal to each other, while for one type of attribute, several choices are possible. An instance is the stroking of a path. At that place, linewidth and linestyle are different kind of attributes. The linewidth might be thin, normal, thick, etc., and the linestyle might exist solid, dashed etc.

Attributes ever occur in lists passed as an optional keyword statement to a method or a function. Usually, attributes are the commencement keyword argument, and then i can just pass the list without specifying the keyword. Once more, for the path case, a typical telephone call looks similar

                            c              .              stroke              (              path              ,              [              style              .              linewidth              .              Thick              ,              style              .              linestyle              .              dashed              ])            

Here, nosotros too encounter another characteristic of PyX'southward attribute arrangement. For many attributes useful default values are stored equally fellow member variables of the bodily attribute. For instance, style.linewidth.Thick is equivalent to fashion.linewidth(0.04, type="w", unit="cm") , that is \(0.04\) width cm (see Sect. Module unit for more information about PyX's unit arrangement).

Another important characteristic of PyX attributes is what is call attributed merging. A trivial example is the following:

                            # the following 2 lines are equivalent              c              .              stroke              (              path              ,              [              style              .              linewidth              .              Thick              ,              way              .              linewidth              .              sparse              ])              c              .              stroke              (              path              ,              [              style              .              linewidth              .              thin              ])            

Here, the style.linewidth.thin aspect overrides the preceding style.linewidth.Thick declaration. This is specially important in more circuitous cases where PyX defines default attributes for a sure operation. When calling the respective methods with an attribute listing, this list is appended to the list of defaults. This fashion, the user can hands override certain defaults, while leaving the other default values intact. In addition, every aspect kind defines a special articulate attribute, which allows to selectively delete a default value. For path stroking this looks like

                            # the following two lines are equivalent              c              .              stroke              (              path              ,              [              manner              .              linewidth              .              Thick              ,              fashion              .              linewidth              .              articulate              ])              c              .              stroke              (              path              )            

The clear attribute is too provided by the base classes of the various styles. For instance, style.strokestyle.clear clears all strokestyle subclasses i.east. style.linewidth and style.linestyle . Since all attributes derive from attr.attr , you tin can remove all defaults using attr.clear . An overview over the most important attribute types provided past PyX is given in the following tabular array.

Aspect category

description

examples

deco.deco

decorator specifying the way the path is drawn

deco.stroked , deco.filled , deco.arrow , deco.text

style.strokestyle

style used for path stroking

style.linecap , fashion.linejoin , fashion.miterlimit , style.dash , style.linestyle , style.linewidth , colour.color

style.fillstyle

manner used for path filling

color.color , blueprint.blueprint

manner.filltype

type of path filling

mode.fillrule.nonzero_winding (default), manner.fillrule.even_odd

deformer.deformer

operations changing the shape of the path

deformer.cycloid , deformer.smoothed

text.textattr

attributes used for typesetting

text.halign , text.valign , text.mathmode , text.phantom , text.size , text.parbox

trafo.trafo

transformations applied when drawing object

trafo.mirror , trafo.rotate , trafo.scale , trafo.slant , trafo.translate

Todo

specify which classes in the table are in fact instances

Note that operations commonly allow for sure attribute categories just. For example when stroking a path, text attributes are not immune, while stroke attributes and decorators are. Some attributes might belong to several attribute categories similar colours, which are both, stroke and fill attributes.

Last, we discuss another important feature of PyX's attribute organisation. In order to allow the easy customisation of predefined attributes, it is possible to create a modified aspect by calling of an attribute instance, thereby specifying new parameters. A typical example is to modify the mode a path is stroked or filled by constructing advisable deco.stroked or deco.filled instances. For instance, the code

                            c              .              stroke              (              path              ,              [              deco              .              filled              ([              color              .              rgb              .              light-green              ])])            

draws a path filled in green with a black outline. Here, deco.filled is already an case which is modified to fill with the given color. Note that an equivalent version would be

                            c              .              draw              (              path              ,              [              deco              .              stroked              ,              deco              .              filled              ([              colour              .              rgb              .              green              ])])            

In particular, you tin can come across that deco.stroked is already an attribute instance, since otherwise you were not allowed to pass it as a parameter to the draw method. Another case where the modification of a decorator is useful are arrows. For example, the following code draws an arrow head with a more acute bending (compared to the default value of \(45\) degrees):

                            c              .              stroke              (              path              ,              [              deco              .              earrow              (              angle              =              30              )])            

Todo

changeable attributes