10

This MWE code is adapted from this example on www.texample.net and was originally written by SE user cfr:

\documentclass{article}

\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, shapes.geometric, calc, shadows}
\usepackage{forest}
\usepackage{adjustbox}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{col6in}{blue!20}
\colorlet{col6out}{blue!30}
\colorlet{col7out}{orange}
\colorlet{col7in}{orange!50}
\colorlet{col8out}{orange!40}
\colorlet{col8in}{orange!20}
\colorlet{linecol}{blue!60}

\begin{document}

\tikzset{
  basic/.style  = {draw, drop shadow, rectangle},
  root/.style   = {basic, rounded corners=2pt, thin, align=center,
                   fill=green!30},
  level 2/.style = {basic, rounded corners=6pt, thin,align=center, fill=blue!10},
  level 3/.style = {basic, thin, align=left, fill=green!10}
}

\pgfkeys{/forest,
  rect/.append style   = {rectangle, rounded corners = 2pt,
                         inner color = col6in, outer color = col6out},
  ellip/.append style  = {ellipse, inner color = col5in,
                          outer color = col5out},
  orect/.append style  = {rect, font = \sffamily\bfseries\LARGE,
                         text width = 325pt, text centered,
                         minimum height = 10pt, outer color = col7out,
                         inner color=col7in},
  oellip/.append style = {ellip, inner color = col8in, outer color = col8out,
                          font = \sffamily\bfseries\large, text centered}}

\begin{figure}[h]
\begin{adjustbox}{max width=1.2\textwidth,center}    
    \begin{forest}
      for tree={
          font=\sffamily\bfseries,
          line width=1pt,
          draw=linecol,
          ellip,
          align=center,
          child anchor=north,
          parent anchor=south,
          drop shadow,
          l sep+=12.5pt,
          edge path={
            \noexpand\path[color=linecol, rounded corners=5pt,
              >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
              (!u.parent anchor) -- +(0,-5pt) -|
              (.child anchor)\forestoption{edge label};
            },
          where level={3}{tier=tier3}{},
          where level={0}{l sep-=15pt}{},
          where level={1}{
            if n={1}{
              edge path={
                \noexpand\path[color=linecol, rounded corners=5pt,
                  >={Stealth[length=10pt]}, line width=1pt, ->,
                  \forestoption{edge}]
                  (!u.west) -| (.child anchor)\forestoption{edge label};
                },
            }{
              edge path={
                \noexpand\path[color=linecol, rounded corners=5pt,
                  >={Stealth[length=10pt]}, line width=1pt, ->,
                  \forestoption{edge}]
                  (!u.east) -| (.child anchor)\forestoption{edge label};
                },
            }
          }{},
      }
      [\Huge Total drag, yshift = 3cm, inner color=col1in, outer color=col1out
        [\huge Viscous drag, yshift = 1cm, inner color=col2in, outer color=col2out
          [\Large Displacement separation, inner color=col4in, outer color=col4out
          ]
          [\Large Boundary layer shear, inner color=col4in, outer color=col4out 
          ]
        ]
        [\huge Vortex drag, yshift = 1cm, inner color=col3in, outer color=col3out
          [\Large Trailing vortices due to lift
          ]
        ]
        [\huge Wave drag, yshift = 1cm, inner color=col3in, outer color=col3out
              [\Large Waves due to lift
              ]
              [\Large Waves due to volume
              ]
        ]  
        ]
       ]
    \end{forest}
    \end{adjustbox}
    \end{figure}
    \end{document}

produces this:

enter image description here

How can I add a large horizontal curly brace do add a comment to all the bottom nodes, to get something like this:

enter image description here

5
  • Could you please provide a full, compilable MWE with the relevant preamble? Sep 11 '15 at 11:28
  • Hi there, sorry. Updated.
    – Jonny
    Sep 11 '15 at 11:30
  • Your code didn't quite compile as expected but I believe my answer should answer at least the brace adding part. Sep 11 '15 at 11:33
  • What was the problem with compiling? I did test the code and it runs as is. Perhaps it is the elocalloc.sty package that is missing? i easily got that from CTAN.
    – Jonny
    Sep 11 '15 at 11:38
  • It was just a page size problem. It looks the same once that is changed. Sep 11 '15 at 11:41
6

Heiko Oberdiek's answer is a good way to do this, but another is to specify the addition as part of the specification of the tree itself. In this case, you can use relative node names to handle the positioning.

Note that the backgrounds library is not required to solve the issue of the edge path drawing over the root node. The problem is just a result of not specifying that the 2 non-standard paths in the first level should apply to only the first and last nodes - not the middle one as well. Checking whether the node is first or last fixes the issue, and the middle node is then aligned with the parent using calign with current so nothing strange happens to the paths at all.

