# Handy TikZ's node version in Asymptote?

I am interested in a variation of the classical SIR model in epidemics. The illustration with TikZ is simple with handy nodes.

\documentclass[tikz,border=5mm]{standalone}
\begin{document}
\begin{tikzpicture}
\def\a{1.5}
\path[nodes={draw,circle,minimum size=8mm,fill=yellow,draw=blue}]
(210:\a) node (S) {$S$}
(-30:\a) node (I) {$I$}
(90:\a)  node (R) {$R$}
;
\draw[->] (S)--(I);
\draw[->] (I)--(R);
\draw[->] (R)--(S);
\draw[->] (R.0) to[out=0,in=60] (I.60);
\end{tikzpicture}
\end{document}


For me it's quite complicated when using Asymptote to illustrate the above simple diagram. Asymptote is powerful, and I suppose it should cover graceful feature of TikZ's node (inner sep, minimum width, shape=circle, shape=ellipse, anchor, .center, S.30, etc). The following is what I have tried so far.

First try fails in controlling arrow tips, circle shape, and size of labels.

// http://asymptote.ualberta.ca/
unitsize(1.5cm);
path R=dir(90), S=dir(210), I=dir(-30);

Label LS = Label("$S$", FillDraw(yellow,blue));
Label LI = Label("$I$", FillDraw(yellow,blue));
Label LR = Label("$R$", FillDraw(yellow,blue));

draw(S--I--R--cycle);
path pRI=arc((0,0),1,90,-30);
draw(pRI);
label(LS,S);
label(LI,I);
label(LR,R);


Second try can make circle shape, arrow tips, but fails in controlling incline connector, size of labels, filling and drawing shape with color (yellow, blue).

// http://asymptote.ualberta.ca/
unitsize(1.5cm);
import flowchart;
pair R=dir(90), S=dir(210), I=dir(-30);
block blockS=circle("S",S);
block blockI=circle("I",I);
block blockR=circle("R",R);

draw(blockS,blue);
draw(blockI);
draw(blockR);

add(new void(picture pic, transform t) {
blockconnector operator --=blockconnector(pic,t);
});


In summary, I have 2 questions in drawing with Asymptote.

Question 1: How to draw arrows from S to I, I to R, R to I such that arrow tips touch the blue boundaries?

Question 2: How to make circular/elliptic shapes around label S,I,R ?

Update 24 Dec 2020 It seems that Asymptote's objects do the job. In my third try, arrow tips touched the blue boundaries, but all shapes are ellipses, not circles (see I), and I have to specify boundary point by hand (see point(LI,dir(120),t)). The code is extracted from Asymptote's gallery, so my questions is more reasonable.

unitsize(1.5cm);
pair R=dir(90), S=dir(210), I=dir(-30);
real margin=3mm;

object LS=draw("$S$",ellipse,S,margin,FillDraw(yellow,blue));
object LI=draw("$I$",ellipse,I,margin,FillDraw(yellow,blue));
object LR=draw("$R$",ellipse,R,margin,FillDraw(yellow,blue));

add(new void(frame f, transform t) {
picture pic;
pair R1=point(LR,NE,t), I1=point(LI,NE,t);
path pRI=R1 .. controls R1+30*dir(45) and I1+40*dir(35).. I1;

});

shipout(bbox(5mm));

• Although I'm normally all in favor of using Asymptote, for diagrams with arrows between text TikZ is far superior. Do you have a really good reason to use Asymptote instead for this? (E.g., you want to incorporate this diagram into another, more complex diagram?) Commented Dec 18, 2020 at 19:45
• I've had very good luck with the package here: github.com/taoari/asy-graphtheory/blob/master/Usage.md (Although I'll note that it is not official, and the documentation is not the best, and I know of a bug or two that the author has not fixed.) Commented Dec 19, 2020 at 14:14
• @CharlesStaats While we are thinking more about a really good reason to use Asymptote to draw diagrams with arrows, I have just added an update code. It seems that Asymptote's objects is similar to TikZ's node's. Commented Dec 23, 2020 at 18:03
• @CharlesStaats: I agree that for 2D diagrams with arrows, TikZ is a good choice. The reason for my question is from an advertising of Asymptote: "Why was the name Asymptote chosen? Well, it isn't the perfect graphics package, but we do think it is getting there asymptotically..." Moreover, 3D node seems promissing concept. asymptote.sourceforge.io/FAQ/section1.html#whyasy Commented Dec 27, 2020 at 6:28

Diagrams with arrows can be drawn with plain Asymptote, ALMOST as simple as with plain TikZ.

I am quite comfortable with this solution, but still open for better ones. My way is using plain Asymptote: no other command/module needed.

Note that a circle is an ellipse with equal sizes. By combining object and label, we can get the circle shape, hence making uniform size for all circle shapes (similar to minimum width of TikZ's node).

object
S=draw("",ellipse,(0,0),xmargin=3mm,FillDraw(yellow,blue)),
I=draw("",ellipse,(4cm,0),xmargin=3mm,FillDraw(yellow,blue)),
R=draw("",ellipse,(2cm,3cm),xmargin=3mm,FillDraw(yellow,blue));
label("S",(0,0));
label("I",(4cm,0));
label("R",(2cm,3cm));
pair
S1=point(S,E), I1=point(I,W),
I2=point(I,dir(120)), R1=point(R,dir(-60)),
R2=point(R,dir(-120)), S2=point(S,dir(60)),
R3=point(R,dir(-20)), I3=point(I,dir(70))
;
draw(S1--I1,red,Arrow());
draw(I2--R1,red,Arrow());
draw(R2--S2,red,Arrow());
draw(R3 .. controls R3+1cm*dir(0) and I3+1cm*dir(70) .. I3,red,Arrow());


So far, usual TikZ's node involving options (inner sep, inner xsep, inner ysep, fill, draw, minimum size, shorten >, anchor of border shape, shorten <, circle, ellipse, rectangle, loop, scale, sloped, rotate, text color) are easily translated to Asymptote. I am not going to test some other features (anchors of text, aligning nodes, ...).

// Diagrams with arrows can be drawn with plain Asymptote
object
S=draw("",ellipse,(0,0),xmargin=6mm,FillDraw(yellow,blue)),
I=draw("",ellipse,(4cm,0),xmargin=3mm,FillDraw(yellow,blue)),
R=draw("",ellipse,(2cm,3cm),xmargin=3mm,FillDraw(yellow,blue));
label(scale(3)*"S",(0,0));
label(scale(.5)*"i",(4cm,0));
label("R",(2cm,3cm));

pair
S1=point(S,E), I1=point(I,W),
I2=point(I,dir(120)), R1=point(R,dir(-60)),
R2=point(R,dir(-120)), S2=point(S,dir(60)),
R3=point(R,dir(-20)), I3=point(I,dir(70)),
I4=point(I,dir(-45))
;

draw("$\alpha$",S1--I1,purple,Arrow(),margin=TrueMargin(.5mm, 2mm));
draw(Label("$\beta$",align=SW),I2--R1,red,Arrow(),margin=TrueMargin(1mm));
draw(Label("gamma",Rotate(R2-S2)),R2--S2,red,Arrow());
draw("$\delta$",R3{0} .. {-60}I3,red,Arrow(),margin=TrueMargin(2mm));
draw(Label("go to Heaven",align=plain.S,EndPoint),I4--I4+1cm*dir(-45),cyan,Arrow);



Sometimes TikZ makes LaTeX more beautiful with tables as tikzpicture via matrix of nodes, matrix of math nodes. In my current opinion, those options should not be expected in Asymptote due to standalone nature of each figure, and Asymptote's strength is real 3D. I am not considering TikZ as a standard of drawing, but it is a starting viewpoint when caring what Asymptote can help me/us expressing ideas visually.

This is long comment, and still not a concise answer.

I found the 2009 link that use import node; In that node.asy, the syntax is still somehow not so handy in my subjective opinion. Also see Jim Heffron's answer from 2014.

From the above link, I make my 4th try. First recall that the syntax of object from plain_boxes.asy

object draw(picture pic=currentpicture, Label L, envelope e,
pair position=(0,0), real xmargin=0, real ymargin=xmargin,
pen p=currentpen, filltype filltype=NoFill);


There are shapes of box (rectangle), ellipse, roundbox, but there is no circle shape. We can control Draw, Fill, xmargin and ymargin (like TikZ's inner sep); we can get any point in the boundary (TikZ's anchors) of the defined object.

object
cat = draw("cat", box, (0,0), Draw),
dog = draw("dog", ellipse, (2cm,0), Fill(olive)),
elephant = draw("elephant", roundbox, (0,-2cm),xmargin=2mm,FillDraw(lightblue, darkblue));

pair C=point(cat,E),Ct=point(cat,S);
pair D=point(dog,-90), Dt=point(dog,SW);
pair E=point(elephant,N), Et=point(elephant,NNE);


Then I come to this, simple code with quite good look, except all shapes are ellipses, not circles.

object
S=draw("S",ellipse,(0,0),xmargin=3mm,FillDraw(yellow,blue)),
I=draw("I",ellipse,(4cm,0),xmargin=3mm,FillDraw(yellow,blue)),
R=draw("R",ellipse,(2cm,3cm),xmargin=3mm,FillDraw(yellow,blue));

pair
S1=point(S,E), I1=point(I,W),
I2=point(I,dir(120)), R1=point(R,dir(-60)),
R2=point(R,dir(-120)), S2=point(S,dir(60)),
R3=point(R,dir(-20)), I3=point(I,dir(70))
;

draw(S1--I1,red,Arrow());
draw(I2--R1,red,Arrow());
draw(R2--S2,red,Arrow());
draw(R3 .. controls  R3+1cm*dir(0) and  I3+1cm*dir(70) .. I3,red,Arrow());


Update: by putting the circle shape (@Nguyen Van Chi mimicked form the roundbox shape in plain_boxes.asy), it works well (change ellipse to circle) ^^ I think now defining a new shape (trapezium, parallellogram, star, ...) is an comfortable task in Asymptote (even more comfortable than defining a new shape in TikZ's node)

//////////////////////////////////////////////////////
// code for the circle shape from Nguyen Van Chi,
// inspired by the roundbox shape (see plain_boxes.asy)
path circle(frame dest, frame src=dest, real xmargin=0, real ymargin=xmargin,
pen p=currentpen, filltype filltype=NoFill, bool above=true)
{
pair m=min(src);
pair M=max(src);
pair bound=M-m;
real a=bound.x+2*xmargin;
real b=bound.y+2*ymargin;
path g=shift(m-(xmargin,ymargin))*(circle((a/2,b/2),max(a,b)/2));
frame F;
if(above == false) {
filltype.fill(F,g,p);
prepend(dest,F);
} else filltype.fill(dest,g,p);
return g;
}

path circle(frame f, Label L, real xmargin=0, real ymargin=xmargin,
pen p=currentpen, filltype filltype=NoFill, bool above=true)
{
return circle(f,xmargin,ymargin,p,filltype,above);
}
//////////////////////////////////////////////////////

object
S=draw("S",circle,(0,0),xmargin=3mm,FillDraw(yellow,blue)),
I=draw("I",circle,(4cm,0),xmargin=3mm,FillDraw(yellow,blue)),
R=draw("R",circle,(2cm,3cm),xmargin=3mm,FillDraw(yellow,blue));

pair
S1=point(S,E), I1=point(I,W),
I2=point(I,dir(120)), R1=point(R,dir(-60)),
R2=point(R,dir(-120)), S2=point(S,dir(60)),
R3=point(R,dir(-20)), I3=point(I,dir(70))
;