6

I'm trying to reproduce the following tree structure with Tikz:enter image description here


Following several questions here I got the following snippet, which almost does the job, except for the fact that I am not able to remove the root node. In the followingm, the snippet and my temporary solution.

  \begin{tikzpicture}
    \tikzstyle{bplus}=[rectangle split, rectangle split horizontal,draw]
    \tikzstyle{every node}=[bplus]
    \tikzstyle{level 1}=[sibling distance=90mm]
    \tikzstyle{level 2}=[sibling distance=25mm]
    \node {U} [->]
      child {node {A \nodepart{two} B \nodepart{three} C \nodepart{four}}
        child {node {D \nodepart{two} E \nodepart{three} F \nodepart{four} G}}
        child {node {H \nodepart{two} I \nodepart{three} J \nodepart{four} K}}    
        child {node {L \nodepart{two} M \nodepart{three} N  \nodepart{four}}}    
      } 
    ;
  \end{tikzpicture}

How can I remove the root node and the arrow?

enter image description here

2
  • Welcome. // Can you please turn this code snippet, which can't be compiled, into a MWE, e.g. this way: tex.meta.stackexchange.com/a/10137/245790 ? Thank you
    – MS-SPO
    Dec 10, 2023 at 19:47
  • Just don't draw first node in the tree. By this will the second become root node,
    – Zarko
    Dec 10, 2023 at 20:48

3 Answers 3

11

May I suggest using forest instead of the base TikZ tree methods. There are many advantages to using forest for trees over other methods:

  • much more compact syntax (labelled bracketting)
  • automatic packing of nodes so that they will not overlap
  • generally more compact trees

Here's your tree using it:

\documentclass{article}
\usepackage{forest}
\tikzset{bplus/.style={rectangle split, rectangle split horizontal,draw}}


\begin{document}
\begin{forest}for tree={bplus, edge={->},l sep=1cm}
[{A \nodepart{two} B \nodepart{three} C \nodepart{four}}
    [{D \nodepart{two} E \nodepart{three} F \nodepart{four} G}]
    [{H \nodepart{two} I \nodepart{three} J \nodepart{four} K}]
    [{L \nodepart{two} M \nodepart{three} N  \nodepart{four}}]
]
\end{forest}
\end{document}

Also, the \tikzstyle command is deprecated. You should use instead \tikzset as in this example.

If you do want to use the base methods, then you need to remove the U node from your code:

 \begin{tikzpicture}[every node/.style=bplus,level 1/.style={sibling distance=25mm},->]
      \node {A \nodepart{two} B \nodepart{three} C \nodepart{four}}
        child {node {D \nodepart{two} E \nodepart{three} F \nodepart{four} G}}
        child {node {H \nodepart{two} I \nodepart{three} J \nodepart{four} K}}    
        child {node {L \nodepart{two} M \nodepart{three} N  \nodepart{four}}}     
    ;
  \end{tikzpicture}

Inspired by Zarko's simplification of the multipart node input (which is quite wordy), here's another version of that command which takes a comma separated list instead. You may also want to incorporate their format for the nodes, which makes them uniform size.

To accommodate having each branch project from a particular cell of the parent, I've added an multi edge style to specify which specific node part of the parent you want that edge to project from. If you always want the nodes to map 1:1 from node parts to sequence of daughters, then you can simply use the auto edge style which does this automatically.

\documentclass{article}
\usepackage{forest}

\tikzset{bplus/.style={rectangle split, rectangle split horizontal,text width=1em, text centered, inner xsep=2pt,draw}}

