Become a member!

Manual Práctico del Lenguaje DOT (Graphviz) para desarrolladores y analistas

Para desarrolladores, analistas y arquitectos de software que quieren producir diagramas profesionales, claros y visualmente atractivos

  • 🇮🇹 Este artículo también está disponible en italiano.
  • 🇬🇧 This article is also available in english.

Introducción

En el trabajo diario de quienes desarrollan software — ya seas analista, desarrollador backend, frontend, experto en bases de datos o arquitecto — siempre llega el momento en que un diagrama se vuelve fundamental.

Lo necesitas cuando debes:

  • explicar un flujo complejo,
  • diseñar la pipeline CI/CD,
  • presentar la arquitectura a un nuevo colega,
  • analizar dependencias entre módulos,
  • documentar una base de datos,
  • preparar una presentación técnica,
  • razonar sobre un refactoring,
  • identificar cuellos de botella.

Graphviz y su lenguaje DOT son herramientas ideales: textuales (versionables), rápidas de escribir, visualmente atractivas al renderizar, flexibles.

Instalación de Graphviz

Antes de empezar, asegúrate de tener Graphviz instalado:

  • Windows: Descarga el instalador desde graphviz.org/download o usa winget install graphviz
  • macOS: brew install graphviz
  • Linux: sudo apt install graphviz (Debian/Ubuntu) o sudo dnf install graphviz (Fedora/RHEL)

Verifica la instalación con dot -V — deberías ver la versión instalada.

Este manual pretende ser la guía definitiva para quienes en el desarrollo de software quieren usar el lenguaje DOT al máximo. Encontrarás:

  • explicación profunda de los atributos con todas las opciones relevantes,
  • ejemplos completos, reutilizables y comentados,
  • mejores prácticas para gráficos profesionales,
  • sugerencias sobre el uso de los motores de layout,
  • escenarios concretos del mundo del desarrollo (diseño, refactoring, análisis, arquitectura).

El lenguaje DOT: bases sólidas

DOT describe grafos con una sintaxis muy simple:

digraph Nombre {
    nodoA -> nodoB;
}

O sin dirección:

graph Nombre {
    nodoA -- nodoB;
}

Conceptos clave:

  • nodos: entidades (funciones, objetos, microservicios, tablas de BD)
  • arcos: relaciones, llamadas, flujos
  • atributos: aspecto visual o metadatos

Quick Start: tu primer diagrama en 30 segundos

Prueba inmediatamente online (sin instalar nada)

Todos los ejemplos de este artículo se pueden probar directamente online usando Edotor.net:

  1. Ve a edotor.net

  2. Copia el código DOT de cualquier ejemplo de este artículo

  3. Pégalo en el área izquierda (reemplazando el código existente)

  4. Verás el renderizado inmediato en el área derecha

Es la forma más rápida de experimentar sin instalar Graphviz. Cuando estés listo para producción, instala Graphviz localmente.

Primer ejemplo para probar

Copia este código y pruébalo en edotor.net:

digraph MyFirstGraph {
    node [shape=box, style=rounded, fillcolor=lightblue, style="rounded,filled"];
    edge [color=blue];

    Start -> Process -> End;
    Process -> Error [style=dashed, label="on failure"];
    Error -> Process [label="retry"];
}

O usa la línea de comandos local

Crea un archivo hello.dot con el código anterior y genera la imagen SVG:

dot -Tsvg hello.dot -o hello.svg

Abre hello.svg en el navegador y verás tu primer flowchart! De aquí en adelante, todo se basa en variaciones y combinaciones de estos conceptos.


Atributos fundamentales (con opciones completas)

Los atributos se pueden aplicar globalmente a:

  • graph
  • node
  • edge
  • a elementos individuales

Ejemplo:

digraph demo {
    graph [rankdir=LR];
    node [shape=box];
    edge [color=grey];

    A -> B;
}

A continuación, la lista de los atributos más importantes con sus opciones más útiles en el ámbito del software.


Atributos de los nodos (node)

shape — forma del nodo

Opciones útiles:

  • box
  • ellipse
  • circle
  • diamond (decisiones en flows)
  • record (diagramas de clases, estructuras de datos)
  • plaintext (contenidos completamente personalizados con HTML-label)
  • note
  • folder (disponible en algunas builds)

Ejemplo:

node [shape=box];

Usos típicos:

  • box → módulos de software
  • ellipse → estados
  • diamond → decisiones

style — estilo gráfico

Opciones comunes:

  • filled
  • dashed
  • dotted
  • bold
  • rounded
  • combinaciones: "filled,rounded"

Ejemplo:

node [style="filled,rounded"];

fillcolor — color de relleno

Formatos:

  • nombres (ej. "lightgrey")
  • HEX (ej. "#AABBCC")
  • RGB ("#rrggbb")
  • HSL (en algunas builds)

fontname, fontcolor, fontsize

Ej.:

node [fontname="Arial", fontsize=12, fontcolor="#333333"];

margin

Margen interno del nodo.

node [margin="0.2,0.1"];

Atributos de los arcos (edge)

arrowsize

Escala de la flecha. Default ~1.0

edge [arrowsize=0.8];

arrowhead / arrowtail

Opciones útiles:

  • normal
  • empty (triángulo vacío, muy legible)
  • diamond
  • onormal
  • crow (diagramas ER)
  • tee
  • none

style y color

edge [style=dashed, color="#888888"];

label

Etiqueta del arco.

A -> B [label="calls"];

Atributos del grafo (graph)

rankdir

Dirección del layout (solo dot):

  • TB (top → bottom)
  • BT (bottom → top)
  • LR (left → right)
  • RL (right → left)

Ej.:

graph [rankdir=LR];

splines

Controla la forma de los arcos:

  • true (default)
  • false (líneas rectas)
  • polyline
  • ortho (ortogonales, óptimo para diagramas “de arquitecto”)

ranksep, nodesep

Espacios horizontales/verticales.

graph [ranksep=0.8, nodesep=0.6];

Layout Engines: elegir el correcto

Graphviz no tiene un solo motor de renderizado: ofrece varios, cada uno optimizado para tipos específicos de grafos. Elegir el engine correcto significa obtener diagramas más legibles y profesionales.

Se especifica el engine usando el flag -K desde CLI:

dot -Kdot -Tsvg file.dot -o output.svg
dot -Kneato -Tsvg file.dot -o output.svg

O en el propio archivo DOT:

graph G {
    layout=neato;
    // ...
}

A continuación, los principales engines y cuándo usarlos.


Motores de layout disponibles

dot — layout jerárquico (default)

Qué hace: Dispone los nodos de forma jerárquica, siguiendo la dirección de los arcos. Es el más usado.

Perfecto para:

  • Flowcharts y diagramas de flujo
  • Pipelines CI/CD
  • Call graph (grafo de llamadas entre funciones)
  • Arquitecturas por capas (presentation → business → data)
  • Procesos secuenciales
  • Diagramas de dependencias con dirección clara

Ejemplo de comando:

dot -Tsvg flowchart.dot -o flowchart.svg

Cuándo evitarlo: Si el grafo no tiene una estructura jerárquica clara o contiene muchos ciclos.

neato — layout de fuerza física

Qué hace: Posiciona los nodos simulando fuerzas físicas (repulsión/atracción), generando layouts orgánicos y simétricos.

Útil para:

  • Grafos no dirigidos (sin flechas)
  • Redes conceptuales y mapas mentales
  • Relaciones no jerárquicas entre entidades
  • Grafos pequeños/medianos donde quieres evidenciar clusters naturales

Ejemplo de comando:

dot -Kneato -Tsvg concepts.dot -o concepts.svg

Cuándo evitarlo: Con grafos muy grandes (>100 nodos) o fuertemente direccionales.

fdp — force-directed placement

Qué hace: Similar a neato, pero usa un algoritmo diferente (Fruchterman-Reingold). Generalmente más rápido en grafos medianos.

