[Tex/LaTex] Plotting the Cantor function

asymptotemetapostplottikz-pgf

I would like to know if there is an (easy?) way of plotting the Cantor function (devil's staircase) using LaTeX.

Doing it manually with TikZ seems like madness somehow and my knowledge of plotting using TikZ is also very limited. With that being said, I have seen it plotted many times in math scripts so how is it done? Does anyone know?

Here is a reference to the Cantor function.

Best Answer

I advise for an external solution, too. But surely, it is possible in TeX. It just takes a bit of time.

As this is a recursive solution, it might take more time than a non-recursive, but the recursive one is relative easy to implement.

If one defines cantor 2 edge/.style={move to} the diagonal part will not be drawn. (It's not an edge in an TikZ path operator kind of way.)

You start your path as usual with \draw and whatever options you want and then insert as another option:

cantor start={<lower x>}{<upper x>}{<lower y>}{<upper y>}{<level>}

There are the value keys

  • /tikz/lower cantor and /tikz/upper cantor, as well as
  • /tikz/y cantor.

I don't know how much sense the y cantor value makes so I added it as a “fun” definition. In the proper staircase definition y cantor equals 0.5. (However, then I’d use the definition marked as such.)

Code

\documentclass[tikz]{standalone}
\tikzset{
  if/.code n args=3{\pgfmathparse{#1}\ifnum\pgfmathresult=0
    \pgfkeysalso{#3}\else\pgfkeysalso{#2}\fi},
  lower cantor/.initial=.3333, upper cantor/.initial=.6667, y cantor/.initial=.5,
  declare function={
    cantor_l(\lowerBound,\upperBound)=
      (\pgfkeysvalueof{/tikz/lower\space cantor})*(\upperBound-\lowerBound)+\lowerBound;
    cantor_u(\lowerBound,\upperBound)=
      (\pgfkeysvalueof{/tikz/upper\space cantor})*(\upperBound-\lowerBound)+\lowerBound;
    cantor(\lowerBound,\upperBound)=% fun definition
      (\pgfkeysvalueof{/tikz/y\space cantor})*(\upperBound-\lowerBound)+\lowerBound;},
  cantor start/.style n args=5{%
    insert path={(#1,#3)},
    cantor={#1}{#2}{#3}{#4}{#5}{0},
    insert path={to[every cantor edge/.try, cantor 1 edge/.try] (#2,#4)}},
  cantor/.style n args=6{%
    /utils/exec=%
      \pgfmathsetmacro\lBx{cantor_l(#1,#2)}%
      \pgfmathsetmacro\uBx{cantor_u(#1,#2)}%
%      \pgfmathsetmacro\y{.5*(#3+#4)},% proper definition
      \pgfmathsetmacro\y{cantor(#3,#4)},% fun
    style/.expanded={
      if={#6<#5}{cantor={#1}{\lBx}{#3}{\y}{#5}{#6+1}}{},
      insert path={
        to[every cantor edge/.try, cantor 1 edge/.try] (\lBx,\y)
        to[every cantor edge/.try, cantor 2 edge/.try] (\uBx,\y)},
      if={#6<#5}{cantor={\uBx}{#2}{\y}{#4}{#5}{#6+1}}{}}}}
\begin{document}
\foreach \level in {0,...,5}{
\begin{tikzpicture}[line join=round] % cantor 1 edge/.style={move to}
  \useasboundingbox[draw, scale=6, help lines]
    (0,0) grid[xstep=1/9, ystep=.25] (1,1);
  \draw[thick, cantor start={0}{6}{0}{6}{\level}{0}];
\end{tikzpicture}}
\foreach \val[evaluate={\lc=1/\val;\uc=(\val-1)/\val;}] in {2,...,9}{
\begin{tikzpicture}[line join=round, lower cantor=\lc, upper cantor=\uc]
%  \useasboundingbox[draw, scale=6, help lines]
%    (0,0) grid[xstep=\lc*\lc, ystep=.25] (1,1);
  \draw[thick, cantor start={0}{6}{0}{6}{6}{0}];
  \node [anchor=north west] at (0,6) {$\frac1\val$};
\end{tikzpicture}}
\foreach \val in {1,...,9}{
\begin{tikzpicture}[line join=round, y cantor=.\val, cantor 1 edge/.style={move to}]
  \draw[thick, cantor start={0}{6}{0}{6}{6}{0}];
  \node[anchor=north west] at (0,6) {$.\val$};
\end{tikzpicture}}
\end{document}

Output

enter image description here enter image description hereenter image description here