Asymptote is an excellent tool to greate more complex editable graphs. However, the documentation is thin and very hard to navigate. Here are some notes.
Output formats can be specified
asy -f <format>
At least these formats are supported:
The main drawing command is draw
. It most important arguments are
draw(path)
If the path contains a single pair, it just draws a dot.
Dots can be drawn with dot(pair)
. Dots are drawn using the current line width, and the width is magnified by system variable dotfactor
. For instance:
The dot is drawn using the current line width, multiplied but dotfactor
(default: 6).
The basic way to add labels to points is with
label(Label L, pair position, align align, pen p, filltype filltype)
align is the location of label with respective to the position. By default, the label is centered at the position. This should be a vector (pair) that indicates the position of the closest corner of the lable with respect to the point.
There are a number of pre-defined compas directions (N
, S
, E
, W
, SE
, SW
, ENE
and such) that define the direction where to shift the label away from the point by a suitable amount. For instance, when using align NW
, then the label is positioned top-right of the position, so that its lower-right corner is in the NW direction.
2*N + E
), and one can supply other vectors. A useful way to create vectors is function dir
that creates an unit vector in given direction (in degrees).filltype: the background of a label can be filled with a given color, e.g. you may want to specify Fill(white)
to add a white background on a label that is on top of obscured by other elements.
The following image demonstrates a few of these tools:
dir(30)
by 32. This number depends on the size and should be found by experimenting.dir(150)
point, however, to the opposite direction (inside of the circle) of it. The background is filled white in order to remove the spoke behind the label.size(80mm);
draw(unitcircle);
draw((0,0)--(1,0));
/* pre-determined direction 'E' */
label("$0^\circ$", (1,0), E);
draw((0,0)--dir(30));
/* label the origin, shift far to direction of 30deg */
label("$30^\circ$", (0,0), 32*dir(30));
draw((0,0)--dir(150));
/* label the 150deg point, shift to the opposite direction
fill background white to cover the spike */
label("$150^\circ$", dir(150), -dir(150),
Fill(white));
This results in
Frames and pictures are a way to repeate certain complex drawings when potentially transforming those in the process.
Pictures are, well, pictures.
The following example demonstrates how to create a new picture, and add it to the main picture several times with small modifications. We create the main picture that contains a diagonal line, and another picture object that contains a scaled unit circle. Thereafter we a) add the circle-picture on the main picture unchanged, and b) add it second time, scaled and shifted to the end of the diagonal line:
/* set the total size, for all pictures we do */
size(120mm);
/* Draw a diagonal line on the base pic */
draw((0,0)--(1,1));
/* Create a new picture, containing a circle */
picture p = new picture;
draw(p, scale(0.2)*unitcircle);
/* put the circle at the origin */
add(p);
/* put the circle again, shifted and scaled */
add(shift((1,1))*scale(2)*p);
This results in
The originally defined size applies to the new pictures as well, so adding a new picture will automatically scale in a way that the unit size will be the same as on the original picture.
Frames are somewhat similar to pictures, but it seems one cannot change size or unitsize on frames. The result will be in postscript units. However, one can use similar add
function, and scale frames.
Output to console can be done using write
, it accepts a list of arguments that will be printed, no spaces are inserted between the list items. It can print various asymptote data structures, including pairs and paths. See example in Functions.
There are two types of for loops, both following the java/C++ style. The first one contains the explicit initializer, condition, and increment statement, all separated by semicolons:
The other is the “variable : collection” syntax to loop over all variables in a collection:
Note that in both cases the loop variable must be defined inside of the loop operator. The loop variable only exists within the loop and is lost as soon as the loop exits.
Function definition is fairly similar to function in C++ and java. You have to declare the return type, and argument types. Argument default values are accepted.
Function must return a value–a missing return statement results in an error, unless the return value is declared as void.
real multiply(real x, real y=3) {
real z = x*y;
return z;
}
write("2*3=", multiply(2));
write("2*4=", multiply(2, 4));
The output is:
2*3=6
2*4=8