\forestset{multi edge/.style={edge path={\noexpand\path[\forestoption{edge}] (!u.#1 south)--(.child anchor)\forestoption{edge label};}},
auto edge/.style={for tree={edge path={\noexpand\path[\forestoption{edge}] (!u.\getnode{\forestoption{n}} south)--(.child anchor)\forestoption{edge label};}}
}}


\ExplSyntaxOn
\seq_new:N \l_tree_node_seq
\seq_set_from_clist:Nn \c_node_names_seq {one,two,three,four}
\NewDocumentCommand{\mpn}{m}{
    \seq_set_from_clist:Nn \l_tree_node_seq {#1}
    \seq_map_indexed_inline:Nn \l_tree_node_seq { 
        \nodepart{\getnode {##1}} {##2}
    }
}
\NewDocumentCommand{\getnode}{m}{\seq_item:Nn \c_node_names_seq {#1}}
\ExplSyntaxOff  

\begin{document}

\begin{forest}for tree={bplus, auto edge,edge={->},l sep=1cm}
[\mpn{A,B,C,D}
    [\mpn{D,E,F,G}]
    [\mpn{H,I,J,K}]
    [\mpn{L,M,N},multi edge=four]
]
\end{forest}
\end{document}

output of code

2
  • Thanks for your answer! I have one last question actually: in all the results, I'd like the first arrow from the left to emanate from A, the second from B and the last one from C. Is there a way to impose this?
    – VoB
    Dec 11, 2023 at 9:19
  • @VoB Yes, I've added a style that allows you to do this.
    – Alan Munn
    Dec 11, 2023 at 15:27
4

Small variation of the nice @Alan Munn answer (+1): shorter code for nodes contents and wee bit nicer formatted multi part nodes:

\documentclass[margin=3mm]{standalone}
\usepackage{forest}
\usetikzlibrary{arrows.meta,
                shapes.multipart}
\newcommand\mpn[4]{\nodepart{one}   #1
                   \nodepart{two}   #2
                   \nodepart{three} #3
                   \nodepart{four}  #4}


\begin{document}
    \begin{forest}
for tree = {
    rectangle split, rectangle split horizontal, 
    rectangle split parts=4,
    text width=1em, text centered, inner xsep=2pt,
    draw,
    edge = {semithick, -Straight Barb},
    l sep=12mm,
    s sep= 2mm,
            }
[\mpn{A}{B}{C}{ }
    [\mpn{D}{E}{F}{G}]
    [\mpn{H}{I}{J}{K}]
    [\mpn{L}{M}{N}{ }]
]
\end{forest}
\end{document}

enter image description here

Addendum:
Combining of the @Alan Munn code for forming list of forest nodes contents but with formatting of tree as i use in my original answer:

\documentclass[margin=3mm]{standalone}
\usepackage{forest}
\usetikzlibrary{arrows.meta,
                shapes.multipart}

\ExplSyntaxOn   % proposed by Alan Mun
\seq_new:N \l_tree_node_seq
\seq_set_from_clist:Nn \c_node_names_seq {one,two,three,four}
\NewDocumentCommand{\mpn}{m}{
    \seq_set_from_clist:Nn \l_tree_node_seq {#1}
    \seq_map_indexed_inline:Nn \l_tree_node_seq {
        \nodepart{\seq_item:Nn \c_node_names_seq {##1}} {##2}
    }
}
\ExplSyntaxOff

\begin{document}
    \begin{forest}
for tree = {
    rectangle split, rectangle split horizontal,   % <---
    text width=1em, text centered, inner xsep=2pt, % <---
    draw,
    edge = {semithick, -Straight Barb},
    l sep=12mm,
    s sep= 2mm,
            }
[\mpn{A,B,C,~} % <---
    [\mpn{D,E,F,G}]
    [\mpn{H,I,J,K}]
    [\mpn{L,M,N,~}] % <---
]
\end{forest}
\end{document}

Result is the same as before!

4

I'd make greater use of forest's own facilities to shorten the code and simplify the syntax. I present two solutions. The first utilises forest's builtin support for tabulars. This is the simplest. The second utilises split option to allow a simple, colon-separated input syntax for specifying the content of a multipart node. This is a bit more elaborate, but still easily accomplished with forest's own processing facilities, and produces a more aesthetically pleasing result.

Method 1 (Simpler, Not-Quite-As-Pretty)

forest has built-in support for tabulars, so I would leverage this capability. This code is derived from Alan Munn's answer. This makes it possible to use the familiar syntax used to define tabular rows to separate the different parts of each node in the tree.

\documentclass[border=5pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703670/ addaswyd o ateb Alun Munn: https://tex.stackexchange.com/a/703663/
\usepackage{forest}
\forestset{%
  bplus/.style={%
    align={|c|c|c|c|},
    before typesetting nodes={%
      content={\hline ##1\\\hline},
    },
  },
}


\begin{document}
\begin{forest}
  for tree={bplus, edge={->},l sep'=1cm}
  [A & B & C &
    [D & E & F & G]
    [H & I & J & K,calign with current edge]
    [L & M & N  &]
  ]
\end{forest}
\end{document}

tabular nodes

Method 2 (Prettier, Slightly-More-Complex)

Since these do not look quite so nice as the multipart nodes, it may be worth noting that you can use this style with a simplified syntax just by utilising forest's split option. I don't like using a comma to separate within forest nodes because I then have to keep track of the { and }. Instead, I'd recommend picking some other punctuation mark which doesn't occur in your nodes themselves and isn't treated specially by TikZ or forest. This example uses a colon, but you do pick something else if your tree contains colons else you'll be back to needing additional brace groups.

\documentclass[border=5pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703670/ addaswyd o ateb Alun Munn: https://tex.stackexchange.com/a/703663/
\usepackage{forest}
\forestset{%
  bplus/.style={%
    draw,
    rectangle split,
    rectangle split horizontal,
    before typesetting nodes={%
      split option={content}{:}{content',temptoksb,temptoksc,temptoksd},
      content+={\nodepart{two}},
      content+/.register=temptoksb,
      content+={\nodepart{three}},
      content+/.register=temptoksc,
      content+={\nodepart{four}},
      content+/.register=temptoksd,
    },
  },
}

\begin{document}
\begin{forest}
  for tree={bplus, edge={->},l sep'=1cm}
  [A:B:C:
    [D:E:F:G]
    [H:I:J:K, calign with current edge]
    [L:M:N:]
  ]
\end{forest}
\end{document}

multipart nodes using forest's split option for simplified syntax

This can be modified in various ways e.g. to accommodate edges from different parts of the parent and/or child nodes.

custom anchors for edges

\documentclass[border=5pt]{standalone}
% ateb: https://tex.stackexchange.com/a/703670/ addaswyd o ateb Alun Munn: https://tex.stackexchange.com/a/703663/
\ExplSyntaxOn
\cs_new_protected_nopar:Nn \bplus_anchor:n
{
  \int_case:nn { #1 }
  {
    { 1 } { one }
    { 2 } { two }
    { 3 } { three }
    { 4 } { four }
  }
}
\cs_generate_variant:Nn \bplus_anchor:n { o }
\cs_new_eq:NN \bplusanchor \bplus_anchor:o 
\ExplSyntaxOff
\usepackage{forest}
\forestset{%
  edge from/.style args={#1 to #2}{%
    edge path'={(!u.#1) -- (.#2)},
  },
  bplus/.style={%
    draw,
    rectangle split,
    rectangle split horizontal,
    child anchor=north,
    edge from/.process={Ow+ow{n}{\bplusanchor{##1}}{##1 south to child anchor}},
    text width=1em,
    /tikz/align=center,
    before typesetting nodes={%
      split option={content}{:}{content',temptoksb,temptoksc,temptoksd},
      content+={\nodepart{two}},
      content+/.register=temptoksb,
      content+={\nodepart{three}},
      content+/.register=temptoksc,
      content+={\nodepart{four}},
      content+/.register=temptoksd,
    },
  },
}

\begin{document}
\begin{forest}
  for tree={bplus, edge={->},l sep'=1cm}
  [A:B:C:
    [D:E:F:G]
    [H:I:J:K, child anchor=two north]
    [L:M:N:,edge from=four south to three north ]
  ]
\end{forest}
\end{document}

Personally, I'd probably use the first method because multipart nodes behave slightly oddly in some cases. But provided you're not doing anything further complicated, the multipart approaches definitely have a neater, more symmetric look.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .