CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-igraph

High performance graph data structures and algorithms for Python

Pending
Overview
Eval results
Files

layout.mddocs/

Layout

Graph layout and positioning algorithms for visualization and spatial analysis. igraph provides over 30 layout algorithms ranging from force-directed methods to specialized algorithms for trees, hierarchies, and large networks.

Capabilities

Force-Directed Layouts

Physics-based layouts that simulate forces between vertices to achieve aesthetically pleasing arrangements.

class Graph:
    def layout_fruchterman_reingold(self, weights=None, maxiter=500, area=None, coolexp=1.5, repulserad=None, dim=2, **kwargs):
        """
        Fruchterman-Reingold force-directed layout.
        
        Parameters:
        - weights: str/list, edge weights (shorter for higher weights)
        - maxiter: int, maximum iterations
        - area: float, area of layout (None for automatic)
        - coolexp: float, cooling exponent
        - repulserad: float, repulsion radius (None for automatic)
        - dim: int, number of dimensions (2 or 3)
        
        Returns:
        Layout object with vertex coordinates
        """

    def layout_kamada_kawai(self, weights=None, maxiter=None, epsilon=0, kkconst=None, dim=2, **kwargs):
        """
        Kamada-Kawai spring-based layout.
        
        Parameters:
        - weights: edge weights
        - maxiter: int, maximum iterations (None for automatic)
        - epsilon: float, stopping criterion
        - kkconst: float, spring constant (None for automatic)
        - dim: int, dimensions
        
        Returns:
        Layout object
        """

    def layout_spring(self, weights=None, maxiter=500, area=None, coolexp=1.5, repulserad=None, dim=2, **kwargs):
        """
        Alias for layout_fruchterman_reingold().
        """

    def layout_davidson_harel(self, weights=None, maxiter=10, fineiter=None, cool_fact=0.75, weight_node_dist=1.0, weight_border=0.0, weight_edge_lengths=None, weight_edge_crossings=1.0, weight_node_edge_dist=0.2, **kwargs):
        """
        Davidson-Harel layout with multiple aesthetic criteria.
        
        Parameters:
        - weights: edge weights
        - maxiter: int, coarse iterations
        - fineiter: int, fine-tuning iterations
        - cool_fact: float, cooling factor
        - weight_*: float, weights for different aesthetic criteria
        
        Returns:
        Layout object
        """

Usage Examples:

import igraph as ig

# Create sample graph
g = ig.Graph.Barabasi(50, m=2)

# Fruchterman-Reingold (most common)
fr_layout = g.layout_fruchterman_reingold()
print(f"FR layout shape: {len(fr_layout)} x {len(fr_layout[0])}")

# With edge weights (closer vertices for higher weights)
g.es["weight"] = [1.0 + i*0.1 for i in range(g.ecount())]
weighted_fr = g.layout_fruchterman_reingold(weights="weight")

# Kamada-Kawai (good for smaller graphs)
kk_layout = g.layout_kamada_kawai(maxiter=1000)

# 3D layout
fr_3d = g.layout_fruchterman_reingold(dim=3)
print(f"3D layout shape: {len(fr_3d)} x {len(fr_3d[0])}")  # N x 3

# Davidson-Harel with custom weights
dh_layout = g.layout_davidson_harel(
    maxiter=20,
    weight_node_dist=2.0,
    weight_edge_crossings=0.5
)

Tree and Hierarchical Layouts

Specialized layouts for trees, DAGs, and hierarchical structures.

class Graph:
    def layout_reingold_tilford(self, mode=ALL, root=None):
        """
        Reingold-Tilford tree layout.
        
        Parameters:
        - mode: tree direction (ALL, OUT, IN)
        - root: int/list, root vertices (None for automatic)
        
        Returns:
        Layout object with hierarchical positioning
        """

    def layout_reingold_tilford_circular(self, mode=ALL, root=None):
        """
        Circular Reingold-Tilford layout.
        
        Parameters:
        - mode: tree direction
        - root: root vertices
        
        Returns:
        Layout object in circular arrangement
        """

    def layout_sugiyama(self, layers=None, weights=None, hgap=1, vgap=1, maxiter=100, **kwargs):
        """
        Sugiyama layered layout for directed acyclic graphs.
        
        Parameters:
        - layers: list, predefined layer assignment
        - weights: edge weights
        - hgap: float, horizontal gap between vertices
        - vgap: float, vertical gap between layers
        - maxiter: int, maximum iterations for crossing reduction
        
        Returns:
        Layout object with layered structure
        """

Usage Examples:

# Tree layouts
tree = ig.Graph.Tree(31, children=2)  # Binary tree

# Standard tree layout
tree_layout = tree.layout_reingold_tilford(root=[0])

# Circular tree layout
circular_tree = tree.layout_reingold_tilford_circular(root=[0])

# For directed acyclic graphs
dag = ig.Graph([(0,1), (0,2), (1,3), (1,4), (2,4), (2,5), (3,6), (4,6), (5,6)], directed=True)

# Sugiyama layered layout
sugiyama_layout = dag.layout_sugiyama()

