Next: three, Previous: embed, Up: Base modules
graph
This package implements two-dimensional linear and logarithmic graphs,
including automatic scale and tick selection (with the ability to
override manually). A graph is a guide
(that can be drawn with
the draw command, with an optional legend) constructed with one of
the following routines:
guide graph(picture pic=currentpicture, real f(real), real a, real b, int n=ngraph, interpolate join=operator --);
Returns a graph using the scaling information for picture pic
(see automatic scaling) of the function f
on the interval
[a
,b
], sampling at n
evenly spaced points, with
one of these interpolation types:
guide graph(picture pic=currentpicture, real x(real), real y(real), real a, real b, int n=ngraph, interpolate join=operator --);
Returns a graph using the scaling information for picture pic
of the parametrized function
(x
(t),y
(t)) for t in
[a
,b
], sampling at n
evenly spaced points, with
the given interpolation type.
guide graph(picture pic=currentpicture, pair z(real), real a, real b, int n=ngraph, interpolate join=operator --);
Returns a graph using the scaling information for picture pic
of the parametrized function
z
(t) for t in [a
,b
], sampling at
n
evenly spaced points, with the given interpolation type.
guide graph(picture pic=currentpicture, pair[] z, bool[] cond={}, interpolate join=operator --);
Returns a graph using the scaling information for picture pic
of those elements of the array
z
for which the corresponding elements of the boolean array
cond
are true
, with the given interpolation type.
guide graph(picture pic=currentpicture, real[] x, real[] y, bool[] cond={}, interpolate join=operator --);
Returns a graph using the scaling information for picture pic
of those elements of the arrays
(x
,y
) for which the corresponding elements of the boolean array
cond
are true
, with the given interpolation type.
guide graph(real f(real), real a, real b, int n=ngraph, real T(real), interpolate join=operator --);
Returns a graph using the scaling information for picture pic
of the function f
on the interval
[T
(a
),T
(b
)], sampling at n
points evenly
spaced in [a
,b
], with the given interpolation type.
@cindex @code{polargraph} guide polargraph(real f(real), real a, real b, int n=ngraph, interpolate join=operator --);
Returns a polar-coordinate graph using the scaling information for
picture pic
of the function f
on the interval
[a
,b
], sampling at n
evenly spaced points, with
the given interpolation type.
An axis can be drawn on a picture with one of the following commands:
void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, bool put=Below);
Draw an x axis on picture pic
from x=xmin
to
x=xmax
using pen p
, optionally labelling it with
Label L
. The relative label location along the axis (a real number from
[0,1]) defaults to 1 (see Label), so that the label is drawn at the
end of the axis. An infinite value of xmin
or xmax
specifies that the corresponding axis limit will be
automatically determined from the picture limits.
The optional arrow
argument takes the same values as in the
draw
command (see arrows). If put
=Below
and
the extend
flag for axis
is false
, the axis is
drawn before any existing objects in the current picture.
The axis placement is determined by one of the following axis
types:
YZero(bool extend=true)
extend
=false.
YEquals(real Y, bool extend=true)
Y
extending to the full
dimensions of the picture, unless extend
=false.
Bottom(bool extend=false)
Top(bool extend=false)
BottomTop(bool extend=false)
Custom axis types can be created by following the examples in graph.asy
.
One can easily override the default values for the standard axis types:
import graph; YZero=new axis(bool extend=true) { return new void(picture pic, axisT axis) { real y=pic.scale.x.scale.logarithmic ? 1 : 0; axis.value=I*pic.scale.y.T(y); axis.position=1; axis.side=right; axis.align=2.5E; axis.value2=Infinity; axis.extend=extend; }; }; YZero=YZero();
The default tick option is NoTicks
.
The option LeftTicks
(RightTicks
) can be used to draw
ticks on the left (right) of the path, relative to the direction in which
the path is drawn. These tick routines accept a number of optional arguments:
ticks LeftTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, int N=0, int n=0, real Step=0, real step=0, bool begin=true, bool end=true, real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen);
If any of these parameters are omitted, reasonable defaults will be chosen:
Label format
defaultformat
, initially
"$%.4g$"), rotation, pen, and alignment (for example, LeftSide
,
Center
, or RightSide
) relative to the axis. To enable
LaTeX
math mode fonts, the format string should begin and
end with $
see format; if the format string is "%"
,
the tick label will be suppressed;
ticklabel
string(real x)
returning the label (by default,
format(format.s,x)) for each tick value x
;
bool beginlabel
bool endlabel
int N
int n
real Step
N
=0
);
real step
n
=0
);
bool begin
bool end
real Size
PostScript
coordinates);
real size
PostScript
coordinates);
bool extend;
pen pTick
pen ptick
It is also possible to specify custom tick locations with
LeftTicks
and RightTicks
by passing explicit real
arrays Ticks
and (optionally) ticks
containing the
locations of the big and small ticks, respectively:
ticks LeftTicks(Label format="", ticklabel ticklabel=null, bool beginlabel=true, bool endlabel=true, real[] Ticks, real[] ticks=new real[], real Size=0, real size=0, bool extend=false, pen pTick=nullpen, pen ptick=nullpen)
void yaxis(picture pic=currentpicture, Label L="", axis axis=XZero, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, arrowbar arrow=None, bool put=Below);
Draw a y axis on picture pic
from y=ymin
to
y=ymax
using pen p
, optionally labelling it with
Label L
. The relative location of the label (a real number from
[0,1]) defaults to 1 (see Label). An infinite value of ymin
or ymax
specifies that the corresponding axis limit will be
automatically determined from the picture limits.
The optional arrow
argument takes the same values as in the
draw
command (see arrows). If put
=Below
and
the extend
flag for axis
is false
, the axis is
drawn before any existing objects in the current picture.
The tick type is specified by ticks
and the axis placement is
determined by one of the following axis
types:
XZero(bool extend=true)
extend
=false.
XEquals(real X, bool extend=true)
X
extending to the full
dimensions of the picture, unless extend
=false.
Left(bool extend=false)
Right(bool extend=false)
LeftRight(bool extend=false)
void xequals(picture pic=currentpicture, Label L="", real x, bool extend=false, real ymin=-infinity, real ymax=infinity, pen p=currentpen, ticks ticks=NoTicks, bool put=Above, arrowbar arrow=None);and
void yequals(picture pic=currentpicture, Label L="", real y, bool extend=false, real xmin=-infinity, real xmax=infinity, pen p=currentpen, ticks ticks=NoTicks, bool put=Above, arrowbar arrow=None);can be respectively used to call
yaxis
and
xaxis
with the appropriate axis types XEquals(x,extend)
and
YEquals(y,extend)
. This is the recommended way of drawing vertical
or horizontal lines and axes at arbitrary locations.
void axis(picture pic=currentpicture, Label L="", guide g, pen p=currentpen, ticks ticks, ticklocate locate, arrowbar arrow=None, int[] divisor=new int[], bool put=Above, bool opposite=false);
This routine can be used to draw on picture pic
a general axis
based on an arbitrary path g
, using pen p
.
One can optionally label the axis with Label L
and add an arrow
arrow
. The tick type is given by ticks
.
The optional integer array divisor
specifies what tick divisors
to try in the attempt to produce uncrowded tick labels. A true
value for the flag opposite
identifies an unlabelled secondary
axis (typically drawn opposite a primary axis). The axis is drawn
on top of any existing objects in the current picture only if put
is Above
. The tick locater ticklocate
is
constructed by the routine
ticklocate ticklocate(real a, real b, autoscaleT S=defaultS, real tickmin=-infinity, real tickmax=infinity, real time(real)=null, pair dir(real)=zero);where
a
and b
specify the respective tick values at
point(g,0)
and point(g,length(g))
, S
specifies
the autoscaling transformation, the function real time(real v)
returns the time corresponding to the value v
, and
pair dir(real t)
returns the absolute tick direction as a
function of t
(zero means draw the tick perpendicular to the axis).
Label
is given as the Label
argument, the format
argument will be used to format a string based on
the tick location):
void xtick(picture pic=currentpicture, Label L="", pair z, pair dir=N, string format="", real size=Ticksize, pen p=currentpen); void ytick(picture pic=currentpicture, Label L="", explicit pair z, pair dir=E, string format="", real size=Ticksize, pen p=currentpen); void ytick(picture pic=currentpicture, Label L="", real y, pair dir=E, string format="", real size=Ticksize, pen p=currentpen); void tick(picture pic=currentpicture, pair z, pair dir, real size=Ticksize, pen p=currentpen); void labelx(picture pic=currentpicture, Label L="", pair z, align align=S, string format="", pen p=nullpen); void labelx(picture pic=currentpicture, Label L, string format="", explicit pen p=currentpen); void labely(picture pic=currentpicture, Label L="", explicit pair z, align align=W, string format="", pen p=nullpen); void labely(picture pic=currentpicture, Label L="", real y, align align=W, string format="", pen p=nullpen); void labely(picture pic=currentpicture, Label L, string format="", explicit pen p=nullpen);
Here are some simple examples of two-dimensional graphs:
import graph; size(150,0); real f(real x) {return exp(x);} pair F(real x) {return (x,f(x));} xaxis("$x$"); yaxis("$y$",0); draw(graph(f,-4,2,operator ..),red); labely(1,E); label("$e^x$",F(1),SE);
xasy
(see GUI). If an
UnFill(real xmargin=0, real ymargin=xmargin)
or
Fill(pen)
option is specified to add
, the legend will obscure
any underlying objects. Here we illustrate how to clip the portion of
the picture covered by a label:
import graph; size(400,200,IgnoreAspect); real Sin(real t) {return sin(2pi*t);} real Cos(real t) {return cos(2pi*t);} draw(graph(Sin,0,1),red,"$\sin(2\pi x)$"); draw(graph(Cos,0,1),blue,"$\cos(2\pi x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); label("LABEL",point(0),UnFill(1mm)); add(point(E),legend(20E),UnFill);
To specify a fixed size for the graph proper, use attach
.
import graph; size(250,200,IgnoreAspect); real Sin(real t) {return sin(2pi*t);} real Cos(real t) {return cos(2pi*t);} draw(graph(Sin,0,1),red,"$\sin(2\pi x)$"); draw(graph(Cos,0,1),blue,"$\cos(2\pi x)$"); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks); label("LABEL",point(0),UnFill(1mm)); attach(point(E),legend(20E),UnFill);
import graph; size(200,150,IgnoreAspect); real[] x={0,1,2,3}; real[] y=x^2; draw(graph(x,y),red,MarkFill[0]); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks(Label(fontsize(8)),new real[]{0,4,9}));
marker marker(path g, markroutine markroutine=marknodes, pen p=currentpen, filltype filltype=NoFill, bool put=Above);using the path
unitcircle
(see filltype), are drawn
below each node. Any frame can be converted to a marker, using
marker marker(frame f, markroutine markroutine=marknodes, bool put=Above);In the right-hand graph, the unit n-sided regular polygon
polygon(int n)
and the unit n-point cross
cross(int n)
are used to build a custom marker frame.
Here markuniform(int n)
adds this frame at n
uniformly spaced points along the arclength of the path. This example also
illustrates the errorbar
routines:
void errorbars(picture pic=currentpicture, pair[] z, pair[] dp, pair[] dm={}, bool[] cond={}, pen p=currentpen, real size=0); void errorbars(picture pic=currentpicture, real[] x, real[] y, real[] dpx, real[] dpy, real[] dmx={}, real[] dmy={}, bool[] cond={}, pen p=currentpen, real size=0);
Here, the positive and negative extents of the error are given by the
absolute values of the elements of the pair array dp
and the
optional pair array dm
. If dm
is not specified, the
positive and negative extents of the error are assumed to be equal.
import graph; picture pic; real xsize=200, ysize=140; size(pic,xsize,ysize,IgnoreAspect); pair[] f={(5,5),(50,20),(90,90)}; pair[] df={(0,0),(5,7),(0,5)}; errorbars(pic,f,df,red); draw(pic,graph(pic,f),"legend", marker(scale(0.8mm)*unitcircle,blue,Fill,Below)); xaxis(pic,"$x$",BottomTop,LeftTicks); yaxis(pic,"$y$",LeftRight,RightTicks); add(point(pic,NW),pic,legend(pic,20SE),UnFill); picture pic2; size(pic2,xsize,ysize,IgnoreAspect); frame mark; filldraw(mark,scale(0.8mm)*polygon(6),green); draw(mark,scale(0.8mm)*cross(6),blue); draw(pic2,graph(pic2,f),marker(mark,markuniform(5))); xaxis(pic2,"$x$",BottomTop,LeftTicks); yaxis(pic2,"$y$",LeftRight,RightTicks); yequals(pic2,55.0,red+Dotted); xequals(pic2,70.0,red+Dotted); // Fit pic to W of origin: add(pic.fit(),W); // Fit pic2 to E of (5mm,0): add((5mm,0),pic2.fit(),E);
xlimits(picture pic=currentpicture, real min=-infinity, real max=infinity, bool crop=Crop);
and the analogous function ylimits
can be uncommented
to restrict the respective axes limits for picture pic
to the
specified min
and max
values (alternatively, the function
limits(pair, pair)
can be used to limit the axes to the
box having opposite vertices at the given pairs).
Existing objects in picture pic
will be cropped to lie
within the given limits if crop
=Crop
. The function
crop(picture pic)
is equivalent to calling both
xlimits(Crop)
and ylimits(Crop)
.
import graph; size(0,200); real x(real t) {return cos(2pi*t);} real y(real t) {return sin(2pi*t);} draw(graph(x,y,0,1)); //xlimits(0,1); //ylimits(-1,0); xaxis("$x$",BottomTop,LeftTicks("$%#.1f$")); yaxis("$y$",LeftRight,RightTicks("$%#.1f$"));
Axis scaling can be requested and/or automatic selection of the
axis limits can be inhibited with the scale
routine:
void scale(picture pic=currentpicture, scaleT x, scaleT y);
This sets the scalings for picture pic
. The graph
routines
accept an optional picture
argument for determining the appropriate
scalings to use; if none is given, it uses those set for currentpicture
.
All path coordinates (and any call to limits
, etc.)
refer to scaled data. Two frequently used scaling routines
Linear
and Log
are predefined in graph
.
Scaling routines can be given two optional boolean arguments:
automin
and automax
. These default to true
, but can
be respectively set to false
to disable automatic selection of
"nice" axis minimum and maximum values. Linear
can also take as an optional final argument a multiplicative scaling
factor (e.g. for a depth axis, Linear(-1)
requests axis reversal).
For example, to draw a log graph of a function, use scale(Log,Log)
:
import graph; size(200,200,IgnoreAspect); real f(real t) {return 1/t;} scale(Log,Log); draw(graph(f,0.1,10)); //xlimits(1,10); //ylimits(0.1,1); xaxis("$x$",BottomTop,LeftTicks); yaxis("$y$",LeftRight,RightTicks);
By extending the ticks, one can easily produce a logarithmic grid:
import graph; size(200,200,IgnoreAspect); real f(real t) {return 1/t;} scale(Log,Log); draw(graph(f,0.1,10),red); pen thin=linewidth(0.5*linewidth()); xaxis("$x$",BottomTop,LeftTicks(begin=false,end=false,extend=true, ptick=thin)); yaxis("$y$",LeftRight,RightTicks(begin=false,end=false,extend=true, ptick=thin));
One can also specify custom tick locations and formats for logarithmic axes:
import graph; size(300,175,IgnoreAspect); scale(Log,Log); draw(graph(identity,5,20)); xlimits(5,20); ylimits(1,100); xaxis("$M/M_\odot$",BottomTop,LeftTicks(new real[] {6,10,12,14,16,18})); yaxis("$\nu_{\rm upp}$ [Hz]",LeftRight, RightTicks(new string(real x){return format(pow10(x));}));
Here is an example of a "broken" linear x axis that omits the segment [3,8]:
import graph; size(200,150,IgnoreAspect); // Break the axis at 3; restart at 8. real a=3, b=8; scale(Broken(a,b),Linear); real[] x={1,2,10}; real[] y=x^2; draw(graph(x,y),red,MarkFill[0]); xaxis("$x$",BottomTop,LeftTicks(new real[]{0,1,2,9,10})); yaxis("$y$",LeftRight,RightTicks); label(rotate(90)*Break,(a,currentpicture.userMin.y)); label(rotate(90)*Break,(a,currentpicture.userMax.y));
Asymptote
can draw secondary axes with the routines
picture secondaryX(picture primary=currentpicture, void f(picture)); picture secondaryY(picture primary=currentpicture, void f(picture));
In this example, secondaryY
is used to draw a secondary linear
y axis against a primary logarithmic y axis:
import graph; texpreamble("\def\Arg{\mathop {\rm Arg}\nolimits}"); size(10cm,5cm,IgnoreAspect); real ampl(real x) {return 2.5/(1+x^2);} real phas(real x) {return -atan(x)/pi;} scale(Log,Log); draw(graph(ampl,0.01,10)); ylimits(.001,100); xaxis("$\omega\tau_0$",BottomTop,LeftTicks); yaxis("$|G(\omega\tau_0)|$",Left,RightTicks); picture q=secondaryY(new void(picture pic) { scale(pic,Log,Linear); draw(pic,graph(pic,phas,0.01,10),red); ylimits(pic,-1.0,1.5); yaxis(pic,"$\Arg G/\pi$",Right,red, LeftTicks("$% #.1f$", begin=false,end=false)); yequals(pic,1,Dotted); }); label(q,"(1,0)",Scale(q,(1,0)),red); add(q);
A secondary logarithmic y axis can be drawn like this:
import graph; size(9cm,6cm,IgnoreAspect); string data="secondaryaxis.csv"; file in=line(csv(input(data))); string[] titlelabel=in; string[] columnlabel=in; real[][] a=dimension(in,0,0); a=transpose(a); real[] t=a[0], susceptible=a[1], infectious=a[2], dead=a[3], larvae=a[4]; real[] susceptibleM=a[5], exposed=a[6],infectiousM=a[7]; draw(graph(t,susceptible,t >= 10 && t <= 15)); draw(graph(t,dead,t >= 10 && t <= 15),dashed); xaxis("Time ($\tau$)",BottomTop,LeftTicks); yaxis(Left,RightTicks); picture secondary=secondaryY(new void(picture pic) { scale(pic,Linear,Log); draw(pic,graph(pic,t,infectious,t >= 10 && t <= 15),red); yaxis(pic,Right,red,LeftTicks(begin=false,end=false)); }); add(secondary); label(shift(5mm*N)*"Proportion of crows",point(NW),E);
stats
module.
import graph; import stats; size(400,200,IgnoreAspect); int n=10000; real[] a=new real[n]; for(int i=0; i < n; ++i) a[i]=Gaussrand(); int nbins=100; real dx=(max(a)-min(a))/(nbins-1); real[] x=min(a)-dx/2+sequence(nbins+1)*dx; real[] freq=frequency(x,a); freq /= (dx*sum(freq)); histogram(x,freq); draw(graph(Gaussian,min(a),max(a)),red); xaxis("$x$",BottomTop,LeftTicks); yaxis("$dP/dx$",LeftRight,RightTicks);
stats
module.
size(400,200,IgnoreAspect); import graph; import stats; file fin=line(input("leastsquares.dat")); real[][] a=dimension(fin,0,0); a=transpose(a); real[] t=a[0], rho=a[1]; // Read in parameters from the keyboard: //real first=getreal("first"); //real step=getreal("step"); //real last=getreal("last"); real first=100; real step=50; real last=700; // Remove negative or zero values of rho: t=rho > 0 ? t : null; rho=rho > 0 ? rho : null; scale(Log,Linear); int n=step > 0 ? ceil((last-first)/step) : 0; real[] T,xi,dxi; for(int i=0; i <= n; ++i) { real first=first+i*step; real[] logrho=(t >= first && t <= last) ? log(rho) : null; real[] logt=(t >= first && t <= last) ? -log(t) : null; if(logt.length < 2) break; // Fit to the line logt=L.m*logrho+L.b: linefit L=leastsquares(logt,logrho); T.push(first); xi.push(L.m); dxi.push(L.dm); } draw(graph(T,xi),blue); errorbars(T,xi,dxi,red); ylimits(0); xaxis("$T$",BottomTop,LeftTicks); yaxis("$\xi$",LeftRight,RightTicks);
axis
routine.
import graph; size(0,100); guide g=ellipse((0,0),1,2); axis(Label("C",align=10W),g,LeftTicks(endlabel=false,8,end=false), ticklocate(0,360,new real(real v) { path h=(0,0)--max(abs(max(g)),abs(min(g)))*dir(v); return intersect(g,h).x;}));
typedef path vector(real); void vectorfield(picture pic=currentpicture, path g, int n, vector vector, real arrowsize=0, real arrowlength=0, pen p=currentpen);Here is a simple example of a flow field:
import graph; defaultpen(1.0); size(0,150,IgnoreAspect); real arrowsize=4mm; real arrowlength=2arrowsize; // Return a vector interpolated linearly between a and b. vector vector(pair a, pair b) { return new path(real x) { return (0,0)--arrowlength*interp(a,b,x); }; } real alpha=1; real f(real x) {return alpha/x;} real epsilon=0.5; path p=graph(f,epsilon,1/epsilon); int n=2; draw(p); xaxis("$x$"); yaxis("$y$"); vectorfield(p,n,vector(W,W),arrowsize); vectorfield((0,0)--(currentpicture.userMax.x,0),n,vector(NE,NW), arrowsize); vectorfield((0,0)--(0,currentpicture.userMax.y),n,vector(NE,NE), arrowsize);
Asymptote
can also generate color density images
and palettes. The following palettes are predefined in
palette.asy
:
pen[] Grayscale(int NColors=256)
pen[] Rainbow(int NColors=65501)
pen[] BWRainbow(int NColors=65485)
pen[] BWRainbow2(int NColors=65485)
The function cmyk(pen[] Palette)
may be used to convert any
of these palettes to the CMYK colorspace.
A color density plot can added to a picture pic
by generating
from a real[][] array data
, using palette palette
, an image
spanning the rectangular region with opposite corners at coordinates
initial
and final
:
void image(picture pic=currentpicture, real[][] data, pen[] palette, pair initial, pair final);
An optionally labelled palette bar may be generated with the routine
picture palette(real[][] data, real width=Ticksize, pen[] palette, Label L, pen p=currentpen, paletteticks ticks=PaletteTicks)
The argument paletteticks
is a special tick type (see ticks)
that takes the following arguments:
paletteticks PaletteTicks(int N=0, real Step=0, bool beginlabel=true, bool endlabel=true, Label format="", pen pTick=nullpen);
The image and palette bar can be fit (and optionally aligned) to a frame
and added to picture dest
at the location origin
using
add(pair origin=0, picture dest=currentpicture, frame)
:
import graph; import palette; int n=256; real ninv=2pi/n; real[][] v=new real[n][n]; for(int i=0; i < n; ++i) for(int j=0; j < n; ++j) v[i][j]=sin(i*ninv)*cos(j*ninv); pen[] Palette=BWRainbow(); picture plot; image(plot,v,Palette,(0,0),(1,1)); picture bar=palette(v,5mm,Palette,"$A$",PaletteTicks("$%+#.1f$")); add(plot.fit(250,250),W); add((1cm,0),bar.fit(0,250),E);
Asymptote
's graphics routines, were generated from the examples
diatom.asy
and westnile.asy
, using the comma-separated
data in diatom.csv
and westnile.csv
.