6

I am trying to set up a tikz matrix (actually, in this case, a tikz-cd) where I call different macros within the cells, which will determine the content that appears. This all works fine provided I don't have optional arguments on the macros. However, once I use optional arguments, the text that is supposed to define the node instead appears as text. How can I fix this?

Here's an MWE:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{cd}
\newcommand{\qw}{\arrow[dash,thick]{l}}
%hardcoded parameters
\newcommand{\hardmeter}[0]{|[operator,label={[yshift=0.1cm]above right:0}]| {} \qw}
\newcommand{\hardgate}[1]{|[operator,fill=blue]| #1 \qw}
%optional parameters
\newcommand{\optmeter}[1][a]{|[operator,label={[yshift=0.1cm]above right:#1}]| {} \qw}
\newcommand{\optgate}[2][a]{|[operator,#1]| #2 \qw}

\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
    },
    operator/.style={draw,fill=white,minimum size=1.5em}
}

\begin{document}
What's supposed to happen: \\\\
\begin{tikzcd}
& \hardgate{H} & \hardmeter
\end{tikzcd}\\\\
What actually happens:\\
\begin{tikzcd}
& \optgate[fill=blue]{H} & \optmeter[0]
\end{tikzcd}
\end{document} 

Here's the output: enter image description here

I'm sure this will have been asked before, but perhaps without knowing the solution/correct search term, I'm struggling to find it.


Update:

@egreg's solution works for the problem as specified. However, as soon as I make my macros more complex, it stops working. For example, if I want to choose to do one of two different things based on the optional parameter, perhaps interpreting that parameter using pgfkeys, the the original issue recurs.

\documentclass{article}
\usepackage{tikz,xparse,ifthen}
\usetikzlibrary{cd}
\NewExpandableDocumentCommand{\meter}{O{}m}{%
\pgfkeys{#1}
\ifthenelse{\pgfkeysvalueof{/quant/wires}=1}{
  |[operator,label=#2]| {}
}{
  %do something different
  foo
}
}
\tikzset{
    every node/.style={
        anchor=center,minimum size=0pt,inner sep=0pt,outer sep=0pt,thick
    },
    operator/.style={draw,fill=white,minimum size=1.5em}
}
\pgfkeys{/quant/wires/.initial=1}
\begin{document}
\begin{center}
\begin{tikzcd}
 \meter{0} & \meter[/quant/wires=1]{0} & \meter[/quant/wires=2]{0}
\end{tikzcd}
\end{center}
\end{document} 
  • generically, foo will be doing something that is not with a single node, and requires a command that is executed after the matrix is rendered. In this instance, it will look at the value of the wires key and draw a box covering that many rows, with the top row being where the command is executed. I have that command working, but it makes the MWE very non-minimal to include. – DaftWullie Aug 20 '18 at 17:29
  • 2
    The packages help to automate certain tasks, but they limit the possibilities since they are specific applications, those tasks can be done in a general way using the basic codes, even what I have seen in your examples is not complex or difficult to automate using basic code of tikz, the worst thing is not knowing where you want to go, you are only tied in a single path under a package, when you have all the possibilities open with the basic code. – J Leon V. Aug 20 '18 at 18:40
  • 3
    In addition to what @JLeonV. says I would like to argue that it is not particularly nice to accept an answer, then extend the question, and unaccept the answer. egreg answered your question. If you have a new question, even if it is "just" an extension of your previous question, you should IMHO ask a new question. Imagine you solved someone's problem and the someone would just add requirements afterwards, how would you feel about that? (Plus asking questions is free.) – marmot Aug 20 '18 at 19:31
  • 1
    One more thing: the downvote does not come from me. – marmot Aug 21 '18 at 17:23
  • 1
    \ifthenelse is not expandable and should not be used inside a command that should be expandable. The ifthen package can be useful for simple switchs on the document level but is quite unsuited for all internal programming. – Ulrike Fischer Aug 22 '18 at 7:14
5

You could use xparse and \NewExpandableDocumentCommand, but the \optmeter command should have a dummy mandatory argument.

\documentclass{article}
\usepackage{tikz-cd}
\usepackage{xparse}

\newcommand{\qw}{\arrow[dash,thick]{l}}

%hardcoded parameters
\newcommand{\hardmeter}[0]{|[operator,label={[yshift=0.1cm]above right:0}]| {} \qw}
\newcommand{\hardgate}[1]{|[operator,fill=blue]| #1 \qw}
%optional parameters
\NewExpandableDocumentCommand{\optmeter}{O{a}m}{%
  |[operator,label={[yshift=0.1cm]above right:#1}]| {} \qw
}
\NewExpandableDocumentCommand{\optgate}{O{a}{m}}{|[operator,#1]| #2 \qw}

\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,
  },
  operator/.style={
    draw,
    fill=white,
    minimum size=1.5em,
  },
}

\begin{document}
What's supposed to happen:
\[
\begin{tikzcd}
& \hardgate{H} & \hardmeter
\end{tikzcd}
\]
What actually happens:
\[
\begin{tikzcd}
& \optgate[fill=blue]{H} & \optmeter[0]{}
\end{tikzcd}
\]
\end{document}

enter image description here

5

Just for completeness. TikZ allows you to do most things just with styles. That is, I am not sure I would use a command for that.

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{cd}
\newcommand{\qw}{\arrow[dash,thick]{l}}
%hardcoded parameters
\newcommand{\hardmeter}[0]{|[operator,label={[yshift=0.1cm]above right:0}]| {} \qw}
\newcommand{\hardgate}[1]{|[operator,fill=blue]| #1 \qw}

\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
    },
    operator/.style={draw,fill=white,minimum size=1.5em},
    hard/.style={operator,label={[yshift=0.1cm]above right:#1},fill=blue,
    append after command={\pgfextra{\arrow[dash,thick]{l}}}}
}

\begin{document}
What's supposed to happen: \\\\
\begin{tikzcd}
& \hardgate{H} & \hardmeter
\end{tikzcd}\\\\
What actually happens:\\
\begin{tikzcd}
& |[hard]| H & |[hard=0]| O & |[hard,fill=red]| U & |[hard=2,fill=red]| R
\end{tikzcd}
\end{document} 

enter image description here

UPDATE: Sort of an answer to your updated question. I patched something that does what I think it is supposed to do. It is IMHO a very bizarre construction. The basic trick is to defer the ifthenelse to /quant/wires/, which had to become a code, and then to use \pgfkeysalso to smuggle the options back to the node style.

\documentclass{article}
\usepackage{tikz,xparse,ifthen}
\usetikzlibrary{cd}
\NewExpandableDocumentCommand{\meter}{O{}m}{%
|[#1,label=#2]| {}
}
\tikzset{
    every node/.style={
        anchor=center,minimum size=0pt,inner sep=0pt,outer sep=0pt,thick
    },
    operator/.style={draw,fill=white,minimum size=1.5em}
}
\pgfkeys{/quant/wires/.code={\ifcase#1
\or
\pgfkeysalso{/tikz/.cd,operator}
\or
\pgfkeysalso{/tikz/.cd,operator,fill=blue}
\or
\fi}}
\begin{document}
\begin{center}
\begin{tikzcd}
 \meter{0} & \meter[/quant/wires=1]{0} & \meter[/quant/wires=2]{0}
\end{tikzcd}
\end{center}
\end{document} 

enter image description here

I understand that this will kill all your remaining sympathy for marmots, but I do not think that it is a good style to unaccept a working answer just because it does not meet requirements that were added afterwards. I do believe that @egreg deserves the check mark next to his nice answer, which I am using here, and that you should ask a new question here. After all, questions are free of charge.

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.