Your code contains a great deal of unnecessary baggage. While orect may have been a perfectly useful style when first created, it really is not of much use to you here. Excess baggage is also responsible for methods such as first reducing the separation between levels and then manually shifting each node within each level to increase it. This makes it more likely things will not work as you expect and more difficult to figure out why, as well as making more work for you.

I've removed a good deal of the excess baggage. Obviously, your original diagram may require some of this be added back, but I seriously doubt that it requires all of it and it cannot possibly require doing X and then undoing X a few lines later.

Anyway, for what it is worth, here's my version:

brace as part of tree using relative node names

The brace itself is a decoration as in Heiko's answer, but the decoration is specified along with the tree's root node, using the tikz key:

tikz={\draw [decorate, line width=2.5pt, decoration={brace, mirror, amplitude=10mm}] (!F.south -| !F.west) +(0,-5mm) coordinate (a) -- (a -| !L.east) node [midway, below=15mm, Large] {bla bla bla} ;}

!F refers to the first leaf node relative to the current (root) node; !L refers to the last leaf node. Because ellipses have their south-western and south-eastern points on their boundary, the south, west and east anchors of these nodes are used for placement.

Large is a style defined for convenience, equivalent to font=\sffamily\bfseries\Large.

By packing most of the formatting into styles, the structure of the tree is somewhat more obvious from the code specifying it. (We could put the tikz specification for the brace in the tree's preamble, too, but I didn't bother here.)

\documentclass[tikz,border=10pt]{standalone}

\usetikzlibrary{arrows.meta, decorations.pathreplacing, shadows}
\usepackage{forest}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{linecol}{blue!60}

\begin{document}

