I was wondering if anyone could suggest software/packages to create nice knot diagrams (hopefully with a link to images they have made in the past).
I have used xy-pic recently but am mainly interested in hearing about other options.
Update 2024: This answer was based on my first method of drawing knots, using nodes. This eventually got superseded by more sophisticated techniques, which are outlined in my other answers. The code originally used here is actually still available as part of my knots
TikZ library and so this method does still work. However, it is not the most general or flexible way to draw knots - for better techniques, see my other answers.
In about 2011, I wrote a prototype package for drawing knots using TikZ/PGF. It was originally designed to draw very specific link diagrams (see the image at the end of this post) and only afterwards did I start to extract the more general bits.
The principle behind it was that if you design the knot around the intersections then it is quite straightforward to do the over/under style since you know exactly where the crossings are. In addition, TikZ already has a method where it breaks a path at a specific location, namely if that location is a node. So by placing nodes at the intersections and then joining them together, you can draw a knot. The extra is that when joining the nodes it is useful to have some additional anchors to define the various strands. The knots
library defines the following helpful node shapes:
knot crossing
knot over cross
knot under cross
knot vert
knot horiz
For detailed instructions, see the knots
documentation.
Here are some examples. The preamble for all is:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{%
arrows,
knots,
calc,
}
\tikzset{
every path/.style={
red,
line width=2pt
},
every node/.style={
transform shape,
knot crossing,
inner sep=1.5pt
}
}
First, a trefoil (don't forget \begin{document} ... \end{document}
):
\begin{tikzpicture}
\foreach \brk in {0,1,2} {
\begin{scope}[rotate=\brk * 120]
\node (k\brk) at (0,-1) {};
\end{scope}
}
\draw (0,0) \foreach \brk in {0,1,2} {
let \n0=\brk,
\n1={int(Mod(\brk+1,3))},
\n2={int(Mod(\brk+2,3))}
in (k\n0) .. controls (k\n0.16 south east) and (k\n1.16 south west) ..
(k\n1.center) .. controls (k\n1.4 north east) and (k\n2.4 north west) ..
(k\n2)} (k2);
\end{tikzpicture}
This extends very easily to, for example, a cinquefoil:
\begin{tikzpicture}
\foreach \brk in {0,...,4} {
\begin{scope}[rotate=\brk * 72]
\node (k\brk) at (0,-1.5) {};
\end{scope}
}
\draw (0,0) \foreach \brk in {0,...,4} {
let \n0=\brk,
\n1={int(Mod(\brk+1,5))},
\n2={int(Mod(\brk+2,5))}
in (k\n0) .. controls (k\n0.16 south east) and (k\n1.16 south west) ..
(k\n1.center) .. controls (k\n1.4 north east) and (k\n2.4 north west) ..
(k\n2)} (k2);
\end{tikzpicture}
(K)not sure what this one is called, it's an obvious extension of the figure 8 knot:
\begin{tikzpicture}
\node[rotate=45] (tl) at (-1,1) {};
\node[rotate=-45] (tr) at (1,1) {};
\edef\twists{10}
\foreach \brk in {0,...,\twists} {
\node (m\brk) at (0,-1 - \brk) {};
}
\foreach \brk in {1,...,\twists} {
\pgfmathparse{int(\brk - 1)}
\edef\brl{\pgfmathresult}
\draw (m\brk) .. controls (m\brk.4 north west) and (m\brl.4 south west) .. (m\brl.center);
\draw (m\brk.center) .. controls (m\brk.4 north east) and (m\brl.4 south east) .. (m\brl);
}
\draw (m0) .. controls (m0.8 north west) and (tl.3 south west) .. (tl.center);
\draw (m0.center) .. controls (m0.8 north east) and (tr.3 south east) .. (tr);
\draw (tl.center) .. controls (tl.16 north east) and (tr.16 north west) .. (tr);
\draw (m\twists) .. controls (m\twists.32 south east) and (tr.32 north east) .. (tr.center);
\draw (m\twists.center) .. controls (m\twists.32 south west) and (tl.32 north west) .. (tl);
\draw (tl) -- (tr.center);
\end{tikzpicture}
Most of the images listed at this nLab page were done using this package and then exported to SVG via tex4ht
.
The following monstrosity is an example of the special type of link that the original package was designed for! (The code for this has not made it into subsequent packages.)
Run with xelatex
or use package auto-pst-pdf
or run latex
->dvips
->ps2pdf
\documentclass{article}
\usepackage{pst-knot}
\begin{document}
\begin{pspicture}(-2,-2)(5,2)
\psKnot[linewidth=3pt,linecolor=red](0,0){3-1}
\psKnot[linewidth=3pt,linecolor=blue](4,0){4-1}
\end{pspicture}
\end{document}
The documentation explains the meaning of 3-1
and 4-1
The question is old, so just for the record. MetaPost package fiziko may not be the most practical or stable tool for drawing knots, but the images it produces look somewhat fancy. All examples are in ConTeXt, but the same code can be used in LuaLaTeX or standalone as well:
\startMPcode
input fiziko.mp;
path p;
p := (dir(90)*4/3cm) {dir(0)} .. tension 3/2
.. (dir(90 + 120)*4/3cm){dir(90 + 30)} .. tension 3/2
.. (dir(90 - 120)*4/3cm){dir(-90 - 30)} .. tension 3/2
.. cycle;
% p := pathSubdivide(p, 6);
addStrandToKnot (primeOne) (p, 1/5cm, "l", "1, -1, 1");
draw knotFromStrands (primeOne);
\stopMPcode
\startMPcode
input fiziko.mp;
path p;
p := (0, 2cm) .. (1/2cm, 3/2cm) .. (-1/2cm, 0) .. (1/2cm, -2/3cm) .. (4/3cm, 0) .. (0, 3/2cm) .. (-4/3cm, 0) .. (-1/2cm, -2/3cm) .. (1/2cm, 0) .. (-1/2cm, 3/2cm) .. cycle ;
% p := pathSubdivide(p, 6) shifted (4cm, -1/2cm);
addStrandToKnot (primeTwo) (p, 1/6cm, "l", "1, -1, 1, -1, 1");
draw knotFromStrands (primeTwo);
\stopMPcode
\startMPcode
input fiziko.mp;
path p[];
p1 := (fullcircle scaled 2cm) shifted (-1/2cm, 0);
p2 := p1 shifted (1cm, 0);
p3 := (-2cm, 0) -- (2cm, 0);
% p3 := pathSubdivide(p3, 4);
addStrandToKnot (someKnot) (p1, 1/6cm, "l", "0, 1, 0, 1");
addStrandToKnot (someKnot) (p2, 1/6cm, "l", "");
addStrandToKnot (someKnot) (p3, 1/6cm, "l", "1, -1, 1, -1");
draw knotFromStrands (someKnot);
\stopMPcode
In addStrandToKnot (primeOne) (p, 1/5cm, "l", "1, -1, 1");
, primeOne
is the knot name. p
is a path along which the strand should be drawn (note that pathSubdivide
thing, the path should contain some reasonable number of points; upd: with recent updates there's no need to subdivide paths for knots in most cases), 1/5cm
is the strand thickness, "l"
is the type of shading (can be "l"
, "t"
or "e"
, the latter is simply empty outline which works much faster and "t"
doesn't work very well for now) and "1, -1, 1"
is a list of "layers" where intersections in order of appearance along the path, go (above default "zero" level or below it).
And knotFromStrands (primeOne)
actually draws all the strands and returns a picture.
Upd:
Default shading settings have been changed since the images above were produced and the output would look somewhat different now. These settings can be altered with defineMinStrokeWidth
macro, which determines shading stroke width (default is 1/5pt
) and defineLightDirection
, which determines where does "light" come from (default is -1/8pi, 1/8pi
). For instance, first knot with
defineLightDirection(1/8pi, -1/6pi);
defineMinStrokeWidth(1/5pt);
would look like this:
emp
package to include metapost code directly into the document. Eventually, it stopped working and I tried gmp
ctan.org/pkg/gmp , it did work similarly, but it was slow and I switched to LuaLaTeX, but now I can't get gmp
to do its thing. You can try it, maybe it's just my setup. I'll try and find a way to make it work and, in case of success, will follow up here.
Commented
Jul 26, 2020 at 12:24
(This question, although old, keeps coming up when I search for tikz knots
- yes, I know I'm searching for my own package but it's how I find the documentation when I'm on a foreign machine - so I thought I'd add an answer about the tikz knots library which was developed some time after this question was asked.)
There's a TikZ library, knots
, which is available on CTAN (as part of a package called spath3
) and github. There are quite a few questions on this site with examples using this package, here are just a few:
(The interface just asked me "Are you sure you want to add yet another answer?")
The spath3
(which the knots
library is actually part of) has now been extended with a new set of routines that are useful in drawing knots. These work by actually cutting a path at the points where it intersects with another path and inserting gaps at those points, so it is particularly suited to situations where there is a non-uniform background, or where the aim is to style different pieces of the diagram differently (for example to illustrate a 3-colouring).
Here's a trefoil example. For more examples, see the documentation (texdoc spath3
) or look on github.
\documentclass{article}
%\url{https://tex.stackexchange.com/q/17181/86}
\usepackage{tikz}
\usetikzlibrary{spath3, intersections, hobby}
\begin{document}
\begin{tikzpicture}[
use Hobby shortcut,
every trefoil component/.style={ultra thick, draw, red},
trefoil component 1/.style={blue},
]
\path[spath/save=trefoil] ([closed]90:2) foreach \k in {1,...,3} { .. (-30+\k*240:.5) .. (90+\k*240:2) } (90:2);
\tikzset{spath/knot={trefoil}{8pt}{1,3,5}}
\end{tikzpicture}
\end{document}
syzygy
module of Asymptote for some specific sorts of knots. katlas.math.toronto.edu/drorbn/index.php?title=06-1350/…