23

How do we draw a figure like this in tikz?

I am able to draw the straight lines, but these curves are too challenging -- how to draw them nice?

enter image description here

The minimal template is:

\begin{tikzpicture}
\draw[->] (0,0,0)--(0,8,0);
\draw[->] (4,0,0)--(4,8,0);
\end{tikzpicture}

I really appreciate your patience!

  • 1
    Very nice and good question for my opinion. – Sebastiano Dec 17 '18 at 21:33
24

That's a standard task for the knot library.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{knots,arrows.meta}
\begin{document}
\begin{tikzpicture}
\path (-0.5,6.5) coordinate (x1) (4.5,5) coordinate (x2) 
(-0.5,3.5) coordinate (x3) (4.5,2.5) coordinate (x4); 
\begin{knot}%[draft mode=crossings]
\strand[{Circle}-{Circle}] (0,0) -- (0,8);
\strand[{Circle}-{Circle}] (4,0) -- (4,8);
\strand[{Circle}-{Circle},looseness=0.5] (2,8) to[out=-90,in=90] (x1)
to[out=-90,in=90] (x2) to[out=-90,in=90] (x3)
to[out=-90,in=90] (x4) to[out=-90,in=90] (2,0);
\flipcrossings{2,4,6,8}
\end{knot}
\end{tikzpicture}
\end{document}

enter image description here

Or with the ordering as in your picture.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{knots,arrows.meta}
\begin{document}
\begin{tikzpicture}
\path (-0.5,6.5) coordinate (x1) (4.5,5) coordinate (x2) 
(-0.5,3.5) coordinate (x3) (4.5,2.5) coordinate (x4); 
\begin{knot}%[draft mode=crossings]
\strand[{Circle}-{Circle}] (0,0) -- (0,8);
\strand[{Circle}-{Circle}] (4,0) -- (4,8);
\strand[{Circle}-{Circle},looseness=0.5] (2,8) to[out=-90,in=90] (x1)
to[out=-90,in=90] (x2) to[out=-90,in=90] (x3)
to[out=-90,in=90] (x4) to[out=-90,in=90] (2,0);
\flipcrossings{2,3,5,8}
\end{knot}
\end{tikzpicture}
\end{document}

enter image description here

To find out which crossing has which number, uncomment [draft mode=crossings].

  • You are superfast! :-) – Sebastiano Dec 17 '18 at 21:51
  • Oh my god! I dont know this thing exist in tikz!!!! Thank you - (I was not aware and just posted another more technical question!) – annie heart Dec 17 '18 at 21:57
  • Very interesting! Is the knot library documented anywhere? – Hafid Boukhoulda Dec 18 '18 at 7:14
  • @HafidBoukhoulda Yes, here. – marmot Dec 18 '18 at 11:44
  • 1
    @HafidBoukhoulda It is the library. There might be a package of the same name, which is not to be confused with the library. Another very useful (or even more useful) library by the same author which is not mentioned in the pgfmanual is tikzmark. – marmot Dec 18 '18 at 18:39
12

Here's a version in plain Metapost featuring a useful idiom to find all the intersection points between two paths.

enter image description here

This is wrapped up in luamplib so compile it with lualatex (or work out how to adapt it for plain mpost).

\documentclass[border=5mm]{standalone}
\usepackage{luatex85}
\usepackage{luamplib}
\begin{document}
\mplibtextextlabel{enable}
\begin{mplibcode}
beginfig(1);
    path s, t, a, b;
    a = (down--up) scaled 164 shifted 72 left;
    b = (down--up) scaled 164 shifted 72 right;
    t = ((-36*4, 0) for x=-35 upto 36: .. (4x, 88 sind(10x)) endfor) rotated 90 reflectedabout(up, down);
    s = point 0 of t shifted 20 down {up} .. {direction 2 of t} subpath (2,70) of t {direction 70 of t} .. point 72 of t shifted 20 up {up};

    pickup pencircle scaled 1;

    forsuffixes $=a, b, s:
        draw $;
        fill fullcircle scaled 4 shifted point 0 of $;
        fill fullcircle scaled 4 shifted point infinity of $;
    endfor

    vardef over_and_under(expr a, b) = 
        save x, y, r, n, A, B, p;
        path r; numeric n; picture A, B, p;
        r := a;
        n = 0;
        forever:
            r := r cutbefore b;
            exitif length cuttings = 0;
            r := subpath (epsilon, infinity) of r;
            z[incr n] = point 0 of r;
        endfor
        A = image(draw a);
        B = image(draw b);
        for i=0 upto n:
            if known z[i]:
                unfill fullcircle scaled 10 shifted z[i];
                p :=  if odd i: B else: A fi;
                clip p to fullcircle scaled 10 shifted z[i];
                draw p;
            fi
        endfor
    enddef;

    over_and_under(a, s);
    over_and_under(b, s);

endfig;
\end{mplibcode}
\end{document}
  • It is not the same ordering as in the OP's screenshot, though. You have (b=back, f=front) bfbfbfbf and the OP bffbfbbf reading from top to bottom along the curved path. – marmot Dec 19 '18 at 0:26
  • @marmot - that's true. I guess if I was doing lots of these it would be worth working out a way to specify the order. But I'm only trying to show what's possible with MP, not create a whole new notation. One of the great strengths of plain MP is that it is simple to create your own task-specific notations. – Thruston Dec 19 '18 at 9:46
  • 2
    It's also possible that the OP intended it to be regularly over and under, but made a mistake... :-) – Thruston Dec 19 '18 at 9:48
  • Sorry, don't get me wrong. But I could draw a blue dragon, arguing that the OP may secretly have wanted one. I guess a fair question would be: how much extra effort is it to achieve a custom ordering. – marmot Dec 22 '18 at 9:30
  • Thanks! +1 see unsolved tex.stackexchange.com/questions/466279/… – annie heart Dec 27 '18 at 4:50
3

Here is an attempt using the snake decoration from tikz library decorations.pathmorphing. The intersections library is used to calculate the crossovers locations. White circles are then drawn at intersection points.

\documentclass[tikz,border=5pt]{standalone}
\usetikzlibrary{intersections,decorations.pathmorphing}
\begin{document}

\begin{tikzpicture}[thick,rotate=90,xscale=.7,dot/.style={inner sep=1.5pt,fill,circle},cut/.style={inner sep=3pt,fill=white,circle}]

\draw[name path=curve,decorate, decoration={snake, segment length=2.96cm, amplitude=-2cm}] (0,0)node[dot]{} -- (9,0)node[dot]{};
\path[name path=la](-1, 1.5) -- (10, 1.5);
\path[name path=lb](-1,-1.5) -- (10,-1.5);

\path [name intersections={of=la and curve}];
\node[cut] at(intersection-1){} (intersection-4) node[cut]{} (intersection-2) node(2)[cut,fill=none]{} (intersection-3) node(3)[cut,fill=none]{};
\draw (-1,1.5) node[dot]{} -- (2) (2) -- (3) (3) -- (10,1.5) node[dot]{};

\path [name intersections={of=lb and curve}];
\node[cut] at(intersection-2){} (intersection-3) node[cut]{} (intersection-1) node(1)[cut,fill=none]{} (intersection-4) node(4)[cut,fill=none]{};
\draw (-1,-1.5) node[dot]{} -- (1) (1) -- (4) (4) -- (10,-1.5) node[dot]{};

\end{tikzpicture}

\end{document}

enter image description here

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.