ascii-petgraph
ASCII visualization for petgraph directed graphs. Render your graphs in the terminal with force-directed layouts and Unicode box-drawing.
╭───────╮
│ Start │
╰───────╯
│ init
└───────────┐
↓
╭─────────╮
│ Loading │────→╭───────╮
╰─────────╯ │ Ready │
↑ ╰───────╯
│ │
│retry │complete
↓ ↓
╭───────╮ ╭──────╮
│ Error │─────→│ Done │
╰───────╯ ╰──────╯
Features
- Force-directed layout - Physics simulation with spring forces, repulsion, and gravity
- Unicode box-drawing - Beautiful node boxes and edge routing with arrows
- Configurable styles - Single, double, rounded, or ASCII borders
- Ratatui integration - Drop-in widget for TUI applications
- Mutable color API - Change node/edge colors after layout
- Extension trait - Add
.to_ascii()to any petgraph graph
Installation
Add to your Cargo.toml:
[]
= "0.1"
= "0.8"
= "0.29" # Optional, for TUI rendering
Quick Start
Basic Usage
use DiGraph;
use RenderedGraph;
Extension Trait (Recommended)
Import AsciiGraphExt to add .to_ascii() method to any petgraph graph:
use DiGraph;
use AsciiGraphExt;
let mut graph = new;
let a = graph.add_node;
let b = graph.add_node;
graph.add_edge;
// Extension method - works on DiGraph, StableGraph, DiGraphMap
let mut rendered = graph.to_ascii;
rendered.run_simulation;
Ratatui Widget
use ;
use Frame;
Configuration
Builder API
use ;
use DiGraph;
let graph: = /* ... */;
let mut rendered = builder
.graph
.border_style // Rounded corners
.gravity // Stronger downward force
.spring_constant // Tighter clustering
.repulsion_constant // More node separation
.build;
rendered.run_simulation;
Box Border Styles
| Style | Example | Characters |
|---|---|---|
BoxBorder::Single |
┌─┐│└─┘ |
Default |
BoxBorder::Double |
╔═╗║╚═╝ |
Emphasized |
BoxBorder::Rounded |
╭─╮│╰─╯ |
Modern |
BoxBorder::Ascii |
+-+|+-+ |
Compatible |
use BoxBorder;
rendered.set_border_style;
Colors
Change colors after the graph is created (colors don't affect layout):
use Color;
// Individual nodes
rendered.set_node_border_color;
rendered.set_node_text_color;
// Individual edges
rendered.set_edge_color;
rendered.set_edge_text_color;
// Bulk operations
rendered.set_all_node_border_colors;
rendered.set_all_edge_colors;
// Reset to defaults
rendered.reset_node_styles;
rendered.reset_edge_styles;
Scaling for Large Graphs
When graphs exceed terminal width, use scaling modes:
use ScalingMode;
// Truncate long labels to 8 chars
rendered.set_scaling_mode;
// Use numeric IDs (0, 1, 2...) instead of labels
rendered.set_scaling_mode;
// Auto-detect best mode for terminal width
rendered.auto_scale; // 80-column terminal
Supported Graph Types
The AsciiGraphExt trait is implemented for:
| Type | Description |
|---|---|
DiGraph<N, E> |
Standard directed graph |
StableGraph<N, E> |
Directed graph with stable indices |
DiGraphMap<N, E> |
Directed graph with hashable nodes |
Both owned and referenced graphs are supported:
// Owned (graph is consumed)
let rendered = graph.to_ascii;
// Reference (graph can still be used)
let rendered = .to_ascii;
Physics Simulation
The layout uses force-directed simulation:
- Spring forces: Edges pull connected nodes together
- Repulsion forces: Nodes push each other apart
- Gravity: Pulls nodes downward (root nodes float up, sinks settle down)
- Damping: Velocities decay for stability
Manual Simulation Control
// Step-by-step simulation
while !rendered.is_stable
// Or run to completion
rendered.run_simulation;
println!;
Physics Parameters
| Parameter | Default | Effect |
|---|---|---|
spring_constant |
0.05 | Higher = tighter edge clustering |
spring_length |
150.0 | Ideal edge length in physics units |
repulsion_constant |
10000.0 | Higher = more node separation |
gravity |
0.3 | Downward force strength |
damping |
0.85 | Velocity decay (0-1) |
max_iterations |
1000 | Simulation limit |
Examples
Run the examples:
# Basic terminal output
# Interactive TUI with colors
State Machine Example
use DiGraph;
use ;
use Color;
let mut graph = new;
let idle = graph.add_node;
let running = graph.add_node;
let paused = graph.add_node;
let done = graph.add_node;
graph.add_edge;
graph.add_edge;
graph.add_edge;
graph.add_edge;
let mut rendered = builder
.graph
.border_style
.build;
rendered.run_simulation;
// Color by state
rendered.set_node_border_color;
rendered.set_node_border_color;
rendered.set_node_border_color;
rendered.set_node_border_color;
API Reference
Core Types
| Type | Description |
|---|---|
RenderedGraph<N, E> |
Main type holding graph + layout + styles |
RenderedGraphBuilder<N, E> |
Builder for configuration |
BoxBorder |
Node border style enum |
NodeStyle |
Per-node styling (border, colors) |
EdgeStyle |
Per-edge styling (line color, text color) |
ScalingMode |
Label handling for large graphs |
Key Methods
Comparison with ascii-dag
| Feature | ascii-petgraph | ascii-dag |
|---|---|---|
| Layout Algorithm | Force-directed | Sugiyama (layered) |
| Input | petgraph types | Custom DAG type |
| Best For | General graphs | DAGs / hierarchies |
| Animation | Simulation steps | Static |
| Dependencies | petgraph, ratatui | Zero |
Use ascii-petgraph when you already have a petgraph graph and want physics-based layout. Use ascii-dag for zero-dependency DAG visualization with hierarchical layout.
License
MIT License - Copyright (c) 2026 Eleftherios Ioannidis, Microsoft Corporation
See LICENSE for details.