9

I am trying to use TikZ together with a macro that I defined via \NewDocumentCommand (for multiple optional arguments), but it doesn't behave as expected. TikZ is giving up on the path instead of working with the macro expansion.

Minimal example:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{positioning}

\NewDocumentCommand{\myEdge}{O{} O{auto} m}{edge [#1] node [#2] {#3}}

\begin{document}
% This works
\begin{tikzpicture}
  \node (test1) {test1};
  \node (test2) [right=of test1] {test2} edge [] node [auto] {test3} (test1);
\end{tikzpicture}

% This does not
\begin{tikzpicture}
  \node (test1) {test1};
  \node (test2) [right=of test1] {test2} \myEdge{test3} (test1);
\end{tikzpicture}
\end{document}

Output:

! Package tikz Error: Giving up on this path. Did you forget a semicolon?.

See the tikz package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.19 ...e (test2) [right=of test1] {test2} \myEdge
                                                  {test3} (test1);

Edit: The answer given by @Werner works beautifully when only using the macro with the required argument, or not using it more than once per path. But the following example still fails:

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\usetikzlibrary{positioning}

\DeclareExpandableDocumentCommand{\myEdge}{O{} O{auto} m}{edge [#1] node [#2] {#3}}
\begin{document}
% This works
\begin{tikzpicture}
  \node (node1) {node1};
  \node (node2) [right=of node1] {node2};
  \node (node3) [right=of node2] {node3} edge [bend left] node [right] {edge1} (node2) edge [] node [auto] {edge2} (node1);
\end{tikzpicture}

% This does not
\begin{tikzpicture}
  \node (node1) {node1};
  \node (node2) [right=of node1] {node2};
  \node (node3) [right=of node2] {node3} \myEdge[bend left][right]{edge1} (node2) \myEdge{edge2} (node1);
\end{tikzpicture}
\end{document}

The error:

! Package tikz Error: Giving up on this path. Did you forget a semicolon?.

See the tikz package documentation for explanation.
Type  H <return>  for immediate help.
 ...                                              

l.19 ...left][right]{edge1} (node2) \myEdge{edge2}
                                                   (node1);

I feel like I am missing some fundamental understanding of how either xparse generates those macros, or how TikZ parses the path.

  • If you place your last nonworking line replacing the dots \edef\temp{\noexpand....}\temp it works and shows that it is still an expansion issue. – percusse Oct 30 '12 at 7:53
7

The desired output is achieved using \DeclareExpandableDocumentCommand:

\DeclareExpandableDocumentCommand{\myEdge}{O{} O{auto} m}{edge [#1] node [#2] {#3}}

As mentioned, this is only a partial solution since it only works sometimes, maybe. The requirement that the command be expandable stems from the fact that tikz is building a path on-the-go, and therefore scans your input, assembling it into pieces. If it finds a piece in the path generation it doesn't understand, it assumes you should have actually closed the path (with a trailing ;). So, since \myEdge isn't part of the tikz path lingo, it has a problem interpreting it. This is a typical expansion issue.

  • 1
    Not part of the initial question, but: Is there a different, less fragile way to do this then? And thanks for the answer :-) – dominikh Oct 30 '12 at 12:38

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.