Plotting functions

Although plotting is not even a side purpose of PARI, a number of plotting functions are provided. There are three types of graphic functions.


High-level plotting functions

(all the functions starting with ploth) in which the user has little to do but explain what type of plot he wants, and whose syntax is similar to the one used in the preceding section.


Low-level plotting functions

(called rectplot functions, sharing the prefix plot), where every drawing primitive (point, line, box, etc.) is specified by the user. These low-level functions work as follows. You have at your disposal 16 virtual windows which are filled independently, and can then be physically ORed on a single window at user-defined positions. These windows are numbered from 0 to 15, and must be initialized before being used by the function plotinit, which specifies the height and width of the virtual window (called a rectwindow in the sequel). At all times, a virtual cursor (initialized at [0,0]) is attached to the window, and its current value can be obtained using the function plotcursor.

A number of primitive graphic objects (called rect objects) can then be drawn in these windows, using a default color attached to that window (which can be changed using the plotcolor function) and only the part of the object which is inside the window will be drawn, with the exception of polygons and strings which are drawn entirely. The ones sharing the prefix plotr draw relatively to the current position of the virtual cursor, the others use absolute coordinates. Those having the prefix plotrecth put in the rectwindow a large batch of rect objects corresponding to the output of the related ploth function.

Finally, the actual physical drawing is done using plotdraw. The rectwindows are preserved so that further drawings using the same windows at different positions or different windows can be done without extra work. To erase a window, use plotkill. It is not possible to partially erase a window: erase it completely, initialize it again, then fill it with the graphic objects that you want to keep.

In addition to initializing the window, you may use a scaled window to avoid unnecessary conversions. For this, use plotscale. As long as this function is not called, the scaling is simply the number of pixels, the origin being at the upper left and the y-coordinates going downwards.

Plotting functions are platform independent, but a number of graphical drivers are available for screen output: X11-windows (including Openwindows and Motif), Windows's Graphical Device Interface, and the FLTK graphical libraries and one may even write the graphical objects to a PostScript or SVG file and use an external viewer to open it. The physical window opened by plotdraw or any of the ploth* functions is completely separated from gp (technically, a fork is done, and all memory unrelated to the graphics engine is immediately freed in the child process), which means you can go on working in the current gp session, without having to kill the window first. This window can be closed, enlarged or reduced using the standard window manager functions. No zooming procedure is implemented though.


Functions for PostScript or SVG output

in the same way that printtex allows you to have a TeX output corresponding to printed results, the functions plotexport, plothexport and plothrawexport convert a plot to a character string in either PostScript or Scalable Vector Graphics format. This string can then be written to a file in the customary way, using write. These export routines are available even if no Graphic Library is.


parploth(X = a, b, expr, {flags = 0}, {n = 0})

Parallel version of ploth. High precision plot of the function y = f(x) represented by the expression expr, x going from a to b. This opens a specific window (which is killed whenever you click on it), and returns a four-component vector giving the coordinates of the bounding box in the form [xmin,xmax,ymin,ymax].

Important note. parploth may evaluate expr thousands of times; given the relatively low resolution of plotting devices, few significant digits of the result will be meaningful. Hence you should keep the current precision to a minimum (e.g. 9) before calling this function.

The parameter n specifies the number of reference point on the graph, where a value of 0 means we use the hardwired default values; the binary digits of flag have the same meaning as in ploth: 1 = Parametric; 2 = Recursive; 4 = no_Rescale; 8 = no_X_axis; 16 = no_Y_axis; 32 = no_Frame; 64 = no_Lines; 128 = Points_too; 256 = Splines; 512 = no_X_ticks; 1024 = no_Y_ticks; 2048 = Same_ticks; 4096 = Complex.

For instance:

  \\ circle
  parploth(X=0,2*Pi,[sin(X),cos(X)], "Parametric")
  \\ two entwined sinusoidal curves
  parploth(X=0,2*Pi,[sin(X),cos(X)])
  \\ circle cut by the line y = x
  parploth(X=0,2*Pi,[X,X,sin(X),cos(X)], "Parametric")
  \\ circle
  parploth(X=0,2*Pi,exp(I*X), "Complex")
  \\ circle cut by the line y = x
  parploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex")

