# optional arguments to tikzpicture to set style globally

I can't get my head around how to get tikz and pgfkeys to do what I want. I would like to define a command which draws a little tikz picture. I'd like this command that would take optional keyval arguments that get passed to the optional argument of \tikz and that get dealt with appropriately. This last stage is causing me trouble. Here's what I have so far

\documentclass{article}
\usepackage{tikz}
\usepackage{xparse}
\tikzset{
foo/.style={color=#1},
foo/.default=black,
bar/.style={color=#1},
bar/.default=black,
}

\NewDocumentCommand{\drawthing}{o}{
\tikz[#1]{\draw[thick,foo] (0,1)--(1,0);
\draw[thick,foo] (0,0)--(1,1);
\draw[thick,bar] (0,0) -- (0,1);
}
}

\begin{document}
Here is text\drawthing[foo=red,bar=blue]
\end{document}


So what this does is \drawthing draws three lines. Two are "foo" lines and one is a "bar" line. I'd like to be able to control the colours of these two types of thing individually. The default style should be that both are black.

The problem is I'm not understanding something about how the keys work. I'm sure it's a simple thing but I am really struggling with it. So it looks like foo=red is having no effect. When I write \draw[thick,foo=green] that works fine. But I want to have this set globally for this picture, so I want to have an option that works as an argument to the tikzpicture as a whole.

What obvious and simple trick have I missed?

-

The reason is that you have specified the foo style with a default key which kicks in if none given.

What you need to realize is that a style only applies to the current segment of code. \draw[foo] ... and \draw[color=black] is equivalent in your case.

## Usage of keys

When you use keys you have to explicitly use them or redefine them.

Consider this:

\tikzset{
foo/.style={#1},
bar/.style={foo={#1}}
}


This will let foo have an empty style! It will simply do nothing unless you add an argument.
\draw[foo={color=green,thick}] is thus equivalent to \draw[color=green,thick]. Also \draw[bar={color=green,thick}] is equivalent to \draw[foo={color=green,thick}]. It is just another alias for the same key.

If you however do the styles like this:

\tikzset{
foo/.style={#1},
bar/.style={foo/.append style={#1}}
}


You will collect styles in to the key foo by using style bar. This is very good in cases where scoped environments are used:

\begin{tikzpicture} % Now all styles who uses foo will do nothing
\draw[foo] (0,0) -- ++(1,0);
\begin{scope}[foo=very thick,bar={color=red},yshift=-1ex]
\draw[foo] (0,0) -- ++(1,0); % Will be red and thick
\draw[foo=dotted] (0,-1ex) -- ++(1,0); % Will be red and thick and dashed
\end{scope}
\end{tikzpicture}


However, as you can see using bar has the effect of adding to the foo style until the end of the environment.

What goes wrong?

If we use the following definitions and the following code it is seen that other behaviour is taking place

\tikzset{
foo/.style={color=#1},
foo/.default=black, % If no argument is given then this kicks in as argument.
bar/.style={foo/.append style={#1}}
}

\begin{tikzpicture}[foo=red] % Now everything will have the style red attached
\draw (0,0) -- ++(1,0); % red
\draw[foo] (0,-1ex) -- ++(1,0); % will have black color as foo is called without an argument, so /.default kicks in!
\begin{scope}[bar=very thick,yshift=-2ex]
\draw[foo] (0,0) -- ++(1,0); % Will be thick, but not red
\draw[foo=red] (0,-1ex) -- ++(1,0); % Will be red and thick
\end{scope}
\end{tikzpicture}


Remember everytime you define default this will be the argument passed if none is given. Thus it could potentially overwrite what you have done.

However as you will see here everything that is not related to the argument #1 is handled properly

\tikzset{
foo/.style={dashed,color=#1},
foo/.default=black, % If no argument is given then this kicks in as argument.
bar/.style={foo/.append style={#1}}
}

\begin{tikzpicture}[foo=red] % Now everything will have the style red and dashed attached
\draw (0,0) -- ++(1,0); % red, dashed
\draw[foo] (0,-1ex) -- ++(1,0); % will have black color and dashed as foo is called with out an argument, so /.default kicks in!
\begin{scope}[bar=very thick,yshift=-2ex]
\draw[foo] (0,0) -- ++(1,0); % Will be dashed, thick, but not red
\draw[foo=red] (0,-1ex) -- ++(1,0); % Will be red and thick and dashed
\end{scope}
\end{tikzpicture}


If you write dashed,very thick,dotted,thick it will only be dotted and thick, not very thick, nor combined dashed and dotted.

The solution is to use another key as the style, but which you never should need to use otherwise.

\tikzset{
foo hidden/.style={}, % Provide a hidden style
foo/.style={foo hidden/.append style={color=#1}}, % foo changes foo hidden
foo/.default=orange,
bar hidden/.style={},
bar/.style={bar hidden/.append style={color=#1}}, % bar changes bar hidden
bar/.default=green,
}

\NewDocumentCommand{\drawthing}{o}{
\tikz[#1]{\draw[thick,foo hidden] (0,1)--(1,0);
\draw[thick,foo hidden] (0,0)--(1,1);
\draw[thick,bar hidden] (0,0) -- (0,1);
}
}

Blue and red: \drawthing[foo=red,bar=blue]

Green and blue: \drawthing[foo=blue,bar]

Black and orange: \drawthing[foo]


If you want it to always have the default you are then allowed to do:

\NewDocumentCommand{\drawthing}{o}{
\tikz[foo,bar,#1]{\draw[thick,foo hidden] (0,1)--(1,0);
\draw[thick,foo hidden] (0,0)--(1,1);
\draw[thick,bar hidden] (0,0) -- (0,1);
}
}

-
This is a great answer. Thanks! – Seamus Jan 20 '12 at 14:59
This is unbelievably clear. If I could upvote twice, I would. – cfr Nov 15 '14 at 0:40