Útil para:

  • Grafos no dirigidos de tamaño medio
  • Visualizaciones de redes sociales (amistades, conexiones)
  • Análisis de dependencias sin dirección fuerte

Ejemplo de comando:

dot -Kfdp -Tsvg network.dot -o network.svg

sfdp — scalable force-directed placement

Qué hace: Versión optimizada de fdp para grafos muy grandes (miles de nodos).

Óptimo para:

  • Análisis de dependencias en codebases complejos
  • Grafo de clases de un proyecto enterprise
  • Redes complejas (infraestructuras, microservicios)
  • Cuando neato o fdp son demasiado lentos

Ejemplo de comando:

dot -Ksfdp -Tsvg dependencies.dot -o dependencies.svg

Tip: Usa sfdp cuando tengas más de 100-200 nodos.

circo — layout circular

Qué hace: Dispone los nodos en círculos concéntricos alrededor de un nodo central.

Ideal para:

  • Visualizar módulos satélite alrededor de un núcleo central
  • Arquitecturas hub-and-spoke
  • Representar componentes que dependen de un servicio central

Ejemplo de comando:

dot -Kcirco -Tsvg modules.dot -o modules.svg

Ejemplo práctico: Un servicio API central con 10 microservicios que lo llaman.

twopi — layout radial

Qué hace: Crea un layout de árbol radial, con el nodo raíz al centro y los niveles que se expanden hacia el exterior.

Perfecto para:

  • Árboles jerárquicos (org chart, sistema de archivos)
  • Taxonomías
  • Mind maps estructurados
  • Visualizar expansiones desde un punto central

Ejemplo de comando:

dot -Ktwopi -Tsvg tree.dot -o tree.svg

Cómo elegir en la práctica

Tipo de grafo Engine recomendado
Flowchart, pipeline, procesos dot
Arquitecturas en capas dot
Call graph, árbol de dependencias dot
Red conceptual, brainstorming neato
Red social, grafos medianos no dirigidos fdp
Grafos grandes (>200 nodos) sfdp
Hub central con satélites circo
Árboles jerárquicos, org chart twopi

Regla práctica: Si tienes flechas y una dirección clara → usa dot. De lo contrario, prueba neato o fdp.


Tipologías de gráficos y cuándo usarlos en la vida real de un developer

Esta es la sección más extensa. Para cada tipo de gráfico encontrarás:

  • Cuándo usarlo en la vida real
  • Atributos recomendados
  • Ejemplo completo

Flowchart: entender el comportamiento

En el trabajo cotidiano sucede a menudo que debemos explicar un flujo decisional complejo: un procedimiento de validación con múltiples ramas, un proceso de onboarding de usuario, o simplemente el comportamiento de una función con muchos if/else anidados. El flowchart es la herramienta ideal para esto.

Cuándo necesitas un flowchart:

Estás en fase de análisis de requisitos y debes entender todos los casos posibles. Estás debuggeando una lógica que parece enloquecida y quieres ver visualmente dónde se bifurca el flujo. Debes escribir documentación para un proceso empresarial complejo. Estás haciendo onboarding de un nuevo colega y quieres mostrarle cómo funciona el sistema de autenticación.

El flowchart muestra visualmente las decisiones (rombos), los procesos (rectángulos redondeados), y el flujo lógico (flechas). Es inmediato, claro, universal.

Atributos recomendados para flowcharts profesionales:

Usa rankdir=TB (top-to-bottom) para seguir la convención estándar de los flowcharts. Usa shape=diamond para los nodos decisionales (las condiciones if/else). Usa style=rounded para los pasos de proceso, así se distinguen de los rombos. Usa colores tenues (fillcolor) para evidenciar inicio (verde claro), errores (rojo claro), fin (gris).

Ejemplo completo:

digraph Flow {
    graph [rankdir=TB, nodesep=0.6];
    node [fontname="Arial"];

    Start   [shape=oval, style=filled, fillcolor="#C1F2C7"];
    Check   [shape=diamond, label="Valid input?"];
    Process [shape=box, style="filled,rounded", fillcolor="#F0F4FF"];
    Error   [shape=box, fillcolor="#FFEAEA", style=filled];
    End     [shape=oval, fillcolor="#DDDDDD", style=filled];

    Start -> Check;
    Check -> Process [label="yes"];
    Check -> Error   [label="no"];
    Process -> End;
}

Qué hace este ejemplo: Parte de un estado inicial (Start), pasa a través de una validación (Check), y se bifurca en dos caminos: éxito (Process) o error (Error). Usa colores para hacer inmediatamente claro qué es positivo y qué negativo.


Grafos de dependencias: entender el software como sistema

Cuando trabajas en un proyecto existente, una de las primeras preguntas que te haces es: “¿Qué depende de qué?” Si debes hacer refactoring de un módulo, quieres saber quién lo usa. Si debes actualizar una librería, quieres entender el impacto en cascada. Si estás diseñando una nueva feature, quieres ver dónde se inserta en la arquitectura existente.

El grafo de dependencias es el mapa de tu sistema. Muestra módulos, servicios, clases o microservicios como nodos, y las dependencias como flechas. Es fundamental para:

Refactoring seguro: Antes de tocar un módulo, ves quién lo llama. Análisis de impacto: Si modificas una API, ves inmediatamente todos los consumidores. Documentación automática: Genera el grafo desde el código (con herramientas como Doxygen, Madge o scripts custom) y mantenlo actualizado. Dependency injection mapping: Visualiza cómo Spring, Angular o .NET inyectan las dependencias.

Atributos útiles:

Usa rankdir=LR (left-to-right) para tener un flujo horizontal, típico de las dependency chains. Usa shape=box para los módulos/servicios. Usa color y penwidth para evidenciar dependencias críticas o problemáticas (ej. dependencias circulares en rojo). Usa style=dashed para dependencias opcionales o débiles.

Ejemplo:

digraph Deps {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F7FAFF", fontname="Inter"];
    edge [color="#555555"];

    UI -> API;
    API -> Auth;
    API -> UserService;
    UserService -> Database [color="#FF5555", penwidth=2, label="critical"];
}

Qué hace este ejemplo: Muestra una arquitectura web clásica: UI llama a API, API depende de Auth y UserService, UserService habla con Database. La dependencia crítica (UserService → Database) está resaltada en rojo con línea gruesa: si la BD cae, todo colapsa.


Arquitectura de software: clusters y capas

Cuando diseñas una arquitectura o documentas la existente, necesitas mostrar agrupamientos lógicos y separación de niveles. Un sistema web típico tiene Presentación, Negocio, Datos. Un proyecto de microservicios tiene límites lógicos (edge, services, datastores). Un sistema legacy podría tener módulos separados por dominio.

El diagrama de arquitectura con clusters te permite:

Visualizar capas separadas: Presentation Layer, Business Layer, Data Layer. Cada capa es un box coloreado que contiene sus componentes. Mostrar límites de microservicios: Edge Gateway, Services, Datastores. Cada límite es un cluster. Documentar módulos legacy: Aísla los módulos por responsabilidad (Auth, Orders, Reporting) así queda claro quién hace qué. Presentar la arquitectura a stakeholders: Un diagrama por capas es universal y comprensible incluso para los no técnicos.

Atributos útiles:

Usa subgraph cluster_* para crear agrupamientos visuales. Usa compound=true para permitir arcos que atraviesen los clusters. Usa splines=ortho para líneas ortogonales, típicas de los diagramas “de arquitecto”. Usa shape=cylinder para las bases de datos, así son inmediatamente reconocibles.

Ejemplo de arquitectura en capas:

digraph Architecture {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial"];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#E8F4F8";
        UI;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#FFF4E6";
        ServiceA; ServiceB;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        fillcolor="#F0F0F0";
        DB [shape=cylinder, fillcolor="#D0E8FF"];
    }

    UI -> ServiceA;
    UI -> ServiceB;
    ServiceA -> DB;
    ServiceB -> DB;
}

