5

I have a tikz matrix, I'd like to reorder the rows from top to bottom to bottom to top

\matrix
{
  a & b & c\\
  d & e & f\\
  g & h & i\\
}

to

\matrix
{
  g & h & i\\
  d & e & f\\
  a & b & c\\
}

Of course I can do it by hand for simple cases but I have a lot of matrices that might change. I'd like some reordering macro. The end of line delimes are by \ so it probably could be quite easy.

1 Answer 1

5

Arbitrary permutations of matrix entries

If you want to permute matrix entries, this can be done as follows. Here is a proof of principle, which works. You define a matrix, and save it via

\matrix[matrix of nodes,save cells=A]
{
  a & b & c\\
  d & e & f\\
  g & h & i\\
};

where A serves an identifier (in case you have several matrices). This matrix can be recast in a permuted form using

\matrix[xshift=3cm,matrix of nodes,declare function={mati(\i,\j)=4-\i;
matj(\i,\j)=\j;},reorder cells=A]
{
   &  & \\
   &  & \\
   &  & \\
};

Here the functions mati(\i,\j) and matj(\i,\j) define the mapping of the row index \i and the column index \j. In this case at hand, it just reverts the ordering of the rows.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{matrix}
\makeatletter
\tikzset{save cells/.style={cells={nodes={execute at begin
node={\ifcsname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
\else%
\expandafter\newbox\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
\fi%
\expandafter\expandafter\global\setbox\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname=\hbox\bgroup},
execute at end
node={\egroup%
\expandafter\copy\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
}}}},
reorder cells/.style={nodes in empty cells,
cells={nodes={execute at begin
node={
\setbox0=\hbox\bgroup},
execute at end
node={\egroup%
\pgfmathtruncatemacro{\myi}{mati(\the\pgfmatrixcurrentrow,\the\pgfmatrixcurrentcolumn)}%
\pgfmathtruncatemacro{\myj}{matj(\the\pgfmatrixcurrentrow,\the\pgfmatrixcurrentcolumn)}%
%\typeout{(\the\pgfmatrixcurrentrow,\the\pgfmatrixcurrentcolumn)->(\myi,\myj)}%
\expandafter\copy\csname matrixcellbox#1-\myi-\myj\endcsname%
}}}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\matrix[matrix of nodes,save cells=A]
{
  a & b & c\\
  d & e & f\\
  g & h & i\\
};
\matrix[xshift=3cm,matrix of nodes,declare function={mati(\i,\j)=4-\i;
matj(\i,\j)=\j;},reorder cells=A]
{
   &  & \\
   &  & \\
   &  & \\
};
\end{tikzpicture}
\end{document}

enter image description here

At the expense of even more complex style definitions, one can spare the user from having to enter an empty matrix by employing these routines. Of course, one can also make the nodes math. The mapping is also slightly more complex in this example:

\documentclass[tikz,border=3mm]{standalone}
\usepackage{etoolbox}
\usetikzlibrary{matrix}
\newcommand{\CreateEmptyMatrix}[3]{% based on https://tex.stackexchange.com/a/60400
\xdef#3{}%
  \foreach \j in {1,...,#1}{
    \foreach \i in {1,...,\the\numexpr#2-1} {%
      \begingroup\edef\x{\endgroup
         \noexpand\gappto\noexpand#3{ {} \&}}\x
      }%
    \gappto#3{\\}%
  }
}
\makeatletter
\tikzset{save cells/.style={cells={nodes={execute at begin
node={\ifcsname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
\else%
\expandafter\newbox\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
\fi%
\expandafter\expandafter\global\setbox\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname=\hbox\bgroup},
execute at end
node={\egroup%
\expandafter\copy\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
}}},
execute at end matrix={%
\expandafter\xdef\csname matrix@rows@#1\endcsname{\the\pgfmatrixcurrentrow}%
\expandafter\xdef\csname matrix@colss@#1\endcsname{\the\pgfmatrixcurrentcolumn}%
}},
save math cells/.style={cells={nodes={execute at begin
node={\ifcsname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
\else%
\expandafter\newbox\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
\fi%
\expandafter\expandafter\global\setbox\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname=\hbox\bgroup$},
execute at end
node={$\egroup%
\expandafter\copy\csname matrixcellbox#1-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
}}},
execute at end matrix={%
\expandafter\xdef\csname matrix@rows@#1\endcsname{\the\pgfmatrixcurrentrow}%
\expandafter\xdef\csname matrix@cols@#1\endcsname{\the\pgfmatrixcurrentcolumn}%
}},
reorder cells/.style={/utils/exec=%
\edef\myrows{\csname matrix@rows@#1\endcsname}%
\edef\mycols{\csname matrix@cols@#1\endcsname}%
\CreateEmptyMatrix{\myrows}{\mycols}{\myemptymatrix},
ampersand replacement=\&,
node contents=\myemptymatrix,
nodes in empty cells,
cells={nodes={execute at begin
node={
\setbox0=\hbox\bgroup},
execute at end
node={\egroup%
\edef\myrows{\csname matrix@rows@#1\endcsname}%
\edef\mycols{\csname matrix@cols@#1\endcsname}%
\pgfmathtruncatemacro{\myi}{max(1,min(\myrows,mati(\the\pgfmatrixcurrentrow,\the\pgfmatrixcurrentcolumn)))}%
\pgfmathtruncatemacro{\myj}{max(1,min(\mycols,matj(\the\pgfmatrixcurrentrow,\the\pgfmatrixcurrentcolumn)))}%
%\typeout{(\the\pgfmatrixcurrentrow,\the\pgfmatrixcurrentcolumn)->(\myi,\myj)}%
\expandafter\copy\csname matrixcellbox#1-\myi-\myj\endcsname%
}}}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\matrix[matrix of nodes,save math cells=A]
{
  a & b & c\\
  d & e & f\\
  g & h & i\\
};
\matrix[xshift=3cm,matrix of nodes,
declare function={mati(\i,\j)=4-\i;
matj(\i,\j)=4-\j;},reorder cells=A]
{
};
\end{tikzpicture}
\end{document}

enter image description here

Of course, one may suppress the output of the first matrix, e.g. by shooting it into a box that we never use.

OLDER ANSWER: This effect can be achieved by dialing negative row sep.

\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{matrix}
\tikzset{swap rows/.style={row sep=-3em,yshift=1em}}
\begin{document}
\begin{tikzpicture}
\matrix[matrix of math nodes]
{
  a & b & c\\
  d & e & f\\
  g & h & i\\
};
\matrix[xshift=3cm,matrix of math nodes,swap rows]
{
  a & b & c\\
  d & e & f\\
  g & h & i\\
};
\end{tikzpicture}
\end{document}

enter image description here

Similar tricks have been used here and here.

0

You must log in to answer this question.