\tikzset{
  ellip/.append style  = {ellipse, col in out = 5},
  col in out/.style = {inner color = col#1in, outer color = col#1out},
  font sizing/.style={font=\sffamily\bfseries#1},
  Huge/.style={font sizing=\Huge},
  huge/.style={font sizing=\huge},
  Large/.style={font sizing=\Large},
}

\begin{forest}
  for tree={
      font=\sffamily\bfseries,
      line width=1pt,
      draw=linecol,
      ellip,
      align=center,
      child anchor=north,
      parent anchor=south,
      drop shadow,
      l sep+=10mm,
      edge={color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->},
      edge path={% this is the default code for the edge from parent to child
        \noexpand\path[\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
        },
      if level=1{
        huge,
        if n=1{
          col in out=2,
          for children={col in out=4},
          edge path={% this overrides the path from parent to child for this particular case i.e. level is 1 and child is first (n=1)
            \noexpand\path[\forestoption{edge}] (!u.west) -| (.child anchor)\forestoption{edge label};
            },
        }{
          col in out=3,
          if n'=1{
            edge path={% this overrides the path from parent to child for this particular case i.e. level is 1 and child is last (n'=1)
              \noexpand\path[\forestoption{edge}] (!u.east) -| (.child anchor)\forestoption{edge label};
            },
          }{% if the child is neither the first one nor the last one, it must be the middle one, so align the parent with this one to avoid kinks in the edge path in this case
            calign with current
          }
        }
      }{},
      if level=2{Large}{}
  }
  [Total drag, Huge, col in out=1, tikz={\draw [decorate, line width=2.5pt, decoration={brace, mirror, amplitude=10mm}] (!F.south -| !F.west) +(0,-5mm) coordinate (a) -- (a -| !L.east) node [midway, below=15mm, Large] {bla bla bla} ;}
    [Viscous drag
      [Displacement separation
      ]
      [Boundary layer shear
      ]
    ]
    [Vortex drag
      [Trailing vortices due to lift
      ]
    ]
    [Wave drag
          [Waves due to lift
          ]
          [Waves due to volume
          ]
    ]
   ]
\end{forest}
\end{document}

EDIT

In response to the request in comments for braces under each of the terminal nodes, we can define a style under label which takes one argument, which is the text to be printed underneath the brace:

many braces

Complete code:

\documentclass[tikz,border=10pt]{standalone}

\usetikzlibrary{arrows.meta, decorations.pathreplacing, shadows}
\usepackage{forest}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{linecol}{blue!60}

\begin{document}

\tikzset{
  ellip/.append style  = {ellipse, col in out = 5},
  col in out/.style = {inner color = col#1in, outer color = col#1out},
  font sizing/.style={font=\sffamily\bfseries#1},
  Huge/.style={font sizing=\Huge},
  huge/.style={font sizing=\huge},
  Large/.style={font sizing=\Large},
}
\forestset{
  under label/.style = {
    tikz={\draw [decorate, line width=2.5pt, decoration={brace, mirror, amplitude=10mm}] (.south -| .west) +(0,-2.5mm) coordinate (a) -- (a -| .east) node [midway, below=12.5mm, Large] {#1} ;}
  }
}

\begin{forest}
  for tree={
      font=\sffamily\bfseries,
      line width=1pt,
      draw=linecol,
      ellip,
      align=center,
      child anchor=north,
      parent anchor=south,
      drop shadow,
      l sep+=10mm,
      edge={color=linecol, rounded corners=5pt, >={Stealth[length=10pt]}, line width=1pt, ->},
      edge path={% this is the default code for the edge from parent to child
        \noexpand\path[\forestoption{edge}] (!u.parent anchor) -- +(0,-5pt) -| (.child anchor)\forestoption{edge label};
        },
      if level=1{
        huge,
        if n=1{
          col in out=2,
          for children={col in out=4},
          edge path={% this overrides the path from parent to child for this particular case i.e. level is 1 and child is first (n=1)
            \noexpand\path[\forestoption{edge}] (!u.west) -| (.child anchor)\forestoption{edge label};
            },
        }{
          col in out=3,
          if n'=1{
            edge path={% this overrides the path from parent to child for this particular case i.e. level is 1 and child is last (n'=1)
              \noexpand\path[\forestoption{edge}] (!u.east) -| (.child anchor)\forestoption{edge label};
            },
          }{% if the child is neither the first one nor the last one, it must be the middle one, so align the parent with this one to avoid kinks in the edge path in this case
            calign with current
          }
        }
      }{},
      if level=2{Large}{}
  }
  [Total drag, Huge, col in out=1
    [Viscous drag
      [Displacement separation, under label={The why}
      ]
      [Boundary layer shear, under label={The what}
      ]
    ]
    [Vortex drag
      [Trailing vortices due to lift, under label={The how}
      ]
    ]
    [Wave drag
      [Waves due to lift, under label={Sufficient explanation}
      ]
      [Waves due to volume, under label={Necessary information}
      ]
    ]
   ]
\end{forest}
\end{document}
16
  • 1
    Please, don't be sorry! I hope it wasn't me who introduced the style. This phenomenon you mention about some people adding and adding to the code without pruning it's really common around here. I've seen cases in which there are three redefinitions of a command in the preamble but just one (the last one) is effectively used. Sep 11 '15 at 22:38
  • 1
    @Jonny I appreciate that. It's OK. People don't think about it sometimes even when their code is identical. And, actually, your effective code was much less like the original than I thought when I wrote that because you weren't actually using lots of it ;).
    – cfr
    Sep 12 '15 at 11:12
  • 1
    @Jonny Just realised that I forgot to edit my answer to remove my grumbling, so I've done that and added a couple of comments in the code while I was there. Hope this is helpful ;).
    – cfr
    Sep 13 '15 at 20:32
  • 1
    @Jonny The col in out is used to reference them. It provides a kind of template where #1 is a slot in the template which gets filled in by whatever number is specified when the style is used. Once the number is slotted in, the filled out template references the relevant colours. Does that help?
    – cfr
    Sep 14 '15 at 14:51
  • 1
    @Jonny Please see edit.
    – cfr
    Sep 17 '15 at 11:30
7

Additional TikZ material can be put before \end{forest}:

 \usetikzlibrary{decorations, decorations.pathmorphing} % in the preamble

  % inside environment forest
  \draw[thick, decorate, decoration={brace, amplitude=1.5em}]
      ([yshift=-.5em]current bounding box.south east) --
      node[below=2em, font=\sffamily\bfseries\Large]
        {Bla bla bla}
      ([yshift=-.5em]current bounding box.south west)
   ;
\end{forest}

The brace is drawn as decoration brace. Since the brace covers the full width at the bottom of the image, the current bounding box can be used to span the whole width.

The issue with the line above the root node is fixed by putting the line on the background layer with library backgrounds:

  edge path={
    \noexpand\scoped[on background layer]
    \noexpand\path[color=linecol, rounded corners=5pt,
      >={Stealth[length=10pt]}, line width=1pt, ->,
      \forestoption{edge}, on background layer]
      (!u.east) -| (.child anchor)\forestoption{edge label};
    },

Full example:

\documentclass{article}

\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{arrows.meta, shapes.geometric, calc, shadows}
\usetikzlibrary{decorations, decorations.pathreplacing}
\usetikzlibrary{backgrounds}
\usepackage{forest}
\usepackage{adjustbox}

\colorlet{mygreen}{green!75!black}
\colorlet{col1in}{red!30}
\colorlet{col1out}{red!40}
\colorlet{col2in}{mygreen!40}
\colorlet{col2out}{mygreen!50}
\colorlet{col3in}{blue!30}
\colorlet{col3out}{blue!40}
\colorlet{col4in}{mygreen!20}
\colorlet{col4out}{mygreen!30}
\colorlet{col5in}{blue!10}
\colorlet{col5out}{blue!20}
\colorlet{col6in}{blue!20}
\colorlet{col6out}{blue!30}
\colorlet{col7out}{orange}
\colorlet{col7in}{orange!50}
\colorlet{col8out}{orange!40}
\colorlet{col8in}{orange!20}
\colorlet{linecol}{blue!60}

\begin{document}

\tikzset{
  basic/.style  = {draw, drop shadow, rectangle},
  root/.style   = {basic, rounded corners=2pt, thin, align=center,
                   fill=green!30},
  level 2/.style = {basic, rounded corners=6pt, thin,align=center, fill=blue!10},
  level 3/.style = {basic, thin, align=left, fill=green!10}
}

\pgfkeys{/forest,
  rect/.append style   = {rectangle, rounded corners = 2pt,
                         inner color = col6in, outer color = col6out},
  ellip/.append style  = {ellipse, inner color = col5in,
                          outer color = col5out},
  orect/.append style  = {rect, font = \sffamily\bfseries\LARGE,
                         text width = 325pt, text centered,
                         minimum height = 10pt, outer color = col7out,
                         inner color=col7in},
  oellip/.append style = {ellip, inner color = col8in, outer color = col8out,
                          font = \sffamily\bfseries\large, text centered}}

\begin{figure}[h]
\begin{adjustbox}{max width=1.2\textwidth,center}    
    \begin{forest}
      for tree={
          font=\sffamily\bfseries,
          line width=1pt,
          draw=linecol,
          ellip,
          align=center,
          child anchor=north,
          parent anchor=south,
          drop shadow,
          l sep+=12.5pt,
          edge path={
            \noexpand\path[color=linecol, rounded corners=5pt,
              >={Stealth[length=10pt]}, line width=1pt, ->, \forestoption{edge}]
              (!u.parent anchor) -- +(0,-5pt) -|
              (.child anchor)\forestoption{edge label};
            },
          where level={3}{tier=tier3}{},
          where level={0}{l sep-=15pt}{},
          where level={1}{
            if n={1}{
              edge path={
                \noexpand\path[color=linecol, rounded corners=5pt,
                  >={Stealth[length=10pt]}, line width=1pt, ->,
                  \forestoption{edge}]
                  (!u.west) -| (.child anchor)\forestoption{edge label};
                },
            }{
              edge path={
                \noexpand\scoped[on background layer]
                \noexpand\path[color=linecol, rounded corners=5pt,
                  >={Stealth[length=10pt]}, line width=1pt, ->,
                  \forestoption{edge}, on background layer]
                  (!u.east) -| (.child anchor)\forestoption{edge label};
                },
            }
          }{},
      }
      [\Huge Total drag, yshift = 3cm, inner color=col1in, outer color=col1out
        [\huge Viscous drag, yshift = 1cm, inner color=col2in, outer color=col2out
          [\Large Displacement separation, inner color=col4in, outer color=col4out
          ]
          [\Large Boundary layer shear, inner color=col4in, outer color=col4out 
          ]
        ]
        [\huge Vortex drag, yshift = 1cm, inner color=col3in, outer color=col3out
          [\Large Trailing vortices due to lift
          ]
        ]
        [\huge Wave drag, yshift = 1cm, inner color=col3in, outer color=col3out
              [\Large Waves due to lift
              ]
              [\Large Waves due to volume
              ]
        ]  
        ]
       ]
       %
       \draw[thick, decorate, decoration={brace, amplitude=1.5em}]
          ([yshift=-.5em]current bounding box.south east) --
          node[below=2em, font=\sffamily\bfseries\Large]
            {Bla bla bla}
          ([yshift=-.5em]current bounding box.south west)
       ;
    \end{forest}
\end{adjustbox}
\end{figure}
\end{document}

Result

2

You can use decorations from tikz to add in the brace.

\usetikzlibrary{decorations.pathreplacing}

\draw [decorate,decoration=brace,mirror,amplitude=20pt},xshift=-1em,yshift=-2em](-20,-2) -- (20,-2) node [black,midway,yshift=-3em]{\footnotesize blahblah};

mirror flips the orientation of the brace (without it the brace points upwards).

amplitude determines the depth of the brace (as it is horizontal not vertical).

5
  • Thak you. Where in the tikz environment do I place the \draw macro?
    – Jonny
    Sep 11 '15 at 11:39
  • At the bottom works fine just before \end{forest}. Sep 11 '15 at 11:41
  • Mm, doesn't seem to work. I get error: Paragraph ended before \forest was complete ...e,decoration=brace,mirror,amplitude=20pt}
    – Jonny
    Sep 11 '15 at 11:45
  • Nevermind, got it to work with the other answer. Thanks!
    – Jonny
    Sep 11 '15 at 11:48
  • I don't seem to get the same error as you. Don't forget to accept Heiko Oberdiek's answer if it worked for you. Sep 11 '15 at 11:55

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.