The library syntax is parploth(GEN a,GEN b,GEN code, long flag, long n, long prec).


parplothexport(fmt, X = a, b, expr, {flags = 0}, {n = 0})

Parallel version of plothexport. Plot of expression expr, X goes from a to b in high resolution, returning the resulting picture as a character string which can then be written to a file.

The format fmt is either "ps" (PostScript output) or "svg" (Scalable Vector Graphics). All other parameters and flags are as in ploth.

   ? s = parplothexport("svg", x=1,10, x^2+3);
   ? write("graph.svg", s);

The above only works if graph.svg does not already exist, otherwise write will append to the existing file and produce an invalid svg. Here is a version that truncates an existing file (beware!):

  ? n = fileopen("graph.svg", "w");
  ? filewrite(n, s);
  ? fileclose(n);

This is intentionally more complicated.

The library syntax is parplothexport(GEN fmt, GEN a, GEN b, GEN code, long flags, long n, long prec),


plot(X = a, b, expr, {Ymin}, {Ymax})

Crude ASCII plot of the function represented by expression expr from a to b, with Y ranging from Ymin to Ymax. If Ymin (resp. Ymax) is not given, the minimum (resp. the maximum) of the computed values of the expression is used instead.

The library syntax is pariplot(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, GEN ymin, GEN ymax, long prec)


plotarc(w, x2, y2, {filled = 0})

Let (x1,y1) be the current position of the virtual cursor. Draws in the rectwindow w the outline of the ellipse that fits inside the box such that the points (x1,y1) and (x2,y2) are opposite corners. The virtual cursor does not move. If filled = 1, fills the ellipse.

  ? plotinit(1);plotmove(1,0,0);
  ? plotarc(1,50,50); plotdraw([1,100,100]);

The library syntax is void plotarc(long w, GEN x2, GEN y2, long filled).


plotbox(w, x2, y2, {filled = 0})

Let (x1,y1) be the current position of the virtual cursor. Draw in the rectwindow w the outline of the rectangle which is such that the points (x1,y1) and (x2,y2) are opposite corners. Only the part of the rectangle which is in w is drawn. The virtual cursor does not move. If filled = 1, fill the box.

The library syntax is void plotbox(long w, GEN x2, GEN y2, long filled).


plotclip(w)

