Skip to main content

Render directed graphs as ASCII/Unicode art

Project description

graphtty

Render directed graphs as ASCII/Unicode art for console output.

Installation

pip install graphtty

Screenshots

React Agent (monokai theme)

React Agent

Deep Agent (ocean theme)

Deep Agent

Workflow Agent (forest theme)

Workflow Agent

Supervisor Agent (dracula theme)

Supervisor Agent

CLI

Render any graph JSON file straight from the terminal:

graphtty graph.json
graphtty graph.json --theme monokai
graphtty graph.json --ascii
graphtty graph.json --no-types

Options

usage: graphtty [-h] [-t THEME] [--ascii] [--no-types] [--list-themes] [file]

positional arguments:
  file                  Path to a graph JSON file

options:
  -h, --help            show this help message and exit
  -t THEME, --theme THEME
                        Color theme (use --list-themes to see options)
  --ascii               Use plain ASCII instead of Unicode box-drawing characters
  --no-types            Hide node type labels
  --list-themes         List available themes and exit

Themes

Five built-in color themes that style nodes by type:

graphtty graph.json --theme monokai
graphtty graph.json --theme ocean
graphtty graph.json --theme forest
graphtty graph.json --theme dracula
graphtty graph.json                   # default (no color)

List all available themes:

graphtty --list-themes

Python API

Simple linear chain

from graphtty import AsciiGraph, AsciiNode, AsciiEdge, render

graph = AsciiGraph(
    nodes=[
        AsciiNode(id="a", name="Start", type="entry"),
        AsciiNode(id="b", name="Process", type="tool"),
        AsciiNode(id="c", name="End", type="exit"),
    ],
    edges=[
        AsciiEdge(source="a", target="b"),
        AsciiEdge(source="b", target="c"),
    ],
)

print(render(graph))
  ┌ entry ───┐
  │  Start   │
  └────┬─────┘
       │
       ▼
  ┌ tool ────┐
  │ Process  │
  └─────┬────┘
        │
        ▼
  ┌ exit ──┐
  │  End   │
  └────────┘

Branching with edge labels

graph = AsciiGraph(
    nodes=[
        AsciiNode(id="start", name="User Input", type="entry"),
        AsciiNode(id="router", name="Router", type="condition"),
        AsciiNode(id="search", name="Web Search", type="tool"),
        AsciiNode(id="calc", name="Calculator", type="tool"),
        AsciiNode(id="respond", name="Respond", type="model"),
    ],
    edges=[
        AsciiEdge(source="start", target="router"),
        AsciiEdge(source="router", target="search", label="search"),
        AsciiEdge(source="router", target="calc", label="calc"),
        AsciiEdge(source="search", target="respond"),
        AsciiEdge(source="calc", target="respond"),
    ],
)

print(render(graph))
          ┌ entry ─────┐
          │ User Input │
          └──────┬─────┘
                 │
                 ▼
          ┌ condition ─┐
          │   Router   │
          └──────┬─────┘
         ┌search─└──calc──┐
         ▼                ▼
  ┌ tool ──────┐   ┌ tool ──────┐
  │ Web Search │   │ Calculator │
  └──────┬─────┘   └─────┬─────┘
         └──────┌─────────┘
                ▼
          ┌ model ───┐
          │ Respond  │
          └──────────┘

Nested subgraphs

sub = AsciiGraph(
    nodes=[
        AsciiNode(id="s1", name="Fetch Data", type="tool"),
        AsciiNode(id="s2", name="Transform", type="action"),
    ],
    edges=[AsciiEdge(source="s1", target="s2")],
)

graph = AsciiGraph(
    nodes=[
        AsciiNode(id="a", name="Start", type="entry"),
        AsciiNode(id="b", name="ETL Pipeline", type="subgraph", subgraph=sub),
        AsciiNode(id="c", name="Done", type="exit"),
    ],
    edges=[
        AsciiEdge(source="a", target="b"),
        AsciiEdge(source="b", target="c"),
    ],
)

print(render(graph))
      ┌ entry ──┐
      │  Start  │
      └────┬────┘
           │
           ▼
  ┌ subgraph ──────┐
  │  ETL Pipeline  │
  │ ┌ tool ──────┐ │
  │ │ Fetch Data │ │
  │ └──────┬─────┘ │
  │        │       │
  │        ▼       │
  │ ┌ action ────┐ │
  │ │ Transform  │ │
  │ └────────────┘ │
  └───────┬────────┘
          │
          ▼
     ┌ exit ──┐
     │  Done  │
     └────────┘

Node descriptions

graph = AsciiGraph(
    nodes=[
        AsciiNode(id="a", name="LLM", type="model", description="gpt-4o"),
    ],
)

print(render(graph))

Themes (Python API)

from graphtty import render, RenderOptions, get_theme

options = RenderOptions(theme=get_theme("monokai"))
print(render(graph, options))

Render options

from graphtty import RenderOptions

options = RenderOptions(
    use_unicode=True,   # Use Unicode box-drawing characters (default: True)
    show_types=True,    # Show node types in box borders (default: True)
    padding=2,          # Padding around the diagram (default: 2)
)

print(render(graph, options))

JSON format

graphtty reads a simple JSON format:

{
  "nodes": [
    { "id": "a", "name": "Start", "type": "entry" },
    { "id": "b", "name": "Process", "type": "tool", "description": "optional detail" },
    { "id": "c", "name": "End", "type": "exit" }
  ],
  "edges": [
    { "source": "a", "target": "b", "label": "optional" },
    { "source": "b", "target": "c" }
  ]
}

Testing

uv run pytest tests/ -v

Acknowledgements

Built with :heart: on top of grandalf, a Python library for graph layout using the Sugiyama algorithm.

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

graphtty-0.0.1.tar.gz (187.6 kB view details)

Uploaded Source

Built Distribution

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

graphtty-0.0.1-py3-none-any.whl (16.3 kB view details)

Uploaded Python 3

File details

Details for the file graphtty-0.0.1.tar.gz.

File metadata

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

File hashes

Hashes for graphtty-0.0.1.tar.gz
Algorithm Hash digest
SHA256 791f786c6e30382769fed816806569b09a385b3ffa6fe99d779179b65941c078
MD5 303aa2c1a4448a233eacb2d1dc5bb268
BLAKE2b-256 b02a6f5c523593f3b2222d8f0845cb5cad4e84657887daa5f0a5bcba950e0c14

See more details on using hashes here.

Provenance

The following attestation bundles were made for graphtty-0.0.1.tar.gz:

Publisher: cd.yml on cristipufu/graphtty

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

File details

Details for the file graphtty-0.0.1-py3-none-any.whl.

File metadata

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

File hashes

Hashes for graphtty-0.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 ef1548710fcb1a07e8d0ee8d5803ec44d7b1db2bca0cec503004a84d762cd85f
MD5 752ef86e4245b9e5330179b25ca628f8
BLAKE2b-256 e48bda560c321025cffe57848b632a9f2f2c8994179727e844d0ab30a0ad5504

See more details on using hashes here.

Provenance

The following attestation bundles were made for graphtty-0.0.1-py3-none-any.whl:

Publisher: cd.yml on cristipufu/graphtty

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