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
    Sep 14 '16 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. Sep 14 '16 at 19:21
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. Sep 15 '16 at 8:16

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.