6

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}].

Make42
  • 1,772
  • @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 03 '15 at 00: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 03 '15 at 04:32
  • @cfr: Thanks for the encouragement. Have you beaten the beast by any chance? (= understood it, and can explain it?) – Make42 Dec 03 '15 at 09:11
  • @user49283 You are right : my first (now deleted) comment was wrong. Mark Wibrow's answer is perfect. – Paul Gaborit Dec 03 '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 03 '15 at 14:03
  • @user49283 specifying the sibling angle before the child nodes doesn't work in this case because the small mindmap style installs a level 2 concept style which overrides the sibling angle. – Mark Wibrow Dec 07 '15 at 13:04
  • @MarkWibrow : That explains the effect in "Does not work 2", but does not explain the issue in "Does not work 1" and "Does not work 3". Also: Do you know how to "What would be best"? – Make42 Dec 07 '15 at 13:44
  • @user49283 I think it explains all three. The mindmap, small mindmap and large mindmap all install different variants of the level concept styles from level 1 concept to level 4 concept, with different fonts, sibling angles and level distances. The manual explains how to changes these. My updated answer below provides a new growth key which enables the specification of relative angles between siblings. – Mark Wibrow Dec 07 '15 at 14:51
  • @MarkWibrow : You wrote that sibling angle gets overridden from small mindmap. From your last answer I take it that it also gets overridden from mindmap - so what is it good for if it gets overridden all the time? How do I use it without getting overridden? – Make42 Dec 07 '15 at 15:48
  • @user49283 I guess you have to define your own level concept styles or your own mindmap styles. You could take a look at the file tikzlibrarymindmap.code.tex in the PGF distribution. All the style settings are at the end of the file (although it uses the old-fashioned \tikzstyle command rather than \tikzset). The small, large and huge mindmap styles all inherit from the mindmap style. – Mark Wibrow Dec 07 '15 at 18:02
  • @MarkWibrow: That is what I've done in http://tex.stackexchange.com/questions/281947/tikz-fill-concepts-in-mindmaps-nicely/282037. However your solution of using level 2 concept/.append style={sibling angle=45} does the job afterrall. It would be pretty neat though to have a style that does this in one go, sort of this sibling=45. Do you know how to do this? – Make42 Dec 08 '15 at 13:25

1 Answers1

10

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.

Mark Wibrow
  • 70,437
  • 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 03 '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 03 '15 at 10:08
  • Very useful, indeed! – cfr Dec 03 '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 07 '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 07 '15 at 12:43
  • @MarkWibrow: Very nice! And if I don't want just one angle for all sibling I can use [clockwise from=0, level 2/.append style={sibling angle=60}] as shown in your example. +1 – Make42 Dec 08 '15 at 13:20
  • As for the second example for grow cyclic list, it should propably be \foreach \n [count=\i]in {#1}{\global\let\tikzgrowthpositionscount=\i} since remember does not make the variable accessible outside the for loop. – Jasper Habicht Jul 20 '22 at 08:34
  • 1
    See https://tex.stackexchange.com/q/651446/4427 for fixes to the present code – egreg Jul 20 '22 at 08:35