# Manual layer assignment
layers = [0, 1, 1, 2, 2, 2, 3]  # Layer for each vertex
manual_sugiyama = dag.layout_sugiyama(layers=layers, hgap=2, vgap=1.5)

Large Graph Layouts

Efficient algorithms designed for large networks with thousands or millions of vertices.

class Graph:
    def layout_drl(self, weights=None, dim=2, fixednode=None, **kwargs):
        """
        DrL (Distributed Recursive Layout) for large graphs.
        
        Parameters:
        - weights: edge weights
        - dim: int, dimensions (2 or 3)
        - fixednode: list, vertices with fixed positions
        
        Returns:
        Layout object
        """

    def layout_graphopt(self, weights=None, niter=500, node_charge=0.001, node_mass=30, spring_length=0, spring_constant=1, max_sa_movement=5, **kwargs):
        """
        GraphOpt layout algorithm.
        
        Parameters:
        - weights: edge weights
        - niter: int, number of iterations
        - node_charge: float, vertex charge (repulsion)
        - node_mass: float, vertex mass
        - spring_length: float, natural spring length
        - spring_constant: float, spring force constant
        - max_sa_movement: float, maximum movement per iteration
        
        Returns:
        Layout object
        """

    def layout_lgl(self, weights=None, maxiter=150, maxdelta=None, area=None, coolexp=1.5, repulserad=None, cellsize=None, **kwargs):
        """
        Large Graph Layout (LGL) algorithm.
        
        Parameters:
        - weights: edge weights
        - maxiter: int, maximum iterations
        - maxdelta: float, maximum movement (None for automatic)
        - area: float, layout area
        - coolexp: float, cooling exponent
        - repulserad: float, repulsion radius
        - cellsize: float, cell size for spatial indexing
        
        Returns:
        Layout object
        """

Usage Examples:

# Large network
large_g = ig.Graph.Barabasi(1000, m=3)

# DrL layout (good for large networks)
drl_layout = large_g.layout_drl()

# GraphOpt layout
graphopt_layout = large_g.layout_graphopt(niter=1000, node_charge=0.002)

# LGL layout
lgl_layout = large_g.layout_lgl(maxiter=200)

# For very large graphs, use fewer iterations
if large_g.vcount() > 5000:
    quick_layout = large_g.layout_drl(dim=2)  # Default parameters are efficient

Geometric and Grid Layouts

Regular and geometric layout patterns for specific visualization needs.

class Graph:
    def layout_circle(self, order=None):
        """
        Circular layout with vertices on a circle.
        
        Parameters:
        - order: list, vertex ordering (None for current order)
        
        Returns:
        Layout object with circular positioning
        """

    def layout_grid(self, width=0, dim=2):
        """
        Grid layout in regular pattern.
        
        Parameters:
        - width: int, grid width (0 for automatic square)
        - dim: int, dimensions
        
        Returns:
        Layout object with grid positioning
        """

    def layout_sphere(self):
        """
        Spherical layout in 3D space.
        
        Returns:
        Layout object with 3D spherical coordinates
        """

    def layout_random(self, dim=2):
        """
        Random vertex positions.
        
        Parameters:
        - dim: int, dimensions
        
        Returns:
        Layout object with random coordinates
        """

    def layout_fruchterman_reingold_3d(self, **kwargs):
        """
        3D Fruchterman-Reingold layout (alias for layout_fruchterman_reingold(dim=3)).
        
        Returns:
        Layout object with 3D coordinates
        """

    def layout_kamada_kawai_3d(self, **kwargs):
        """
        3D Kamada-Kawai layout (alias for layout_kamada_kawai(dim=3)).
        
        Returns:
        Layout object with 3D coordinates
        """

    def layout_random_3d(self, **kwargs):
        """
        3D random layout (alias for layout_random(dim=3)).
        
        Returns:
        Layout object with 3D random coordinates
        """

    def layout_grid_3d(self, **kwargs):
        """
        3D grid layout (alias for layout_grid(dim=3)).
        
        Returns:
        Layout object with 3D grid coordinates
        """

Usage Examples:

# Geometric layouts
g = ig.Graph.Ring(12)

# Circular layout
circle_layout = g.layout_circle()

# Custom vertex ordering for circle
vertex_order = list(range(0, 12, 2)) + list(range(1, 12, 2))  # Even then odd
ordered_circle = g.layout_circle(order=vertex_order)

# Grid layout
grid_g = ig.Graph.Lattice([4, 3])  # 4x3 grid graph
grid_layout = grid_g.layout_grid(width=4)

# 3D sphere
sphere_layout = g.layout_sphere()

# Random layout (useful as starting point)
random_layout = g.layout_random(dim=2)

Multidimensional Scaling

Layouts based on preserving distances and similarities between vertices.

class Graph:
    def layout_mds(self, weights=None, dim=2, **kwargs):
        """
        Multidimensional scaling layout.
        
        Parameters:
        - weights: edge weights for distance calculation
        - dim: int, target dimensions
        
        Returns:
        Layout object preserving graph distances
        """

    def layout_gem(self, weights=None, maxiter=40*40, temp_max=None, temp_min=None, temp_init=None):
        """
        GEM (Graph EMbedder) layout algorithm.
        
        Parameters:
        - weights: edge weights
        - maxiter: int, maximum iterations
        - temp_max: float, maximum temperature
        - temp_min: float, minimum temperature  
        - temp_init: float, initial temperature
        
        Returns:
        Layout object
        """

