5

I have some macros \foo that expand to |[some style]| the content, and I’d like to be able to do: execute at empty cell={\foo} (I can already do \foo inside a matrix). But it seems like execute at empty cell does not allow this syntax. Any idea how to make this work?

Importantly: I want BOTH syntax to work since I might also use normal syntax), so sayed differently, I want to find a command \createNode such that execute at empty cell={\createNode{\node[red]{A};}} works and execute at empty cell={\createNode{|[red]|A}} works as well.

\documentclass[options]{article}
\usepackage{tikz}
\usetikzlibrary{matrix}

\begin{document}

For now I do:

\begin{tikzpicture}
  \matrix [matrix of math nodes,
    execute at empty cell={\node[red]{A};
  }]
  {
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };
\end{tikzpicture}

And I would like this to work (the reason being that I internally call existing macros that expand to this):

\begin{tikzpicture}
  \matrix [matrix of math nodes,
    %% This ----------------v
    execute at empty cell={|[red]| A}
  ]
  {
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };
\end{tikzpicture}


\end{document}

EDIT

Thanks for the answer, sadly it does not work for both, it is broken now for \node:

replace empty cell with={\node[red]{A};}

instead, I get an error saying that node is not defined.

I also tried to replace this code with directly:

    execute at empty cell={
      \tikz@lib@matrix@start@cell
      |[red]| A%
      \tikz@lib@matrix@end@cell
    }

but it is not working (error ERROR: Argument of \tikz@next has an extra }.). Any idea why?

