3

The code below used to draw a plot of a permutation:

\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}  

Using TexLive2017, this would result in a grid showing the points of the permutation (2,4,1,3) like thisplot of permutation 2413

With TexLive2019, I get error messages, starting with "Undefined control sequence. \plotpermgrid{2,4,1,3}"

The problem appears to be related to the line

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

In TexLive2017, this sets \n to the number of elements of the permutation, and, critically, allows \n to be used after the \foreach has finished. In TexLive2019, TexLine2020, and MikTex, \n is set within the loop, but cannot be used afterwards.

I could fix this by adding a second parameter for the number of elements, but this doesn't seem to be an elegant solution, and would be susceptible to errors.

I've tried using counters, but (with a counter called gridsize), I get errors when I write \foreach \i in {0,1,2,...,{\thegridsize}}.

I don't have the option to go back to TexLive2017, and I have a large number of LaTeX documents which use \plotpermgrid as defined above.

How can I change the definition of \plotpermgrid so that it works using TexLive2019 or later, while still taking a single parameter as before?

1
  • Welcome to TeX.SE! – Zarko Dec 19 '20 at 13:50
2

Welcome to SE!

Actually the error you encountered was undefined control sequence \n (or words to that effect). \n is evaluated in \foreach which, in turn, is in a group. So, when the \foreach is finished, \n is forgotten. The trick is to make \n in effect global while the \foreach is running, as here:

\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}  

The graphic produced is precisely what you posted.

3

You should instead compute the length of the input array:

\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} 

Using {#1} transforms the argument in a properly delimited PGF array. The method has worked since TeX Live 2013 (TikZ/PGF version 3.0.0).

I believe that leaving \n defined after \foreach \i [count=\n] in {...}{...} has been deemed a bug and fixed, because all temporary control sequences used in a \foreach loop should be local to the loop and not leave anything outside it (unless made global).


Having been informed (in a very unpleasant way, to be honest) that dim doesn't always behave as expected, although in your situation it should, provided the argument to \plotpermgrid has at least two items, I provide a safer solution.

\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} 

You can even avoid to define \n and use \clistlen{#1} where \n is used.

4
  • Where can I read about clistlen? -Google and TikZ manual does not help. – hpekristiansen Dec 19 '20 at 23:44
  • @hpekristiansen It's defined it ad hoc in the code I wrote. It uses expl3 features. – egreg Dec 19 '20 at 23:46
  • Thanks - I see it now. A shame that non-readable by mortals expl3 is needed. – hpekristiansen Dec 19 '20 at 23:54
  • @hpekristiansen The function \clist_count:n returns the number of items in its argument, which is supposed to be a comma separated list. – egreg Dec 20 '20 at 0:51
2

A wee bit different approach. Defined is only one new command which can be used in text, grid is drawn as nodes, no global sewing dimension of grid:

\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} 

enter image description here

Addendum. If plot of termination in a grid (\PPG) is always used in tikzpicture environment, for example:

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

then may be better that tikzpicture is removed from definition of \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

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.