Usage Examples:

# MDS layout (preserves shortest path distances)
mds_layout = g.layout_mds()

# With edge weights
g.es["weight"] = [abs(i-j) + 1 for i, j in g.get_edgelist()]
weighted_mds = g.layout_mds(weights="weight")

# GEM layout
gem_layout = g.layout_gem(maxiter=2000)

Layout Manipulation

Methods for transforming, scaling, and adjusting existing layouts.

class Layout:
    def scale(self, *args):
        """
        Scale layout coordinates.
        
        Parameters:
        - args: scaling factors (single value or per-dimension)
        
        Returns:
        None (modifies in place)
        """

    def translate(self, *args):
        """
        Translate layout coordinates.
        
        Parameters:
        - args: translation offsets
        
        Returns:
        None (modifies in place)
        """

    def rotate(self, angle, dim1=0, dim2=1):
        """
        Rotate layout in specified plane.
        
        Parameters:
        - angle: float, rotation angle in radians
        - dim1, dim2: int, dimensions defining rotation plane
        
        Returns:
        None (modifies in place)
        """

    def mirror(self, dim):
        """
        Mirror layout along specified dimension.
        
        Parameters:
        - dim: int, dimension to mirror
        
        Returns:
        None (modifies in place)
        """

    def fit_into(self, bbox, keep_aspect_ratio=True):
        """
        Fit layout into bounding box.
        
        Parameters:
        - bbox: BoundingBox or (left, top, right, bottom)
        - keep_aspect_ratio: bool, preserve proportions
        
        Returns:
        None (modifies in place)
        """

    def copy(self):
        """
        Create copy of layout.
        
        Returns:
        Layout, independent copy
        """

Usage Examples:

from igraph.drawing import BoundingBox
import math

# Create and manipulate layout
layout = g.layout_fruchterman_reingold()

# Make a copy for manipulation
layout_copy = layout.copy()

# Scale by factor of 2
layout_copy.scale(2.0)

# Translate to center at origin
center_x = sum(pos[0] for pos in layout_copy) / len(layout_copy)
center_y = sum(pos[1] for pos in layout_copy) / len(layout_copy)
layout_copy.translate(-center_x, -center_y)

# Rotate 45 degrees
layout_copy.rotate(math.pi/4)

# Mirror horizontally
layout_copy.mirror(0)

# Fit into specific bounding box
bbox = BoundingBox(0, 0, 800, 600)
layout_copy.fit_into(bbox, keep_aspect_ratio=True)

# Different scaling per dimension
layout2 = layout.copy()
layout2.scale(1.5, 0.8)  # Stretch horizontally, compress vertically

Layout Comparison and Selection

Techniques for choosing appropriate layouts and comparing their quality.

Usage Examples:

import time

# Compare layout algorithms for a specific graph
g = ig.Graph.Barabasi(100, m=3)

layouts = {}
times = {}

# Test different algorithms
algorithms = [
    ("fruchterman_reingold", g.layout_fruchterman_reingold),
    ("kamada_kawai", g.layout_kamada_kawai), 
    ("drl", g.layout_drl),
    ("graphopt", g.layout_graphopt)
]

for name, method in algorithms:
    start_time = time.time()
    try:
        layout = method()
        layouts[name] = layout
        times[name] = time.time() - start_time
        print(f"{name}: {times[name]:.3f}s")
    except Exception as e:
        print(f"{name}: failed ({e})")

# Layout quality metrics (custom functions)
def layout_stress(graph, layout, weights=None):
    """Calculate layout stress (difference between graph and Euclidean distances)."""
    import math
    stress = 0
    dist_matrix = graph.shortest_paths(weights=weights)
    
    for i in range(len(layout)):
        for j in range(i+1, len(layout)):
            # Euclidean distance in layout
            euclidean = math.sqrt(sum((layout[i][k] - layout[j][k])**2 for k in range(2)))
            # Graph distance
            graph_dist = dist_matrix[i][j]
            if graph_dist != float('inf'):
                stress += (euclidean - graph_dist) ** 2
    return stress

# Evaluate layouts
for name, layout in layouts.items():
    if layout:
        stress = layout_stress(g, layout)
        print(f"{name} stress: {stress:.2f}")

# Adaptive layout selection based on graph size
def choose_layout(graph):
    """Choose appropriate layout algorithm based on graph properties."""
    n = graph.vcount()
    m = graph.ecount()
    
    if n <= 100:
        return graph.layout_kamada_kawai()
    elif n <= 1000:
        return graph.layout_fruchterman_reingold()
    else:
        return graph.layout_drl()

optimal_layout = choose_layout(g)

Install with Tessl CLI

npx tessl i tessl/pypi-igraph

docs

analysis.md

clustering.md

community.md

data-types.md

graph-creation.md

graph-structure.md

index.md

io-formats.md

layout.md

sequences.md

visualization.md

tile.json