Qué hace este ejemplo: Define tres capas con subgraph cluster_*. Presentation contiene UI, Business contiene dos servicios, Data contiene la BD (con shape=cylinder). Las flechas muestran el flujo: UI → Services → DB. La arquitectura es inmediatamente comprensible.


Mapa de Microservicios: entender un ecosistema distribuido

Si trabajas con microservicios, tienes decenas de servicios que se comunican entre sí: API Gateway, servicios de dominio (Orders, Users, Notifications), bases de datos, colas, cachés. Cuando llega un incidente en producción, la primera pregunta es: “¿Quién habla con quién? ¿Dónde está el cuello de botella?”

El mapa de microservicios es tu GPS en el caos distribuido. Te sirve para:

Diseño arquitectural: Antes de escribir código, dibuja el mapa. Identifica los límites lógicos (edge, core services, datastores). Documentación de API: Muestra quién llama a qué servicio y a través de qué protocolo (REST, gRPC, eventos). Análisis de performance: Durante un incidente, miras el mapa y entiendes inmediatamente si el problema está en el API Gateway, en un servicio específico, o en la BD compartida. Post-mortem: Después de una caída, el mapa ayuda a reconstruir la cadena de fallos.

Atributos útiles:

Usa cluster para separar los límites lógicos (Edge, Services, Data). Usa shape=cylinder para bases de datos, shape=box para servicios. Usa label en los arcos para especificar el protocolo (HTTP, gRPC, Kafka). Usa shape=plaintext con tabla HTML para servicios complejos con múltiples puertos.

Ejemplo:

digraph Micro {
    graph [rankdir=LR, splines=true];
    node [shape=plaintext];

    subgraph cluster_gateway {
        label="Edge";
        Gateway [label="API Gateway"];
    }

    subgraph cluster_services {
        label="Services";
        Order; User; Notification;
    }

    subgraph cluster_data {
        label="Datastores";
        DB [shape=cylinder, label="Postgres"];
        Cache [shape=box, label="Redis"];
    }

    Gateway -> User;
    Gateway -> Order;
    Order -> DB;
    User -> Cache;
    Notification -> User;
}

Qué hace este ejemplo: Organiza el ecosistema en tres clusters: Edge (Gateway), Services (Order, User, Notification), Datastores (DB, Cache). Las flechas muestran las llamadas: Gateway → User/Order, Order → DB, User → Cache. Es el mapa completo del sistema.


Diagramas de estado: modelar comportamientos

Muchos sistemas tienen un comportamiento basado en estados: una petición HTTP puede estar Idle, Loading, Success, Error. Un pedido de e-commerce pasa de Draft → Pending → Confirmed → Shipped. Un sistema embebido tiene estados de encendido, standby, operativo, error. Una interfaz UI tiene estados de carga, lista, error.

El diagrama de estados modela estos comportamientos como un grafo: cada nodo es un estado, cada arco es una transición etiquetada con el evento que la causa. Es fundamental para:

Diseñar máquinas de estados: Antes de implementar el patrón state en el código, dibuja el diagrama. Documentar protocolos: Los protocolos de red (TCP, WebSocket, custom) tienen máquinas de estado precisas. El diagrama las hace explícitas. Modelar flujos UI/UX: Cuando diseñas una app, dibuja los estados de la interfaz: carga, lista, error, vacía. Debug de sistemas embebidos: Si un dispositivo se bloquea en un estado, el diagrama te ayuda a entender qué transiciones faltan.

Atributos útiles:

Usa shape=circle para los estados (convención estándar de las FSM). Usa rankdir=LR para layout horizontal, típico de los diagramas de estado. Usa label en los arcos para mostrar el evento que causa la transición. Usa shape=doublecircle para estados finales/terminales.

Ejemplo:

digraph States {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle -> Loading   [label="start"];
    Loading -> Ready  [label="success"];
    Loading -> Error  [label="fail"];
    Error -> Idle     [label="reset"];
    Ready -> Idle     [label="finish"];
}

Qué hace este ejemplo: Modela el ciclo de vida de una petición asíncrona: parte de Idle, va a Loading cuando empieza la llamada, luego Success o Error según el resultado. Desde Error puede volver a Idle con un reset. Desde Ready puede volver a Idle al completarse. Cada transición está etiquetada con el evento que la causa.


Diagramas de clases con record

Cuando diseñas un sistema orientado a objetos, o quieres documentar el dominio de una aplicación, el diagrama de clases es el estándar. Muestra clases con atributos y métodos, y las relaciones entre ellas (herencia, composición, dependencia).

DOT no es UML, pero con shape=record obtienes algo muy similar y perfectamente legible. Es útil para:

Diseño inicial: Antes de escribir el código, dibuja las clases principales del dominio. Identifica atributos, métodos, relaciones. Refactoring: Cuando debes reestructurar un módulo, dibuja el estado actual y el deseado. Compara los dos diagramas. Domain-Driven Design (DDD): Modela las entidades, value objects, agregados. El diagrama ayuda a visualizar los límites del dominio. Documentación: Genera el diagrama automáticamente desde el código (con herramientas como Doxygen) y mantenlo actualizado.

Atributos útiles:

Usa shape=record para crear boxes con secciones separadas (nombre clase | atributos | métodos). Usa fontname="Courier New" o monospace para hacerlo similar al código. Usa arrowhead=onormal para herencia (flecha vacía, estándar UML). Usa \l (backslash-l) para alinear el texto a la izquierda dentro de los records.

Ejemplo:

digraph Classes {
    node [shape=record, fontname="Courier New"];

    Person [label="{Person|name: string\l age: int\l|greet()}"];
    Employee [label="{Employee|id: int\l role: string\l|work()}"];

    Person -> Employee [arrowhead="onormal"];
}

Qué hace este ejemplo: Define dos clases: Person (con atributos nombre, edad, método greet) y Employee (con id, rol, método work). Person es la superclase de Employee (flecha con arrowhead=onormal, estándar UML para la herencia). El \l alinea el texto a la izquierda dentro de los records.


Diagramas ER profesionales con HTML-label

Si trabajas con bases de datos, tarde o temprano debes dibujar el esquema de las tablas: claves primarias, foreign keys, relaciones 1:N o N:N. El diagrama Entity-Relationship (ER) es el estándar para esto.

DOT soporta tablas HTML dentro de los nodos con shape=plaintext, permitiéndote crear diagramas ER limpios y profesionales. Es fundamental para:

Diseño de bases de datos: Antes de escribir las migraciones, dibuja el esquema. Identifica las entidades, los atributos, las relaciones. Valida el diseño con el equipo. Data modeling: Cuando diseñas un nuevo módulo, parte del modelo de datos. El diagrama ER te ayuda a razonar sobre normalización y performance. Reverse engineering: Cuando heredas una BD legacy sin documentación, genera el diagrama ER desde la BD misma (con herramientas como SchemaSpy o pg_dump + script) para entender la estructura. Documentación: El diagrama ER es comprensible incluso para los no desarrolladores (product managers, analistas de negocio).

Atributos útiles:

Usa shape=plaintext para habilitar HTML label. Usa <TABLE> HTML para crear boxes estructurados con encabezado (nombre tabla) y filas (campos). Usa arrowhead=crow para relaciones 1:N (estándar de los diagramas ER). Usa label="1:N" en los arcos para hacer explícita la cardinalidad.

Ejemplo:

digraph ER {
    node [shape=plaintext];

    User [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>User</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>email</TD></TR>
        </TABLE>
    >];

    Order [label=<
        <TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0">
            <TR><TD><B>Order</B></TD></TR>
            <TR><TD>id PK</TD></TR>
            <TR><TD>user_id FK</TD></TR>
        </TABLE>
    >];

    User -> Order [label="1:N", arrowhead="crow"];
}

