Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to create a series of images that visualise a recursion tree as walked on by an algorithm. That means that different styles are applied to nodes depending on the step the algorithm is in, such as hiding, highlighting, etc. Consider this example:

example
[source]

As you can see, some styles are (not) applied "from image i on"; for instance, hidden nodes become unvisited (grayed out) and then normal, but never change back. Other styles are applied more flexibly, for example the yellowish highlighting active (which shows what node the visualised algorithm currently investigates). Above image was created by explicitly writing code for six images. Naturally, I want to avoid duplicating code as much as possible.

I thought that the following should be a straightforward way to achieve this:

\tikzset{<TikZ style definitions>}
\newcommand{\image}[1]{<TikZ image code>}
\begin{document}
  \foreach \n in {1,...,<N>}{%
    \image{\n}
  }
\end{document}

Now, \image has to choose styles depending on parameter #1 (i.e. \n); I am fine with hardcoding which style is applied on which image numbers.

But neither

\node \ifthenelse{<condition>}{[style=<name>]}{} {<label>};

nor

\node[\ifthenelse{<condition>}{style=<name>}{}] {<label>};

works. So I tried to use ifthenelse inside the (now parametric) style definition, which also failed, and then put

\tikzset{%
  test/.code={\ifthenelse{<condition>}{style=<name>}{}}
}

in the preamble, together with

\node[test=<param>] {<label>};

in the image; this does not work, either.

How can I choose TikZ styles conditionally?

A feasible workaround might be to create the nodes conditionally (i.e. duplicating node definitions for each case), but this is nasty for trees. Therefore, I would prefer a more surgical solution.

I use xifthen for conditions, in particular \isin. For example, I try assigning style active by checking

