View Auto-Layout

Overview

The View Auto-Layout feature provides automatic graph layout algorithms for ArchiMate views, enabling diagram generation with minimal manual positioning. Two complementary algorithms are available:

  • Force-Directed Layout: Physics-based simulation using spring-embedder algorithm for organic, aesthetically pleasing layouts

  • Hierarchical Layout: Layer-based Sugiyama algorithm for structured, dependency-aware layouts

Quickstart

Basic usage:

from pyArchimate.view.layout import apply_layout
from pyArchimate.view.layout.core import LayoutConfig

# Apply force-directed layout
config = LayoutConfig(algorithm="force_directed", spacing=50)
result = apply_layout(my_view, config)

# Apply hierarchical layout
config = LayoutConfig(algorithm="hierarchical", spacing=100)
result = apply_layout(my_view, config)

if result.success:
    print(f"Laid out {result.elements_processed} elements in {result.layout_time_ms}ms")

Algorithms

Force-Directed Layout

The force-directed layout uses a Spring-Embedder physics simulation:

  • Repulsive forces: Nodes push each other away

  • Attractive forces: Connected nodes pull toward each other

  • Damping: Reduces oscillation and accelerates convergence

  • Early exit: Stops iterations when all nodes move less than 0.01px

Configuration parameters:

  • spacing: Minimum space between elements (pixels)

  • margin: Margin around canvas edges

  • layer_priority: β€œmandatory” or β€œsoft” for ArchiMate layer constraints

Performance: <5 seconds for 500 elements on modern hardware

Hierarchical Layout

The hierarchical layout uses the Sugiyama layer-based algorithm:

  • Layer assignment: Elements grouped by dependency depth

  • Crossing minimization: Edge routing optimized to reduce crossing count

  • Node ordering: Elements arranged within layers for visual clarity

Configuration parameters:

  • spacing: Vertical/horizontal gap between layers and elements

  • margin: Canvas margin

  • layer_priority: β€œmandatory” (enforce ArchiMate layers) or β€œsoft” (use dependency levels)

Performance: <1 second for 500 elements

Auto-Format

Elements can be automatically standardized:

from pyArchimate.view.layout import apply_format
from pyArchimate.view.layout.core import LayoutConfig

config = LayoutConfig(alignment="grid", grid_size=10)
result = apply_format(my_view, config)

Features:

  • Standardized sizing: All elements use ArchiMate standard dimensions (120Γ—55 pixels)

  • Font normalization: Segoe UI 9pt for all text

  • Grid alignment: Optional snap-to-grid positioning

  • Element exclusion: Specify elements to exclude from formatting

SVG Export

Views can be exported to SVG with automatic symbol rendering:

svg_string = my_view.to_svg()
my_view.to_svg(filepath="diagram.svg")

Features:

  • ArchiMate symbols: Official symbol definitions for all element types

  • Standard colors: ArchiMate-compliant color palette

  • Orthogonal routing: Connections use horizontal/vertical segments

  • Relationship styling: Official ArchiMate relationship rendering

Configuration Options

LayoutConfig parameters:

config = LayoutConfig(
    algorithm="force_directed",        # or "hierarchical"
    spacing=50,                        # Element spacing in pixels
    margin=20,                         # Canvas margin in pixels
    alignment="free",                  # or "grid" for grid snapping
    grid_size=10,                      # Grid cell size when alignment="grid"
    excluded_element_ids=[],           # Element IDs to exclude from repositioning
    routing_style="orthogonal",        # or "mixed_45" for diagonal segments
    layer_priority="mandatory",        # or "soft" for layer constraints
    node_size_constraints={}           # Optional min/max size constraints
)

Edge Cases

The layout algorithms handle several edge cases gracefully:

  • Single element: No layout needed, element remains at original position

  • No connections: Elements distributed across canvas using repulsion

  • Circular dependencies: Detected and resolved using topological analysis

  • Disconnected components: Each component laid out independently

  • Identical element sizes: Variance tracking ensures consistent spacing

Error Handling

Layout operations return a LayoutResult object:

result = apply_layout(view, config)

if result.success:
    print(f"Success: {result.elements_processed} elements laid out")
else:
    print(f"Error: {result.error_message}")
    print(f"Quality metrics: {result.quality_metrics}")

Common error scenarios:

  • Invalid algorithm name β†’ ValueError raised

  • Invalid spacing/margin values β†’ ValueError raised

  • Invalid configuration β†’ ValueError raised

  • Layout timeout β†’ operation completes with partial results

Undo/Rollback

Layout operations can be undone:

from pyArchimate.view.layout import undo_layout

# Apply layout
result = apply_layout(view, config)

# Undo to restore previous positions
undo_result = undo_layout(view)

if undo_result.success:
    print("Layout undone, original positions restored")

Performance Targets

Benchmark results on modern hardware (Intel i7, 16GB RAM):

  • Force-directed 100 elements: <500ms

  • Force-directed 300 elements: <2 seconds

  • Force-directed 500 elements: <5 seconds

  • Hierarchical 300 elements: <1 second

  • Hierarchical 500 elements: <1 second

SVG export overhead: <5% additional time

Advanced Topics

Custom Element Sizing

Override standard sizing for specific elements:

# Per-element override
element.width = 150
element.height = 80

# Or use size constraints in config
config = LayoutConfig(
    node_size_constraints={
        "min_width": 100,
        "max_width": 200,
        "min_height": 50,
        "max_height": 150
    }
)

Element Exclusion

Exclude specific elements from repositioning:

config = LayoutConfig(excluded_element_ids=[elem1.id, elem2.id])
result = apply_layout(view, config)
# elem1 and elem2 remain at original positions

Routing Styles

Two routing styles for connections:

  • orthogonal: Horizontal/vertical segments only (default, clean appearance)

  • mixed_45: Horizontal/vertical with optional Β±45Β° angles (more direct paths)

config = LayoutConfig(routing_style="mixed_45")
result = apply_layout(view, config)

Layer Constraints

Two modes for enforcing ArchiMate layer hierarchy:

  • mandatory: Strictly enforce Business > Application > Technology > Motivation

  • soft: Prefer layer order but allow violations if needed for layout

config = LayoutConfig(layer_priority="soft")  # More flexible layout
result = apply_layout(view, config)

Troubleshooting

Layout appears too dense

  • Increase spacing parameter (default 50, try 75-100)

  • Try hierarchical algorithm instead of force-directed

Elements are scattered too far

  • Increase margin parameter (adds inward force near edges)

  • Try smaller spacing value

Layout takes too long

  • Force-directed with 500+ elements may take 5-10 seconds

  • Use hierarchical algorithm for faster results

  • Reduce spacing to decrease force calculation iterations

Connections overlap too much

  • Increase spacing to create more room

  • Try different routing style (mixed_45)

  • Check if element exclusion is inadvertently skipping elements

See Also