Grandalf: Graph and Drawing Algorithms Framework
Grandalf is a pure Python package designed for experimenting with graph drawing algorithms. It currently implements two main layouts: the Sugiyama hierarchical layout and a force-driven (energy minimization) approach. Its primary function is to compute node (x,y) coordinates and route edges, providing the structural layout information without performing the actual graphical rendering, which is left to external graphics toolkits. The current version is 0.8, released in January 2023.
Warnings
- gotcha Grandalf focuses solely on computing graph layouts (node coordinates and edge routing). It does not provide any graphical rendering capabilities. Users must integrate it with their preferred graphics toolkit (e.g., Matplotlib, PyQt, Tkinter, etc.) to visualize the generated layouts.
- gotcha The library is primarily for 'experimentations' and has a 'Development Status :: 3 - Alpha' on PyPI. While functional for graphs up to thousands of nodes, it may not be as fast or feature-rich as mature C++ libraries like Graphviz or OGDF. It's best suited for scenarios where a simple, pure-Python, and hackable graph layout solution is preferred.
- gotcha Layout classes operate on a `graph_core` which is separate from the original `Graph`. If you modify the underlying graph (add/remove vertices/edges), you typically need to create a new layout instance to recompute the positions, as the layout objects do not automatically react to graph mutations.
Install
-
pip install grandalf
Imports
- Vertex, Edge, Graph
from grandalf.graphs import Vertex, Edge, Graph
- SugiyamaLayout, ForceDirectedLayout
from grandalf.layouts import SugiyamaLayout, ForceDirectedLayout
- digraph_core
from grandalf.digraph import digraph_core
Quickstart
from grandalf.graphs import Vertex, Edge, Graph
from grandalf.layouts import SugiyamaLayout
# Define nodes (vertices)
V = [Vertex(data) for data in range(10)]
# Define edges for a simple graph
X = [(0, 1), (0, 2), (1, 3), (2, 3), (4, 5), (4, 6), (5, 7), (6, 7), (3, 8), (7, 9)]
E = [Edge(V[u], V[v]) for u, v in X]
# Create a graph instance
g = Graph(V, E)
# Assign placeholder dimensions (width, height) to vertices;
# x,y will be set by the layout algorithm.
for v in V:
v.view = [0, 0, 20, 20] # [x, y, width, height]
# Iterate through graph components (e.g., for Sugiyama, it processes connected components)
for gr in g.sugiyama():
# Instantiate the Sugiyama layout algorithm for the current component
lay = SugiyamaLayout(gr)
# Initialize and run the layout steps
lay.init_all()
lay.algo_graph_layered()
lay.algo_node_coordinatization()
lay.algo_edge_routing()
print(f"--- Layout for Graph Component ---")
for v in gr.V:
# After layout, v.view[0] and v.view[1] contain the calculated (x, y) coordinates
print(f" Vertex {v.data}: (x={v.view[0]}, y={v.view[1]})")