Two layouts in fframes_kit::layout place the nodes of the tree and graph figures. Both
compute once and give the same result on every run and machine. The shared graph layouts of
layout::graph_layout are a third choice, through Graph::layout and TreeTrace::with_layout.
tidy_tree(children, root)places a tree:children[i]lists the children of nodei.xis in slots (siblings and neighbouring subtrees are at least one slot apart at every depth),yis the depth. Parents sit midway over their children, and the leftmost node is atx = 0.layered(count, edges)(withcs) places a directed graph in layers with Sugiyama’s method:yis the layer, sources at 0 and edges pointing down, andxthe slot in the layer, with crossings reduced. Cycles are fine. Connected parts sit side by side, and nodes without edges follow in layer 0.
Gallery scene: CsLayouts compares the two layouts on the same graph.

CsLayouts 8 suse fframes_kit::layout::{layered, tidy_tree};
// a root with two children, the first with two of its ownlet tree = tidy_tree(&[vec![1, 2], vec![3, 4], vec![], vec![], vec![]], 0);assert_eq!(tree[1], (0.5, 1.0));assert_eq!(tree[0].0, f64::midpoint(tree[1].0, tree[2].0));
let graph = layered(4, &[(0, 1), (0, 2), (1, 3), (2, 3)]);assert_eq!((graph[0].1, graph[3].1), (0.0, 2.0));To draw the tree layout, apply its positions to a graph and build the trace once:
use fframes_kit::layout::tidy_tree;use fframes_kit::prelude::*;
let positions = tidy_tree(&[vec![1, 2], vec![3, 4], vec![], vec![], vec![]], 0);let graph = Graph::new(&["A", "B", "C", "D", "E"], &[(0, 1), (0, 2), (1, 3), (1, 4)], true) .at(&positions);let trace = GraphTrace::bfs(&graph, 0);
fn draw<'a>(ui: &mut Ui<'a, '_, '_>, trace: &'a GraphTrace) -> Svgr<'a> { ui.show(GraphView { trace: Some(trace), step_time: 0.8, ..ui.defaults() })}