Qué hace este ejemplo: Define dos tablas (User y Order) usando HTML. Cada tabla tiene un encabezado en negrita y filas para los campos. La flecha con arrowhead=crow y label="1:N" muestra la relación: un User tiene muchos Order (clave externa user_id en Order).


Diagramas de Pipeline CI/CD

Si trabajas en un equipo que hace integración y despliegue continuos, tienes una pipeline que ejecuta pasos automáticos: build, test, análisis estático, packaging, deploy, monitoreo. Cuando algo se rompe, o cuando haces onboarding de un nuevo developer, necesitas un diagrama que muestre toda la pipeline.

El diagrama CI/CD visualiza el flujo automático desde el commit hasta el deploy. Es útil para:

DevOps y SRE: Documentar la pipeline existente. Identificar cuellos de botella (¿qué paso requiere más tiempo?). Onboarding de equipo: Un nuevo developer mira el diagrama y entiende inmediatamente qué sucede después de un git push. Optimización: ¿Quieres paralelizar algunos pasos? El diagrama te muestra cuáles dependen de cuáles. Debugging: ¿La pipeline falla? El diagrama te ayuda a entender en qué paso y por qué (flecha punteada para los reintentos).

Atributos útiles:

Usa rankdir=LR para flujo horizontal (típico de las pipelines). Usa shape=box con style=filled para los pasos, coloreándolos por tipo (build=azul, test=verde, deploy=rojo). Usa style=dotted con label="retry" para mostrar mecanismos de reintento automático. Usa label en los arcos para indicar condiciones (ej. “only on master branch”).

Ejemplo:

digraph CICD {
    graph [rankdir=LR];
    node [shape=box, style=filled, fillcolor="#F8FBFF"];

    Code -> Build -> Test -> Package -> Deploy -> Monitor;

    Test -> Build [style=dotted, label="retry"];
}

Qué hace este ejemplo: Muestra una pipeline clásica: Code → Build → Test → Package → Deploy → Monitor. La flecha punteada de Test a Build muestra un reintento automático en caso de fallo de los tests. Es un flujo lineal, inmediatamente comprensible.


Restar complejidad: mapas conceptuales y análisis

No todos los diagramas deben ser jerárquicos o direccionales. A veces necesitas visualizar relaciones conceptuales sin una estructura fija: durante un brainstorming, cuando haces diseño colectivo con el equipo, o cuando quieres mapear las dependencias conceptuales entre áreas tecnológicas.

El mapa conceptual no tiene un “inicio” o un “fin”: es una red de nodos conectados orgánicamente. Es útil para:

Brainstorming: Partes de una idea central y agregas nodos conectados mientras discutes con el equipo. El mapa crece naturalmente. Diseño colectivo: Durante una sesión de diseño, mapea los componentes y sus relaciones. Aún no sabes la jerarquía, pero sabes que “Backend habla con Database y API”. Análisis de dependencias conceptuales: Quieres entender qué áreas tecnológicas están conectadas (ej. Security → Logging → Observability). Documentación de alto nivel: Para stakeholders no técnicos, un mapa conceptual es más accesible que un grafo jerárquico.

Atributos útiles:

Usa el engine neato o fdp en lugar de dot, para obtener un layout orgánico basado en fuerzas físicas. Usa shape=ellipse para nodos conceptuales (no procesos). Usa style=filled con colores tenues para agrupamientos visuales. Usa grafos no dirigidos (graph en lugar de digraph) si las relaciones son bidireccionales.

Ejemplo con engine neato:

graph Concepts {
    layout=neato;
    node [shape=ellipse, style=filled, fillcolor="#EFEFFF"];

    Backend -- Database;
    Backend -- API;
    API -- Security;
    Security -- Logging;
    Logging -- Observability;
}

Evitar superposiciones: overlap y splines

Uno de los problemas más comunes cuando se dibujan grafos complejos es la superposición de flechas, textos y nodos. Graphviz ofrece atributos específicos para controlar este comportamiento y hacer los diagramas más legibles.

El problema: superposiciones no deseadas

Cuando tienes muchos nodos y flechas, especialmente con layouts jerárquicos o con splines=ortho, las flechas pueden superponerse a los labels de los clusters o a los nodos. Aquí un ejemplo típico del problema:

