Algorithms for calculating 2D coordinates for graph nodes.
Calculates coordinates mapping node IDs to {x, y} float coordinate tuples.
These coordinates can be used for rendering graphs visually via custom SVG elements,
exporting data for web dashboards (using Cytoscape.js or D3.js), or generating layouts.
Overview
| Algorithm | Function | Mathematical Model | Best For | Time Complexity |
|---|---|---|---|---|
| Circular | circular/2 | Uniform spacing on unit circle | Symmetric/small graphs, cycles | $O(V)$ |
| Random | random/2 | Uniform distribution in bounding box | Initial states, baseline checks | $O(V)$ |
| Spring | spring/2 | Fruchterman-Reingold force model | Social networks, general graphs | $O(I \cdot (V^2 + E))$ |
| Tutte | tutte/3 | Gauss-Seidel barycentric relaxation | Planar graphs, routing visual flow | $O(I \cdot (V + E))$ |
| Shell | shell/3 | Concentric circles placement | Hierarchies, core-periphery structures | $O(V)$ |
| Multipartite | multipartite/3 | Parallel rows/columns alignment | Bipartite graphs, neural nets, flow nets | $O(V)$ |
Graph Layout Visualization (Spring vs. Circular)
The layout determines the structural aesthetic. Spring layout cluster connected nodes together, whereas Circular layout focuses purely on ordering.
Usage Example
Below is an example showing how layout coordinates can be mapped directly to generate a visual representation:
iex> graph = Yog.from_unweighted_edges(:undirected, [{1, 2}, {2, 3}])
iex> pos = Yog.Layout.circular(graph, radius: 10.0)
iex> Map.keys(pos) |> Enum.sort()
[1, 2, 3]
Summary
Functions
Positions nodes uniformly spaced on a circle.
Positions nodes in parallel layers (columns or rows).
Positions nodes randomly within a specified bounding box.
Positions nodes in concentric circles (shells).
Positions nodes using a spring/force-directed model (Fruchterman-Reingold).
Positions nodes using Tutte's barycentric embedding.
Functions
@spec circular( Yog.Graph.t(), keyword() ) :: %{required(Yog.Graph.node_id()) => {float(), float()}}
Positions nodes uniformly spaced on a circle.
Delegates to Yog.Layout.Circular.layout/2.
@spec multipartite(Yog.Graph.t(), [[Yog.Graph.node_id()]], keyword()) :: %{ required(Yog.Graph.node_id()) => {float(), float()} }
Positions nodes in parallel layers (columns or rows).
Delegates to Yog.Layout.Multipartite.layout/3.
@spec random( Yog.Graph.t(), keyword() ) :: %{required(Yog.Graph.node_id()) => {float(), float()}}
Positions nodes randomly within a specified bounding box.
Delegates to Yog.Layout.Random.layout/2.
@spec shell(Yog.Graph.t(), [[Yog.Graph.node_id()]], keyword()) :: %{ required(Yog.Graph.node_id()) => {float(), float()} }
Positions nodes in concentric circles (shells).
Delegates to Yog.Layout.Shell.layout/3.
@spec spring( Yog.Graph.t(), keyword() ) :: %{required(Yog.Graph.node_id()) => {float(), float()}}
Positions nodes using a spring/force-directed model (Fruchterman-Reingold).
Delegates to Yog.Layout.Spring.layout/2.
@spec tutte(Yog.Graph.t(), [Yog.Graph.node_id()], keyword()) :: %{ required(Yog.Graph.node_id()) => {float(), float()} }
Positions nodes using Tutte's barycentric embedding.
Delegates to Yog.Layout.Tutte.layout/3.