Shell layout algorithm for positioning graph nodes in concentric circles.
Groups nodes into user-specified "shells" (concentric circles) and positions the nodes in each shell uniformly along its circumference. This is extremely useful for hierarchical visualizations, bipartite/tripartite visual grouping, or displaying networks with distinct core/periphery structures.
Mathematical Model
Given a list of shells $S = [S_0, S_1, \dots, S_m]$, where each $S_j$ is a list of node IDs:
- Each shell $S_j$ is assigned a radius $R_j$. If not specified, radii are linearly spaced: $$ R_j = \frac{j + 1}{m + 1} $$
- The nodes within shell $S_j$ are positioned using the circular layout equations: $$ \theta_i = \frac{2 \pi \cdot i}{|S_j|} $$ $$ x_i = c_x + R_j \cdot \cos(\theta_i) $$ $$ y_i = c_y + R_j \cdot \sin(\theta_i) $$
For a single-node shell ($|S_j| = 1$), the node is placed at the center if it is the only shell, or on the circle circumference if there are other shells.
Complexities
- Time Complexity: $O(V)$ where $V$ is the number of nodes.
- Space Complexity: $O(V)$ auxiliary space.
Summary
Functions
Positions nodes in concentric circles (shells).
Functions
@spec layout(Yog.Graph.t(), [[Yog.Graph.node_id()]], keyword()) :: %{ required(Yog.Graph.node_id()) => {float(), float()} }
Positions nodes in concentric circles (shells).
Requires a list of shells, where each shell is a list of node IDs.
Options
:center- The{x, y}coordinates of the center of the shells (default:{0.0, 0.0}).:radii- Optional list of float radii, one for each shell.
Examples
iex> graph = Yog.undirected() |> Yog.add_nodes_from([1, 2, 3, 4])
iex> pos = Yog.Layout.Shell.layout(graph, [[1, 2], [3, 4]])
iex> Map.keys(pos) |> Enum.sort()
[1, 2, 3, 4]