digraph OverlapProblem {
    graph [rankdir=TB, splines=ortho];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Problema: Con splines=ortho las flechas pueden atravesar los labels de los clusters haciendo el diagrama confuso.

La solución: overlap y splines

Graphviz ofrece varios atributos para resolver este problema:

overlap — evita superposiciones entre nodos

graph [overlap=false];

Opciones principales:

  • false o voronoi — evita superposiciones (mejor calidad, más lento)
  • scale — escala el grafo para evitar superposiciones
  • scalexy — escala con proporciones diferentes en X e Y
  • true (default) — permite superposiciones

splines — controla la forma de los arcos

graph [splines=true];

Opciones:

  • true o spline — curvas suaves que evitan nodos (recomendado)
  • curved — arcos ligeramente curvos
  • polyline — líneas quebradas
  • ortho — líneas ortogonales (¡puede causar superposiciones!)
  • line o false — líneas rectas

sep — margen extra entre elementos

graph [sep="+0.2"];

Agrega margen entre nodos y arcos (en pulgadas). El + significa “agregar al valor por defecto”.

ranksep y nodesep — espaciado entre niveles y nodos

graph [ranksep=0.8, nodesep=0.6];

Aumenta el espacio vertical (ranksep) y horizontal (nodesep) entre los elementos.

Ejemplo mejorado

Aquí el mismo grafo con atributos optimizados para evitar superposiciones:

digraph OverlapSolved {
    graph [
        rankdir=TB,
        ranksep=0.8,
        nodesep=0.6,
        overlap=false,
        splines=true,
        sep="+0.2"
    ];
    node [shape=box, style=rounded];

    subgraph cluster_a {
        label="Component A";
        style=filled;
        fillcolor="#E8F4F8";
        A1; A2;
    }

    subgraph cluster_b {
        label="Component B";
        style=filled;
        fillcolor="#FFF4E6";
        B1; B2;
    }

    subgraph cluster_c {
        label="Component C";
        style=filled;
        fillcolor="#F0F0F0";
        C1; C2;
    }

    A1 -> B1;
    A2 -> B2;
    B1 -> C1;
    B2 -> C2;
    A1 -> C1;
}

Resultado: Las flechas ahora evitan los nodos y los labels, el grafo es más espacioso y legible. Los colores de fondo ayudan a distinguir los clusters.

Cuándo usar qué

Escenario Atributos recomendados
Diagramas complejos con muchos nodos overlap=false, splines=true
Grafos jerárquicos (flowcharts, arquitecturas) ranksep=0.8, nodesep=0.6, splines=true
Grafos con clusters overlap=false, sep="+0.2"
Diagramas “de arquitecto” con líneas rectas splines=polyline (evita ortho)
Grafos pequeños y simples default (no hace falta modificar)

Regla práctica: Comienza siempre con overlap=false y splines=true si tienes más de 10 nodos o usas clusters.

Ejemplo completo con todas las mejores prácticas

Aquí un ejemplo real que combina todos los atributos recomendados: arquitectura de microservicios con 4 capas, muchos nodos y arcos, clusters coloreados, espacios optimizados:

digraph CompleteExample {
    graph [
        rankdir=TB,
        ranksep=1.0,
        nodesep=0.7,
        overlap=false,
        splines=true,
        sep="+0.25"
    ];
    node [shape=box, style="rounded,filled", fillcolor="#F0F4FF", fontname="Arial", fontsize=11];
    edge [color="#555555", arrowsize=0.8];

    subgraph cluster_frontend {
        label="Frontend Layer";
        style=filled;
        fillcolor="#E8F4F8";
        color="#5A9FD4";

        WebUI [label="Web UI"];
        MobileApp [label="Mobile App"];
    }

    subgraph cluster_api {
        label="API Gateway Layer";
        style=filled;
        fillcolor="#FFF4E6";
        color="#E8A87C";

        Gateway [label="API Gateway"];
        LoadBalancer [label="Load Balancer"];
    }

    subgraph cluster_services {
        label="Microservices Layer";
        style=filled;
        fillcolor="#F0F8E8";
        color="#90C290";

        AuthService [label="Auth Service"];
        UserService [label="User Service"];
        OrderService [label="Order Service"];
        PaymentService [label="Payment Service"];
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        fillcolor="#F5F5F5";
        color="#999999";

        UsersDB [shape=cylinder, fillcolor="#D0E8FF", label="Users DB"];
        OrdersDB [shape=cylinder, fillcolor="#D0E8FF", label="Orders DB"];
        Cache [shape=box, fillcolor="#FFE8D0", label="Redis Cache"];
    }

    // Frontend to Gateway
    WebUI -> LoadBalancer [label="HTTPS"];
    MobileApp -> LoadBalancer [label="HTTPS"];

    // Gateway to Services
    LoadBalancer -> Gateway;
    Gateway -> AuthService [label="gRPC"];
    Gateway -> UserService [label="REST"];
    Gateway -> OrderService [label="REST"];

    // Service dependencies
    OrderService -> PaymentService [label="API call"];
    UserService -> AuthService [label="validate"];
    PaymentService -> AuthService [label="validate"];

    // Data access
    AuthService -> UsersDB;
    UserService -> UsersDB;
    UserService -> Cache [style=dashed, label="cache"];
    OrderService -> OrdersDB;
    OrderService -> Cache [style=dashed, label="cache"];
}

Línea de comandos:

dot -Tsvg overlap_complete.dot -o overlap_complete.svg

Qué demuestra este ejemplo:

  • overlap=false: Ninguna superposición entre nodos, incluso con 13 nodos y 4 clusters
  • splines=true: Flechas curvas que evitan elegantemente nodos y labels
  • sep="+0.25": Margen extra que mantiene todo legible
  • ranksep=1.0, nodesep=0.7: Espaciado generoso entre capas y nodos
  • Clusters coloreados: Cada capa tiene un color distintivo para identificación inmediata
  • Labels en los arcos: Protocolos (HTTPS, gRPC, REST) y tipo de conexión explícitos
  • Style dashed para cache: Dependencias opcionales visualizadas diferentemente
  • Cylinder shape para DB: Bases de datos inmediatamente reconocibles

Esta es la plantilla perfecta para documentar arquitecturas complejas de forma profesional y legible.


Color Schemes: paletas profesionales listas para usar

Graphviz incluye color schemes predefinidos basados en paletas profesionales de ColorBrewer. En lugar de elegir colores manualmente, puedes usar paletas probadas para legibilidad, accesibilidad y profesionalismo.

Cómo funcionan los color schemes

Usa el atributo colorscheme para seleccionar una paleta, luego usa los números 1-9 (o más, depende del esquema) en lugar de los códigos hex:

node [colorscheme=set39, fillcolor=1, color=2];

Los color schemes están organizados en categorías:

  • Qualitative (set1, set2, set3, pastel1, pastel2, dark2, paired, accent) — Para categorías distintas
  • Sequential (blues3-9, greens3-9, reds3-9, purples3-9, oranges3-9) — Para valores progresivos
  • Diverging (rdylgn3-11, spectral3-11, rdbu3-11) — Para datos con punto central

Referencia completa: graphviz.org/docs/attrs/colorscheme/

Ejemplos prácticos con color schemes profesionales

Cada ejemplo usa el mismo diagrama (proceso de 5 pasos) pero con paletas diferentes. Compara y elige el más adecuado para tu caso de uso.

Ejemplo 1: Set39 (cualitativo, vívido)

Óptimo para distinguir categorías diferentes, presentaciones coloridas, dashboards.

digraph ProcessSet39 {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=set39, fontname=Arial];
    edge [colorscheme=set39, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=2, label="Validate"];
    Process [fillcolor=3, label="Process"];
    Store [fillcolor=4, label="Store"];
    Notify [fillcolor=5, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=2];
    Process -> Store [color=3];
    Store -> Notify [color=4];
}

Línea de comandos:

dot -Tsvg colorscheme_set39.dot -o colorscheme_set39.svg

Ejemplo 2: Pastel19 (cualitativo, suave)

Colores pastel para documentación técnica, wikis, posts de blog. Menos impactante pero más legible a largo plazo.

digraph ProcessPastel {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=pastel19, fontname=Arial, fontcolor="#333333"];
    edge [colorscheme=dark28, penwidth=2];

    Start [fillcolor=1, label="Start"];
    Validate [fillcolor=3, label="Validate"];
    Process [fillcolor=5, label="Process"];
    Store [fillcolor=7, label="Store"];
    Notify [fillcolor=9, label="Notify"];

    Start -> Validate [color=1];
    Validate -> Process [color=3];
    Process -> Store [color=5];
    Store -> Notify [color=7];
}

Línea de comandos:

dot -Tsvg colorscheme_pastel.dot -o colorscheme_pastel.svg

Ejemplo 3: Blues9 (secuencial, progresión)

Ideal para mostrar intensidad creciente, prioridades, fases de maduración.

digraph ProcessBlues {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=blues9, fontname=Arial];
    edge [color="#2171B5", penwidth=2];

    Start [fillcolor=2, fontcolor=black, label="Start"];
    Validate [fillcolor=4, fontcolor=white, label="Validate"];
    Process [fillcolor=6, fontcolor=white, label="Process"];
    Store [fillcolor=8, fontcolor=white, label="Store"];
    Notify [fillcolor=9, fontcolor=white, label="Notify"];

    Start -> Validate -> Process -> Store -> Notify;
}

Línea de comandos:

dot -Tsvg colorscheme_blues.dot -o colorscheme_blues.svg

Ejemplo 4: RdYlGn9 (divergente, semáforo)

Perfecto para estados de éxito/warning/error, health checks, monitoreo.

digraph ProcessStatus {
    graph [rankdir=LR, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=rdylgn9, fontname=Arial, fontcolor=black];
    edge [penwidth=2, color="#666666"];

    Idle [fillcolor=5, label="Idle\n(neutral)"];
    Starting [fillcolor=7, label="Starting\n(ok)"];
    Running [fillcolor=9, label="Running\n(good)"];
    Warning [fillcolor=4, label="Warning"];
    Error [fillcolor=1, label="Error"];

    Idle -> Starting -> Running;
    Running -> Warning [style=dashed];
    Warning -> Error [style=dashed];
    Running -> Idle [label="stop"];
}

Línea de comandos:

dot -Tsvg colorscheme_rdylgn.dot -o colorscheme_rdylgn.svg

Ejemplo 5: Paired12 (cualitativo, parejas)

Usa pares de colores coordinados. Óptimo para comparaciones, versiones A/B, relaciones.

digraph ProcessPaired {
    graph [rankdir=TB, bgcolor=white];
    node [shape=box, style="rounded,filled", colorscheme=paired12, fontname=Arial];
    edge [colorscheme=paired12, penwidth=2];

    subgraph cluster_v1 {
        label="Version 1.x";
        style=filled;
        fillcolor="#F0F0F0";
        V1_Start [fillcolor=1, label="Start v1"];
        V1_Process [fillcolor=1, label="Process v1"];
        V1_End [fillcolor=1, label="End v1"];
        V1_Start -> V1_Process -> V1_End;
    }

    subgraph cluster_v2 {
        label="Version 2.x";
        style=filled;
        fillcolor="#F8F8F8";
        V2_Start [fillcolor=2, label="Start v2"];
        V2_Process [fillcolor=2, label="Process v2"];
        V2_End [fillcolor=2, label="End v2"];
        V2_Start -> V2_Process -> V2_End;
    }

    V1_Start -> V2_Start [label="upgrade", color=4, style=dashed];
}

Línea de comandos:

dot -Tsvg colorscheme_paired.dot -o colorscheme_paired.svg

Ejemplo 6: Accent8 (cualitativo, contrastes fuertes)

Máximo contraste entre elementos. Para evidenciar diferencias importantes.

digraph ProcessAccent {
    graph [rankdir=LR, bgcolor="#F5F5F5"];
    node [shape=box, style="rounded,filled", colorscheme=accent8, fontname=Arial, fontcolor=black];
    edge [colorscheme=accent8, penwidth=2];

    Input [fillcolor=1, label="Input"];
    Parse [fillcolor=2, label="Parse"];
    Transform [fillcolor=3, label="Transform"];
    Validate [fillcolor=4, label="Validate"];
    Output [fillcolor=5, label="Output"];

    Input -> Parse [color=1];
    Parse -> Transform [color=2];
    Transform -> Validate [color=3];
    Validate -> Output [color=4];
    Validate -> Parse [color=6, label="retry", style=dashed];
}

Línea de comandos:

dot -Tsvg colorscheme_accent.dot -o colorscheme_accent.svg

Cuándo usar qué color scheme

Escenario Color Scheme Recomendado
Categorías diferentes, presentaciones set39, set28, dark28
Documentación técnica, wikis pastel19, pastel28
Progresión, prioridades, niveles blues9, greens9, purples9, oranges9
Estados (ok/warning/error) rdylgn9, rdylbu9, spectral9
Comparaciones, versiones A/B paired12, paired11
Máximo contraste accent8, set39
Accesibilidad (daltonismo) set2, dark2 (ColorBrewer safe)

Combinar color schemes

Puedes usar esquemas diferentes para nodos y arcos:

node [colorscheme=pastel19, fillcolor=3];
edge [colorscheme=dark28, color=2];

Tip: Prueba siempre los colores con ColorBrewer para verificar accesibilidad e imprimibilidad.


Técnicas avanzadas: ports, ranks, compound edges

Ports en records — Conecta arcos a campos específicos de un record usando la sintaxis nodo:puerto:

ClassA:field1 -> ClassB:field2;

Forzar nodos al mismo nivel — Usa rank=same para posicionar múltiples nodos en la misma fila horizontal:

{ rank=same; A; B; C; }

Compound edges entre clusters — Conecta clusters enteros en lugar de nodos individuales con lhead y ltail:

edge [lhead=cluster_B, ltail=cluster_A];

Arcos ortogonales — Crea arcos con ángulos rectos para un estilo “de arquitecto”:

graph [splines=ortho];

Estilo profesional: consejos prácticos

  • Usa paletas coherentes.
  • Evita gradientes demasiado brillantes.
  • Usa Inter, Arial o Roboto para legibilidad.
  • Usa ortho para arcos “de arquitecto”.
  • Mantén márgenes adecuados (nodesep, ranksep).
  • Prefiere SVG para calidad en blogs.
  • Mantén los archivos DOT versionados.

Estilos gráficos listos para usar

Aquí encuentras 5 variantes estilísticas para el mismo diagrama de estados, listas para copiar y adaptar a tus diagramas. Cada estilo define colores, fuentes, tamaños y formas para crear un look coherente.

Estilo 1: Corporate Blue (profesional, formal)

Paleta azul/gris, fuente Arial, estilo limpio para presentaciones corporativas.

