5

I'm starting to believe that tikz just wasn't meant for me...

how was I able to get this wrong:

\documentclass[a4paper,10pt]{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{shapes,arrows,positioning,calc,trees,mindmap,backgrounds,shadows}

\begin{document}

\begin{tikzpicture}
\path[mindmap,concept,concept color=red] (0,0) node (languages) {Languages} [clockwise from=90]
    child { node {Markdown} }
    child[ sibling angle=110, level distance=8cm] { node {R}  [clockwise from=130]
        child[ level distance = 4cm] { node {control structures (if, for, \mbox{while, repeat,} \mbox{next, break)}} }
        child[ sibling angle = 90, level distance=6cm] { node {data types} [clockwise from=110] 
            child { node {vectors} }
            child { node {lists} }
            child { node {matrices} }
            child { node {data frames} }
            child { node {factors} }
            child { node {dates} }
            child { node {time} }
            child { node {data.table} }
            child { node {missing values} }
        }
        child[ sibling angle = 20] { node {functions} }
    }
    child[sibling angle=130] { node {RMarkdown} }
;
\end{tikzpicture}

\end{document}

How come "functions" is not 20 degrees from "data types"? How does sibling angle work? (reading the manual was not helping)

What does not work

Does not work 1

Mark Wibrow's answer is great... or would be if working for me. Before getting into details of his functions, I should share an even more basic example that does not work for me:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{trees,mindmap}

\begin{document}
\begin{tikzpicture}[mindmap, concept color=blue!20, every child node/.style={concept}]

\node[concept] (languages) {O} [clockwise from=90, sibling angle=90]
  child { node {A} }
  child { node {B} }
  child { node {C}
   child { node {C1} }
   child { node {C1} }
   child { node {C1} }
  }
  child { node {D} };

\end{tikzpicture}
\end{document}

enter image description here

Does not work 2 - Strange result changes

Having small mindmap instead of mindmap looks suspiciously like Mark Wibrow's result (though this may be by chance):

enter image description here

Does not work 3 - Mark Wibrow's code

Using Mark Wibrow's last code brings the results shown by him, but if I change his [clockwise from=0, sibling angle=45] to [clockwise from=0, sibling angle=10] the result does not change for the C1-nodes.

What would be best

After playing around a lot I think what would be best, would be something like Mark Wibrow's angle list, but with not with absolute values, but that the list contains the angles from each node to the previous node. For example instead of (for seven nodes) [grow cyclic list={120,70,40,5,-30,-80,-100}] to have [grow cyclic list={120,-50,-30,-35,-35,-50,-20}].

  • @Paul Gaborit: If that is the case, why is the node "R" 110° from "Markdown" and why would "functions" be affected by sibling angle in the first place? – Make42 Dec 3 '15 at 0:07
  • 1
    Growth directions for this library have to be one of, if not the, most counterintuitive makers of chaos in the entire TikZ ecosystem. If it means TikZ ain't for you, it ain't for me either. – cfr Dec 3 '15 at 4:32
  • @cfr: Thanks for the encouragement. Have you beaten the beast by any chance? (= understood it, and can explain it?) – Make42 Dec 3 '15 at 9:11
  • @user49283 You are right : my first (now deleted) comment was wrong. Mark Wibrow's answer is perfect. – Paul Gaborit Dec 3 '15 at 10:03
  • 1
    No. I learnt to avoid the clockwise from key, I think. But Mark Wibrow has a much better solution (and an explanation). – cfr Dec 3 '15 at 14:03
9

It isn't amazingly clear from the manual (if at all), but when using the clockwise from key the angle B for the child node is basically:

B = A - (n-1)*s

where A is the start angle, n is the number of the current child, and s is the current value of the sibling angle (which could be set globally, locally or in a level, or every child style). So if the start angle is A=130 and the sibling angle is set to s=20 in the child options for the third child (n=3) then the angle for the node is B=130-(3-1)*20=90, which I think is what you get.

Therefore, if you use the clockwise from key and you want the nth child node to appear at a specific angle B then the sibling angle s should be set to:

s = (A - B) / (n-1)

Confusing? Well, maybe. But what might be of more use in this case is a grow cyclic absolute key in which the sibling angle given in the child options gives the absolute angle of the child. The sibling angle must be given for every child node (otherwise it will be whatever the sibling angle is set at in the current scope), but other growth functions can still be installed for (great, ...) grand children.

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{trees,mindmap}
\tikzset{grow cyclic absolute/.style={%
  growth function=\tikzgrowcyclicabsolute}}
\def\tikzgrowcyclicabsolute{%
  \pgftransformshift{%
   \pgfpointpolar{\pgfkeysvalueof{/tikz/sibling angle}}%
    {\the\tikzleveldistance}}}
\begin{document}
\begin{tikzpicture}[small mindmap, concept color=blue!20,  
  every child node/.style={concept}]
\node [concept] (languages) 
  {O} [grow cyclic absolute] 
    child [sibling angle=90]  { node {A} }
    child [sibling angle=0]   { node {B} }
    child [sibling angle=-45] { node {C} 
      [clockwise from=0, sibling angle=45]
      child { node {C1} }
      child { node {C1} }
      child { node {C1} }
    }
    child [sibling angle=210] { node {D} };
\end{tikzpicture}
\end{document}

enter image description here

To avoid the annoyance of cluttering up the child code with endless sibling angles, an alternative grow cyclic list growth function could be used to specify the growth angles when the growth function set:

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{trees,mindmap}
\tikzset{grow cyclic list/.code={%
  \def\tikzgrowthpositions{{#1}}%
  \foreach \n [count=\i,remember=\i]in {#1}{}%
  \let\tikzgrowthpositionscount=\i%
  \tikzset{growth function=\tikzgrowcycliclist}}}
\def\tikzgrowcycliclist{%
  \pgftransformshift{%
    \pgfpointpolar{\tikzgrowthpositions[mod(\the\tikznumberofcurrentchild-1,\tikzgrowthpositionscount)]}%
      {\the\tikzleveldistance}}}
\begin{document}
\begin{tikzpicture}[small mindmap, concept color=blue!20,  
  every child node/.style={concept}]
\node [concept] (languages) 
  {O} [grow cyclic list={90,0,-45,210}] 
    child { node {A} }
    child { node {B} }
    child { node {C} 
      [clockwise from=0, sibling angle=45]
      child { node {C1} }
      child { node {C1} }
      child { node {C1} }
    }
    child { node {D} };
\end{tikzpicture}
\end{document}

The result is the same as before.

The advantage of being specifying the angle absolutely, is that any angles can be pre-processed into absolute angles. The following demonstrates an example of this, where given a starting angle, the angles between siblings can be specified in a list. This list is pre-processed into absolute angles.

\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{trees,mindmap}
\makeatletter
\tikzset{%
grow clockwise/.code args={first at #1 then turning #2}{%
  \pgfmathparse{#1}%
  \let\tikzgrowthpositions=\pgfmathresult%
  \let\tikz@tmpangle=\pgfmathresult%
  \c@pgf@counta=1\relax%
  \pgfutil@for\tikz@tmp:=#2\do{%
    \advance\c@pgf@counta by1\relax%
    \pgfmathparse{Mod(\tikz@tmpangle-\tikz@tmp, 360)}%
    \let\tikz@tmpangle=\pgfmathresult%
    \edef\tikzgrowthpositions{\tikzgrowthpositions,\tikz@tmpangle}%
  }%
  \edef\tikzgrowthpositions{{\tikzgrowthpositions}}%
  \edef\tikzgrowthpositionscount{\the\c@pgf@counta}%
  \tikzset{growth function=\tikzgrowcycliclist}%
}}
\def\tikzgrowcycliclist{%
  \pgftransformshift{%
    \pgfpointpolar{\tikzgrowthpositions[mod(\the\tikznumberofcurrentchild-1,\tikzgrowthpositionscount)]}%
      {\the\tikzleveldistance}}}
\begin{document}
\begin{tikzpicture}[small mindmap, concept color=blue!20,  
  every child node/.style={concept}]
\node [concept] (languages) 
  {O} [grow clockwise={first at 90 then turning 90,45,105}] 
    child { node {A} }
    child { node {B} }
    child { node {C} 
      [clockwise from=0,  level 2/.append style={sibling angle=60}]
      child { node {C1} }
      child { node {C1} }
      child { node {C1} }
    }
    child { node {D} };
\end{tikzpicture}
\end{document}

The result is the same as before.

  • I reached the same conclusion after a few tries... but after you ;-). +1 for the explanations and for the 'grow cyclic absolute' key. – Paul Gaborit Dec 3 '15 at 10:02
  • 3
    @PaulGaborit I couldn't work it out from the manual or from trying out examples. I had to look at the code in tikzlibrarytrees.code.tex. So its unsurprising people have trouble with it. – Mark Wibrow Dec 3 '15 at 10:08
  • Very useful, indeed! – cfr Dec 3 '15 at 14:05
  • @MarkWibrow: Thanks for the great grow cyclic list. Your example does not work completely however: If I change sibling angle=45 to e.g. =60 nothing changes for the node {C1}. I have to put sibling angle=60 into every child[] of each node {C1}. It's not an issue of your grow cyclic list - I checked. What should I do? – Make42 Dec 7 '15 at 10:02
  • The small mindmap key defines a series of styles including a level 2 concept style (i.e., a style for concepts at level 2) which sets the sibling angle to 60.The sibling angle specification before the child nodes is overidden by this setting. So instead try level 2 concept/.append style={sibling angle=45}. See section 58.2 "The Mindmap Style" in the last pgf manual. – Mark Wibrow Dec 7 '15 at 12:43

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.