Then, I tried it on my real world example, but it does not work as all normal nodes at least are removed. I use something like this, but without success, does it ring a bell?

     /tikz/replace empty cell with/.code={%
      \def\tikz@at@emptycell{%
        \tikz@lib@matrix@start@cell
        #1%
        \tikz@lib@matrix@end@cell
      }%
    },
  /tikz/replace empty cell with={%
    % /tikz/execute at empty cell={%
      % We want to check if there is a
      \ifcsname zxExecuteAtCell-\tikzcdmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
        \csname zxExecuteAtCell-\tikzcdmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn\endcsname%
      \else%
        \ifdefined\zxCustomExecuteAtEmptyCell\zxCustomExecuteAtEmptyCell%
        \else%
          \coordinate[
          % yshift=axis_height, % We already do that elsewhere
          name=\tikzmatrixname
          -\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn];
        \fi%
      \fi%
    },
5
  • Can't you manipulate the output of the internal macros so they expand to what you need? It wouldn't be hard to take the | out, for example. If you had to, you could also pass it to a custom key which passed it on to execute at empty cells, though I imagine that would be needlessly circuitous.
    – cfr
    Sep 22 at 0:18
  • @cfr I guess I could, but this would require the rewrite of a significant portion of my library, I hope it will not break other code. I’m not sure to understand your second suggestion though.
    – tobiasBora
    Sep 22 at 0:39
  • Basically, similar to the idea below but cruder. Essentially you either prepare something the existing key will accept or you pass the something you already have to a different key (or some intermediate position). I thought it would generally be easier to prepare something for the existing key by editing out the | programmatically. That is, you take whatever the current internals spits out, parse it and remove the | delimiters, then pass it to the key. Alternatively, you pass what it spits out to a key which removes them and passes it to the existing key. But the ans below is far neater.
    – cfr
    Sep 22 at 0:49
  • @cfr Actually, I realized that I cannot really use \node{}; directly, since \node will not give a default name to the nodes based on the position in the matrix, which is really important for my application. (or maybe I can manually specify it, but then it gets quite ugly)
    – tobiasBora
    Sep 22 at 1:28
  • Define \createnode{} to parse the argument as a regular expression and substitute as necessary. If the expression has constraints as a result of your internal manipulations, make use of them. You'll need at least minimal predictability e.g. no | except the two would help a lot - then you can just remove them, remove the unneeded \node and add \node as you want.
    – cfr
    Sep 22 at 6:26

2 Answers 2

6

The matrix library allows a cell to be of the form

  • <node content>,
  • |<extra>| <node content> (where <extra> is any node specification allowed between node and the {) as well as
  • any normal paths starting with \path, \draw, \node, etc.

The detection of a \path, \draw, \node, etc. is a special hack that oftentimes fails with a more complex cell (can't start with \tikzset or a macro that has an optional argument).

However, we can employ the same hack check that the matrix library does by putting \tikz@lib@matrix@start@cell in front of the parameter (\node[red]{A}; or |[red]| A). However, since this usually is encountered at the start of a cell where & (= \pgfmatrixnextcell) has already done its work we must emulate this by expanding our parameter twice.

Code

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\makeatletter
\tikzset{
  matrix of nodes/.append style={
    execute at empty cell/.code=%
      \expandafter\def\expandafter\tikz@at@emptycell\expandafter
        {\tikz@at@emptycell\expandafter\expandafter\expandafter
          \tikz@lib@matrix@start@cell##1\tikz@lib@matrix@end@cell}}}
\makeatother
\begin{document}

For now I do:

\tikz
  \matrix [matrix of math nodes, execute at empty cell={\node[red]{A};}]{
    8 &   & |[green]| B \\
      & 5 & \\
    4 &   & 2 \\
  };


And I would like this to work (the reason being that I internally
  call existing macros that expand to this):

\tikz
  \matrix [matrix of math nodes, execute at empty cell={|[red]| A}]{
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };

Multiple:

\tikz
  \matrix [matrix of math nodes,
    execute at empty cell={|[red]| A},
    execute at empty cell={\draw (0,.5ex) circle[radius=1em];},
    execute at empty cell={|[blue, draw, xshift=1em]|  C},
  ]{
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };
\end{document}
6
  • "[...] we must emulate this by expanding our parameter twice" Nice catch! But I still think the existing execute at empty cell=\tikz@lib@matrix@empty@cell in matrix of nodes style should be cleared, since it will add an empty \node with name <matrix name>-<row>-<col>. This may cause node naming crashes. Also the extended syntax of execute at empty cell seems too powerful: I prefer only one execution of \tikz@lib@matrix@start@cell per cell. I will try to revise my answer with these thoughts. Sep 22 at 11:32
  • It will only add an empty node when nodes in empty cells is set. That will already “conflict” with any other execute at empty cell as before. (OP needs to decide whether that should stay or not.) And execute at empty cell already collects with multiple calls. I try to not to change to much already present behavior. And yes, only the last node created with the shorthand syntax will have the matrix node name. Sep 22 at 15:02
  • That said, I don't like how the <matrix name>-<row>-<col> is hard-coded into the matrix of nodes things but so hard to access with a manual \node because who wants to write name=\tikzmatrixname-\the\pgfmatrixcurrentrow-\the\pgfmatrixcurrentcolumn. I'd save that in a key matrix node which then can be added much easier to any node we need to name that way. But maybe all this discussion is moot if OP only wants to add one node per cell anyway. Sep 22 at 15:03
  • 1
    @tobiasBora Yes, there's some black magic happening with the way the underlying PGF matrix and the library's code work together I can't seem to get a grasp on. On the other hand, \matrix[matrix of nodes]{\e\\}; both work with \def\a{\b}\def\b{\c}\def\c{\d}\def\d{\e}\def\e{|[red]|B} or \def\a{\b}\def\b{\c}\def\c{\d}\def\d{\e}\def\e{\draw(0,0)--(1,1);}. Sep 25 at 18:54
  • 1
    Your \test works with \def and \newcommand. The xparse manual mentions something about tables and \omit. Internally the matrix uses the \halign primitive and real & so it wouldn't surprise me if the TikZ matrix behaves differently with \New(Expandable)DocumentCommand. I think not using the shorthand is a good idea if you can control the input. Sep 25 at 18:57
5
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}

\makeatletter
\tikzset{
  replace empty cell with/.code={%
    \edef\tikz@at@emptycell{%
      \noexpand\tikz@lib@matrix@start@cell
      \unexpanded\expandafter\expandafter\expandafter{#1}%
      \noexpand\tikz@lib@matrix@end@cell
    }%
  }
}
\makeatother

% for better aligment and spacing
\tikzset{
  every picture/.append style={
    baseline=0pt,
    column sep={.5cm, between origins},
    row sep={.5cm, between origins},
    inner xsep=.5pt
  },
}

\begin{document}

\verb|replace empty cell with=|

\begin{tikzpicture}
  \matrix [
    matrix of math nodes,
    replace empty cell with={|[red]| A},
  ]
  {
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };
\end{tikzpicture}
\verb+{|[red]| A}+

\begin{tikzpicture}
  \matrix [
    matrix of math nodes,
    replace empty cell with={\node[red] {A};},
  ]
  {
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };
\end{tikzpicture}
\verb+{\node[red] {A};}+

\begin{tikzpicture}
  \matrix [
    matrix of math nodes,
    column sep={.5cm,between origins},
    replace empty cell with={\draw (0em,.3em) circle[radius=.4em];},
  ]
  {
    8 &   & |[green]| B \\
    & 5 &   \\
    4 &   & 2 \\
  };
\end{tikzpicture}
\verb+{\draw (0em,.3em) circle[radius=.4em];}+
\end{document}

now all three forms are supported

Explanations

  • \tikz@lib@matrix@start@cell<cell content>\tikz@lib@matrix@end@cell can parse <cell content> ::= "|[red]| A" to \node[red] {A};. These macros are originally used by option matrix of nodes, see related source lines in tikzlibrarymatrix.code.tex.
  • \tikz@at@emptycell holds the accumulated code passed to execute at empty cell, see corresponding source line in tikz.code.tex. Since matrix of nodes (called by matrix of math nodes) contains execute at empty cell=\tikz@lib@matrix@empty@cell, \def\tikz@at@emptycell{...} is used to overwrite existing value.
  • Thanks to @Qrrbrbirlbel (see this answer), now replace empty cell with=<cell content> accepts all three forms of cell content: |<styles>| <node text>, \node ...;, and \draw ...;.
6
  • 2
    Very elegant. Could you explain why you need execute at empty cells=\empty?
    – cfr
    Sep 22 at 0:52
  • Thanks a lot, unfortunately it seems to fail now on \node{A} (cf my edit for details)
    – tobiasBora
    Sep 22 at 1:12
  • 1
    @tobiasBora I think the idea is you pass that syntax to execute at empty cell as you normally would and not that the new key works for both.
    – cfr
    Sep 22 at 4:24
  • @cfr oh, but then it is not really what I want, since the user might provide either value. The proposed regex parsing might work, but it seems quite complicated and not extremely reliable. Why isn't this working for all? It seems to internally already check the shape of the expression.
    – tobiasBora
    Sep 22 at 7:28
  • 1
    @tobiasBora Now execute empty cell with={\node {A};} is supported. I need more time to come up with a execute at empty cell solution, if you prefer that form. Sep 22 at 12:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .