TransWikia.com

Changing newcommand to have optional argument breaks command

TeX - LaTeX Asked by Gigi Bayte 2 on May 31, 2021

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#1bfseries},
        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=sffamilysmall}]]
}
{;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}

One Answer

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={sffamilybfseriesLarge#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=sffamilysmall},
  },
  @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.

Correct answer by schtandard on May 31, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP