3

I'm working with trees of different depth, created with forest package, and I'd like to automatically colour their background with different shades of gray, starting from the same shade down to white, for example:

Tree-level tree
level 0: black!60 % darkest gray
level 1: black!30
level 2: black!0 % white

Four-level tree
level 0: black!60 % darkest gray
level 1: black!40
level 2: black!20
level 3: black!0 % white

Is there any way to get the maximum level of the tree and automatize the filling using the formula below?
darkest = 60 % parameter
level n: black!((maxlevel-level)*darkest/maxlevel)

My working code so far (with maxlevel manually set to 2, and darkest gray set to 40):

\documentclass{book}
\usepackage[edges]{forest}
\forestset{
  AlignOddChildren/.style = {
    for tree={
      if={isodd(n_children())}{
        calign primary child/.pgfmath={(n_children()+1)/2},
        calign=child edge
      }{}
    }
  },
}
\begin{document}
\begin{forest}
  for tree = {draw, rectangle, thick, align=center},
    forked edges,
    for tree = {fill/.wrap pgfmath arg={black!#1}{40*(2-level())/2}},
    AlignOddChildren
    [ Maintenance
      [ Corrective\\Maintenance\\(CM)
        [ Run to failure\\(RTF) ]
      ]
      [ Preventive\\Maintenance\\(PvM)
        [ Experience-based\\Maintenance\\(EBM) ]
        [ Time-based\\Maintenance\\(TBM) ]
      ]
      [ Predictive\\Maintenance\\(PdM)
        [ Condition-based\\Maintenance\\(CBM) ]
      ]
    ]
\end{forest}    
\end{document}

I found somewhere this code for getting the maximum level, but I don't know how to use it (replacing maxlevel() in the expression does not work):

maxlevel/.max={level}{tree}

Thank you!

  • 3
    Welcome to TeX.se. Instead of just listing your requirements, and expecting someone to do it for you, perhaps you could post (in the form of a compilable minimal document) some code to show what you've tried. – Alan Munn Mar 08 '18 at 18:36
  • Hi, thank you for your reply. Actually I don't need someone to do the whole work for me, I just need to know how to get the "maxlevel" parameter before trying to write any code (the way that parameter is obtained may affect the way I'm going to write the code) – Taekwondavide Mar 08 '18 at 18:43
  • 1
  • 2
    Maximum of an expression over a(ny) set of nodes can be computed by using aggregate function max, section of 3.14 of the docs. The level of a node is stored in level. – Sašo Živanović Mar 08 '18 at 21:19
  • prooftrees.tex has at least one example of this kind (maybe two), so you could look at how I do it there. But @SašoŽivanović really covered the approach already. – cfr Mar 09 '18 at 23:57
  • 1
    My answer at https://tex.stackexchange.com/questions/327014/tikz-forest-how-to-format-stylize-a-node-based-on-its-level/327100#327100 may be helpful for the shading, though it uses a hard-coded maximum, rather than max. – cfr Mar 10 '18 at 00:09
  • Thanks everyone. I managed to understand the use of "args", thanks to the "How to uniquely color parent/children/grandchildren branch nodes?" example, but I'm still having problems in understanding how to use aggregate functions to get the maximum level (it's quite different from any language I know) – Taekwondavide Mar 10 '18 at 16:45
  • @cfr ok, I updated my post with the whole code – Taekwondavide Mar 11 '18 at 15:30

1 Answers1

6

You can use .max to get the maximum level of the tree and store this in a temporary register. This can then be used in an expression to specify the fill.

For example,

\documentclass[border=10pt]{standalone}
\usepackage[edges]{forest}
\forestset{
  AlignOddChildren/.style = {
    for tree={
      if={isodd(n_children())}{
        calign primary child/.process={Ow+n {n children}{(##1+1)/2}},
        calign=child edge
      }{}
    }
  },
  gradual fill/.style={
    before typesetting nodes={
      tempcounta/.max={level}{r,tree},
      for tree={
        fill/.process={
          ROw2+nw {tempcounta} {level} { (100*##2)/##1 } {white!##1!black!60}
        },
      },
    },
  },
}
\begin{document}
\begin{forest}
  for tree = {draw, rectangle, thick, align=center},
  forked edges,
  gradual fill,
  AlignOddChildren,
    [ Maintenance
      [ Corrective\\Maintenance\\(CM)
        [ Run to failure\\(RTF) ]
      ]
      [ Preventive\\Maintenance\\(PvM)
        [ Experience-based\\Maintenance\\(EBM) ]
        [ Time-based\\Maintenance\\(TBM) ]
      ]
      [ Predictive\\Maintenance\\(PdM)
        [ Condition-based\\Maintenance\\(CBM) ]
      ]
    ]
\end{forest}    
\begin{forest}
  for tree = {draw, rectangle, thick, align=center},
  forked edges,
  gradual fill,
  AlignOddChildren,
    [ Maintenance
      [ Corrective\\Maintenance\\(CM)
        [ Run to failure\\(RTF) ]
        [ Preventive\\Maintenance\\(PvM)
          [ Experience-based\\Maintenance\\(EBM) ]
          [ Time-based\\Maintenance\\(TBM) ]
          [ Predictive\\Maintenance\\(PdM)
            [ Condition-based\\Maintenance\\(CBM) ]
          ]
        ]
      ]
    ]
\end{forest}    
\end{document}

graduated shading by level and tree depth

cfr
  • 198,882