Visualization Module API
The visualization module provides graph rendering capabilities using Graphviz.
Module: graph_renderer.py
Generates visual representations of circuit DAGs.
Functions
visualize_gate_graph(dag_filename, output_filename=None)
Create and save a graph visualization from a DAG JSON file.
Parameters:
dag_filename(str): Name of DAG JSON file indata/dag_output/output_filename(str, optional): Custom output filename (default:<dag_filename>_graph.png)
Returns:
str: Path to the generated PNG file
Example:
from opentestability.visualization.graph_renderer import visualize_gate_graph
# Default output name
png_path = visualize_gate_graph("circuit_dag.json")
# Creates: data/graphs/circuit_dag_graph.png
# Custom output name
png_path = visualize_gate_graph("circuit_dag.json", "my_circuit.png")
# Creates: data/graphs/my_circuit.png
CLI Usage:
python3 -m opentestability.visualization.graph_renderer circuit_dag.json
load_dag(dag_filename)
Load DAG data from JSON file.
Parameters:
dag_filename(str): Name of DAG JSON file indata/dag_output/
Returns:
tuple:(edges, labels, primary_inputs, primary_outputs)where:edges(list): List of[source, target]edge pairslabels(dict): Node label mappingsprimary_inputs(list): Primary input signal namesprimary_outputs(list): Primary output signal names
Raises:
FileNotFoundError: If DAG file doesn’t exist
Example:
from opentestability.visualization.graph_renderer import load_dag
edges, labels, pi, po = load_dag("circuit_dag.json")
print(f"Graph has {len(edges)} edges")
print(f"Inputs: {pi}")
print(f"Outputs: {po}")
create_graph_visualization(edges, labels, primary_inputs, primary_outputs)
Create a styled Graphviz graph from DAG data.
Parameters:
edges(list): List of[source, target]edge pairslabels(dict): Node label mappingsprimary_inputs(list): Primary input signal namesprimary_outputs(list): Primary output signal names
Returns:
pygraphviz.AGraph: Configured Graphviz graph object
Example:
from opentestability.visualization.graph_renderer import (
load_dag, create_graph_visualization
)
edges, labels, pi, po = load_dag("circuit_dag.json")
graph = create_graph_visualization(edges, labels, pi, po)
# Customize further
graph.graph_attr['rankdir'] = 'TB' # Top to bottom layout
graph.layout(prog='dot')
graph.draw('custom_output.png')
format_gate_label(label)
Format gate labels for better visualization.
Parameters:
label(str): Original label string
Returns:
str: Formatted label (truncated if too long)
Example:
from opentestability.visualization.graph_renderer import format_gate_label
label = format_gate_label("very_long_signal_name (AND2X1)")
# Returns truncated version for display
render_graph_with_custom_style(dag_filename, style_config=None)
Render graph with custom styling options.
Parameters:
dag_filename(str): Name of DAG JSON filestyle_config(dict, optional): Custom style settings
Returns:
str: Path to the generated visualization
Default Style Config:
{
'input_color': '#aec7e8', # Light blue
'output_color': '#98df8a', # Light green
'gate_color': '#ffbb78', # Light orange
'wire_color': '#d3d3d3', # Light gray
'edge_color': '#000000', # Black
'font_name': 'Arial',
'font_size': 10,
'node_shape': 'box',
'rankdir': 'LR' # Left to right
}
Example:
from opentestability.visualization.graph_renderer import render_graph_with_custom_style
# Custom dark theme
dark_style = {
'input_color': '#4a90e2',
'output_color': '#50c878',
'gate_color': '#ff6b6b',
'wire_color': '#cccccc',
'edge_color': '#333333',
'font_name': 'Courier',
'font_size': 12,
'rankdir': 'TB' # Top to bottom
}
render_graph_with_custom_style("circuit_dag.json", dark_style)
Visual Styling
Node Types and Colors
The visualization uses different colors for different node types:
| Node Type | Default Color | Description |
|---|---|---|
| Primary Input | Light Blue (#aec7e8) |
Circuit inputs |
| Primary Output | Light Green (#98df8a) |
Circuit outputs |
| Gate | Light Orange (#ffbb78) |
Logic gates |
| Wire | Light Gray (#d3d3d3) |
Intermediate signals |
Layout Algorithms
Graphviz supports multiple layout engines via the prog parameter:
| Engine | Best For | Characteristics |
|---|---|---|
dot |
Hierarchical graphs | Directed, top-down |
neato |
Undirected graphs | Spring model |
fdp |
Large graphs | Force-directed |
sfdp |
Very large graphs | Scalable force-directed |
circo |
Circular layout | Radial |
twopi |
Radial layout | Tree structure |
Example:
from opentestability.visualization.graph_renderer import (
load_dag, create_graph_visualization
)
edges, labels, pi, po = load_dag("circuit_dag.json")
graph = create_graph_visualization(edges, labels, pi, po)
# Try different layouts
for layout in ['dot', 'neato', 'fdp']:
graph.layout(prog=layout)
graph.draw(f'circuit_{layout}.png')
Advanced Usage
Custom Node Attributes
import pygraphviz as pgv
from opentestability.visualization.graph_renderer import load_dag
edges, labels, pi, po = load_dag("circuit_dag.json")
# Create custom graph
G = pgv.AGraph(directed=True, strict=False)
G.graph_attr['rankdir'] = 'LR'
G.graph_attr['dpi'] = '300' # High resolution
# Add nodes with custom attributes
for node, label in labels.items():
if node in pi:
G.add_node(node, label=label, shape='ellipse',
fillcolor='lightblue', style='filled')
elif node in po:
G.add_node(node, label=label, shape='ellipse',
fillcolor='lightgreen', style='filled')
else:
G.add_node(node, label=label, shape='box',
fillcolor='wheat', style='filled')
# Add edges with weights
for source, target in edges:
G.add_edge(source, target, color='gray', penwidth=2)
G.layout(prog='dot')
G.draw('custom_circuit.png')
Highlighting Critical Paths
from opentestability.visualization.graph_renderer import (
load_dag, create_graph_visualization
)
# Load graph
edges, labels, pi, po = load_dag("circuit_dag.json")
graph = create_graph_visualization(edges, labels, pi, po)
# Highlight specific paths (e.g., from SCOAP analysis)
critical_signals = ['n15', 'n23', 'n45']
for node in critical_signals:
n = graph.get_node(node)
n.attr['fillcolor'] = 'red'
n.attr['style'] = 'filled'
graph.layout(prog='dot')
graph.draw('critical_path.png')
Subgraph Visualization
from opentestability.visualization.graph_renderer import load_dag
import pygraphviz as pgv
edges, labels, pi, po = load_dag("large_circuit_dag.json")
# Extract subgraph around a specific node
center_node = 'n25'
depth = 2
# BFS to find nearby nodes
from collections import deque
visited = set()
queue = deque([(center_node, 0)])
subgraph_nodes = set()
while queue:
node, d = queue.popleft()
if d <= depth and node not in visited:
visited.add(node)
subgraph_nodes.add(node)
# Add neighbors
for src, tgt in edges:
if src == node:
queue.append((tgt, d + 1))
# Create subgraph
G = pgv.AGraph(directed=True)
for node in subgraph_nodes:
G.add_node(node, label=labels.get(node, node))
for src, tgt in edges:
if src in subgraph_nodes and tgt in subgraph_nodes:
G.add_edge(src, tgt)
G.layout(prog='dot')
G.draw(f'subgraph_{center_node}.png')
Output Formats
Supported Formats
Graphviz supports multiple output formats:
from opentestability.visualization.graph_renderer import (
load_dag, create_graph_visualization
)
edges, labels, pi, po = load_dag("circuit_dag.json")
graph = create_graph_visualization(edges, labels, pi, po)
graph.layout(prog='dot')
# Different output formats
graph.draw('circuit.png') # PNG (default)
graph.draw('circuit.pdf') # PDF (vector)
graph.draw('circuit.svg') # SVG (vector)
graph.draw('circuit.ps') # PostScript
graph.draw('circuit.dot') # DOT source
Resolution Control
# High-resolution output for publications
graph.graph_attr['dpi'] = '300'
graph.draw('high_res_circuit.png')
# Lower resolution for quick previews
graph.graph_attr['dpi'] = '72'
graph.draw('preview_circuit.png')
Integration Examples
With SCOAP Results
import json
from opentestability.visualization.graph_renderer import (
load_dag, create_graph_visualization
)
# Load DAG
edges, labels, pi, po = load_dag("circuit_dag.json")
# Load SCOAP results
with open("data/results/scoap_results.json", 'r') as f:
scoap = json.load(f)
# Create graph
graph = create_graph_visualization(edges, labels, pi, po)
# Color nodes by controllability (CC0 + CC1)
for node in labels:
if node in scoap:
cc = scoap[node]['CC0'] + scoap[node]['CC1']
# Red = hard to control, Green = easy to control
if cc > 10:
color = 'red'
elif cc > 5:
color = 'yellow'
else:
color = 'lightgreen'
n = graph.get_node(node)
n.attr['fillcolor'] = color
n.attr['style'] = 'filled'
graph.layout(prog='dot')
graph.draw('scoap_colored_circuit.png')
With Reconvergence Analysis
import json
from opentestability.visualization.graph_renderer import (
load_dag, create_graph_visualization
)
# Load data
edges, labels, pi, po = load_dag("circuit_dag.json")
with open("data/reconvergence_output/circuit_reconv.json", 'r') as f:
reconv = json.load(f)
# Create graph
graph = create_graph_visualization(edges, labels, pi, po)
# Highlight reconvergence points
reconv_points = set()
for rc in reconv:
reconv_points.add(rc['fanout_point'])
reconv_points.add(rc['reconverge_point'])
for node in reconv_points:
n = graph.get_node(node)
n.attr['fillcolor'] = 'orange'
n.attr['style'] = 'filled'
n.attr['penwidth'] = 3
graph.layout(prog='dot')
graph.draw('reconvergence_highlighted.png')
Performance
Large Graphs
For circuits with 1000+ nodes:
- dot: Best for hierarchical circuits
- sfdp: Best for large flat circuits
- Rendering time: 1-10 seconds
- Output size: 100KB - 10MB (PNG)
Optimization Tips
- Use subgraph visualization for exploration
- Reduce node labels for large graphs
- Use vector formats (SVG/PDF) for scalability
- Adjust DPI based on usage (72 for screen, 300 for print)
# For large circuits, simplify labels
def simplify_label(label):
# Remove gate types for cleaner view
return label.split('(')[0]
for node in graph.nodes():
n = graph.get_node(node)
n.attr['label'] = simplify_label(n.attr['label'])
Dependencies
Required Packages
- pygraphviz: Python interface to Graphviz
pip install pygraphviz
System Requirements
- Graphviz: System-level installation required
# Linux/WSL sudo apt-get install graphviz graphviz-dev # macOS brew install graphviz # Windows # Download from graphviz.org and add to PATH
Troubleshooting
Common Issues
ImportError: pygraphviz
# Install system graphviz first, then:
pip install --upgrade pygraphviz
Layout engine not found
# Check available programs
import pygraphviz as pgv
print(pgv.AGraph().layout_programs())
Memory issues with large graphs
# Use sfdp for large graphs
graph.layout(prog='sfdp')
# Or reduce graph size with subgraph extraction