\ifthenelse{\isin{!#1!}{!1!2!4!6!}}{<set style active>}{<no style>}

in the case of root node a, where #1 is the parameter of \image. Ideally, I would be able to put such a statement at every affected node, that is the information which style is applied on which image is defined locally at the styled elements (for all images at once).

share|improve this question
1  
Using \node \ifnum#1=1 [style 1]\fi {<label>}; works fine. I think that you might get better answers if you made your question a little more concrete: What are the styles going to change, are they always going to be used in a loop, how many different options will you need? This can probably be solved more elegantly if the problem is described more concretely. –  Jake May 15 '12 at 17:06
    
@Jake I already said that I needed more complex conditions than number equality. I will include a small example tomorrow, though, if there is no answer till then. –  Raphael May 15 '12 at 18:09
    
I have been using the solution from Is there something like \providetikzstyle similar to \providecommand?, although it really should be \providetikzset based on Should \tikzset or \tikzstyle be used to define TikZ styles?. –  Peter Grill May 15 '12 at 18:42
    
For those interested, see here how it turned out. –  Raphael Jul 9 '12 at 20:55
add comment

3 Answers

up vote 9 down vote accepted

A really simple approach would probably be to use the image number directly to index the style:

\documentclass{article}

\usepackage{tikz}

\tikzset{
    image/.cd,
    1/.style={fill=orange},
    2/.style={fill=yellow},
    3/.style={fill=cyan}
}

\newcommand{\image}[1]{
    \tikz{ \draw [image/#1] circle [radius=1cm];}
}

\begin{document}
  \foreach \n in {1,...,3}{%
    \expandafter\image\expandafter{\n}
  }
\end{document}

However, as Jake pointed out, a more complex selection scheme is probably wanted by the OP, who in particular mentioned a "parametric style". The following uses Jake's example, but moves the testing from the macro to the style definition:

\documentclass{article}

\usepackage{tikz}
\usepackage{xifthen}

\tikzset{
    image/.cd,
    1/.style={fill=orange},
    2/.style={fill=yellow},
    3/.style={fill=cyan},
    test/.code={%
      \ifthenelse{\isin{#1}{ABC}}{\tikzset{image/1}}{
      \ifthenelse{\isin{#1}{DEF}}{\tikzset{image/2}}{
      \ifthenelse{\isin{#1}{GHI}}{\tikzset{image/3}}{
      }}}
    },
}

\newcommand{\image}[1]{
    \tikz{ \draw [image/test=#1] circle [radius=1cm];}
}

\begin{document}
  \foreach \n in {A,E,G}{%
    \expandafter\image\expandafter{\n}
  }
\end{document}

enter image description here

share|improve this answer
    
I don't think the OP is actually using numbers in their application, but strings and substrings. At least that's what I gather from their last sentence "I use xifthen for conditions, in particular \isin." and the somewhat testy "I already said that I needed more complex conditions than number equality.". –  Jake May 15 '12 at 19:59
    
@Jake: Hm... I now found the \isin part, but I must still be overlooking where they already said that more complex conditions are needed. I will wait for a more complete MWE that details these constraints. –  Daniel May 15 '12 at 20:11
    
Sorry, that last bit was in reply to my comment on their question. –  Jake May 15 '12 at 20:14
    
@Jake: No, that was fine. I had found the comment, but still do not know to what exactly the already in "as I already said" refers. Said where? Anyway, I have improved my solution that now resembles yours, but with the tests in the style definition. –  Daniel May 15 '12 at 20:35
    
Ah yes, now I understand. Nice answer! –  Jake May 15 '12 at 20:46
show 1 more comment

You could use a "variable" style in your drawing that is set to the desired value according to your condition before the drawing command:

\documentclass{article}

\usepackage{xifthen}
\usepackage{tikz}

\tikzset{
    current style/.style={},
    first/.style={fill=orange},
    second/.style={fill=yellow},
    third/.style={fill=cyan}
}

\newcommand{\image}[1]{
    \ifthenelse{\isin{#1}{ABC}}{\tikzset{current style/.style=first}}{
        \ifthenelse{\isin{#1}{DEF}}{\tikzset{current style/.style=second}}{
            \ifthenelse{\isin{#1}{GHI}}{\tikzset{current style/.style=third}}{}
        }
    }
    \tikz{ \draw [current style] circle [radius=1cm];}
}

\begin{document}
  \foreach \n in {A,E,G}{%
    \expandafter\image\expandafter{\n}
  }
\end{document}
share|improve this answer
    
Isn't /.is choice more comfortable? –  Marco Daniel May 15 '12 at 18:28
    
Well, that depends on what kind of "complex conditions" the OP needs. I don't think you can use the \isin string comparison method for .is choice, right? –  Jake May 15 '12 at 18:33
    
I don't know. I didn't test it. You are the expert of tikz ;-) –  Marco Daniel May 15 '12 at 18:54
add comment

A style may define other styles... So, no test ! ;-)

\documentclass{standalone}

\usepackage{tikz}

\tikzset{
   set styles 1/.style={
     circle style/.style={fill=red},
     square style/.style={fill=orange},
   },
   set styles 2/.style={
     circle style/.style={fill=cyan},
     square style/.style={fill=violet,fill opacity=.5},
   },
   set styles A/.style={
     circle style/.style={draw},
     square style/.style={fill=violet,fill opacity=.5},
   },
}
\newcommand\image[1]{
  \begin{scope}[set styles #1]
    \path[circle style] circle [radius=.6cm];
    \path[square style] (-.5,-.5) rectangle (.5,.5);
  \end{scope}
}

\begin{document}

\foreach \n in {1,2,A}{%
  \begin{tikzpicture}
    \image{\n}
  \end{tikzpicture}
}

\end{document}

enter image description here

Here, your example with this approach:

\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage[paperwidth=4cm,paperheight=3.25cm,margin=.10cm]{geometry}
\usetikzlibrary{positioning}

\begin{document}

\tikzset{%
  active/.style={fill=yellow!30},
  unvisited/.style={opacity=.2},
  hidden/.style={opacity=0},
  lb/.style={color=green!70!black},
  ub/.style={color=red!70!black},
  ind exp/.style={scale=.7},
  step 1/.style={
    a/.style={active},
    b/.style={},
    c/.style={},
    a b/.style={hidden},
    a c/.style={hidden},
    a ind/.style={lb},
    a exp/.style={hidden},
    b ind/.style={hidden},
    b exp/.style={hidden},
    c ind/.style={hidden},
    c exp/.style={hidden},
  },
  step 2/.style={
    step 1,
    a b/.style={unvisited},
    a c/.style={unvisited},
    b ind/.style={lb},
    c ind/.style={lb},
  },
  step 3/.style={
    step 2,
    a/.style={},
    b/.style={active},
    a b/.style={},
    b exp/.style={ub},
  },
  step 4/.style={
    step 3,
    a/.style={active},
    b/.style={},
    a exp/.style={ub},
  },
  step 5/.style={
    step 4,
    a/.style={},
    c/.style={active},
    a c/.style={},
    c exp/.style={ub},
  },
  step 6/.style={
    step 5,
    a/.style={active},
    c/.style={},
  },
}

\newcommand\mypict[2]{
  \begin{tikzpicture}[level 1/.style={sibling distance=10mm}]
    \begin{scope}[step #1]    
      \node [a] (a) {$[a]$}
      child [a b] { node[b] (b) {$[b]$} }
      child [a c] { node[c] (c) {$[c]$} };

      \node[a ind,ind exp,below right=-3.5mm and -2mm of a] {$5$};
      \node[a exp,ind exp,above right=-3.5mm and -2mm of a] {$#2$};

      \node[b ind,ind exp,below right=-3.5mm and -2mm of b] {$6$};
      \node[b exp,ind exp,above right=-3.5mm and -2mm of b] {$7$};

      \node[c ind,ind exp,below right=-3.5mm and -2mm of c] {$5$};
      \node[c exp,ind exp,above right=-3.5mm and -2mm of c] {$5$};

      \node[right=1cm of a,scale=.7] {$p#1$};
    \end{scope}
  \end{tikzpicture}
}

\foreach \n/\aexp in {1/5,2/5,3/5,4/7,5/7,6/5}{
  \mypict{\n}{\aexp}
  \clearpage
}

\end{document}

enter image description here

share|improve this answer
    
This is very nice, but I don't think it addresses the OPs requirement of checking for the presence of a substring in a larger string (as indicated by the hint that "I use xifthen for conditions, in particular \isin"). Though they never disclosed why they need those kinds of conditionals, so maybe this solution is exactly what they're looking for... –  Jake May 15 '12 at 21:22
    
You're probably right (I missed his first comment). Perhaps he will say more tomorrow. –  Paul Gaborit May 15 '12 at 22:15
    
@Jake: Maybe you skipped my first paragraph. I agree it might not be clear what precisely my needs are, but "the never disclosed why" is clearly not true. Anyway, I'll edit later. –  Raphael May 16 '12 at 8:52
    
I added an example. As it is, your solution would require me to define the same styles multiple times; is this the most efficient way to do things? –  Raphael May 17 '12 at 13:09
    
@Raphael I added your example to my solution. I'm not sure this is the most efficient way but it works and the factorization is good. –  Paul Gaborit May 18 '12 at 8:34
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.