Collapsible Tree

So I took a slightly different tack from lowriniak, making a tree object, rather than just using a tree hierarchy, but the result is much the same. What's worth noting, though, is that this gives you a somewhat more dynamic tree.

Here's the tree making boiler plate:

$tree = <|Root -> <|"Title" -> ".", "Children" -> {}, 
     "Open" -> True|>|>;
$id = 1;
childNodes[parent : _Integer | Root] := $tree[parent]["Children"];
nodeOpen[node : _Integer | Root] := TrueQ@$tree[node]["Open"];
nodeTitle[node_] := $tree[node]["Title"];
toggleNode[node_] := $tree[node]["Open"] = ! $tree[node]["Open"];
addNode[parent : _Integer | Root : Root, node_] := (
   AssociateTo[$tree, $id -> <|"Title" -> node, "Children" -> {}, 
      "Open" -> True|>];
   AppendTo[$tree[parent]["Children"], $id];
   $id++
   );
removeNode[node_Integer] :=

  KeyDropFrom[$tree, Prepend[childNodes[node], node]];
retitleNode[node_Integer, name_] := $tree[node]["Title"] = name;

Then we'll want a way to collect our visible nodes and assign them the right coordinates:

$viewNodes :=
  Block[{
    processing = {},
    nodeStack = {Root},
    visibleNodes = {{Root}},
    layerNodes = {},
    nodeDepth = 1
    },
   While[Length@nodeStack > 0,
    processing = nodeStack;
    nodeStack = {};
    layerNodes = {};
    Do[
     If[nodeOpen@node,
      AppendTo[layerNodes, childNodes@node];
      nodeStack = Join[nodeStack, childNodes@node]
      ],
     {node, processing}];
    AppendTo[visibleNodes, Flatten@layerNodes]
    ];
   visibleNodes
   ];
$allNodes := Block[{nodeOpen = (True &)}, $viewNodes];
$graphNodes :=

  With[{totalTree = $allNodes, nodes = Flatten@$viewNodes},
   Flatten@
    With[{d = Length@totalTree},
     Table[
      With[{l = Length@totalTree[[i]]},
       Table[
        If[MemberQ[nodes, totalTree[[i, j]]],
         {(i - 1), (j - Floor[l/2])/2.2} -> totalTree[[i, j]],
         Nothing],
        {j, l}]
       ],
      {i, d}
      ]
     ]
   ];

Then we'll make a graph and formatting wrapper:

$viewTree :=
 With[{nodes = $graphNodes},
  If[Length@nodes > 1,
   Graph[
    Flatten@
     Table[
      If[nodeOpen@node, Thread[node -> childNodes@node], {}],
      {node, Last /@ nodes}],
    VertexShape -> Table[
      With[{node = node},
       node ->
        EventHandler[
         Graphics[{
           EdgeForm[Hue[.6, .5, .25]],
           GrayLevel[.95],
           Disk[{0, 0}, 50],
           Black,
           Inset@nodeTitle@node
           }
          ], "MouseClicked" :> (toggleNode@node)]
       ], {node, Last /@ nodes}],
    VertexSize -> .15,
    VertexCoordinates -> Reverse /@ nodes
    ],
   With[{node = Last@First@nodes},
    EventHandler[
     Graphics[{
       EdgeForm[Hue[.6, .5, .25]],
       GrayLevel[.95], ,
       Disk[{0, 0}, 50],
       Black,
       Inset@nodeTitle@node
       }
      ],
     "MouseClicked" :> (toggleNode@node)]
    ]
   ]
  ]

Format[HoldPattern[$TreeObject]] :=
 Interpretation[
  Dynamic[$viewTree, TrackedSymbols :> {$viewTree, $tree}],
  $TreeObject]

And this gives you a dynamically editable tree with toggle-able nodes:

Do[
  With[{i = addNode[n]},
   Do[
    With[{j = addNode[i, m]},
     Do[addNode[j, k], {k, RandomInteger[3]}]
     ],
    {m, RandomInteger[5]}
    ]
   ],
  {n, RandomInteger[10]}
  ];
$TreeObject

tree full

Then toggle some nodes:

tree toggles

It isn't as elegant as your source example, but it works as one would hope.


I've made a start, but getting the vertices to stay static relative to each other is a challenge...

Set up the values:

hierarchy = {
   1 -> 11, 1 -> 12, 1 -> 13,

   11 -> 111, 11 -> 112, 11 -> 113,
   12 -> 121, 12 -> 122, 12 -> 123,
   13 -> 131, 13 -> 132, 13 -> 133,

   121 -> 1211, 121 -> 1212, 121 -> 1213
};

Make an association to track 'openness':

select = Association[# -> True & /@ Union[Flatten[List @@@ hierarchy]]];

A function to toggle the 'openness' of an object:

toggle[obj_] := select[obj] = ! select[obj];

Make a nested version so you can do it on trees:

togglenested[obj_] := (
  If[obj != 1, toggle[obj]];
  togglenested /@ Cases[
    hierarchy, 
    rule : Rule[left_, right_] /; left == obj :> right
  ];
  Null
)

Creating the vertex primitive with event handler for clicks:

action[obj_, loc_] :=  Inset[EventHandler[obj, {"MouseClicked" :> togglenested[obj]}], loc]

And make a graph that can be interacted with:

Dynamic[
  GraphPlot[
    Cases[hierarchy, rule : Rule[left_, right_] /; select[left]], 
    VertexRenderingFunction -> (action[#2, #] &), 
    Method -> "LayeredDigraphDrawing"
  ]
]

graph

It's not pretty but that's not too hard to add. The current drawbacks: collapsing the first value means the GraphPlot fails so I turned that off. Also the vertices do rearrange themselves - maybe giving specific coordinates to the values in the select association and then drawing it from there could work?