4

For use in a \foreach loop, I would like to have the style attributes for a rectangle stored in a macro. The style attributes would include the fill color, opacity, etcetera (but the attributes that occur each time are not the same ones each time). Then I would like to use that command, to be expanded in a TikZ \draw command.

I have tried several things to make it work (wrapping the \draw command in a macro, using \edef and/or \expandafter), and tried to google a solution for this problem, but so far unsuccessfully. I boiled down the issue to the following minimal working example. Can anyone help me access the style attributes inside a macro and transfer them to a TikZ drawing command?

\documentclass{minimal}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
    % this works
    \draw[fill=blue,opacity=0.8] (0,0) rectangle (1,1);
\end{tikzpicture}

\begin{tikzpicture}
    % this doesn't work, but I want it to
    \def\styleattributes{fill=blue,opacity=0.8}
    \draw[\styleattributes] (0,0) rectangle (1,1);
\end{tikzpicture}
\end{document}
RobV
  • 616
  • 3
    Use a TikZ style, see here, for example: https://tex.stackexchange.com/questions/21395/tikz-style-with-two-parameters – CarLaTeX Oct 22 '18 at 16:33
  • The number of arguments isn't fixed. The list of attributes is of variable length and the attributes themselves can differ. – RobV Oct 22 '18 at 16:38
  • 1
    Styles can have arguments which can be parametrically set in a \foreach. You can also define "n" styles and use them as parameter of the \foreach. See here, for example: https://tex.stackexchange.com/a/64237/101651 – CarLaTeX Oct 22 '18 at 17:04
  • Yes, thank you! I had come across using expand once but I didn't know about the trick with apply style definition. I will answer my question with code that makes the MWE work. – RobV Oct 22 '18 at 17:12
  • Or you can add the (same) answer as well and I can accept that one as the answer, if you want to get the credit. – RobV Oct 22 '18 at 17:16
  • Don't worry, my idea was different, the important thing is that you solved your problem. – CarLaTeX Oct 22 '18 at 17:32

2 Answers2

5

Thanks to CarLaTeX's comment that pointed to this question, I found the following solution:

\documentclass{minimal}
\usepackage{tikz}

\tikzset{apply style/.code={\tikzset{#1}}}

\begin{document}
    \begin{tikzpicture}
    \def\styleattributes{fill=blue,opacity=0.8}
    \draw[apply style/.expand once=\styleattributes] (0,0) rectangle (1,1);
    \end{tikzpicture}
\end{document}
RobV
  • 616
1

About using TeX macros or LaTeX newcommands to set a TikZ style.

Macros containing style keys often arise when using a foreach loop, but the problem is not caused specifically by the foreach command discussed in the question you refer to.

Loop Space explained in his answer to this question, that compilation errors arise because, when pgfkeys processes a style key, it first splits it into a list of style keys before expanding the TeX macros. Another cause is that pgfkeys determines wether each style key is assigned a value before expanding the TeX macros.

The remedy suggested by Loop Space is to define a style key which expands its argument value once before using it as a style key. Indeed, sometimes expanding once is not sufficient and I rather suggest a key style which performs a complete expansion. It is called expand style in the following code.

The code compares expand style to other style keys called expand style once and expand style twice. It illustrate these facts with eight examples, as simple as possible (which are likely to arise, for instance, when nesting foreach loops to test various styles). In this code, the first two node styles need to be expanded, the third and fourth need to be expanded more than once, the last four need to be expanded more than twice. Conclusion:

  • each macro containing a comma separated list or a value assignement to a key (a key argument preceded by the equal sign) needs one expansion,

  • each macro containing such macros recursively needs one more expansion at each rescursion step,

  • each list of such macros needs one expansion for each item of the list.

\documentclass{article}
\usepackage{tikz}
\tikzset{%
  set style/.style={#1},
  expand style/.style={%completely expands the <value> of its argument (using \edef) before processing the result as a <key>
    set style/.expanded={#1}% needs braces around the argument
  },
  expand style once/.style={%expands the <value> of its argument once before processing the result as a <key>
    set style/.expand once={#1}% needs braces around the argument
  },
  expand style twice/.style={%expands the <value> of its argument twice before processing the result as a <key>
    set style/.expand twice={#1}% needs braces around the argument
  }
}

\begin{document}
\def\mystylearg{fill=yellow}
\def\mystyleargelse{text=red}
\def\mystylelist{draw,circle}
\def\mystylemacroarg{\mystylearg} % minimal macro example needing more than once
\def\mystylemacrolist{\mystylelist} % minimal macro example needing more than once
\def\mystylemacromacroarg{\mystylemacroarg} % minimal macro example needing more than twice 
\def\mystylemacromacrolist{\mystylemacrolist} % minimal macro example needing more than twice

%\tikz\node[\mystylearg] {B}; % fails 
\tikz\node[expand style once=\mystylearg] {B}; % needs expansion
%\tikz\node[expand style=\mystylearg] {B}; % ok (more than enough is ok) 
% \tikz\node[\mystylelist] {B}; % fails
\tikz\node[expand style once=\mystylelist] {B}; % needs expansion
%
%\tikz\node[expand style once=\mystylemacroarg] {B};% fails 
\tikz\node[expand style twice=\mystylemacroarg] {B}; % needs more than once
%\tikz\node[expand style once=\mystylemacrolist] {B}; % fails
\tikz\node[expand style twice=\mystylemacrolist] {B};  % needs more than once
%
%\tikz\node[expand style twice={\mystylearg,\mystyleargelse}] {B}; % fails
\tikz\node[expand style={\mystylearg,\mystyleargelse}] {B}; % needs more than twice
%\tikz\node[expand style twice={\mystylearg,\mystylelist}] {B}; % fails
\tikz\node[expand style={\mystylearg,\mystylelist}] {B}; % needs more than twice 
%\tikz\node[expand style twice={\mystylelist,\mystylearg}] {B}; % fails, the same (commutes)
%\tikz\node[expand style={\mystylelist,\mystylearg}] {B}; % ok, the same (commutes)
%\tikz\node[expand style twice=\mystylemacromacroarg] {B}; % fails 
\tikz\node[expand style=\mystylemacromacroarg] {B}; % needs more than twice
%\tikz\node[expand style twice=\mystylemacromacrolist] {B}; % fails 
\tikz\node[expand style=\mystylemacromacrolist] {B}; % needs more than twice
\end{document}