6

Given a macro that accepts a matrix as an argument

\newcommand{tabler}[1]{\matrix(m)[matrix of nodes, ampersand replacement=\&]{#1};}

I would like to determine the number of columns in matrix m, to be able to iterate over them, starting from the highest column.

Background/Motivation:

Given a list of column widths of size n, and a (* x m) matrix, I want to apply the column widths to the columns of the matrix, starting with column m - n +1.

Visualizing what I'm trying to do:

\tabler{col 1\&col 2\&col 3\&col 4}{3,1,3}
|--col 1--|--col 2--|--col 3––|--col 4––|
          | width 3 | width 1 | width 3 |

Having determined the highest column, I would iterate over the columns, similar to the technique used here, starting from the top, and apply the column styles in reverse order.

Edit for clarification: Effectively, I'm trying to apply the list of column widths to the n right-most columns. I don't know how to directly access the highest column with the tikz style command column x/.stlye which is 1-indexed. Python-style list indexing (where l[-1] returns the last element of list l) would be similarly helpful.

Update: Following @Kevin C's pointer to the \pgf@matrix@numberofcolumns macro, I tried (unsuccessfully) to print the number of columns in the matrix by using the pgfkeys .store in key handler (but don't fully understand the expansion rules to be honest).

Example code:

\documentclass{scrartcl}

\usepackage{xparse, tikz}
\usetikzlibrary{matrix}

\makeatletter
\newcommand\totcol{\pgf@matrix@numberofcolumns}
\makeatother

\pgfkeys{
/tabler/execute macro/.style = {/tabler/save/.expand once=#1},
/tabler/save/.store in=\numcols
}

\NewDocumentCommand\tabler{m}{
    \matrix(m)[/tabler/execute macro={\totcol},
            matrix of nodes,
            ampersand replacement=\&] at (0,0)
    {#1};
    \node at (0,0) {\numcols{}};
}

\begin{document}

\begin{tikzpicture}
\tabler{a \& b\& c \& d \& e\\}
\end{tikzpicture}

\end{document} 

This fails with Undefined control sequence [...] \numcols — what am I missing?

Please let me know if there are better/more elegant ways to accomplish what I've outlined.

Julian
  • 579
  • 3
    Are you a mathematician? – percusse Jan 29 '15 at 22:53
  • 1
    @percusse, just to know: why the question? – Sigur Jan 30 '15 at 00:02
  • 2
    Are 'n' and 'n' different? If so, I don't understand at all. If not, might be slightly less confusing not to suggest they are by using different formatting. – cfr Jan 30 '15 at 01:49
  • @percusse: No, I'm doing computer science and finance. Never made it to the pros :) – Julian Jan 30 '15 at 06:34
  • @cfr: Good call — they are not different: I fixed the formatting. – Julian Jan 30 '15 at 06:40
  • 4
    @Sigur Every sentence is logically valid and I know all the concepts involved but I still don't understand anything ;) – percusse Jan 30 '15 at 12:28
  • @percusse, sounds that the OP wants to save the number of columns of the matrix passed to that macro. It could be 1, or 3, or 4, and so on. Later he want to use this number to make a loop, I guess. – Sigur Jan 30 '15 at 12:32
  • @Sigur Yes, the idea is to get the maximum column (e.g. 4 in the example) and then to apply the widths successively to the columns, starting from the maximum column. (e.g. col 4:3, col 3:1, col 2:3). The widths should be applied to the n right-most columns, independent of the total number of columns m. – Julian Jan 30 '15 at 19:41
  • 1
    The way you define \tabler suggests that it takes one argument, but when you use it later, \tabler seems to take two arguments. I don't quite understand what n is. And what is its relation to {3,1,3}? – Herr K. Jan 30 '15 at 22:00
  • @KevinC the second version takes two arguments. n is the number of elements in the second argument (3 in the case of {3,1,3}). If the matrix has 5 columns, the columns 3-5 should have minimum widths of {3,1,3}, respectively. – Julian Jan 30 '15 at 22:16

2 Answers2

7

PGF has an internal macro that stores the number of columns in a matrix: \pgf@matrix@numberofcolumns. So you can access it by putting, say,

\makeatletter
\newcommand\totcol{\pgf@matrix@numberofcolumns}
\makeatother

in the preamble, and use \totcol to do whatever you need with the styles.

Herr K.
  • 17,946
  • 4
  • 61
  • 118
  • Thank you. That's very promising — from what I understand, \pgf@matrix@numberofcolumns is only defined during the creation of the matrix — I will try to save it to a macro with the /.store in Key Handler in pgf. – Julian Jan 30 '15 at 22:22
5

The answer by Herr K. is correct. However, here are two more details that may be important to be able to fully appreciate this answer.

  1. \pgf@matrix@numberofcolumns is a count, i.e. the TeX version of a LaTeX counter. This is evident from pgfmodulematrix.code.tex. So to use it you need a \the or something of that sort.
  2. The arguably most convenient way of retrieving it is to use execute at end matrix. This is a pgf key that does not seem to have found its way in the pgfmanual.

\documentclass[tikz,border=3.14mm]{standalone}
\usetikzlibrary{matrix}
\makeatletter
\tikzset{store number of columns in/.style={execute at end matrix={
\xdef#1{\the\pgf@matrix@numberofcolumns}}},
store number of rows in/.style={execute at end matrix={
\xdef#1{\the\pgfmatrixcurrentrow}}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\matrix[matrix of nodes,store number of columns in=\mymatcols,
store number of rows in=\mymatrows] (mat){
a & b & c & d & e\\
a & b & c & d & e\\
a & b & c & d & e\\
};
\draw[latex-latex] ([yshift=1ex]mat.north west) -- ([yshift=1ex]mat.north east)
node[midway,fill=white]{\mymatcols};
\draw[latex-latex] ([xshift=-1ex]mat.north west) -- ([xshift=-1ex]mat.south west)
node[midway,fill=white]{\mymatrows};
\end{tikzpicture}
\end{document}

enter image description here

Since this is related information, I also add a way to retrieve the number of rows.