The \arrow
functionality in tikz-cd
is placed in a given cell, and uses the position of that cell, although execution of the code itself (if I'm understanding correctly) is deferred until after the matrix component has finished plotting.
I have several functions that I'd like to achieve the same with. At the moment, they're macros that I call within the 'execute at end picture' key for tikzcd, and I pass the relevant cell parameters as arguments. For example, \slice{col}{title}
puts a dashed line between columns col
and col+1
with a title above the dash. I'd like to be able to put the `slice` command in a cell of the matrix instead of in the key, and to be able to use the column of the cell it's placed in to determine the first parameter (reducing the number of arguments, making a big difference to usability). I'm getting very jumbled with how to get things to evaluate at the right times, and would appreciate some help
I've been trying to work through some of the code for the tikz-cd package, but I get lost very quickly with all the @
symbols, \expandafter
s and \noexpand
s, although I have understood that I probably want to attach my commands to \tikzcd@savedpaths
, and have found this answer quite illuminating.
As a partial step, to get my head around this, I decided to try and write a new macro using the existing \arrow
command which, instead of a d
syntax for indicating a downward step, uses a numerical step, and wants to calculate the name of the target cell. If I just use the name of the target cell as the node text, it appears correctly, but is I use it as the argument for \arrow
, it (presumably) gets evaluated after the matrix is drawn so the current row and column evaluate as the last row and column, and all placement is done relative to that. To be clear, I do not want a solution that just looks at the number in the argument and calls \arrow
, repeating d
that number of times in the argument.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{cd,fit,calc}
\newcommand{\slice}[2]{
\xdef\Loop{}
\foreach \n in {1,...,\the\pgfmatrixcurrentrow} {\xdef\Loop{\Loop(m-\n-#1)} }
\node (slice-#1) [fit=\Loop, inner sep=0pt] {}; %a node that contains column #1
\xdef\Loop{}
\foreach \n in {1,...,\the\pgfmatrixcurrentrow} {\xdef\Loop{\Loop(m-\n-\the\numexpr#1+1\relax)} }
\node (slice2-#1) [fit=\Loop, inner sep=0pt] {}; %a node that contains column #1+1
%now draw a line between the two nodes
\draw[slice] ($1/2*(slice-#1.north east |- m.north)+1/2*(slice2-#1.north west |- m.north)$) to node[pos=0,inner sep=4pt,anchor=south,color=black] {#2} ($1/2*(slice-#1.south east |- m.south)+1/2*(slice2-#1.south west |- m.south)+(0,-3pt)$);
}
\newcommand{\ctrl}[1]{
%implement essentially an arrow command but take a numerical parameter for the number of rows below (positive) or above (negative)
%many ways I could do this, but using \pgfmatrixcurrentrow illustrates one of the issues in wider implementation
\arrow[dash,thick]{\the\numexpr#1+\pgfmatrixcurrentrow\relax-\the\pgfmatrixcurrentcolumn}
%actually calculates target relative to bottom right of matrix (i.e. \pgfmatrixcurrentrow not evaluated at right time).
}
\newcommand{\slicer}[1]{
%somehow have to make this command execute after matrix. Either through key `execute at end picture' or by adding to macro \tikzcd@savedpaths?
%need this \pgfmatrixcurrentcolumn to evaluate immediately, but values inside the slice macro must be evaluated when run (to give total number of rows/cols)
%\slice{\the\pgfmatrixcurrentcolumn}{#1}
%currently gives Undefined control sequence error
}
\tikzcdset{nodes in empty cells,every matrix/.append style={name=m}} %fix name of matrix as m
\tikzset{
every node/.style={
anchor=center,minimum size=0pt,inner sep=0pt,outer sep=0pt,thick
},
slice/.style={thick,red,dash pattern=on 5pt off 3pt},
operator/.style={draw,fill=white,minimum size=1.5em}
}
\begin{document}
\begin{center}
\begin{tikzcd}[execute at end picture={\slice{1}{title}}]
|[operator]| A & |[operator]| B \\
|[operator]| C \arrow[u,dash,thick] & |[operator]| D
\end{tikzcd}
\end{center}
The syntax that I'd like to use to achieve this:
\begin{center}
\begin{tikzcd}
|[operator]| A \slicer{title} & |[operator]| B \\
|[operator]| C \ctrl{-1} & |[operator]| D
\end{tikzcd}
\end{center}
\end{document}
tikzlibrarycd.code.tex
, you'll see that an arrow essentially adds something to a list that will be executed at the very end.\def\tikzcd@ar@new[#1]{% new syntax \pgfutil@g@addto@macro\tikzcd@savedpaths{% \path[/tikz/commutative diagrams/.cd,every arrow,#1]% (\tikzcd@ar@start\tikzcd@startanchor) to (\tikzcd@ar@target\tikzcd@endanchor); }}
Maybe you can use that to add your commands.