Implementation:Iterative Dvc Dagascii
| Knowledge Sources | |
|---|---|
| Domains | Visualization, Pipeline_Management |
| Last Updated | 2026-02-10 10:00 GMT |
Overview
ASCII rendering engine for directed acyclic graphs (DAGs), used to display DVC pipeline structures in the terminal, provided by the DVC library.
Description
The dvc/dagascii.py module (299 lines) implements a complete ASCII art renderer for DAGs. It is used by DVC to visualize pipeline stage dependencies in terminal environments where graphical output is not available. The module relies on the grandalf library for graph layout computation and provides its own canvas abstraction for character-based drawing.
The module contains two classes and two functions:
VertexViewer is a lightweight class that defines the bounding box dimensions for each vertex in the graph layout. It computes the width from the vertex name length (plus 2 for box borders) and uses a fixed height of 3 lines (top border, text, bottom border). The grandalf layout algorithm uses these dimensions to avoid vertex overlaps.
AsciiCanvas is the drawing surface. It initializes a 2D character grid of configurable dimensions and provides four drawing primitives: point (single character placement), line (Bresenham-style line drawing between two coordinates), text (horizontal string placement), and box (rectangular box with + corners, - horizontal edges, and | vertical edges). The draw method renders the canvas to a string by joining all rows with the OS line separator.
_build_sugiyama_layout is an internal function that constructs a grandalf Graph from vertex/edge lists, assigns VertexViewer instances and EdgeViewer instances, and computes the Sugiyama layered layout. It identifies root nodes (vertices with no incoming edges), configures spacing based on the minimum vertex width, and uses route_with_lines for edge routing.
draw is the public entry point. It calls _build_sugiyama_layout, computes the bounding box of all vertices and edge control points, shifts coordinates to the positive plane, creates an AsciiCanvas of the appropriate size, draws edges first (as * characters), then draws vertex boxes on top (so boxes overwrite edge characters where they overlap), and returns the final ASCII string.
Usage
Use draw when you need to render a DVC pipeline DAG as ASCII art -- for example, in the dvc dag command, in log output, or in any terminal-based pipeline visualization tool. The function accepts simple vertex and edge lists, making it easy to integrate with any graph data source.
Code Reference
Source Location
- Repository: DVC
- File:
dvc/dagascii.py - Lines: L1-299
Signature
class VertexViewer:
"""Defines vertex box boundaries for grandalf layout.
Args:
name (str): name of the vertex.
"""
HEIGHT = 3
def __init__(self, name):
...
@property
def h(self) -> int:
"""Height of the box."""
...
@property
def w(self) -> int:
"""Width of the box."""
...
class AsciiCanvas:
"""Class for drawing in ASCII.
Args:
cols (int): number of columns in the canvas. Should be > 1.
lines (int): number of lines in the canvas. Should be > 1.
"""
TIMEOUT = 10
def __init__(self, cols, lines):
...
def draw(self) -> str:
...
def point(self, x, y, char):
...
def line(self, x0, y0, x1, y1, char):
...
def text(self, x, y, text):
...
def box(self, x0, y0, width, height):
...
def _build_sugiyama_layout(vertices, edges):
"""Internal: build Sugiyama layered layout from vertex/edge lists."""
...
def draw(vertices, edges) -> str:
"""Build a DAG and draw it in ASCII.
Args:
vertices (list): list of graph vertices.
edges (list): list of graph edges (tuples of vertex pairs).
Returns:
str: ASCII representation of the DAG.
"""
...
Import
from dvc.dagascii import draw
I/O Contract
draw Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| vertices | list |
Yes | List of graph vertex identifiers (typically stage names as strings). |
| edges | list |
Yes | List of edge tuples (source, target) representing directed dependencies between vertices.
|
draw Output
| Name | Type | Description |
|---|---|---|
| (return value) | str |
Multi-line ASCII string rendering of the DAG. Vertices are drawn as boxes with +---+ borders, edges as * characters.
|
AsciiCanvas Drawing Primitives
| Method | Parameters | Description |
|---|---|---|
| point | x, y, char |
Place a single character at coordinates (x, y). |
| line | x0, y0, x1, y1, char |
Draw a line between two points using Bresenham-style rasterization. |
| text | x, y, text |
Print a horizontal string starting at (x, y). |
| box | x0, y0, width, height |
vertical edges. |
| draw | (none) | Render the canvas to a string by joining all rows with the OS line separator. |
Usage Examples
Basic Usage
from dvc.dagascii import draw
# Define a simple pipeline graph
vertices = ["prepare", "train", "evaluate"]
edges = [("prepare", "train"), ("train", "evaluate")]
# Render as ASCII art
ascii_dag = draw(vertices, edges)
print(ascii_dag)
# +----------+
# | evaluate |
# +----------+
# *
# *
# *
# +-------+
# | train |
# +-------+
# *
# *
# *
# +---------+
# | prepare |
# +---------+
Branching Pipeline
from dvc.dagascii import draw
vertices = ["data", "featurize", "train", "evaluate", "report"]
edges = [
("data", "featurize"),
("featurize", "train"),
("featurize", "evaluate"),
("train", "report"),
("evaluate", "report"),
]
print(draw(vertices, edges))