`clips' the content of rectwindow w, i.e remove all parts of the drawing that would not be visible on the screen. Together with plotcopy this function enables you to draw on a scratchpad before committing the part you're interested in to the final picture.

The library syntax is void plotclip(long w).


plotcolor(w, c)

Set default color to c in rectwindow w. Return [R,G,B] value attached to color. Possible values for c are

* a t_VEC or t_VECSMALL [R,G,B] giving the color RGB value (all 3 values are between 0 and 255), e.g. [250,235,215] or equivalently [0xfa, 0xeb, 0xd7] for antiquewhite;

* a t_STR giving a valid colour name (see the rgb.txt file in X11 distributions), e.g. "antiquewhite" or an RGV value given by a # followed by 6 hexadecimal digits, e.g. "#faebd7" for antiquewhite;

* a t_INT, an index in the graphcolormap default, factory setting are

0 = white, 1 = black, 2 = blue, 3 = violetred, 4 = red, 5 = green, 6 = grey, 7 = gainsborough

and the color index is a non-negative integer in [0,7]. But this can be changed (see ??graphcolormap); note that for historical reasons, graphcolormap is 0-based, so the color c is a non-negative integer, strictly less than the length of the colormap.

  ? plotinit(0,100,100);
  ? plotcolor(0, "turquoise")
  %2 = [64, 224, 208]
  ? plotbox(0, 50,50,1);
  ? plotmove(0, 50,50);
  ? plotcolor(0, 2) \\ blue
  %4 = [0, 0, 255]
  ? plotbox(0, 50,50,1);
  ? plotdraw(0);

The library syntax is GEN plotcolor(long w, GEN c).


plotcopy(sourcew, destw, dx, dy, {flag = 0})

Copy the contents of rectwindow sourcew to rectwindow destw with offset (dx,dy). If flag's bit 1 is set, dx and dy express fractions of the size of the current output device, otherwise dx and dy are in pixels. dx and dy are relative positions of northwest corners if other bits of flag vanish, otherwise of: 2: southwest, 4: southeast, 6: northeast corners.

The library syntax is void plotcopy(long sourcew, long destw, GEN dx, GEN dy, long flag).


plotcursor(w)

Give as a 2-component vector the current (scaled) position of the virtual cursor corresponding to the rectwindow w.

The library syntax is GEN plotcursor(long w).


plotdraw(w, {flag = 0})

Physically draw the rectwindow w. More generally, w can be of the form [w1,x1,y1,w2,x2,y2,...] (number of components must be divisible by 3; the windows w1, w2, etc. are physically placed with their upper left corner at physical position (x1,y1), (x2,y2),...respectively, and are then drawn together. Overlapping regions will thus be drawn twice, and the windows are considered transparent. Then display the whole drawing in a window on your screen. If flag ! = 0, x1, y1 etc. express fractions of the size of the current output device

The library syntax is void plotdraw(GEN w, long flag).


plotexport(fmt, list, {flag = 0})

Draw list of rectwindows as in plotdraw(list,flag), returning the resulting picture as a character string which can then be written to a file. The format fmt is either "ps" (PostScript output) or "svg" (Scalable Vector Graphics).

   ? plotinit(0, 100, 100);
   ? plotbox(0, 50, 50);
   ? plotcolor(0, 2);
   ? plotbox(0, 30, 30);
   ? plotdraw(0); \\ watch result on screen
   ? s = plotexport("svg", 0);
   ? write("graph.svg", s); \\ dump result to file

The library syntax is GEN plotexport(GEN fmt, GEN list, long flag).


ploth(X = a, b, expr, {flag = 0}, {n = 0})

High precision plot of the function y = f(x) represented by the expression expr, x going from a to b. This opens a specific window (which is killed whenever you click on it), and returns a four-component vector giving the coordinates of the bounding box in the form [xmin,xmax,ymin,ymax].

Important note. ploth may evaluate expr thousands of times; given the relatively low resolution of plotting devices, few significant digits of the result will be meaningful. Hence you should keep the current precision to a minimum (e.g. 9) before calling this function.

n specifies the number of reference point on the graph, where a value of 0 means we use the hardwired default values (1000 for general plot, 1500 for parametric plot, and 8 for recursive plot).

If no flag is given, expr is either a scalar expression f(X), in which case the plane curve y = f(X) will be drawn, or a vector [f1(X),...,fk(X)], and then all the curves y = fi(X) will be drawn in the same window.

The binary digits of flag mean:

* 1 = Parametric: parametric plot. Here expr must be a vector with an even number of components. Successive pairs are then understood as the parametric coordinates of a plane curve. Each of these are then drawn.

For instance:

  ploth(X=0,2*Pi,[sin(X),cos(X)], "Parametric")
  ploth(X=0,2*Pi,[sin(X),cos(X)])
  ploth(X=0,2*Pi,[X,X,sin(X),cos(X)], "Parametric")

draw successively a circle, two entwined sinusoidal curves and a circle cut by the line y = x.

* 2 = Recursive: recursive plot. If this is set, only one curve can be drawn at a time, i.e. expr must be either a two-component vector (for a single parametric curve, and the parametric flag has to be set), or a scalar function. The idea is to choose pairs of successive reference points, and if their middle point is not too far away from the segment joining them, draw this as a local approximation to the curve. Otherwise, add the middle point to the reference points. This is fast, and usually more precise than usual plot. Compare the results of

  \pb 32
  ploth(X=-1,1, sin(1/X))
  ploth(X=-1,1, sin(1/X), "Recursive")

for instance. Note that this example is pathological as it is impossible to evaluate sin(1/X) close to 0. It is better to avoid the singularity as follows.

  ploth(X=1e-10,1, sin(1/X), "Recursive")

Beware that if you are extremely unlucky, or choose too few reference points, you may draw some nice polygon bearing little resemblance to the original curve. For instance you should never plot recursively an odd function in a symmetric interval around 0. Try

  ploth(x = -20, 20, sin(x), "Recursive")

to see why. Hence, it's usually a good idea to try and plot the same curve with slightly different parameters.

The other values toggle various display options:

* 4 = no_Rescale: do not rescale plot according to the computed extrema. This is used in conjunction with plotscale when graphing multiple functions on a rectwindow (as a plotrecth call):

    s = plothsizes();
    plotinit(0, s[2]-1, s[2]-1);
    plotscale(0, -1,1, -1,1);
    plotrecth(0, t=0,2*Pi, [cos(t),sin(t)], "Parametric|no_Rescale")
    plotdraw([0, -1,1]);

This way we get a proper circle instead of the distorted ellipse produced by

    ploth(t=0,2*Pi, [cos(t),sin(t)], "Parametric")

* 8 = no_X_axis: do not print the x-axis.

* 16 = no_Y_axis: do not print the y-axis.

* 32 = no_Frame: do not print frame.

* 64 = no_Lines: only plot reference points, do not join them.

* 128 = Points_too: plot both lines and points.

* 256 = Splines: use splines to interpolate the points.

* 512 = no_X_ticks: plot no x-ticks.

* 1024 = no_Y_ticks: plot no y-ticks.

* 2048 = Same_ticks: plot all ticks with the same length.

* 4096 = Complex: is a parametric plot but where each member of expr is considered a complex number encoding the two coordinates of a point. For instance:

  ploth(X=0,2*Pi,exp(I*X), "Complex")
  ploth(X=0,2*Pi,[(1+I)*X,exp(I*X)], "Complex")

will draw respectively a circle and a circle cut by the line y = x.

* 8192 = no_MinMax: do not print the boundary numbers (in both directions).

The library syntax is ploth(void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long flag, long n, long prec),


plothexport(fmt, X = a, b, expr, {flags = 0}, {n = 0})

Plot of expression expr, X goes from a to b in high resolution, returning the resulting picture as a character string which can then be written to a file.

The format fmt is either "ps" (PostScript output) or "svg" (Scalable Vector Graphics). All other parameters and flags are as in ploth.

   ? s = plothexport("svg", x=1,10, x^2+3);
   ? write("graph.svg", s);

The library syntax is plothexport(GEN fmt, void *E, GEN (*eval)(void*, GEN), GEN a, GEN b, long flags, long n, long prec),


plothraw(X, Y, {flag = 0})

Given X and Y two vectors of equal length, plots (in high precision) the points whose (x,y)-coordinates are given in X and Y. Automatic positioning and scaling is done, but with the same scaling factor on x and y. If flag is 1, join points, other nonzero flags toggle display options and should be combinations of bits 2k, k ≥ 3 as in ploth.

The library syntax is GEN plothraw(GEN X, GEN Y, long flag).


plothrawexport(fmt, X, Y, {flag = 0})

Given X and Y two vectors of equal length, plots (in high precision) the points whose (x,y)-coordinates are given in X and Y, returning the resulting picture as a character string which can then be written to a file. The format fmt is either "ps" (PostScript output) or "svg" (Scalable Vector Graphics).

Automatic positioning and scaling is done, but with the same scaling factor on x and y. If flag is 1, join points, other nonzero flags toggle display options and should be combinations of bits 2k, k ≥ 3 as in ploth.

The library syntax is GEN plothrawexport(GEN fmt, GEN X, GEN Y, long flag).


plothsizes({flag = 0})

Return data corresponding to the output window in the form of a 8-component vector: window width and height, sizes for ticks in horizontal and vertical directions (this is intended for the gnuplot interface and is currently not significant), width and height of characters, width and height of display, if applicable. If display has no sense, e.g. for svg plots or postscript plots, then width and height of display are set to 0.

If flag = 0, sizes of ticks and characters are in pixels, otherwise are fractions of the screen size

The library syntax is GEN plothsizes(long flag).


plotinit(w, {x}, {y}, {flag = 0})

Initialize the rectwindow w, destroying any rect objects you may have already drawn in w. The virtual cursor is set to (0,0). The rectwindow size is set to width x and height y; omitting either x or y means we use the full size of the device in that direction. If flag = 0, x and y represent pixel units. Otherwise, x and y are understood as fractions of the size of the current output device (hence must be between 0 and 1) and internally converted to pixels.

The plotting device imposes an upper bound for x and y, for instance the number of pixels for screen output. These bounds are available through the plothsizes function. The following sequence initializes in a portable way (i.e independent of the output device) a window of maximal size, accessed through coordinates in the [0,1000] x [0,1000] range:

  s = plothsizes();
  plotinit(0, s[1]-1, s[2]-1);
  plotscale(0, 0,1000, 0,1000);

The library syntax is void plotinit(long w, GEN x = NULL, GEN y = NULL, long flag).


plotkill(w)

Erase rectwindow w and free the corresponding memory. Note that if you want to use the rectwindow w again, you have to use plotinit first to specify the new size. So it's better in this case to use plotinit directly as this throws away any previous work in the given rectwindow.

The library syntax is void plotkill(long w).


plotlines(w, X, Y, {flag = 0})

Draw on the rectwindow w the polygon such that the (x,y)-coordinates of the vertices are in the vectors of equal length X and Y. For simplicity, the whole polygon is drawn, not only the part of the polygon which is inside the rectwindow. If flag is nonzero, close the polygon. In any case, the virtual cursor does not move.

X and Y are allowed to be scalars (in this case, both have to). There, a single segment will be drawn, between the virtual cursor current position and the point (X,Y). And only the part thereof which actually lies within the boundary of w. Then move the virtual cursor to (X,Y), even if it is outside the window. If you want to draw a line from (x1,y1) to (x2,y2) where (x1,y1) is not necessarily the position of the virtual cursor, use plotmove(w,x1,y1) before using this function.

The library syntax is void plotlines(long w, GEN X, GEN Y, long flag).


plotlinetype(w, type)

This function is obsolete and currently a no-op.

Change the type of lines subsequently plotted in rectwindow w. type -2 corresponds to frames, -1 to axes, larger values may correspond to something else. w = -1 changes highlevel plotting.

The library syntax is void plotlinetype(long w, long type).


plotmove(w, x, y)

Move the virtual cursor of the rectwindow w to position (x,y).

The library syntax is void plotmove(long w, GEN x, GEN y).


plotpoints(w, X, Y)

Draw on the rectwindow w the points whose (x,y)-coordinates are in the vectors of equal length X and Y and which are inside w. The virtual cursor does not move. This is basically the same function as plothraw, but either with no scaling factor or with a scale chosen using the function plotscale.

As was the case with the plotlines function, X and Y are allowed to be (simultaneously) scalar. In this case, draw the single point (X,Y) on the rectwindow w (if it is actually inside w), and in any case move the virtual cursor to position (x,y).

If you draw few points in the rectwindow, they will be hard to see; in this case, you can use filled boxes instead. Compare:

  ? plotinit(0, 100,100); plotpoints(0, 50,50);
  ? plotdraw(0)
  ? plotinit(1, 100,100); plotmove(1,48,48); plotrbox(1, 4,4, 1);
  ? plotdraw(1)

The library syntax is void plotpoints(long w, GEN X, GEN Y).


plotpointsize(w, size)

This function is obsolete. It is currently a no-op.

Changes the "size" of following points in rectwindow w. If w = -1, change it in all rectwindows.

The library syntax is void plotpointsize(long w, GEN size).


plotpointtype(w, type)

This function is obsolete and currently a no-op.

change the type of points subsequently plotted in rectwindow w. type = -1 corresponds to a dot, larger values may correspond to something else. w = -1 changes highlevel plotting.

The library syntax is void plotpointtype(long w, long type).


plotrbox(w, dx, dy, {filled})

Draw in the rectwindow w the outline of the rectangle which is such that the points (x1,y1) and (x1+dx,y1+dy) are opposite corners, where (x1,y1) is the current position of the cursor. Only the part of the rectangle which is in w is drawn. The virtual cursor does not move. If filled = 1, fill the box.

The library syntax is void plotrbox(long w, GEN dx, GEN dy, long filled).


plotrecth(w, X = a, b, expr, {flag = 0}, {n = 0})

Writes to rectwindow w the curve output of ploth(w,X = a,b,expr,flag,n). Returns a vector for the bounding box.


plotrecthraw(w, data, {flags = 0})

Plot graph(s) for data in rectwindow w; flag has the same meaning here as in ploth, though recursive plot is no longer significant.

The argument data is a vector of vectors, each corresponding to a list a coordinates. If parametric plot is set, there must be an even number of vectors, each successive pair corresponding to a curve. Otherwise, the first one contains the x coordinates, and the other ones contain the y-coordinates of curves to plot.

The library syntax is GEN plotrecthraw(long w, GEN data, long flags).


plotrline(w, dx, dy)

Draw in the rectwindow w the part of the segment (x1,y1)-(x1+dx,y1+dy) which is inside w, where (x1,y1) is the current position of the virtual cursor, and move the virtual cursor to (x1+dx,y1+dy) (even if it is outside the window).

The library syntax is void plotrline(long w, GEN dx, GEN dy).


plotrmove(w, dx, dy)

Move the virtual cursor of the rectwindow w to position (x1+dx,y1+dy), where (x1,y1) is the initial position of the cursor (i.e. to position (dx,dy) relative to the initial cursor).

The library syntax is void plotrmove(long w, GEN dx, GEN dy).


plotrpoint(w, dx, dy)

Draw the point (x1+dx,y1+dy) on the rectwindow w (if it is inside w), where (x1,y1) is the current position of the cursor, and in any case move the virtual cursor to position (x1+dx,y1+dy).

If you draw few points in the rectwindow, they will be hard to see; in this case, you can use filled boxes instead. Compare:

  ? plotinit(0, 100,100); plotrpoint(0, 50,50); plotrpoint(0, 10,10);
  ? plotdraw(0)
  
  ? thickpoint(w,x,y)= plotmove(w,x-2,y-2); plotrbox(w,4,4,1);
  ? plotinit(1, 100,100); thickpoint(1, 50,50); thickpoint(1, 60,60);
  ? plotdraw(1)

The library syntax is void plotrpoint(long w, GEN dx, GEN dy).


plotscale(w, x1, x2, y1, y2)

Scale the local coordinates of the rectwindow w so that x goes from x1 to x2 and y goes from y1 to y2 (x2 < x1 and y2 < y1 being allowed). Initially, after the initialization of the rectwindow w using the function plotinit, the default scaling is the graphic pixel count, and in particular the y axis is oriented downwards since the origin is at the upper left. The function plotscale allows to change all these defaults and should be used whenever functions are graphed.

The library syntax is void plotscale(long w, GEN x1, GEN x2, GEN y1, GEN y2).


plotstring(w, x, {flags = 0})

Draw on the rectwindow w the String x (see Section se:strings), at the current position of the cursor.

flag is used for justification: bits 1 and 2 regulate horizontal alignment: left if 0, right if 2, center if 1. Bits 4 and 8 regulate vertical alignment: bottom if 0, top if 8, v-center if 4. Can insert additional small gap between point and string: horizontal if bit 16 is set, vertical if bit 32 is set (see the tutorial for an example).

The library syntax is void plotstring(long w, const char *x, long flags).


psdraw(list, {flag = 0})

This function is obsolete, use plotexport and write the result to file.

The library syntax is void psdraw(GEN list, long flag).


psploth(X = a, b, expr, {flags = 0}, {n = 0})

This function is obsolete, use plothexport and write the result to file.

The library syntax is GEN psploth0(GEN X, GEN b, GEN expr, long flags, long prec).


psplothraw(listx, listy, {flag = 0})

This function is obsolete, use plothrawexport and write the result to file.

The library syntax is GEN psplothraw(GEN listx, GEN listy, long flag).