如何在 TikZ 上绘制加泰罗尼亚数图

如何在 TikZ 上绘制加泰罗尼亚数图

这是一个非常简单的问题,但我是 LaTeX 新手。您知道如何编写此类图表吗?

在此处输入图片描述

图片取自加泰罗尼亚数维基百科页面

答案1

一个主意:

\documentclass[border=2mm]{standalone}
\usepackage{tikz}

\newcommand\catalannumber[3]{
  % start point, size, Dyck word (size x 2 booleans)
  \fill[cyan!25]  (#1) rectangle +(#2,#2);
  \fill[fill=lime]
  (#1)
  \foreach \dir in {#3}{
    \ifnum\dir=0
    -- ++(1,0)
    \else
    -- ++(0,1)
    \fi
  } |- (#1);
  \draw[help lines] (#1) grid +(#2,#2);
  \draw[dashed] (#1) -- +(#2,#2);
  \coordinate (prev) at (#1);
  \foreach \dir in {#3}{
    \ifnum\dir=0
    \coordinate (dep) at (1,0);
    \else
    \coordinate (dep) at (0,1);
    \fi
    \draw[line width=2pt,-stealth] (prev) -- ++(dep) coordinate (prev);
  };
}

\begin{document}
\begin{tikzpicture}
  \catalannumber{0,0}{4}{0,1,0,0,1,1,0,1};
  \catalannumber{0,-9}{8}{0,1,0,0,1,1,0,0,0,0,1,1,0,1,1,1};
\end{tikzpicture}
\end{document}

在此处输入图片描述

含所有 Dyck 编号的版本:

\documentclass{article}
\usepackage[margin=1cm]{geometry}
\usepackage{tikz}
\usepackage{ifthen}
\pagestyle{empty}
\newcommand\catalannumber[3]{
  % start point, size, Dyck word (size x 2 booleans)
  \fill[cyan!25]  (#1) rectangle +(#2,#2);
  \fill[fill=lime]
  (#1)
  \foreach \dir in {#3}{
    \ifnum\dir=0
    -- ++(1,0)
    \else
    -- ++(0,1)
    \fi
  } |- (#1);
  \draw[help lines] (#1) grid +(#2,#2);
  \draw[dashed] (#1) -- +(#2,#2);
  \coordinate (prev) at (#1);
  \foreach \dir in {#3}{
    \ifnum\dir=0
    \coordinate (dep) at (1,0);
    \tikzset{label/.style={below}};
    \else
    \coordinate (dep) at (0,1);
    \tikzset{label/.style={left}};
    \fi
    \draw[line width=2pt,-stealth] (prev) --
    ++(dep) coordinate (prev);
  };
}

\newcommand\genallcatalannumbers[6]{%
  \pgfmathtruncatemacro{\steps}{#4+#5}%
  \ifthenelse{#3>\steps}{%
    \ifthenelse{#5<#4}{%
      {%
        \ifthenelse{#4<#2}{%
          \pgfmathtruncatemacro{\nbzero}{#4+1}%
          \genallcatalannumbers{#1}{#2}{#3}{\nbzero}{#5}{#6,0}%
        }{}%
      }%
      {%
        \pgfmathtruncatemacro{\nbone}{#5+1}%
        \genallcatalannumbers{#1}{#2}{#3}{#4}{\nbone}{#6,1}%
      }%
    }{%
      \pgfmathtruncatemacro{\nbzero}{#4+1}%
      \genallcatalannumbers{#1}{#2}{#3}{\nbzero}{#5}{#6,0}%
    }%
  }{%
    \begin{tikzpicture}[myscale]
      \catalannumber{#1}{#2}{#6}
    \end{tikzpicture} %
  }%
}

\newcommand\allcatalannumbers[2]{%
  \pgfmathtruncatemacro{\nbsteps}{2*#2}%
  \genallcatalannumbers{#1}{#2}{\nbsteps}{1}{0}{0}%
}

\begin{document}
\begin{enumerate}
 \foreach \num in {1,...,5}{
   \item%{\LARGE\bfseries \num}
  \tikzset{myscale/.style={scale=2/\num}}
  \noindent\allcatalannumbers{0,0}{\num}\par
}
\end{enumerate}
\end{document}

所有步骤

答案2

砷钛矿Z 的运行速度比 PSTricks 慢,而且我不知道如何在 PSTricks 中编写递归函数,我被迫使用通过\write18宏从 LaTeX 内部执行的外部应用程序。

如果你编译以下 C# 源代码

// This is CatalanLocator.cs
using System.Collections.Generic;
using System.IO;

namespace CatalanLocator
{
    class Program
    {
        static void Populate(List<bool> set, int m, int n)
        {
            if (m == 0)
            {
                if (n == 0)
                {
                    using (StreamWriter sw = new StreamWriter("data.txt", true))
                    {
                        sw.Write("{");
                        int x;
                        for (x = 0; x < set.Count - 1; x++)
                            sw.Write("{0},", set[x] ? 1 : 0);
                        sw.WriteLine("{0}}}", set[x] ? 1 : 0);
                    }
                }
                else
                {
                    List<bool> temp = new List<bool>(set);
                    temp.Add(true);
                    Populate(temp, m, n - 1);
                }
            }
            else
            {
                if (m == n)
                {
                    List<bool> temp = new List<bool>(set);
                    temp.Add(false);
                    Populate(temp, m - 1, n);
                }
                else
                {
                    List<bool> temp1 = new List<bool>(set);
                    temp1.Add(false);
                    Populate(temp1, m - 1, n);

                    List<bool> temp2 = new List<bool>(set);
                    temp2.Add(true);
                    Populate(temp2, m, n - 1);
                }
            }
        }
        static void Main(string[] args)
        {
            int N = int.Parse(args[0]);
            Populate(new List<bool>(), N, N);
        }
    }
}

csc CatalanLocator.cs您将获得一个名为的可执行文件CatalanLocator.exe

CatalanLocator 6例如,从 DOS 提示符手动执行将生成一个名为 的文本文件data.txt。它包含多行二进制数集。每组代表一条 Catalan 路径。(Catalan 路径是我自己发明的术语。维基百科可能没有这样的定义。)

不过,我更喜欢从 LaTeX 输入文件执行,CatalanLocator如下面的代码所述:

% CatalanDiagram.tex
\documentclass{article}

\usepackage{pstricks-add}

\usepackage[active,tightpage]{preview}
\PreviewBorder=12pt
\PreviewEnvironment{pspicture}

\newcounter{oX}% old x
\newcounter{oY}% old y
\newcounter{nX}% new x
\newcounter{nY}% new y
\newcounter{N}% N by N grid


\newcommand\CatalanPath[2][-]
{
        % reset all counters
        \setcounter{nX}{0}\setcounter{nY}{0}\setcounter{oX}{0}\setcounter{oY}{0}

        % please make sure there is no blank line allowed in \psforeach
        \psforeach{\i}{#2}
        {
            \ifnum\i=0
                \stepcounter{nX}% move to the right
            \else
                \stepcounter{nY}% move upward
            \fi
            %
            % draw a single segment
            \psline[arrows=#1,linewidth=1pt](\theoX,\theoY)(\thenX,\thenY)
            %
            % renew the old counters
            \setcounter{oX}{\value{nX}}
            \setcounter{oY}{\value{nY}}
        }
}


\newcommand\CatalanDiagram[1]
{
    % probe the given Catalan's set and find the corresponding grid dimension
    \setcounter{N}{0}\psforeach{\i}{#1}{\stepcounter{N}}\setcounter{N}{\numexpr\theN/2\relax}

    \begin{pspicture}(\theN,\theN)
            {
                \psset{fillstyle=solid,linestyle=none,opacity=0.5}

                % fill the upper region
                \pscustom[fillcolor=cyan]{\CatalanPath{#1}\psline(\thenX,\thenY)(0,\thenY)}

                % fill the lower region
                \pscustom[fillcolor=yellow]{\CatalanPath{#1}\psline(\thenX,\thenY)(\thenX,0)}
            }

            % draw grid
            \psgrid[style=gridstyle,gridlabels=0pt]

            % draw a diagonal line
            \psline[linestyle=dashed,dash=3pt 1.5pt,linecolor=red](\theN,\theN)

            % draw Catalan path
            \CatalanPath[->]{#1}
    \end{pspicture}
}


\newread\myfile
\def\temp#1{\CatalanDiagram{#1}}

\begin{document}
    \immediate\write18{cmd /C del data.txt}
    \immediate\write18{CatalanLocator.exe 6}
    \openin\myfile=data.txt\relax
    \loop
        \read\myfile to \j
        \unless\ifeof\myfile
        \expandafter\temp\j\relax
    \repeat
    \closein\myfile
\end{document}

执行latex --shell-escape CatalanDiagram后接着dvips CatalanDiagram执行会ps2pdf CatalanDiagram.ps产生CatalanDiagram.pdf

以下 GIF 图像是动画6×6加泰罗尼亚图。我故意把它弄得很小以节省您的带宽。

在此处输入图片描述

答案3

只是为了好玩...基于 PolGab 的第一个答案的随机版本。

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{backgrounds}
\pgfdeclarelayer{mylayer}
\pgfsetlayers{background,mylayer,main}
\usepackage{etoolbox}

% counters to check movements
\newcounter{up}
\newcounter{rightp}

\newcommand\catalannumber[2]{
\setcounter{up}{0}
\setcounter{rightp}{0}
% start point, size
\begin{pgfonlayer}{background}
\fill[cyan!25]  (#1) rectangle +(#2,#2); 
\end{pgfonlayer}
\draw[help lines] (#1) grid +(#2,#2);
\draw[dashed] (#1) -- +(#2,#2);    
\coordinate (prev) at (#1);    

\pgfmathtruncatemacro\dim{#2*2}
\foreach \x in {1,...,\dim}{   
\pgfmathtruncatemacro\dir{round(rand)}  
% first case
\ifnum\x=1
\pgfmathtruncatemacro\dir{0}
\fi  
% normal behaviour 
\ifnumodd{\x}{
% check number of up to not exceed the diagonal
\pgfmathtruncatemacro\numupadmitted{\x/2}%
\ifnum\numupadmitted=\theup
\pgfmathtruncatemacro\dir{0}  
\fi
}{}
% check number of rightp to not exceed the border
\ifnum\therightp=#2
\pgfmathtruncatemacro\dir{1}
\fi
% movements
\ifnum\dir=0
\coordinate (dep) at (1,0);
\stepcounter{rightp}
\else
\coordinate (dep) at (0,1);  
\stepcounter{up}  
\fi
\draw[line width=2pt,-stealth] (prev) -- ++(dep) node(a\x){} coordinate (prev){};
}
\begin{pgfonlayer}{mylayer}
\fill[orange!25](#1)
\foreach \x in {1,...,\dim}{   
--(a\x.center)
}|-(#1);
\end{pgfonlayer}
}

\begin{document}
\begin{tikzpicture}
  \catalannumber{0,0}{7};
  \catalannumber{0,-10}{9};
\end{tikzpicture}
\end{document}

在此处输入图片描述

答案4

纯粹是为了我自己的娱乐,我制作了一个metapost版本,绘制的图表与 wiki 页面上的其他图像之一相映成趣。 在此处输入图片描述

虽然在我的计算机上生成所有长度为 20 的 Dyck 单词需要大约一分钟的时间,但最终它确实做到了,并且

\begin{mplibcode}
beginfig(0);
    dwords(10);
    draw dyckdiagram(10,4500);
endfig;
\end{mplibcode}

生产

在此处输入图片描述

代码(编译用lualatex):

\documentclass{article}
\usepackage{luamplib}
\mplibnumbersystem{double}
\mplibtextextlabel{enable}
\mplibcodeinherit{enable}
\mplibforcehmode
\begin{document}
\begin{center}
\begin{mplibcode}
color rred,bblue;
rred:=(1.0,.377,.398);
bblue:=(0.37,0.57,0.7);
% http://www.acta.sapientia.ro/acta-info/C1-1/info1-9.pdf
vardef dwords(expr n)=% generates positions of down steps
    for i=1 upto n: b[i]:=2i; endfor;
    cnt:=0;
    forever:
        cnt:=cnt+1;
        for i=1 upto n: D[cnt][b[i]]:=1; endfor; % save down steps
        ind:=0; % haven't bothered to figure out how the following works 
        for i=n-1 downto 1:
            if b[i]<n+i:
                b[i]:=b[i]+1;
                for j=i+1 upto n-1:
                    if b[j-1]+1<2j:
                        b[j]:=2j;
                    else:
                        b[j]:=b[j-1]+1;
                    fi;
                endfor;
                ind:=1;
                exitif true;
            fi;
        endfor;
    exitif ind=0;
    endfor;
enddef;

% stores path
vardef dpath(expr n,m)=
    save hstep_,vstep_,h_; vstep_=hstep_:=0; h:=sqrt(3)/2;
  (0,0)
    for i= 1 upto 2n:
        if not known D[m][i]:
            --((incr hstep_)/2,(incr vstep_)*h)
        else:
            --((incr hstep_)/2,(decr vstep_)*h)
        fi
    endfor
enddef;

% n=half-order, m=word number
vardef dyckdiagram(expr n,m)=
    save p_,q_,g_,d_,h_,pic_; path p_,q_; picture pic_; h_:=sqrt(3)/2;
    pic_:=image(
    for i=n downto 1: % triangular grid
        for j=1 upto i:
            fill fullcircle scaled .5u shifted (u*(.5j+(n-i),h_*j)) withcolor .7;
        endfor;
    endfor;
    d_:=0;% number of down steps
    for i=2 upto 2n:
        if known D[m][i]: % if down
            d_:=d_+1;
            if not known D[m][i-1]: % and previous was up
                fill fullcircle scaled .5u shifted (u*(.5(i-1), (i-2d_+1)*h_)) withcolor rred;
            fi;
        fi;
    endfor;
    draw dpath(n,m) scaled u withpen pencircle scaled .2u withcolor rred;
    r:=sqrt(3)/2;
    % for rounded outlines
  path p[]; p[-1]:= (1,0) for i=1 upto 120: --(1,0) rotated 3i endfor--cycle;
    p[0]:=(.5,r)--(.5*(2n-1),r)--(n/2,n*r)--cycle;
    pen bpen; bpen:=makepen(p[-1]); pickup bpen;
    p[1]:=envelope bpen of p[0];
    draw p[1] scaled u withpen pencircle scaled .2u withcolor bblue;
    );
    pic_
enddef;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
dwords(4);
beginfig(0);
u:=.3cm;
for i=1 upto 3: draw dyckdiagram(4,i) shifted ((i-1)*6u,0); endfor;
endfig;
\end{mplibcode}\\[5pt]
\begin{mplibcode}
beginfig(0);
for i=4 upto 7: draw dyckdiagram(4,i) shifted ((i-4)*6u,0); endfor;
endfig;
\end{mplibcode}\\[5pt]
\begin{mplibcode}
beginfig(0);
for i=8 upto 11: draw dyckdiagram(4,i) shifted ((i-8)*6u,0); endfor;
endfig;
\end{mplibcode}\\[5pt]
\begin{mplibcode}
beginfig(0);
for i=12 upto 14: draw dyckdiagram(4,i) shifted ((i-12)*6u,0); endfor;
endfig;
\end{mplibcode}
\end{center}
%\begin{mplibcode}
%beginfig(0);
%   dwords(10);
%   draw dyckdiagram(10,4500);
%endfig;
%\end{mplibcode}
\end{document}

相关内容