Skip to main content

Automatic layout of Blender node trees

Project description

arrangebpy

Automatic layout of nodes for Blender node trees - A clean, library-focused Python module implementing multiple graph layout algorithms.

Ported from the excellent node-arrange Blender add-on, redesigned as a standalone module for use in other add-ons and tools.

Features

🎨 Multiple Layout Algorithms

  • Sugiyama: Hierarchical layout with minimal edge crossings (default)
  • Topological: Fast layered layout for quick results
  • Grid: Regular grid arrangement, great for organization
  • Orthogonal: Clean orthogonal edge routing for presentations

Complete Sugiyama Implementation

  • Hierarchical node layout with minimal edge crossings
  • Frame-aware layout (respects Blender's node frames)
  • Multi-input socket handling
  • Reroute node optimization

🎛️ Highly Configurable

  • 5 layout directions: Balanced, Left-Up, Right-Down, etc.
  • 3 socket alignment modes: None, Moderate, Full
  • Node stacking: Automatically stack collapsed math nodes
  • Iterative refinement: Better layouts for complex frame hierarchies
  • Adjustable spacing: Control horizontal and vertical spacing

🔧 Clean API Design

  • Unified layout() function for all algorithms
  • Settings-based configuration (no global state)
  • Type-safe with full type hints
  • Well-documented with examples
  • Designed for embedding in other add-ons

Installation

pip install arrangebpy

Or with uv:

uv add arrangebpy

Quick Start

from arrangebpy import layout, LayoutSettings

# Simple usage with defaults (uses Sugiyama)
layout(node_tree)

# Choose a specific algorithm
layout(node_tree, algorithm="topological")  # Fast layout
layout(node_tree, algorithm="grid")         # Grid layout
layout(node_tree, algorithm="orthogonal")   # Orthogonal edges

# Custom settings
from arrangebpy import LayoutSettings
settings = LayoutSettings(
    direction="BALANCED",
    socket_alignment="MODERATE",
    horizontal_spacing=60.0,
    vertical_spacing=30.0,
)
layout(node_tree, algorithm="sugiyama", settings=settings)

Legacy API (Still Supported)

from arrangebpy import sugiyama_layout, LayoutSettings

# Direct function calls still work
sugiyama_layout(node_tree)
sugiyama_layout(node_tree, LayoutSettings(horizontal_spacing=60.0))

Layout Algorithms

Sugiyama (Hierarchical)

Best for most node trees. Creates a hierarchical left-to-right layout with minimal edge crossings.

from arrangebpy import layout, LayoutSettings

layout(ntree, algorithm="sugiyama", settings=LayoutSettings(
    direction="BALANCED",
    socket_alignment="FULL",
    stack_collapsed=True,  # Stack collapsed math nodes
    align_top_layer=True   # Align input/output at top
))

Special Feature - Flat Top Layout:

# Align source and sink nodes (input/output) at Y=0, push others below
layout(ntree, algorithm="sugiyama", settings=LayoutSettings(
    align_top_layer=True  # Clean flat top with I/O aligned
))

Use when: You want the highest quality layout with minimal crossings (shader trees, geometry nodes, etc.)

Topological (Fast Layered)

Quick and simple layered layout without crossing reduction. Much faster than Sugiyama.

from arrangebpy import layout, TopologicalSettings

layout(ntree, algorithm="topological", settings=TopologicalSettings(
    horizontal_spacing=60.0,
    sort_by_degree=True  # Sort nodes by connection count
))

# For perfectly flat horizontal layouts (all nodes at Y=0)
layout(ntree, algorithm="topological", settings=TopologicalSettings(
    flatten=True  # Perfect for simple linear chains
))

Use when: You need quick layouts during development, have very large graphs, or want a perfectly flat horizontal layout.

Grid

Arranges nodes in a regular grid pattern, optionally grouping by type or cluster.

from arrangebpy import layout, GridSettings

layout(ntree, algorithm="grid", settings=GridSettings(
    columns=5,
    grouping="TYPE",  # Group by node type
    cell_width=250.0
))

Use when: You want to organize collections of nodes or create inventory-style layouts.

Orthogonal (Clean Edges)

Uses Sugiyama for node placement but routes edges with only horizontal/vertical segments.

from arrangebpy import layout, OrthogonalSettings

layout(ntree, algorithm="orthogonal", settings=OrthogonalSettings(
    horizontal_spacing=80.0,  # More space for routing
    socket_alignment="FULL"
))

Use when: You need professional-looking layouts for presentations or documentation.

Usage Examples

Default Layout (Sugiyama)

from arrangebpy import layout

# Uses sensible defaults
layout(material.node_tree)

Shader Node Trees (with stacking)

from arrangebpy import LayoutSettings
from arrangebpy.arrange.sugiyama import sugiyama_layout

settings = LayoutSettings(
    # Stack collapsed math nodes
    stack_collapsed=True,
    stack_margin_y_factor=0.4,
    
    # Full socket alignment for cleaner connections
    socket_alignment="FULL",
    
    # Balanced direction
    direction="BALANCED",
    
    # Tight spacing
    horizontal_spacing=50.0,
    vertical_spacing=20.0,
)

sugiyama_layout(shader_node_tree, settings)

Geometry Node Trees

settings = LayoutSettings(
    # More spacing for larger nodes
    horizontal_spacing=70.0,
    vertical_spacing=30.0,
    
    # Left-to-right flow
    direction="RIGHT_DOWN",
    
    # Moderate socket alignment
    socket_alignment="MODERATE",
    
    # High quality layout
    iterations=20,
    crossing_reduction_sweeps=48,
)

sugiyama_layout(geometry_node_tree, settings)

Configuration

All configuration through the LayoutSettings dataclass:

from arrangebpy import LayoutSettings

settings = LayoutSettings(
    # Spacing
    horizontal_spacing=50.0,      # Horizontal spacing between columns
    vertical_spacing=25.0,        # Vertical spacing between nodes
    
    # Layout algorithm
    direction="BALANCED",         # Layout direction
    socket_alignment="MODERATE",  # Socket alignment mode
    iterations=20,                # BK algorithm refinement iterations
    crossing_reduction_sweeps=24, # Edge crossing minimization passes
    
    # Features
    add_reroutes=True,           # Add reroute nodes for clean routing
    stack_collapsed=False,       # Stack collapsed math nodes
    stack_margin_y_factor=0.5,   # Spacing factor for stacks (0-1)
)

Direction Options

  • "BALANCED" - Combines all 4 directions (default, best results)
  • "LEFT_DOWN" - Top-left alignment
  • "RIGHT_DOWN" - Bottom-right alignment
  • "LEFT_UP" - Bottom-left alignment
  • "RIGHT_UP" - Top-right alignment

Socket Alignment Options

  • "NONE" - Only align node tops (fastest)
  • "MODERATE" - Smart alignment based on node heights (default)
  • "FULL" - Always align sockets (cleanest connections)

Use in Blender Add-ons

import bpy
from arrangebpy import LayoutSettings
from arrangebpy.arrange.sugiyama import sugiyama_layout

class MY_OT_ArrangeNodes(bpy.types.Operator):
    bl_idname = "node.my_arrange"
    bl_label = "Arrange Nodes"
    
    def execute(self, context):
        ntree = context.space_data.edit_tree
        
        # Configure based on node tree type
        if ntree.bl_idname == 'ShaderNodeTree':
            settings = LayoutSettings(
                stack_collapsed=True,
                socket_alignment="FULL",
            )
        else:
            settings = LayoutSettings()
        
        sugiyama_layout(ntree, settings)
        return {'FINISHED'}

How It Works

Implements the Sugiyama hierarchical graph layout framework:

  1. Graph Construction - Build directed graph from node tree
  2. Ranking - Assign nodes to horizontal layers
  3. Crossing Minimization - Reduce edge crossings via median heuristic
  4. Coordinate Assignment - Place nodes using Brandes-Köpf algorithm
  5. Edge Routing - Add bend points for clean connections
  6. Realization - Apply positions back to Blender

Architecture

arrangebpy/
├── settings.py              # Configuration
├── arrange/
│   ├── sugiyama.py         # Main orchestration
│   ├── graph.py            # Graph construction
│   ├── ranking.py          # Rank assignment
│   ├── ordering.py         # Crossing minimization
│   ├── placement/
│   │   ├── bk.py           # Brandes-Köpf algorithm
│   │   └── linear_segments.py
│   ├── coordinates.py      # X-coordinate assignment  
│   ├── routing.py          # Edge routing
│   ├── stacking.py         # Node stacking
│   └── ...
└── utils.py

Development

git clone https://github.com/BradyAJohnston/arrangebpy.git
cd arrangebpy

# Install
uv sync

# Run tests
uv run pytest tests/

License

GPL-3.0-or-later

Credits

Based on node-arrange by Leonardo Pike-Excell

Implements algorithms from Sugiyama et al., Brandes & Köpf, and others.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arrangebpy-0.1.0.tar.gz (63.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arrangebpy-0.1.0-py3-none-any.whl (67.5 kB view details)

Uploaded Python 3

File details

Details for the file arrangebpy-0.1.0.tar.gz.

File metadata

  • Download URL: arrangebpy-0.1.0.tar.gz
  • Upload date:
  • Size: 63.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for arrangebpy-0.1.0.tar.gz
Algorithm Hash digest
SHA256 230f57781838889aa2a10c71cea2d435eb0b27bf13fdcfe5ec22e093b36bafe6
MD5 b118f8fb0f54f101eeda9f749d02efee
BLAKE2b-256 d7fdd11c47a133f09e76d252497ee223c22de7ab53f056b78e3cb66774ffa306

See more details on using hashes here.

Provenance

The following attestation bundles were made for arrangebpy-0.1.0.tar.gz:

Publisher: pypi.yml on BradyAJohnston/arrangebpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file arrangebpy-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: arrangebpy-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 67.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for arrangebpy-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 ce383bb51bf95b8c7c70a2b0b2197f782a8e9ede2bacb18616f87077e5f05bfd
MD5 a44d5a026ea670312bbfb3f81d1f5c39
BLAKE2b-256 06183eee56801d93e678c07cdf39aaad81513f4fb8572244e0b0178cc383e3bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for arrangebpy-0.1.0-py3-none-any.whl:

Publisher: pypi.yml on BradyAJohnston/arrangebpy

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page