2

Simply put, I have a command defined for an edge when using the tikzpicture environment.

Command:

\newcommand{\bendangleundiredgenodes}[6]{(#3) edge [-] [bend #2=#1] node [#5] {#6} (#4)}

Usage:

\bendangleundiredgenodes{30}{left}{0}{1}{above}{Test}

This works perfectly fine. However, if I try to make the first argument optional, then I get an error.

Command:

\newcommand{\bendangleundiredgenodes}[6][30]{(#3) edge [-] [bend #2=#1] node [#5] {#6} (#4)}

Usages (both fail):

\bendangleundiredgenodes{left}{0}{1}{above}{Test}
\bendangleundiredgenodes[30]{left}{0}{1}{above}{Test}

Errors (same for both usages):

Package tikz Error: Giving up on this path. Did you forget a semicolon?. \bendangleundiredgenodes
Not defining \perthousand.
Not defining \micro.

Full example usage:

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{shapes, backgrounds, arrows, automata, positioning, decorations.markings, calc}

\newcommand{\bendangleundiredgenodes}[6]{(#3) edge [-] [bend #2=#1] node [#5] {#6} (#4)}

\newenvironment{discretegraph}[2][\Large]{
    \begin{tikzpicture}[
        ->,
        >=stealth',
        auto,
        node distance=#2cm,
        thick,
        main node/.style={circle, draw, font=\sffamily#1\bfseries},
        nolooparrow/.style={-, every loop/.append style={-}},
        double arrows/.style args={##1, ##2, ##3}{
            decorate,
            decoration={
                markings,
                mark=at position 0 with {
                    \coordinate (ta-base-1) at (0,##3pt);
                    \coordinate (ta-base-2) at (0,-##3pt);
                },
                mark=at position 1 with {
                    \draw[##1] (ta-base-1) -- (0,##3pt); \draw[##2] (ta-base-2) -- (0,-##3pt);
                }
            }
        }, every node/.style={font=\sffamily\small}]]
}
{;\end{tikzpicture}}

\begin{document}
    
    \begin{discretegraph}[\normalsize]{3}
        \node[main node] (0) [] {};
        \node[main node] (1) [right of = 0] {};
        
        \path
        \bendangleundiredgenodes{30}{left}{0}{1}{above}{Test}
        
    \end{discretegraph}
    
\end{document}
9
  • 1
    As far as I can see, \path performs a single expansion of the token following it and this works with the \newcommand defined with no optional argument. It can't work with optional arguments.
    – egreg
    Jan 30 at 11:39
  • 1
    commands with optional arguments are not expandable, they don't work in various places. You could try \NewExpandableDocumentCommand from xparse instead (untested as you didn't provide a complete example). Jan 30 at 11:40
  • @UlrikeFischer Added complete example Jan 30 at 11:59
  • And did you try \NewExpandableDocumentCommand? Jan 30 at 12:02
  • @UlrikeFischer Maybe I am being foolish, but I cannot find the documentation for \ NewExpandableDocumentCommand, even in the xparse documentation. Jan 30 at 12:08
1

As others discussed in the comments, you cannot use macros with optional arguments in TikZ paths. However, it seems to me that you don't really gain much by using this macro anyways: It is not any shorter than just inputting the actual path specification.

Instead, you should take advantage of pgfkeys, which is how TikZ drawings are meant to be styled. This also applies to your discretegraph environment. Here's how I would approach it.

  • Replace discretegraph by a key, I named it discrete graph.
  • I chose to keep the node font as an option to discrete graph and ditch the node distance. If you need to change the node distance, do it explicitly. (Explicit is usually better than implicit anyways.)
  • You could use discrete graph/.default to set the default font size, but it is simpler and clearer to just put \Large in the definitions and allow overriding this with the argument, so I did that.
  • Make another key for you edges. I called it sabdul, obviously you should rename it to something corresponding to what they represent. There are different avenues of making it configurable. I followed a style present elsewhere in TikZ and made a second key sabdul' bending the other way.
  • Don't use numbers as node names. While it is legal, it looks like an incomplete coordinate which is confusing.
\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{arrows}

\tikzset{
  discrete graph/.style={
    ->,
    >=stealth',
    auto,
    thick,
    main node/.style={circle, draw, font={\sffamily\bfseries\Large#1}},
    nolooparrow/.style={-, every loop/.append style={-}},
    double arrows/.style args={##1, ##2, ##3}{
      decorate,
      decoration={
        markings,
        mark=at position 0 with {
          \coordinate (ta-base-1) at (0,##3pt);
          \coordinate (ta-base-2) at (0,-##3pt);
        },
        mark=at position 1 with {
          \draw[##1] (ta-base-1) -- (0,##3pt); \draw[##2] (ta-base-2) -- (0,-##3pt);
        }
      }
    },
    every node/.style={font=\sffamily\small},
  },
  @sabdul/.style 2 args={
    -,
%    bend angle=30, % is the default anyway
    bend #2=#1,
  },
  @sabdul/.default=30,
  sabdul/.style={@sabdul={#1}{left}},
  sabdul'/.style={@sabdul={#1}{right}},
}

\begin{document}

\begin{tikzpicture} [
    discrete graph=\normalsize,
    node distance=3cm,
    ]
  \node [main node] (a) {foo};
  \node [main node] (b) [right of=a] {};
  \path (a) edge [sabdul] node [above] {test} (b);
  \path (a) edge [sabdul'=60] node [below] {another test} (b);
\end{tikzpicture}

\end{document}

MWE output


It is usually best to avoid needing keys with several or optional arguments, like I did here. If you really want to, you should read this question. Using the keys from my answer, you could instead define something like

\tikzset{
  sabdul/.style with optarg with default value={left}{-, bend #1=#2},
}

I would recommend the former approach, though.

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.