2

I'm creating a package that generates a tikz picture based on a command with pgf key/value parameters. I want to have two parameters, one that specifies a base shape with a particular fill colour, and another that turns that fill "on" when false (to the specified colour), and "off" (to white) when true. I've created a simplified example below:

\documentclass[border=5pt]{standalone}
\usepackage{xifthen}
\usepackage{tikz}
\newboolean{shapecolour}
\pgfkeys{/tikz/.cd,
 circle/.style={fill=red},
 square/.style={fill=green},
 triangle/.style={fill=yellow},
 blank/.style={fill=white},
 colourshape/.store in=\colourshape,
 colourshape=circle,
 nocolour/.store in=\nocolour,
 nocolour=false,
 circle/.pic={\draw [fill] circle(0.5); },
 square/.pic={\draw [fill] (0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle;},
 triangle/.pic={\draw [fill] (0,0) -- (1,0) -- (0.5, 1) -- cycle;},
 }

\begin{document}

\newcommand{\TestCommand}[1][]{
 \tikzset{colourshape=circle, nocolour=false, #1}
 \setboolean{shapecolour}{\nocolour}
 \pic[\ifthenelse{\boolean{shapecolour}}{blank}{\colourshape}]{\colourshape};
}

\begin{tikzpicture}
 \TestCommand[colourshape=triangle, nocolour=true]
\end{tikzpicture}

\end{document}

This is the desired outcome of my code, based on the pgfkeys arguments put into TestCommand:

desired outcome of code

So the code above should produce a triangle with a white fill. Instead I get the error ! Argument of \boolean has an extra }. I know I can achieve the same result in a more verbose way by specifying a separate pic for each variant of the shape, but I would like to have a more compact solution, especially as there will be more style options to follow.

2
  • 1
    Ouch, you are overriding a lot of default TikZ keys.
    – percusse
    Commented Sep 14, 2016 at 19:15
  • @percusse I know, the real thing doesn't do this. It's a quick and dirty example. It works if I type in the style parameters manually rather than using the conditional, so it's OK. Commented Sep 14, 2016 at 19:21

1 Answer 1

3

It is hard to be certain without more information about the overall project. However, from your example, I would not use a conditional here at all. If you do use a conditional, I would look into PGF's .is if handler, which will make things much easier.

First some keys:

\tikzset{%

We can afford to use verbose names here because the user interface won't require them at all.

  Crazymoomin circle/.pic={\draw [fill=Crazymoomin@fill] (.5,.5) circle (0.5);},
  Crazymoomin square/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle;},
  Crazymoomin triangle/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (1,0) -- (0.5, 1) -- cycle;},

So that we can use simple key names in the user interface, we'll put them on a custom path, but we'll make sure that standard TikZ keys work here, too.

  /Crazymoomin/.search also={/tikz},

Switch paths.

  /Crazymoomin/.cd,

Now we can use simple names without overwriting the defaults.

  fill/.code={%

This will hold a custom colour.

    \colorlet{Crazymoomin@fill}{#1}%
  },

And a shape.

  shape/.store in=\Crazymoomin@shape,

To handle the colour/shape combo neatly, let's make colour shape a choice key.

  colour shape/.is choice,

Now for the options, which each switch to our path and set the pic shape and fill.

  colour shape/triangle/.style={/Crazymoomin/.cd, shape=triangle, fill=yellow},
  colour shape/circle/.style={/Crazymoomin/.cd, shape=circle, fill=red},
  colour shape/square/.style={/Crazymoomin/.cd, shape=square, fill=green},

no colour can just set the fill to white.

  no colour/.style={/Crazymoomin/fill=white},

Make sure we have a default for everything.

  fill=gray,
  shape=circle,
}

Now the command.

\newcommand{\TestCommand}[1][]{%
 \tikzset{%

Switch to our path.

   /Crazymoomin/.cd,

Default setting. This sets the filling colour anyway, so no colour is effectively false by default.

   colour shape=circle,

User options.

   #1,
 }%

And the pic.

 \pic {Crazymoomin \Crazymoomin@shape};
}

Then we can write, for example,

\begin{tikzpicture}
 \TestCommand[colour shape=triangle, no colour]
 \scoped[xshift=12.5mm]{\TestCommand[colour shape=circle, no colour]}
 \scoped[xshift=25mm]{\TestCommand[colour shape=square, no colour]}
 \scoped[yshift=12.5mm]{\TestCommand[colour shape=triangle]}
 \scoped[xshift=12.5mm, yshift=12.5mm]{\TestCommand[colour shape=circle]}
 \scoped[xshift=25mm, yshift=12.5mm]{\TestCommand[colour shape=square]}
\end{tikzpicture}

to produce

shape variations

Obviously this is awkward because I didn't want to mess around too much with \TextCommand which doesn't have any positioning information (eek!?).

Complete code:

\documentclass[border=10pt,multi,tikz]{standalone}
\makeatletter
\tikzset{%
  Crazymoomin circle/.pic={\draw [fill=Crazymoomin@fill] (.5,.5) circle (0.5);},
  Crazymoomin square/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (0,1) -- (1,1) -- (1,0) -- cycle;},
  Crazymoomin triangle/.pic={\draw [fill=Crazymoomin@fill] (0,0) -- (1,0) -- (0.5, 1) -- cycle;},
  /Crazymoomin/.search also={/tikz},
  /Crazymoomin/.cd,
  fill/.code={%
    \colorlet{Crazymoomin@fill}{#1}%
  },
  shape/.store in=\Crazymoomin@shape,
  colour shape/.is choice,
  colour shape/triangle/.style={/Crazymoomin/.cd, shape=triangle, fill=yellow},
  colour shape/circle/.style={/Crazymoomin/.cd, shape=circle, fill=red},
  colour shape/square/.style={/Crazymoomin/.cd, shape=square, fill=green},
  no colour/.style={/Crazymoomin/fill=white},
  fill=gray,
  shape=circle,
}
\newcommand{\TestCommand}[1][]{%
 \tikzset{%
   /Crazymoomin/.cd,
   colour shape=circle,
   #1,
 }%
 \pic {Crazymoomin \Crazymoomin@shape};
}
\makeatother
\begin{document}
\begin{tikzpicture}
 \TestCommand[colour shape=triangle, no colour]
 \scoped[xshift=12.5mm]{\TestCommand[colour shape=circle, no colour]}
 \scoped[xshift=25mm]{\TestCommand[colour shape=square, no colour]}
 \scoped[yshift=12.5mm]{\TestCommand[colour shape=triangle]}
 \scoped[xshift=12.5mm, yshift=12.5mm]{\TestCommand[colour shape=circle]}
 \scoped[xshift=25mm, yshift=12.5mm]{\TestCommand[colour shape=square]}
\end{tikzpicture}
\end{document}
1
  • Thankyou for the answer, very helpful. I do change the outline pattern and colour using keys as well, but I have managed to get this to work because I'm changing separate style attributes. However, your method looks a lot more attractive so i'll see if I can do something similar for those. I wasn't planning on adding positioning information as they will probably either be drawn on their own or as part of a larger Tikz picture where I would expect positioning would be controlled out of scope of the command. I haven't decided yet if I'm going to include it. Commented Sep 15, 2016 at 8:16

You must log in to answer this question.

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