3

I am trying to use a smart way to typeset some diagrams as these single stranded diagrams.

single stranded diagrams

But I would like to do two more things, one is to allow n of them to be stacked together as

stacked

and be able to draw multi-stranded diagrams as

mutltistrand

Now I already have the command for single-stranded diagrams as

\newcommand{\Planar}[3]{
    \begin{tikzpicture}[->,>=stealth'] % if arrow is ture, add these commands
    \draw[color=red] (0,0) rectangle (#1*0.3+0.3,0.7); % draw the outer box according to number of dots
    \newcounter{dotnumber}
    \foreach \dot in {1,...,#1}{ % draw the dots
        \filldraw (0.3*\dot,0) circle [radius=1pt];
        \filldraw (0.3*\dot,0.7) circle [radius=1pt];
    }
    \draw (0.3*#2,0) .. controls +(0,0.2) and +(0,-0.2) .. (0.3*#3,0.7); % draw the line
    \end{tikzpicture}
}

But I am looking for something like this

\Planar[number_of_dots][number_of_levels][first_strand_starting][first_strand_ending][...][last_strand_starting][last_strand_ending][secondlevelstrands...]

That produces the above diagrams with commands as

\Planar[3][1][1]..., 
\Planar[3][level=2][2][2][2][3]
           |this is the number of levels
\Planar[3][1][2][3][1][3][3]
           |this is the starting dot of the first line

I know that this is probably a huge macro and my way of defining the command is hideous, but I would appreciate at least some directions of where to go next.

6

Here is start. Rather than using levels I would define a single pic (see section 18.2 of the tikz manual), that draws one planar diagram and then you can stack them. The first argument of the pic should give the number of dots on the bottom line and the second argument should be a comma separated list of x/y pairs for the strings. This way you can use:

   \begin{tikzpicture}
     \draw (0,0) pic{planar=[3]{1/1}};
     \draw (3,0) pic{planar=[3]{1/2}};
     \draw (6,0) pic{planar=[3]{1/3}};
   \end{tikzpicture}

to draw the diagrams

enter image description here

To stack the diagrams you then put two pics on "top" of each other, so that

   \begin{tikzpicture}
     \draw(0,0) pic{planar=[3]{2/2}};
     \draw(0,0.7) pic{planar=[3]{2/3}};
   \end{tikzpicture}

produces:

enter image description here

Finally, here is an example with multiple strings and four dots: the code

   \begin{tikzpicture}
     \draw(0,0) pic{planar={4}{1/2, 3/1, 3/3}};
   \end{tikzpicture}

produces (the non-planar diagram):

enter image description here

I haven't added a command for the labels, partly because I don't immediately see a good syntax for this and partly because when I draw such diagrams I never label the strings:)

Here is the full code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\tikzset{pics/planar/.style 2 args = {
    code = {
      \draw[color=red] (0,0) rectangle (#1*0.3+0.3,0.7);
      \foreach \dot in {1,...,#1}{ % draw the dots
          \filldraw (0.3*\dot,0) circle [radius=1pt];
          \filldraw (0.3*\dot,0.7) circle [radius=1pt];
      }
      % draw the lines
      \foreach \x/\y in {#2}
        \draw[->,>=stealth](0.3*\x,0) .. controls +(0,0.2) and +(0,-0.2) .. (0.3*\y,0.7);
    }
  }
}

\begin{document}

   \begin{tikzpicture}
     \draw (0,0) pic{planar={3}{1/1}};
     \draw (2,0) pic{planar={3}{1/2}};
     \draw (4,0) pic{planar={3}{1/3}};
   \end{tikzpicture}

   \begin{tikzpicture}
     \draw(0,0) pic{planar={3}{2/2}};
     \draw(0,0.7) pic{planar={3}{2/3}};
   \end{tikzpicture}

   \begin{tikzpicture}
     \draw(0,0) pic{planar={4}{1/2, 3/1, 3/3}};
   \end{tikzpicture}

\end{document}

As you see I have really just repackaged the code from the OP. Personally, I would replace 0.3 and 0.7 above with 0 and 1 and then rescale the whole environment as this is likely to make your life a little easier in the long run.

Edit

Here is a "fancier" \PlanarDiagram macro that accepts a comma separated list of coma separated x/y-pairs to produce products of the corresponding diagrams. For example, the code

\PlanarDiagram(5){{1/2}}                  \quad
\PlanarDiagram{{1/2,2/2}, {2/3,3/1}}      \quad
\PlanarDiagram(4){{1/2, 3/1, 3/3}, {1/1, 2/3, 3/3}}

produces the output

enter image description here

Notice that there is an optional argument, which is enclosed in (...), that gives the number of dots. This another optional argument that you can use to configure the underlying tikzpicture1 environment and the pic. So, for example,

\PlanarDiagram[scale=0.5, draw=blue](4){{1/2, 3/1, 3/3}, {1/1, 2/3, 3/3}}

produces:

enter image description here

Here is the updated code:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{arrows.meta}
\tikzset{pics/planar/.style 2 args = {
    code = {
      \draw[color=red] (0,0) rectangle (#1*0.3+0.3,0.7);
      \foreach \dot in {1,...,#1}{ % draw the dots
          \filldraw (0.3*\dot,0) circle [radius=1pt];
          \filldraw (0.3*\dot,0.7) circle [radius=1pt];
      }
      % draw the lines
      \foreach \x/\y in #2
        \draw[->,>=stealth](0.3*\x,0) .. controls +(0,0.2) and +(0,-0.2) .. (0.3*\y,0.7);
    }
  }
}

\usepackage{xparse}
\NewDocumentCommand\PlanarDiagram{ O{} D(){3} m }{%
   \begin{tikzpicture}[#1]
     \foreach \diag [count=\c] in {#3} {
       \draw(0,\c*0.7) pic[#1]{planar={#2}{\diag}};
     }
  \end{tikzpicture}%
}

\begin{document}

   \PlanarDiagram(5){{1/2}}                  \quad
   \PlanarDiagram{{1/2,2/2}, {2/3,3/1}}      \quad
   \PlanarDiagram(4){{1/2, 3/1, 3/3}, {1/1, 2/3, 3/3}}

   \PlanarDiagram[scale=0.7, draw=blue](4){{1/2, 3/1, 3/3}, {1/1, 2/3, 3/3}}

\end{document}
  • Wow that's super great work! It's kind of overwhelming using the tikz library in the beginning but your answer is a great example for me to work on! Thanks a lot! – water liu Mar 3 '20 at 16:43
3

As an exercise, I took a crack at this with metapost. The syntax is:

planar(n,m)("connections")

where n is the number of points per level, m is the number of levels, and connections is a list of the form

level 1 arrows | level 2 arrows | level 3 arrows |...

where the arrows within each level are given as a comma separated list of ordered pairs. For example

planar(3,1)("(1,1),(2,3),(3,2)");

produces

enter image description here

and

planar(3,2)("(1,1),(2,3),(3,2)|(3,1),(1,3),(2,2)");

produces

enter image description here

Code:

\documentclass{article}
\usepackage{luamplib}
\mplibforcehmode
\begin{document}
\begin{mplibcode}
ux:=1cm; % horizontal scale
uy:=2cm; % vertical scale
ds:=.15*ux; % dot size

def planar(expr pts,levels)(text connections)=
    clearxy; save k,l,n;
    x=(pts+1)*ux; y=levels*uy; % max x, max y
    for i=0 upto levels:
        draw (origin--(x,0)) shifted (0,i*uy) withcolor red; % draw horizontal bars
        for j=1 upto pts: drawdot (j*ux,i*uy) withpen pencircle scaled ds; endfor; % draw dots
    endfor;
    draw origin--(0,y) withcolor red; % draw left vertical bar
    draw (x,0)--(x,y) withcolor red; % draw right vertical bar
    l=length(connections); n=k=0;
    for i=0 upto l:
        if (substring(i,i+1) of connections="|") or (i=l): % find separators
            for p=scantokens(substring(k,i) of connections): % iterate through list up to separator
                drawarrow ((xpart p)*ux,n*uy){up}..{up}((ypart p)*ux,(n+1)*uy) 
                          cutafter fullcircle scaled (ds+1) shifted ((ypart p)*ux,(n+1)*uy);
            endfor;
        k:=i+1; % pickup after separator
        n:=n+1; % increase level
        fi;
    endfor;
enddef;

beginfig(0);
    planar(3,2)("(1,1),(2,3),(3,2)|(3,1),(1,3),(2,2)");
endfig;
\end{mplibcode}
\end{document}
  • Wow this website never stops surprising me! This is a very elegant implementation as well! Thanks! – water liu Mar 3 '20 at 23:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.