Skip to content

05_02_01_visualization_engine - Motor de Renderización Visual

🎨 Propósito

El Visualization Engine transforma la estructura abstracta del grafo en representaciones visuales comprensibles usando algoritmos de layout que minimizan cruces y maximizan legibilidad. Soporta múltiples formatos de salida para diferentes contextos de uso.

🏗️ Arquitectura

Componentes Principales

05_02_01_visualization_engine/
├── layout_engine.hpp       # Algoritmos de layout
├── renderers.hpp           # Backends de renderización
├── d3_template.html        # Template interactivo web
└── README.md              # Documentación

🔄 Pipeline de Visualización

Graph Structure
Layout Algorithm (position nodes/edges)
Rendering Backend (generate output format)
Visual Output (DOT, JSON, ASCII, Mermaid, HTML)

📐 Algoritmos de Layout

1. Hierarchical Layout (Sugiyama's Framework)

Mejor para: Grafos de dependencias DSP con jerarquía clara

Algoritmo: 1. Layer Assignment: Agrupar nodos por nivel jerárquico (L0→L1→L2→L3) 2. Crossing Minimization: Ordenar nodos dentro de capas usando heurística barycenter 3. Coordinate Assignment: Posicionar nodos minimizando longitud de aristas

Uso:

#include "layout_engine.hpp"

using namespace audio_lab::dependency_graph::visualization;

Graph graph = /* ... */;

LayoutConfig config;
config.width = 1200.0;
config.height = 800.0;
config.level_spacing = 150.0;

HierarchicalLayout layout(graph, config);
LayoutMap positions = layout.compute();

Output:

L3 [Engine] ──────────┐
L2     [Cell_A] ← [Cell_B]
          ↓           ↓
L1   [Atom_X] ← [Atom_Y]
       ↓   ↓
L0  [K_add] [K_mul]

2. Force-Directed Layout (Fruchterman-Reingold)

Mejor para: Exploración libre, detección de clusters

Algoritmo: - Nodos se repelen entre sí (como partículas cargadas) - Aristas atraen nodos conectados (como resortes) - Sistema converge a equilibrio visualmente balanceado

Parámetros: - node_spacing: Distancia óptima entre nodos (k) - max_iterations: Iteraciones de simulación (típico: 50-100) - temperature: Temperatura inicial (controla movimiento) - cooling_factor: Decay por iteración (típico: 0.95)

Uso:

ForceDirectedLayout layout(graph, config);
LayoutMap positions = layout.compute();

3. Circular Layout

Mejor para: Visualizar simetría, detectar patrones circulares

Algoritmo: - Distribuir nodos equidistantes en círculo - Radio = 40% de min(width, height)

Uso:

CircularLayout layout(graph, config);
LayoutMap positions = layout.compute();

4. Tree Layout (Reingold-Tilford)

Mejor para: Subgrafos arbóreos, jerarquías estrictas

Algoritmo: - Encontrar nodos raíz (sin dependencias) - Calcular profundidad por BFS - Posicionar nivel por nivel

Uso:

TreeLayout layout(graph, config);
LayoutMap positions = layout.compute();

Factory Pattern

// Uso simplificado con factory
LayoutMap positions = LayoutFactory::compute_layout(
    graph,
    LayoutAlgorithm::HIERARCHICAL,
    config
);

🎨 Backends de Renderización

1. GraphViz DOT

Para: Imágenes estáticas de alta calidad (PDF, PNG, SVG)

Características: - Sintaxis DOT estándar - Subgraphs por nivel jerárquico - Colorización automática - Tooltips con métricas - Estilos por estado (stable=sólido, beta=punteado, etc.)

Uso:

#include "renderers.hpp"

DotRenderer renderer(graph);
std::string dot_output = renderer
    .with_positions(positions)
    .render();

// Guardar y generar imagen
std::ofstream file("graph.dot");
file << dot_output;
file.close();

// Comando externo:
// dot -Tsvg graph.dot -o graph.svg

Output:

digraph DependencyGraph {
  rankdir=BT;
  node [shape=box, style=rounded];

  "add_kernel" [label="Add Kernel\nL0_KERNEL",
                color="#0066CC",
                style="solid,filled"];

  "svf_filter" [label="SVF Filter\nL1_ATOM",
                color="#00AA44",
                style="solid,filled"];

  "svf_filter" -> "add_kernel";
}

2. D3.js JSON

Para: Visualización web interactiva

Características: - JSON compatible con D3.js - Posiciones pre-calculadas o dinámicas - Metadata de nodos/aristas - Estadísticas del grafo

Uso:

D3JsonRenderer renderer(graph);
std::string json_output = renderer
    .with_positions(positions)
    .render();

// Guardar JSON
std::ofstream file("graph.json");
file << json_output;

Output:

{
  "nodes": [
    {
      "id": "add_kernel",
      "label": "Add Kernel",
      "level": "L0_KERNEL",
      "color": "#0066CC",
      "cpu_cycles": 10,
      "x": 500,
      "y": 100
    }
  ],
  "links": [
    {
      "source": 1,
      "target": 0,
      "type": "REQUIRED"
    }
  ]
}

Integración Web: 1. Generar JSON 2. Reemplazar {{GRAPH_DATA}} en d3_template.html 3. Abrir en navegador → Visualización interactiva

3. ASCII Art

Para: Terminal/CLI, visualización rápida

Características: - Árbol jerárquico con box-drawing characters - Información compacta (nivel + CPU) - Detección de ciclos

Uso:

AsciiRenderer renderer(graph);
std::cout << renderer.render();

Output:

└── [L0_KERNEL] Add Kernel (CPU: 10)
    └── [L1_ATOM] SVF Filter (CPU: 120)
        └── [L2_CELL] Synth Voice (CPU: 450)
            └── [L3_ENGINE] Poly Synth (CPU: 2000)

4. Mermaid

Para: Documentación Markdown (GitHub, GitLab)

Características: - Sintaxis Mermaid embebible - Renderiza automáticamente en GitHub - Estilos por nivel (classDef) - Flechas según tipo de dependencia

Uso:

MermaidRenderer renderer(graph);
std::string mermaid = renderer.render();

// Incluir en README.md

Output:

```mermaid
graph TD
  add_kernel["Add Kernel<br/>L0_KERNEL"]:::l0_style
  svf_filter["SVF Filter<br/>L1_ATOM"]:::l1_style
  svf_filter --> add_kernel

  classDef l0_style fill:#0066CC,stroke:#004499,color:#fff
  classDef l1_style fill:#00AA44,stroke:#007722,color:#fff
```

Factory Pattern

std::string output = RenderFactory::render(
    graph,
    RenderFormat::DOT,
    &positions  // opcional
);

🌈 Sistema de Estilos

Colorización por Nivel Jerárquico

Nivel Color Hex Significado
L0_KERNEL 🔵 Azul #0066CC Fundacional (océano profundo)
L1_ATOM 🟢 Verde #00AA44 Crecimiento (bloques vivos)
L2_CELL 🟡 Amarillo #FFAA00 Complejidad media (advertencia)
L3_ENGINE 🔴 Rojo #CC0000 Máxima complejidad (calor)

Estilos por Estado

Estado Estilo GraphViz Mermaid
STABLE Sólido solid -->
BETA Punteado dashed -.->
EXPERIMENTAL Puntos dotted -.->
DEPRECATED Gris + tachado bold,dashed ~~>

Visualización de Métricas

  • CPU usage → Grosor de borde proporcional
  • Many dependencies → Tamaño de nodo más grande
  • Critical path → Aristas más gruesas
  • High betweenness → Nodo destacado

🖥️ Visualización Web Interactiva

Características del Template D3

Controles: - ✅ Selector de layout (Force/Hierarchical/Circular) - ✅ Filtrado por nivel jerárquico - ✅ Filtrado por categoría - ✅ Toggle labels/edges - ✅ Zoom & Pan - ✅ Drag nodes - ✅ Tooltips informativos

Estadísticas en Tiempo Real: - Número de nodos - Número de aristas - Densidad del grafo - Grado promedio

Uso:

# 1. Generar JSON
./visualizer export --format d3-json > graph.json

# 2. Sustituir en template
sed 's/{{GRAPH_DATA}}/'"$(cat graph.json)"'/' d3_template.html > viz.html

# 3. Abrir en navegador
open viz.html

🧪 Testing

Casos de Prueba

TEST_CASE("Hierarchical layout positions nodes correctly") {
    auto graph = create_simple_graph();

    LayoutConfig config;
    config.width = 1000;
    config.height = 800;

    HierarchicalLayout layout(graph, config);
    auto positions = layout.compute();

    // Verificar que L0 está más abajo que L3
    REQUIRE(positions["add_kernel"].y > positions["poly_synth"].y);
}

TEST_CASE("DOT renderer generates valid syntax") {
    auto graph = create_simple_graph();

    DotRenderer renderer(graph);
    std::string dot = renderer.render();

    REQUIRE(dot.find("digraph") != std::string::npos);
    REQUIRE(dot.find("add_kernel") != std::string::npos);
}

Benchmarks

Operación Target Resultado
Hierarchical layout (100 nodes) <50ms
Force-directed (100 nodes, 100 iter) <500ms
DOT render (500 nodes) <100ms
D3 JSON render (500 nodes) <50ms

📊 Complejidad

Algoritmo Tiempo Espacio
Hierarchical O(E + V log V) O(V)
Force-Directed O(I × V²) donde I=iterations O(V)
Circular O(V) O(V)
Tree O(V + E) O(V)
DOT render O(V + E) O(V + E)
JSON render O(V + E) O(V + E)

🔗 Dependencias

# Bibliotecas C++
vcpkg install nlohmann-json:x64-windows

# Herramientas externas (opcional)
# GraphViz para generar imágenes
choco install graphviz
# o
brew install graphviz

📝 Ejemplos Completos

Ejemplo 1: Pipeline Completo

#include "layout_engine.hpp"
#include "renderers.hpp"

// 1. Construir grafo
Graph graph;
GraphBuilder builder(graph);
builder.build_from_catalog("catalog.json");

// 2. Calcular layout
LayoutConfig config;
config.width = 1200;
config.height = 900;

auto positions = LayoutFactory::compute_layout(
    graph,
    LayoutAlgorithm::HIERARCHICAL,
    config
);

// 3. Renderizar en múltiples formatos
auto dot = RenderFactory::render(graph, RenderFormat::DOT, &positions);
auto json = RenderFactory::render(graph, RenderFormat::D3_JSON, &positions);
auto ascii = RenderFactory::render(graph, RenderFormat::ASCII);
auto mermaid = RenderFactory::render(graph, RenderFormat::MERMAID);

// 4. Guardar outputs
save_file("graph.dot", dot);
save_file("graph.json", json);
std::cout << ascii << std::endl;
save_file("ARCHITECTURE.md", "# Architecture\n\n" + mermaid);

Ejemplo 2: Generación de SVG

// Generar DOT
DotRenderer renderer(graph);
std::string dot = renderer.render();

// Guardar
std::ofstream file("output.dot");
file << dot;
file.close();

// Ejecutar GraphViz (requiere graphviz instalado)
system("dot -Tsvg output.dot -o output.svg");
system("dot -Tpng output.dot -o output.png -Gdpi=300");

Ejemplo 3: Visualización Web Standalone

// Generar JSON
D3JsonRenderer renderer(graph);
auto json = renderer.render();

// Leer template
std::ifstream template_file("d3_template.html");
std::string html_template((std::istreambuf_iterator<char>(template_file)),
                          std::istreambuf_iterator<char>());

// Sustituir placeholder
size_t pos = html_template.find("{{GRAPH_DATA}}");
html_template.replace(pos, 14, json);

// Guardar HTML standalone
std::ofstream output("visualization.html");
output << html_template;
output.close();

std::cout << "Open visualization.html in browser" << std::endl;

🚀 Próximos Pasos

Completado: - Layout algorithms (4 tipos) - Rendering backends (4 formatos) - Sistema de estilos completo - Template web interactivo

Pendiente: - Exportación de imágenes desde C++ (sin GraphViz CLI) - Optimización de force-directed para >1000 nodos - Layout híbrido (hierarchical + force dentro de niveles) - Clustering automático para grafos grandes - Progressive rendering para grafos masivos


Status: ✅ Visualización Core Completa Formatos soportados: 4 (DOT, D3-JSON, ASCII, Mermaid) Layouts implementados: 4 (Hierarchical, Force-Directed, Circular, Tree)