digraph CorporateBlue {
    graph [
        rankdir=LR,
        bgcolor="#F8F9FA",
        fontname="Arial",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#E3F2FD",
        color="#1976D2",
        fontname="Arial",
        fontsize=11,
        fontcolor="#1565C0",
        penwidth=2
    ];
    edge [
        color="#1976D2",
        fontname="Arial",
        fontsize=10,
        fontcolor="#424242"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Línea de comandos:

dot -Tsvg style_corporate.dot -o style_corporate.svg

Estilo 2: Dark Mode (moderno, tech)

Fondo oscuro, texto claro, paleta verde/cian para UIs modernas y herramientas para desarrolladores.

digraph DarkMode {
    graph [
        rankdir=LR,
        bgcolor="#1E1E1E",
        fontname="Consolas",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#2D2D30",
        color="#00D9FF",
        fontname="Consolas",
        fontsize=11,
        fontcolor="#E0E0E0",
        penwidth=2
    ];
    edge [
        color="#00D9FF",
        fontname="Consolas",
        fontsize=10,
        fontcolor="#B0B0B0"
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Línea de comandos:

dot -Tsvg style_dark.dot -o style_dark.svg

Estilo 3: Warm Minimal (suave, legible)

Paleta cálida naranja/beige, sans-serif, óptimo para documentación técnica.

digraph WarmMinimal {
    graph [
        rankdir=LR,
        bgcolor="#FFFBF5",
        fontname="Helvetica",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#FFE8CC",
        color="#FF8C42",
        fontname="Helvetica",
        fontsize=11,
        fontcolor="#6B4423",
        penwidth=1.5
    ];
    edge [
        color="#FF8C42",
        fontname="Helvetica",
        fontsize=10,
        fontcolor="#8B5A3C",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Línea de comandos:

dot -Tsvg style_warm.dot -o style_warm.svg

Estilo 4: Monochrome (elegante, imprimible)

Blanco y negro, gradaciones de gris, perfecto para impresión y documentación formal.

digraph Monochrome {
    graph [
        rankdir=LR,
        bgcolor="white",
        fontname="Times-Roman",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#F5F5F5",
        color="#333333",
        fontname="Times-Roman",
        fontsize=11,
        fontcolor="#000000",
        penwidth=2
    ];
    edge [
        color="#333333",
        fontname="Times-Roman",
        fontsize=10,
        fontcolor="#666666",
        penwidth=1.5
    ];

    Idle [label="Idle"];
    Processing [label="Processing"];
    Complete [label="Complete"];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Línea de comandos:

dot -Tsvg style_mono.dot -o style_mono.svg

Estilo 5: Vibrant Gradient (creativo, impactante)

Colores vívidos con degradados, óptimo para presentaciones y slides visualmente llamativas.

digraph VibrantGradient {
    graph [
        rankdir=LR,
        bgcolor="#FAFAFA",
        fontname="Verdana",
        fontsize=12
    ];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#A8E6CF:#56CCF2",
        gradientangle=90,
        color="#2D6A9F",
        fontname="Verdana",
        fontsize=11,
        fontcolor="#1A3A52",
        penwidth=2.5
    ];
    edge [
        color="#9B59B6",
        fontname="Verdana",
        fontsize=10,
        fontcolor="#5B3A72",
        penwidth=2
    ];

    Idle [label="Idle"];
    Processing [label="Processing", fillcolor="#FFD93D:#FF6B9D", gradientangle=90];
    Complete [label="Complete", fillcolor="#6BCF7F:#4ECDC4", gradientangle=90];

    Idle -> Processing [label="start"];
    Processing -> Complete [label="finish"];
    Complete -> Idle [label="reset"];
    Processing -> Idle [label="cancel"];
}

Línea de comandos:

dot -Tsvg style_vibrant.dot -o style_vibrant.svg

Cómo usar estos estilos

Copia el bloque graph, node, edge del estilo que prefieras y aplícalo a tus diagramas. Luego puedes personalizar:

  • Colores: reemplaza los códigos hex con tu paleta
  • Fuentes: usa fontname="NombreFuente" (Arial, Helvetica, Courier, Times, Verdana, Consolas)
  • Tamaños: fontsize para texto, penwidth para grosor de bordes y flechas
  • Shape: box, ellipse, circle, diamond, cylinder, record
  • Degradados: usa fillcolor="color1:color2" con gradientangle (solo algunos formatos de salida)

Notas sobre compatibilidad de fuentes

Las fuentes deben estar instaladas en el sistema donde generas las imágenes:

  • Fuentes universales (funcionan en todas partes): Arial, Helvetica, Times, Times-Roman, Courier
  • Fuentes modernas (verificar disponibilidad): Verdana, Consolas, Roboto, Inter
  • Windows: la mayoría de las fuentes ya están instaladas
  • macOS: excelente soporte para fuentes estándar
  • Linux: instala fonts-liberation o fonts-dejavu para tener equivalentes de Arial/Helvetica
  • CI/CD: usa fuentes básicas o incluye las fuentes en el contenedor Docker

Si una fuente no está disponible, Graphviz usa un fallback (normalmente Times). Para estar seguro, usa siempre fuentes básicas o prueba la generación en el ambiente de producción.


Workflow: cómo integrar Graphviz en el trabajo real

  1. Pon los archivos .gv en el repositorio.

  2. Genera los SVG automáticamente en la CI:

    dot -Tsvg diagram.gv -o diagram.svg
    
  3. Inyecta los SVG en la documentación (README, wiki, blog).

  4. Actualiza los diagramas en cada refactoring.

  5. Usa differ y versionado de los archivos DOT como harías con el código.


Troubleshooting: errores comunes y soluciones

Error: “syntax error in line X near…”

  • Causa: Sintaxis DOT no válida
  • Solución: Controla punto y coma faltantes, llaves no cerradas, comillas no emparejadas
  • Ejemplo: A -> B debe terminar con ;A -> B;

Error: “Warning: Unable to find font…”

  • Causa: La fuente especificada no está instalada en el sistema
  • Solución: Usa fuentes universales (Arial, Helvetica, Times) o instala la fuente requerida
  • Verificar fuentes disponibles: dot -v muestra las fuentes disponibles

El diagrama es demasiado grande/pequeño

  • Solución 1: Agrega graph [size="8,6"] para limitar dimensiones (en pulgadas)
  • Solución 2: Usa graph [ratio=compress] para comprimir automáticamente
  • Solución 3: Genera PNG con DPI personalizado: dot -Tpng -Gdpi=150 file.dot -o file.png

Las flechas se superponen a los nodos

  • Solución: Agrega graph [overlap=false, splines=true] (ver sección “Evitar superposiciones”)

Los nodos están todos alineados horizontalmente en lugar de verticalmente

  • Solución: Usa graph [rankdir=TB] para top-to-bottom (el default es LR = left-to-right)

El cluster no aparece

  • Causa: Nombre del cluster no comienza con cluster_
  • Solución: Renombra subgraph mygroup a subgraph cluster_mygroup

Output SVG demasiado grande (tamaño de archivo)

  • Causa: SVG con muchos elementos
  • Solución 1: Usa PNG en lugar de SVG para grafos muy complejos
  • Solución 2: Optimiza con svgo: svgo input.svg -o output.svg

El grafo no se genera (sin output, sin error)

  • Causa: Comando incorrecto o redirección equivocada
  • Verificación: Usa -v para verbose: dot -v -Tsvg input.dot -o output.svg
  • Test rápido: echo "digraph{A->B}" | dot -Tsvg > test.svg

Los labels de los arcos no se ven

  • Causa: Labels demasiado largos o fuente demasiado pequeña
  • Solución: Aumenta fontsize en los edges o usa \n para dividir labels en múltiples líneas

Template DOT + Comandos Graphviz (CLI)

Cada plantilla incluye:

  1. snippet DOT

  2. comando CLI para generar la imagen

Por coherencia uso el formato SVG, pero puedes reemplazar -Tsvg con:

  • -Tpng
  • -Tpdf
  • -Tjpg
  • -Tgif

Y puedes guardar el input DOT en template.dot o usar pipe.


Flowchart

Template 1 – Proceso básico

digraph FlowBasic {
    graph [rankdir=TB];
    node [shape=rectangle, style=rounded, fontsize=12];

    Start [label="Start", shape=circle];
    Step1 [label="Input validation"];
    Step2 [label="Process request"];
    Step3 [label="Persist data"];
    End [label="End", shape=doublecircle];

    Start -> Step1 -> Step2 -> Step3 -> End;
}

Línea de comandos:

dot -Tsvg FlowBasic.dot -o FlowBasic.svg

Template 2 – Bifurcación (if/else)

digraph FlowIfElse {
    graph [rankdir=TB];
    node [fontsize=12, style=rounded];

    Start [shape=circle];
    Check [shape=diamond, label="Is valid?"];
    A [label="Handle valid case"];
    B [label="Handle error"];
    End [shape=doublecircle];

    Start -> Check;
    Check -> A [label="Yes"];
    Check -> B [label="No"];
    A -> End;
    B -> End;
}

Línea de comandos:

dot -Tsvg FlowIfElse.dot -o FlowIfElse.svg

Template 3 – Proceso con secciones

digraph FlowSections {
    graph [rankdir=TB];
    node [fontsize=11, style=rounded];

    subgraph cluster_input {
        label="Input Stage";
        color=lightgrey;
        style=filled;

        A1 [label="Receive request"];
        A2 [label="Validate payload"];
        A1 -> A2;
    }

    subgraph cluster_processing {
        label="Processing Stage";
        color=lightblue;
        style=filled;

        P1 [label="Transform data"];
        P2 [label="Apply business rules"];
        P1 -> P2;
    }

    subgraph cluster_output {
        label="Output Stage";
        color=lightyellow;
        style=filled;

        O1 [label="Persist"];
        O2 [label="Return response"];
        O1 -> O2;
    }

    A2 -> P1 -> O1;
}

Línea de comandos:

dot -Tsvg FlowSections.dot -o FlowSections.svg

State Machine

Template 4 – Máquina de estados básica

digraph StateMachine {
    graph [rankdir=LR];
    node [shape=circle, fontsize=12];

    Idle;
    Loading;
    Error;
    Success;

    Idle -> Loading [label="start"];
    Loading -> Success [label="ok"];
    Loading -> Error [label="fail"];
    Error -> Idle [label="retry"];
}

Línea de comandos:

dot -Tsvg StateMachine.dot -o StateMachine.svg

Template 5 – Estados anidados

digraph NestedStates {
    graph [rankdir=LR];
    node [fontsize=11];

    subgraph cluster_ready {
        label="Ready state";
        style=dashed;
        R1 [shape=circle, label="Idle"];
        R2 [shape=circle, label="Primed"];
        R1 -> R2 [label="prepare"];
    }

    subgraph cluster_active {
        label="Active state";
        style=dashed;
        A1 [shape=circle, label="Running"];
        A2 [shape=circle, label="Paused"];
        A1 -> A2 [label="pause"];
        A2 -> A1 [label="resume"];
    }

    R2 -> A1 [label="activate"];
}

Línea de comandos:

dot -Tsvg NestedStates.dot -o NestedStates.svg

Sequence Diagram (DOT)

Template 6 – Secuencia horizontal

digraph Sequence {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="POST /login"];
    API -> AuthService [label="Check credentials"];
    AuthService -> DB [label="Query user"];
    DB -> AuthService [label="Result"];
    AuthService -> API [label="Token"];
    API -> Client [label="200 OK"];
}

Línea de comandos:

dot -Tsvg Sequence.dot -o Sequence.svg

Template 7 – Secuencia con activaciones

digraph SequenceActivation {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    User -> Frontend [label="Login"];
    Frontend -> Backend [label="POST /login"];
    Backend -> Backend [label="validate()"];
    Backend -> DB [label="SELECT user"];
    DB -> Backend [label="row found"];
    Backend -> Frontend [label="JWT"];
    Frontend -> User [label="Welcome"];
}

Línea de comandos:

dot -Tsvg SequenceActivation.dot -o SequenceActivation.svg

Dependency Graph

Template 8 – Módulos

digraph DependencyTree {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    App -> ModuleA;
    App -> ModuleB;
    ModuleA -> LibA;
    ModuleA -> LibB;
    ModuleB -> LibB;
}

Línea de comandos:

dot -Tsvg DependencyTree.dot -o DependencyTree.svg

Template 9 – Microservicios

digraph MicroservicesDep {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Gateway -> Auth;
    Gateway -> Orders;
    Auth -> UsersDB;
    Orders -> ProductsService;
    Orders -> Payments;
    Payments -> BankAPI;
}

Línea de comandos:

dot -Tsvg MicroservicesDep.dot -o MicroservicesDep.svg

Architecture Diagram

Template 10 – Por capas

digraph Layered {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=12];

    subgraph cluster_presentation {
        label="Presentation Layer";
        style=filled;
        color=lightyellow;
        UI;
        API;
    }

    subgraph cluster_business {
        label="Business Layer";
        style=filled;
        color=lightblue;
        Services;
    }

    subgraph cluster_data {
        label="Data Layer";
        style=filled;
        color=lightgrey;
        DB;
        Cache;
    }

    UI -> API -> Services -> DB;
    Services -> Cache;
}

Línea de comandos:

dot -Tsvg Layered.dot -o Layered.svg

Template 11 – Hexagonal

digraph Hexagonal {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    AppCore [label="Core Domain"];
    PortIn [label="Inbound Ports"];
    PortOut [label="Outbound Ports"];
    AdapterIn [label="Inbound Adapters"];
    AdapterOut [label="Outbound Adapters"];
    DB [label="Database"];
    UI [label="Frontend/UI"];

    UI -> AdapterIn -> PortIn -> AppCore;
    AppCore -> PortOut -> AdapterOut -> DB;
}

Línea de comandos:

dot -Tsvg Hexagonal.dot -o Hexagonal.svg

ER Diagrams

Template 12 – 1:N

digraph ER_OneToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    User [label="{User|id PK|name|email}"];
    Order [label="{Order|id PK|user_id FK|total}"];

    User -> Order [label="1:N"];
}

Línea de comandos:

dot -Tsvg ER_OneToMany.dot -o ER_OneToMany.svg

Template 13 – N:N

digraph ER_ManyToMany {
    graph [rankdir=LR];
    node [shape=record, fontsize=11];

    Student [label="{Student|id PK|name}"];
    Course [label="{Course|id PK|title}"];
    Enroll [label="{Enroll|student_id FK|course_id FK}"];

    Student -> Enroll;
    Course -> Enroll;
}

Línea de comandos:

dot -Tsvg ER_ManyToMany.dot -o ER_ManyToMany.svg

Call Graph

Template 14 – Básico

digraph CallGraph {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    main -> init;
    main -> loadConfig;
    loadConfig -> readFile;
    readFile -> parseJson;
}

Línea de comandos:

dot -Tsvg CallGraph.dot -o CallGraph.svg

Template 15 – Con categorías

digraph CategorizedCalls {
    graph [rankdir=TB];
    node [shape=box, style=rounded, fontsize=11];

    subgraph cluster_io {
        label="I/O Functions";
        color=lightgrey;
        readFile;
        writeFile;
    }

    subgraph cluster_logic {
        label="Business Logic";
        color=lightblue;
        compute;
        validate;
    }

    main -> compute -> validate;
    compute -> readFile;
    validate -> writeFile;
}

Línea de comandos:

dot -Tsvg CategorizedCalls.dot -o CategorizedCalls.svg

Network Diagram

Template 16 – Básico

digraph Network {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Client -> LoadBalancer;
    LoadBalancer -> AppServer1;
    LoadBalancer -> AppServer2;
    AppServer1 -> DB;
    AppServer2 -> DB;
}

Línea de comandos:

dot -Tsvg Network.dot -o Network.svg

Template 17 – Con protocolos

digraph NetworkProto {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    Client -> API [label="HTTPS"];
    API -> Auth [label="gRPC"];
    API -> Orders [label="REST"];
    Orders -> DB [label="TCP"];
}

Línea de comandos:

dot -Tsvg NetworkProto.dot -o NetworkProto.svg

Timeline / Roadmap

Template 18 – Timeline

digraph Timeline {
    graph [rankdir=LR];
    node [shape=box, style=rounded, fontsize=11];

    Start -> Milestone1 -> Milestone2 -> Milestone3 -> Release;
}

Línea de comandos:

dot -Tsvg Timeline.dot -o Timeline.svg

Template 19 – Roadmap

digraph Roadmap {
    graph [rankdir=LR];
    node [shape=box, fontsize=11];

    subgraph cluster_backend {
        label="Backend";
        B1 [label="Auth module"];
        B2 [label="Payments"];
    }

    subgraph cluster_frontend {
        label="Frontend";
        F1 [label="Login UI"];
        F2 [label="Dashboard"];
    }

    B1 -> B2;
    F1 -> F2;
}

Línea de comandos:

dot -Tsvg Roadmap.dot -o Roadmap.svg

Mind Map

Template 20 – Mapa mental

graph MindMap {
    layout=twopi;
    rankdir=LR;
    node [shape=box, style=rounded, fontsize=11];

    Central -- Idea1;
    Central -- Idea2;
    Central -- Idea3;
    Idea2 -- Sub1;
    Idea2 -- Sub2;
}

Línea de comandos:

dot -Ktwopi -Tsvg MindMap.dot -o MindMap.svg

Component Diagram

Template 21 – Componentes

digraph Components {
    graph [rankdir=LR];
    node [shape=component, fontsize=11];

    UI -> API;
    API -> Service;
    Service -> DB;
}

Línea de comandos:

dot -Tsvg Components.dot -o Components.svg

Class Diagram

Template 22 – Estilo UML

digraph Classes {
    graph [rankdir=TB];
    node [shape=record, fontsize=11];

    Person [label="{Person|name:string|age:int}"];
    Student [label="{Student|grade:int}"];
    Person -> Student;
}

Línea de comandos:

dot -Tsvg Classes.dot -o Classes.svg

Layouts

Template 23 – Horizontal

digraph Horizontal {
    graph [rankdir=LR];
    node [shape=box, style=rounded];
}

Línea de comandos:

dot -Tsvg Horizontal.dot -o Horizontal.svg

Template 24 – Vertical

digraph Vertical {
    graph [rankdir=TB];
    node [shape=box, style=rounded];
}

Línea de comandos:

dot -Tsvg Vertical.dot -o Vertical.svg

Template 25 – Circular

graph Circular {
    layout=circo;
    node [shape=box, style=rounded];
}

Línea de comandos:

dot -Kcirco -Tsvg Circular.dot -o Circular.svg

Estilos profesionales

Template 26 – Tema moderno

digraph Modern {
    graph [rankdir=LR];
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#eef3f8",
        color="#6a8bbf",
        fontsize=11
    ];
    edge [color="#6a8bbf"];

    A -> B -> C;
}

Línea de comandos:

dot -Tsvg Modern.dot -o Modern.svg

Template 27 – Tema Oscuro

digraph Dark {
    bgcolor="#1e1e1e";
    node [
        shape=box,
        style="rounded,filled",
        fillcolor="#333333",
        fontcolor="white",
        color="#777777",
        fontsize=11
    ];
    edge [color="#999999"];

    A -> B -> C;
}

Línea de comandos:

dot -Tsvg Dark.dot -o Dark.svg


Recursos útiles

Documentación oficial

Herramientas online

Integraciones y librerías

  • Graphviz Visual Editor (VSCode): Extensión para preview en vivo en Visual Studio Code
  • PlantUML: plantuml.com — Usa Graphviz para renderizado de UML
  • Mermaid: mermaid.js.org — Alternativa basada en JavaScript a Graphviz para gráficos en Markdown
  • Python graphviz: graphviz.readthedocs.io — Librería Python para generar grafos programáticamente
  • Go graphviz: github.com/goccy/go-graphviz — Binding Go para Graphviz

Galerías y ejemplos

Comunidad y soporte

  • Stack Overflow: Tag graphviz — Preguntas y respuestas de la comunidad
  • Reddit r/graphviz: reddit.com/r/graphviz — Discusiones, ejemplos y ayuda

Herramientas complementarias


Artículo escrito por Daniele Teti — danieleteti.it

Comments

comments powered by Disqus