4

I wanted to create a macro that can be invoked in the middle of a tikz path and behave differently, conditional on one of the arguments.

Here is an example document:

\documentclass[a4paper]{amsart}

\usepackage{ifthen, tikz}

\newcommand{\nameandlabel}[2]{%
    node [midway, \ifthenelse{\equal{#1}{a}}{above}{below}] {#2}%
}

\begin{document}

\begin{tikzpicture}[xscale = 25mm]
    \node (a) at (0, 0) {$A$};
    \node (b) at (1, 0) {$B$};
    \node (c) at (2, 0) {$C$};
    \draw (a) -- (b) node [midway, above] {$f$};
    \draw (b) -- (c) \nameandlabel{a}{$g$};
\end{tikzpicture}

\end{document}

This document does not compile. It results in this error message, which is surprising because \equal is a macro provided by ifthen.

! Undefined control sequence.
<argument> \equal 
                  {a}{a}
l.16     \draw (b) -- (c) \nameandlabel{a}{$g$}
                                               ;

I saw discussion on the TeX-LaTeX Stack Exchange that said that ifthen was obsolete and that the \IfStrEq macro from the xstring package might be used instead. So I changed the example to the following:

\documentclass[a4paper]{amsart}

\usepackage{xstring, tikz}

\newcommand{\nameandlabel}[2]{%
    node [midway, \IfStrEq{#1}{a}{above}{below}] {#2}%
}

\begin{document}

\begin{tikzpicture}[xscale = 25mm]
    \node (a) at (0, 0) {$A$};
    \node (b) at (1, 0) {$B$};
    \node (c) at (2, 0) {$C$};
    \draw (a) -- (b) node [midway, above] {$f$};
    \draw (b) -- (c) \nameandlabel{a}{$g$};
\end{tikzpicture}

\end{document}

But this results in an even more incomprehensible error message:

! Argument of \XC@definec@lor has an extra }.
<inserted text> 
                \par 
l.16     \draw (b) -- (c) \nameandlabel{a}{$g$}
                                               ;

Why does this still not work?

7
  • 2
    TikZ takes charge of parsing and expanding things in the paths so I guess in this case \nameandlabel does not get expanded before TikZ tries to make sense of the path. You may sidestep the problem by proper use of key-val: with \tikzset{a/.style={above}, mystyle/.style={midway,below}} you can do ...(c) node[mystyle,a] {$g$} or node[mystyle] for defaulting to below...
    – Bordaigorl
    Nov 14, 2013 at 18:30
  • Bordaigorl, the following macro works perfectly in my main document: \newcommand{\isomorphismDecoration}[2]{node [midway, #1 = -2.3mm] {$\widetilde{\phantom{#2}}$}}
    – Hammerite
    Nov 14, 2013 at 20:09
  • Yes you are right, it seems to be a genuine conflict with the conditionals commands...just as a temporary workaround you could define a as an alias for above and then change the def of your macro to node [midway, #1] {#2}
    – Bordaigorl
    Nov 14, 2013 at 20:38
  • Is using \ifx unacceptable? If you do not need anything fancier than checking it is an a than you could get away with \ifx#1a{above}\else{below}\fi (which does work in your code)
    – Bordaigorl
    Nov 14, 2013 at 20:41
  • 2
    The \IfStrEq is not fully expandable (meaning it will leave traces besides left and right in the options which clutter up the key parser from PGFkeys). Similar to the problem in (x)ifthen in TikZ (and related question). You will need to do conditional outside of the keys (either outside of the path, inside of \pgfextra{…} or with the /utils/exec key). Nov 14, 2013 at 23:49

2 Answers 2

3

Neither ifthen nor xstring tests work by expansion they both make internal definitions.

If you use a purely expandable test it works as you had intended.

enter image description here

\documentclass[a4paper]{amsart}

\usepackage{ifthen, tikz}

\newcommand{\nameandlabel}[2]{%
    node [midway, \ifx a#1above\else below\fi] {#2}%
}

\begin{document}

\begin{tikzpicture}[x = 25mm]
    \node (a) at (0, 0) {$A$};
    \node (b) at (1, 0) {$B$};
    \node (c) at (2, 0) {$C$};
    \draw (a) -- (b) node [midway, above] {$f$};
    \draw (b) -- (c) \nameandlabel{a}{$g$};
\end{tikzpicture}

\begin{tikzpicture}[x = 25mm]
    \node (a) at (0, 0) {$A$};
    \node (b) at (1, 0) {$B$};
    \node (c) at (2, 0) {$C$};
    \draw (a) -- (b) node [midway, above] {$f$};
    \draw (b) -- (c) \nameandlabel{b}{$g$};
\end{tikzpicture}

\end{document}
3

The David Carlisle's answer is a direct answer to your question. But I think that in your case in place to use conditional it is more in the spirit of TikZ to use a .is choice key handler. Here is an example how to do it.

\documentclass[varwidth]{standalone}
\usepackage{tikz}

\tikzset{
  ab/.is choice,
  ab/a/.style={above},
  ab/b/.style={below},
}
\newcommand{\nameandlabel}[2]{%
    node [midway,ab=#1] {#2}%
}

\begin{document}

  \begin{tikzpicture}[x = 25mm]
      \node (a) at (0, 0) {$A$};
      \node (b) at (1, 0) {$B$};
      \node (c) at (2, 0) {$C$};
      \draw (a) -- (b) node [midway, above] {$f$};
      \draw (b) -- (c) \nameandlabel{a}{$g$};
  \end{tikzpicture}

  \begin{tikzpicture}[x = 25mm]
      \node (a) at (0, 0) {$A$};
      \node (b) at (1, 0) {$B$};
      \node (c) at (2, 0) {$C$};
      \draw (a) -- (b) node [midway, above] {$f$};
      \draw (b) -- (c) \nameandlabel{b}{$g$};
  \end{tikzpicture}

\end{document}

enter image description here

You must log in to answer this question.

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