# Use brackets in a \def macro doesn't work

I am using TikZ to draw some graph drawings (with nodes and directed edges/paths). I have two nodes and an arrow pointing from one node to another. I have made a macro called \pathedge so I can use these arrows repeatedly, but its giving me some trouble. Whenever I put an xshift or a yshift option before any of the nodes on the \draw command it gives me an error. I am pretty sure it has something to do with using brackets '[' ']' in a \def macro but I don't know how to fix it. Here's the minimal code example:

\documentclass{article}

\usepackage{etoolbox}
\usepackage{tikz}

\def\conn{\draw[arrows=->, black!50, thick]}
\newcommand{\pathedge}[4]{
\def\startn{#1}
\def\endn{#2}
\def\startnopts{}
\def\endnopts{}

\ifstrequal{#4}{NE_TO_SW} {
\def\startn{[yshift=-1ex]#1.west}
\def\endn{[xshift=1ex]#2.north}
} {}

\conn (\startn) to node[shape=circle, fill=white, inner sep=0.5pt, font=\sffamily\footnotesize]{#3} (\endn);
}

\begin{document}
\begin{tikzpicture}[scale=1,innode/.style={draw, shape=circle,ultra thick,black}]
\node[innode] (1) at (2,2) {1};
\node[innode] (2) at (4,4) {2};

\pathedge{2}{1}{A}{NE_TO_SW}
\end{tikzpicture}
\end{document}


If I understand you correctly (and this is what the error messages suggest) you want a path from ([yshift=-1ex]#1.west) to ([xshift=1ex]#2.north). The error messages are

! Package pgf Error: No shape named [yshift=-1ex]2 is known.
! Package pgf Error: No shape named [xshift=1ex]1 is known.


The problem is expansion that is done by TikZ but too late. The TikZ path parser needs to see a literal [ which can be solved for the start coordinate with \expandafter(\startn) but that doesn’t work for the target node (because TikZ allows only nodes, coordinates, cycle and plot after -- as well as of course a coordinate).

Though, you can do

\newcommand{\pathedge}[4]{
\def\startn{#1}
\def\endn{#2}
\def\startnopts{}
\def\endnopts{}

\ifstrequal{#4}{NE_TO_SW} {
\def\startn{#1.west}
\def\endn{#2.north}
\def\startnopts{yshift=-1ex}
\def\endnopts{xshift=1ex}
} {}
\conn ([style/.expand once=\startnopts]\startn)
to node[shape=circle, fill=white, inner sep=0.5pt, font=\sffamily\footnotesize]{#3}
([style/.expand once=\endnopts]\endn);
}


(Why don’t you use the .north east and .south west anchors directly?)

But to be honest, I would do this entirely different.

## Code

\documentclass[tikz]{standalone}
\tikzset{
conn/.style={arrows=->, black!50, thick,
every to/.append style={edge node={
node[shape=circle, fill=white, inner sep=0.5pt, font=\sffamily\footnotesize]{#1}}}},
ne to sw/.style={
to path={([yshift=-1ex]\tikztostart.west) --
([xshift=1ex]\tikztotarget.north)\tikztonodes}}}
\makeatletter
\tikzset{% from CVS version
edge node/.code={\expandafter\def\expandafter\tikz@tonodes\expandafter{\tikz@tonodes #1}}}
\makeatother
\begin{document}
\begin{tikzpicture}[innode/.style={draw,shape=circle,ultra thick}]
\node[innode] (1) at (2,2) {1};
\node[innode] (2) at (4,4) {2};
\draw[conn=A] (2) to (1);
\end{tikzpicture}

\begin{tikzpicture}[innode/.style={draw,shape=circle,ultra thick}]
\node[innode] (1) at (2,2) {1};
\node[innode] (2) at (4,4) {2};
\draw[conn=A, ne to sw] (2) to (1);
\end{tikzpicture}
\end{document}

• I really like the second solution ... thanks :) – ahmadh Sep 29 '13 at 22:10
• Can you explain to me the \makeatletter part? – ahmadh Sep 29 '13 at 22:16
• @ahmadh For \makeatletter and \makeatother, see What do \makeatletter and \makeatother do? The edge node key simply adds the code for a node to the internal macro that collects the nodes on an edge so that you can add nodes with a key. – Qrrbrbirlbel Sep 29 '13 at 22:19