Tikz /foreach 问题

Tikz /foreach 问题

下面的代码用于绘制排列图:

\documentclass[a4paper]{article}
\usepackage{tikz}

\newcommand{\normaldot}[1]{ % Make a dot of fixed absolute size.
    \node at #1 {\normalsize $\bullet$};
}

\newcommand{\plotperm}[1]{% plot a permutation
    \foreach \j [count=\i] in {#1} {
        \normaldot{(\i,\j)}{};
    };
}
\newcommand{\plotpermgrid}[1]{% plot a permutation in a grid
    \foreach \i [count=\n] in {#1} {};  % Now \n stores the number of entries of the permutation. 
    \foreach \i in {0,1,2,...,\n}{
        \draw [color=darkgray] ({\i+0.5}, 0.5)--({\i+0.5}, {\n+0.5});
        \draw [color=darkgray] (0.5, {\i+0.5})--({\n+0.5}, {\i+0.5});
    }
    \plotperm{#1};
}

\begin{document}
    \begin{tikzpicture}
        \plotpermgrid{2,4,1,3}
    \end{tikzpicture}
\end{document}  

使用 TexLive2017,这将导致一个网格显示排列点 (2,4,1,3),如下所示排列图 2413

使用 TexLive2019 时,我收到错误消息,以“未定义的控制序列。\plotpermgrid{2,4,1,3}”开头

问题似乎与以下线路有关

\foreach \i [count=\n] in {#1} {};

在 TexLive2017 中,这会设置\n为排列元素的数量,并且,至关重要的是,允许在完成\n后使用\foreach。在 TexLive2019、TexLine2020 和 MikTex 中,\n在循环内设置,但之后不能使用。

我可以通过添加元素数量的第二个参数来解决这个问题,但这似乎不是一个完美的解决方案,而且容易出现错误。

我尝试过使用计数器,但是(使用名为的计数器gridsize),当我写入时会出现错误\foreach \i in {0,1,2,...,{\thegridsize}}

我没有选择返回TexLive2017,并且我有大量使用\plotpermgrid如上所述的LaTeX文档。

我如何更改定义\plotpermgrid以使其使用 TexLive2019 或更高版本工作,同时仍然像以前一样采用单个参数?

答案1

欢迎来到 SE!

实际上,您遇到的错误是undefined control sequence \n(或类似的话)。\n在 中求值\foreach,而 又位于一个组中。因此,当\foreach完成后,\n就会被遗忘。诀窍是在 运行\n时使 变为全局的\foreach,如下所示:

\documentclass[a4paper]{article}
\usepackage{tikz}

\newcommand{\normaldot}[1]{ % Make a dot of fixed absolute size.
    \node at #1 {\normalsize $\bullet$};
}

\newcommand{\plotperm}[1]{% plot a permutation
    \foreach \j [count=\i] in {#1} {
        \normaldot{(\i,\j)}{};
    };
}
\newcommand{\plotpermgrid}[1]{% plot a permutation in a grid
    \foreach \i [count=\n] in {#1} {\global\let\newn=\n};  % Now \newn stores the number of entries of the permutation globally. <<<--- 
    \foreach \i in {0,1,2,...,\newn}{
        \draw [color=darkgray] ({\i+0.5}, 0.5)--({\i+0.5}, {\newn+0.5});
        \draw [color=darkgray] (0.5, {\i+0.5})--({\newn+0.5}, {\i+0.5});
    }
    \plotperm{#1};
}

\begin{document}
    \begin{tikzpicture}
        \plotpermgrid{2,4,1,3}
    \end{tikzpicture}
\end{document}  

生成的图形正是您所发布的。

答案2

您应该计算输入数组的长度:

\documentclass[a4paper]{article}
\usepackage{tikz}

\newcommand{\normaldot}[1]{ % Make a dot of fixed absolute size.
    \node at #1 {\normalsize $\bullet$};
}

\newcommand{\plotperm}[1]{% plot a permutation
    \foreach \j [count=\i] in {#1} {
        \normaldot{(\i,\j)}{};
    };
}
\newcommand{\plotpermgrid}[1]{% plot a permutation in a grid
    \pgfmathsetmacro\n{dim({#1})}% compute the length of the array
    \foreach \i in {0,1,...,\n}{
        \draw [color=darkgray] ({\i+0.5}, 0.5)--({\i+0.5}, {\n+0.5});
        \draw [color=darkgray] (0.5, {\i+0.5})--({\n+0.5}, {\i+0.5});
    }
    \plotperm{#1};
}

\begin{document}

\begin{tikzpicture}
  \plotpermgrid{2,4,1,3}
\end{tikzpicture}

\end{document} 

使用{#1}将参数转换为正确分隔的 PGF 数组。该方法自 TeX Live 2013 (Ti) 以来一直有效Z/PGF 版本 3.0.0)。

我认为,\n在之后留下定义\foreach \i [count=\n] in {...}{...}已被视为错误并已修复,因为\foreach循环中使用的所有临时控制序列都应该是循环本地的,并且不会在循环之外留下任何东西(除非设为全局的)。


在被告知(老实说,以一种非常不愉快的方式)它dim并不总是按预期运行之后,尽管在您的情况下它应该按预期运行,但前提是参数\plotpermgrid至少有两个项目,我提供了一个更安全的解决方案。

\documentclass[a4paper]{article}
\usepackage{tikz}
\usepackage{xparse} % not needed with LaTeX release 2020-10-01 or later

\ExplSyntaxOn
\NewExpandableDocumentCommand{\clistlen}{m}
 {
  \clist_count:n { #1 }
 }
\ExplSyntaxOff


\newcommand{\normaldot}[1]{ % Make a dot of fixed absolute size.
    \node at #1 {\normalsize $\bullet$};
}

\newcommand{\plotperm}[1]{% plot a permutation
    \foreach \j [count=\i] in {#1} {
        \normaldot{(\i,\j)}{};
    };
}
\newcommand{\plotpermgrid}[1]{% plot a permutation in a grid
    \pgfmathsetmacro{\n}{\clistlen{#1}}% get the number of items in #1
    \foreach \i in {0,1,...,\n}{
        \draw [color=darkgray] ({\i+0.5}, 0.5)--({\i+0.5}, {\n+0.5});
        \draw [color=darkgray] (0.5, {\i+0.5})--({\n+0.5}, {\i+0.5});
    }
    \plotperm{#1};
}

\begin{document}

\begin{tikzpicture}
  \plotpermgrid{2,4,1,3}
\end{tikzpicture}

\end{document} 

您甚至可以避免定义\n和使用\clistlen{#1}在哪里\n使用。

答案3

有点不同的方法。仅定义了一个可以在文本中使用的新命令,网格被绘制为节点,没有网格的全局缝合维度:

\documentclass[margin=3mm]{standalone}
\usepackage{tikz}
                         
\newcommand{\PPG}[1]% Plot a Permutation in a Grid
{
    \begin{tikzpicture}[nodes={minimum size=1cm}]
\foreach \i [count=\j] in {#1} %\i: columns, \j: rows
{
\node at (\j-0.5,\i-0.5) {\textbullet};
    \foreach \k in {1,...,\j}
    {
    \node[draw] at (\j-0.5,\k-0.5) {};
    \node[draw] at (\k-0.5,\j-0.5) {};
    }
}
    \end{tikzpicture}
}

\begin{document}

\PPG{2,4,1,3,5}
\begin{tikzpicture}
\PPG{2,4,1,3,5}
\end{tikzpicture}

\end{document} 

在此处输入图片描述

附录。\PPG如果在环境中始终使用 网格终止图 ( ) tikzpicture,例如:

\begin{tikzpicture}
\PPG{2,4,1,3,5}
\end{tikzpicture}

那么可能更好,tikzpicture从定义中删除\PPG

\newcommand{\PPG}[1]% Plot a Permutation in a Grid
{
    \scoped[nodes={minimum size=1cm}]{
\foreach \i [count=\j] in {#1} %\i: columns, \j: rows
{
\node at (\j-0.5,\i-0.5) {\textbullet};
    \foreach \k in {1,...,\j}
    {
    \node[draw] at (\j-0.5,\k-0.5) {};
    \node[draw] at (\k-0.5,\j-0.5) {};
    }
}% end of foreach
                                    }% end  of scoped
}% end of newcommand

相关内容