Hoy voy a hablar de Graphviz, un proyecto que tiene ya unos cuantos años, y que si has ido a la universidad seguramente ya conozcas (al parecer se usa en muchas de ellas).

Para los que no, es algo que os puede resultar muy util a la hora de hacer gráficas relacionales, mapas de red, diagramas de flujo y cualquier otro tipo de representación gráfica similar. Libre, gratuito, facil de usar, potente y se maneja desde la linea de comandos de Linux... es decir, que es uno de esos programas a los que solo les falta tener tetas para ser perfecto...

Graphviz permite generar imágenes (PNG, SVG, GIF, etc) a partir de los datos que definamos mediante texto plano en un archivo, y el resultado no tiene nada que envidiar a algunos de los mejores servicios online de diseño de gráficas de éste tipo (como por ejemplo el genial Gliffy, que esta muy bien y es gratuito para un par de gráficas... pero cuando necesitas hacer más o usar opciones avanzadas, hay que pagar, y no es NADA barato).

Instalación

La instalación de Graphviz es absolutamente trivial, al menos si usamos una distribución de Linux decente como por ejemplo Debian. En éste caso (o en el de las que se basan en ella, como por ejemplo Ubuntu), bastaría con:

$ sudo apt-get install graphviz

Si por algun motivo (por ejemplo, que seamos masoquistas) utilizamos CentOS, Redhat o similares, podemos instalarlo también de forma muy facil con:

$ sudo yum install graphviz

Con ésto ya tendríamos instalado Graphviz y su lenguaje (llamado DOT).

Graphviz incluye también varios algoritmos de trazado gráfico diferentes, cada uno de los cuales crea gráficas de diferente tipo. Los más utilizados son:

  • DOT: Es el mejor para las gráfica de tipo jerárquico.
  • NEATO: Se utiliza para el dibujado de gráficos indirectos.
  • FDP: También se utiliza para el dibujado de gráficos indirectos.
  • TWOPI: Este algoritmo dibuja los elementos de la gráfica situándolos de forma circular alrededor del elemento raiz.

En artículo vamos a utilizar fundamentalmente el algoritmo DOT, ya que es el más común (aunque dependiendo de tus necesidades, quizás te convenga más utilizar otro en algun momento.

Utilización

Hay muchísimos usos en la vida para una gráfica del tipo relacional: mapas de red, esquemas de bases de datos SQL, flujos de datos, organigramas, etc.

Un ejemplo simple para ilustrar el tema sería la preparación de una tortilla (estoy escribiendo ésto de madrugada y tengo mucha hambre, no se me ocurre otra cosa mejor ahora mismo, lo siento).

Partiríamos de un montón de ingredientes sobre la mesa:

Lo primero que tendríamos que hacer sería pelar las patatas...

Una vez peladas hay que cortarlas y freirlas un poco hasta que se hayan dorado. Después, batimos los huevos, y echamos un poco de sal. Ponemos las patatas ya doradas en otra sartén, echamos los huevos batidos, y esperamos a que se haga un poco.

Al cabo del rato, le damos la vuelta a la tortilla y esperamos a que se haga éste otro lado tambien... y cuando esté lista, la servimos en un plato y pa'dentro.

Se podría esquematizar este proceso de la siguiente forma:

Ingredientes -> pelar patatas -> cortar patatas -> dorar patatas -> batir huevos -> echar sal -> mezclar huevos y patatas -> cocinar -> plato terminado

Cualquiera que vea ésto enseguida identifica un flujo, una serie de pasos que hay que hacer uno detrás del otro, y en un orden predefinido.

Pues bien, para dibujar una gráfica que represente precisamente ésto, con Graphviz únicamente tendríamos que definir las acciones y el orden en el que deben producirse. Por lo tanto, utilizando el lenguaje dot, el código sería algo así:

tortilla_v1.dotdownload
digraph tortilla_v1 {

        ingredientes -> pelar_patatas
        pelar_patatas -> cortar_patatas
        cortar_patatas -> freir_patatas
        freir_patatas -> esperar_a_que_se_doren
        esperar_a_que_se_doren -> batir_huevos
        batir_huevos -> echar_sal
        echar_sal -> mezclar_huevos_patatas
        mezclar_huevos_patatas -> cocinar
        cocinar -> dar_la_vuelta
        dar_la_vuelta -> cocinar_de_nuevo
        cocinar_de_nuevo -> servir
}

Sencillísimo, verdad? Ahora ejecutamos Graphviz (a través del comando dot) con el archivo que acabamos de crear (tortilla.dot) de ésta forma:

$ dot -Tpng tortilla.dot -o tortilla.png

Obtendremos un archivo llamado tortilla.png con ésta imagen:

El parámetro -T se utiliza para definir el formato que tendrá nuestra gráfica (png, svg, etc), y el -o indica el archivo donde guardaremos la gráfica generada.

No tiene mala pinta, no? Pues ahora vamos a darle una vuelta de tuerca más para profundizar en las opciones de Graphviz.

Podemos definir no solo las relaciones, sino la forma que tendrán éstas, colores (fondo, letra, etc), tamaños, incluso utilizar imágenes para los nodos, y mil cosas más (todas ellas explicadas en la documentación oficial de Graphviz.

Si pensamos en la forma en la que hemos descrito el proceso para hacer la tortilla, realmente no es un proceso lineal, sino que hay cosas que se pueden hacer al mismo tiempo. Es decir, no tenemos que esperar a que las patatas se doren para batir los huevos, sino que podemos batirlos mientras las patatas se estan dorando. Por lo tanto, el proceso ya no es lineal, sino que se puede dividir en 2 procesos paralelos.

Para representar ésto, basta con crear 2 subfunciones dentro de la función principal que hemos definido (una para cada proceso), pero únicamente para las acciones que vamos a realizar en paralelo, el resto de acciones siguen en la función principal igual que antes.

Es MUY importante que el nombre de estas funciones comience por cluster_, ya que de lo contrario no funcionará):

tortilla_v2.dotdownload
digraph tortilla_v2 {

        subgraph cluster_patatas {
            esperar_a_que_se_doren -> echar_sal_patatas
        }

        subgraph cluster_huevos {
            batir_huevos -> echar_sal_huevos
        }

        ingredientes -> pelar_patatas
        pelar_patatas -> cortar_patatas
        cortar_patatas -> freir_patatas
        freir_patatas -> esperar_a_que_se_doren
        freir_patatas -> batir_huevos
        echar_sal_patatas -> mezclar_huevos_patatas
        echar_sal_huevos -> mezclar_huevos_patatas
        mezclar_huevos_patatas -> cocinar
        cocinar -> dar_la_vuelta
        dar_la_vuelta -> cocinar_de_nuevo
        cocinar_de_nuevo -> servir
}

Y el resultado después de ejecutar el comando dot igual que antes sería:

Vamos a modificar otra cosa más...

La acción de dar_la_vuelta y cocinar puede repetirse tantas veces como sea necesario hasta que la tortilla quede en su punto, verdad? Por lo tanto, hay que modificar el código para indicar que esas acciones se pueden repetir varias veces. Para eso, basta con indicar que al igual que dar_la_vuelta cuelga de cocinar, ahora cocinar tambien colgará de dar_la_vuelta:

tortilla_v3.dotdownload
digraph tortilla_v3 {

        subgraph cluster_patatas {
            esperar_a_que_se_doren -> echar_sal_patatas
        }

        subgraph cluster_huevos {
            batir_huevos -> echar_sal_huevos
        }

        ingredientes -> pelar_patatas
        pelar_patatas -> cortar_patatas
        cortar_patatas -> freir_patatas
        freir_patatas -> esperar_a_que_se_doren
        freir_patatas -> batir_huevos
        echar_sal_patatas -> mezclar_huevos_patatas
        echar_sal_huevos -> mezclar_huevos_patatas
        mezclar_huevos_patatas -> cocinar
        cocinar -> dar_la_vuelta
        dar_la_vuelta -> cocinar
        dar_la_vuelta -> servir
}

Con esa modificación, la imagen resultante sería ésta:

Y añadiendo algunas cosas al código, podemos personalizar aún más la gráfica. Por ejemplo, vamos a cambiar la forma y el color de la acción inicial (ingredientes) y la acción final (servir) para que se diferencien de las demás, a meter los procesos que realizamos en paralelo en un cuadro, y un par de retoques más.

El código quedaría así:

tortilla_v4.dotdownload
digraph tortilla_v4 {

        subgraph cluster_patatas {
                node [style=filled];
                esperar_a_que_se_doren -> echar_sal_patatas
                label = "Patatas";
                color=blue;
        }

        subgraph cluster_huevos {
                node [style=filled];
                batir_huevos -> echar_sal_huevos
                label = "Huevos";
                color=blue
        }

        ingredientes -> pelar_patatas
        pelar_patatas -> cortar_patatas
        cortar_patatas -> freir_patatas
        freir_patatas -> esperar_a_que_se_doren
        freir_patatas -> batir_huevos
        echar_sal_patatas -> mezclar_huevos_patatas
        echar_sal_huevos -> mezclar_huevos_patatas
        mezclar_huevos_patatas -> cocinar
        cocinar -> dar_la_vuelta
        dar_la_vuelta -> cocinar
        dar_la_vuelta -> servir

        ingredientes [ shape=Msquare, color=lightgrey, style=filled ];
        servir [ shape=Msquare, color=lightgrey, style=filled ];

}

Y la imagen resultante, así:

Como veis, las posibilidades son casi infinitas... y más si le echais un ojo a la cantidad de atributos que podeis utilizar para configurar vuestras gráficas.

Veámos otro ejemplo, ésta vez en lugar de un flujo representaremos una jerarquía. Supongamos que tenemos que hacer un esquema que represente cómo será la jerarquía del Nuevo Orden Mundial el dia que finalmente yo gobierne vuestro mundo. Obviamente yo estaría enlo alto de dicho organigrama, y por debajo irían colgando las demás personas que servirían bajo mis órdenes, algunos de los cuales tendrían a su vez otras personas a sus órdenes.

Ésto podría representarse de forma muy básica mediante éste pseudo-código:

  Yo, lider mundial
          |
         / \
        /   \
       /     \
Kim Jong-un   Chuck Norris
                  |
                 / \
                /   \
         B. Obama   El papa
             |         |
             |         |
         M. Rajoy      |
                      / \
                     /   \
             Larry Page  Mark Zuckerberg

Si trasladamos éste esquema al lenguaje dot de Graphviz, tendremos algo parecido a ésto:

nuevo_orden_mundial.dotdownload
graph nuevo_orden_mundial {

    // Configuracion global de la grafica
    fontname = "Verdana";
    splines = ortho;
    fontsize = 20;
    style = dashed;
    shape = box;
    rankdir = R;
    ranksep = 0.5;

    // Configuracion de los elementos de la grafica
    node [
        fontname = "Verdana",
        style = filled,
        color = "#FFFFFF",
        fontcolor = "#000000",
        labelloc = b,
        shape = square,
        margin = 0,
        color = black,
        style = bold,
        fontsize = 8,
        fixedsize = true,
        width = 1.5
        ];

    // Elementos de la grafica
    lider [ label = "Yo, lider mundial", image = "cylon.png" ];
    kim   [ label = "Kim Jong-un", image = "kimjongun.jpeg" ];
    chuck [ label = "Chuck Norris", image = "chucknorris.jpeg" ];
    obama [ label = "B. Obama", image = "obama.jpeg" ];
    emperador [ label = "Emperador", image = "emperador.jpeg" ];
    rajoy [ label = "M. Rajoy", image = "rajoy.jpeg" ];
    larry [ label = "Larry Page", image = "larry.jpeg" ];
    mark  [ label = "Mark Zuckerberg", image = "mark.jpeg" ];

    // Relaciones entre los elementos
    lider -- kim
    lider -- chuck

    chuck -- obama
    chuck -- emperador

    obama -- rajoy

    emperador -- larry
    emperador -- mark
}

Si os parais a leer el código detenidamente, enseguida vereis que es sencillísimo y prácticamente autoexplicativo.

Simplemente se define una gráfica (en nuestro caso de tipo graph y con el nombre nuevo_orden), y luego se definen sus partes:

  • Configuración general de la gráfica: tipos de letra, tamaños, tipos de uniones entre los elementos que la componen, etc.
  • Después podemos definir la configuración de los elementos (nodos) de la gráfica: colores, tipos de letra, forma geométrica del borde que lo rodeará, etc.
  • Luego se definen los nodos, es decir, las partes que se relacionarán en nuestra gráfica: nombre, imagen, y cualquier otra cosa que queramos.
  • Y por último se indica la relación que cada nodo tiene con los demás: Es decir, de quién es hijo cada uno de ellos.

Solo tenemos que darle éste archivo que acabamos de crear a Graphviz para que nos genere la imagen de dicha gráfica. Por lo tanto, de nuevo ejecutamos el comando dot como las anteriores veces:

$ dot -Tpng nuevo-orden-mundial.dot -o nuevo-orden-mundial.png

Y listo... una vez ejecutado ese comando tendremos en el directorio actual un archivo llamado nuevo-orden-mundial.png, que contendrá la imagen con nuestra gráfica. En éste último caso, la gráfica que representaría ésta no-tan-lejana situación con mis súbditos lacayos sería ésta:

Y si estais pensando en integrar éste tipo de gráficas en vuestros blogs creados con Octopress, hay varios plugins que os pueden ayudar a hacerlo y de los cuales ya hablé en éste otro post.

Éstos han sido solo unos ejemplos muy básicos de las cosas que se pueden hacer... si probais las diferentes opciones veréis que se pueden crear gráficas increibles. Y para muestra, os pongo el código y la gráfica resultante de algunos de los ejemplos de la propia web de Graphviz, algunos de los cuales son absolutamente impresionantes (únicamente os muestro las gráficas ya generadas, no el código, para no aburriros... pero si quereis verlo, recordar que son imágenes SVG, por lo que únicamente teneis que darle a Ver código fuente de la imagen en cuestión desde vuestro navegador, y listo!):

Ejemplo para relaciones entre tablas de una base de datos

demo_graphviz_1.dotdownload
digraph g {
	graph [
		rankdir = "LR"
	];
	node [
		fontsize = "16"
		shape = "ellipse"
	];
	edge [
	];
	"node0" [
		label = "<f0> 0x10ba8| <f1>"
		shape = "record"
	];
	"node1" [
		label = "<f0> 0xf7fc4380| <f1> | <f2> |-1"
		shape = "record"
	];
	"node2" [
		label = "<f0> 0xf7fc44b8| | |2"
		shape = "record"
	];
	"node3" [
		label = "<f0> 3.43322790286038071e-06|44.79998779296875|0"
		shape = "record"
	];
	"node4" [
		label = "<f0> 0xf7fc4380| <f1> | <f2> |2"
		shape = "record"
	];
	"node5" [
		label = "<f0> (nil)| | |-1"
		shape = "record"
	];
	"node6" [
		label = "<f0> 0xf7fc4380| <f1> | <f2> |1"
		shape = "record"
	];
	"node7" [
		label = "<f0> 0xf7fc4380| <f1> | <f2> |2"
		shape = "record"
	];
	"node8" [
		label = "<f0> (nil)| | |-1"
		shape = "record"
	];
	"node9" [
		label = "<f0> (nil)| | |-1"
		shape = "record"
	];
	"node10" [
		label = "<f0> (nil)| <f1> | <f2> |-1"
		shape = "record"
	];
	"node11" [
		label = "<f0> (nil)| <f1> | <f2> |-1"
		shape = "record"
	];
	"node12" [
		label = "<f0> 0xf7fc43e0| | |1"
		shape = "record"
	];
	"node0":f0 -> "node1":f0 [
		id = 0
	];
	"node0":f1 -> "node2":f0 [
		id = 1
	];
	"node1":f0 -> "node3":f0 [
		id = 2
	];
	"node1":f1 -> "node4":f0 [
		id = 3
	];
	"node1":f2 -> "node5":f0 [
		id = 4
	];
	"node4":f0 -> "node3":f0 [
		id = 5
	];
	"node4":f1 -> "node6":f0 [
		id = 6
	];
	"node4":f2 -> "node10":f0 [
		id = 7
	];
	"node6":f0 -> "node3":f0 [
		id = 8
	];
	"node6":f1 -> "node7":f0 [
		id = 9
	];
	"node6":f2 -> "node9":f0 [
		id = 10
	];
	"node7":f0 -> "node3":f0 [
		id = 11
	];
	"node7":f1 -> "node1":f0 [
		id = 12
	];
	"node7":f2 -> "node8":f0 [
		id = 13
	];
	"node10":f1 -> "node11":f0 [
		id = 14
	];
	"node10":f2 -> "node12":f0 [
		id = 15
	];
	"node11":f2 -> "node1":f0 [
		id = 16
	];
}

Ejemplo con diferentes formas y colores

demo_graphviz_2.dotdownload
digraph "unix" {
	graph [	fontname = "Helvetica-Oblique",
	      fontsize = 36,
	      label = "\n\n\n\nObject Oriented Graphs\nStephen North, 3/19/93",
	      size = "6,6" ];
	node [	shape = polygon,
	     sides = 4,
	     distortion = "0.0",
	     orientation = "0.0",
	     skew = "0.0",
	     color = white,
	     style = filled,
	     fontname = "Helvetica-Outline" ];
	"5th Edition" [sides=9, distortion="0.936354", orientation=28, skew="-0.126818", color=salmon2];
	"6th Edition" [sides=5, distortion="0.238792", orientation=11, skew="0.995935", color=deepskyblue];
	"PWB 1.0" [sides=8, distortion="0.019636", orientation=79, skew="-0.440424", color=goldenrod2];
	LSX [sides=9, distortion="-0.698271", orientation=22, skew="-0.195492", color=burlywood2];
	"1 BSD" [sides=7, distortion="0.265084", orientation=26, skew="0.403659", color=gold1];
	"Mini Unix" [distortion="0.039386", orientation=2, skew="-0.461120", color=greenyellow];
	Wollongong [sides=5, distortion="0.228564", orientation=63, skew="-0.062846", color=darkseagreen];
	Interdata [distortion="0.624013", orientation=56, skew="0.101396", color=dodgerblue1];
	"Unix/TS 3.0" [sides=8, distortion="0.731383", orientation=43, skew="-0.824612", color=thistle2];
	"PWB 2.0" [sides=6, distortion="0.592100", orientation=34, skew="-0.719269", color=darkolivegreen3];
	"7th Edition" [sides=10, distortion="0.298417", orientation=65, skew="0.310367", color=chocolate];
	"8th Edition" [distortion="-0.997093", orientation=50, skew="-0.061117", color=turquoise3];
	"32V" [sides=7, distortion="0.878516", orientation=19, skew="0.592905", color=steelblue3];
	V7M [sides=10, distortion="-0.960249", orientation=32, skew="0.460424", color=navy];
	"Ultrix-11" [sides=10, distortion="-0.633186", orientation=10, skew="0.333125", color=darkseagreen4];
	Xenix [sides=8, distortion="-0.337997", orientation=52, skew="-0.760726", color=coral];
	"UniPlus+" [sides=7, distortion="0.788483", orientation=39, skew="-0.526284", color=darkolivegreen3];
	"9th Edition" [sides=7, distortion="0.138690", orientation=55, skew="0.554049", color=coral3];
	"2 BSD" [sides=7, distortion="-0.010661", orientation=84, skew="0.179249", color=blanchedalmond];
	"2.8 BSD" [distortion="-0.239422", orientation=44, skew="0.053841", color=lightskyblue1];
	"2.9 BSD" [distortion="-0.843381", orientation=70, skew="-0.601395", color=aquamarine2];
	"3 BSD" [sides=10, distortion="0.251820", orientation=18, skew="-0.530618", color=lemonchiffon];
	"4 BSD" [sides=5, distortion="-0.772300", orientation=24, skew="-0.028475", color=darkorange1];
	"4.1 BSD" [distortion="-0.226170", orientation=38, skew="0.504053", color=lightyellow1];
	"4.2 BSD" [sides=10, distortion="-0.807349", orientation=50, skew="-0.908842", color=darkorchid4];
	"4.3 BSD" [sides=10, distortion="-0.030619", orientation=76, skew="0.985021", color=lemonchiffon2];
	"Ultrix-32" [distortion="-0.644209", orientation=21, skew="0.307836", color=goldenrod3];
	"PWB 1.2" [sides=7, distortion="0.640971", orientation=84, skew="-0.768455", color=cyan];
	"USG 1.0" [distortion="0.758942", orientation=42, skew="0.039886", color=blue];
	"CB Unix 1" [sides=9, distortion="-0.348692", orientation=42, skew="0.767058", color=firebrick];
	"USG 2.0" [distortion="0.748625", orientation=74, skew="-0.647656", color=chartreuse4];
	"CB Unix 2" [sides=10, distortion="0.851818", orientation=32, skew="-0.020120", color=greenyellow];
	"CB Unix 3" [sides=10, distortion="0.992237", orientation=29, skew="0.256102", color=bisque4];
	"Unix/TS++" [sides=6, distortion="0.545461", orientation=16, skew="0.313589", color=mistyrose2];
	"PDP-11 Sys V" [sides=9, distortion="-0.267769", orientation=40, skew="0.271226", color=cadetblue1];
	"USG 3.0" [distortion="-0.848455", orientation=44, skew="0.267152", color=bisque2];
	"Unix/TS 1.0" [distortion="0.305594", orientation=75, skew="0.070516", color=orangered];
	"TS 4.0" [sides=10, distortion="-0.641701", orientation=50, skew="-0.952502", color=crimson];
	"System V.0" [sides=9, distortion="0.021556", orientation=26, skew="-0.729938", color=darkorange1];
	"System V.2" [sides=6, distortion="0.985153", orientation=33, skew="-0.399752", color=darkolivegreen4];
	"System V.3" [sides=7, distortion="-0.687574", orientation=58, skew="-0.180116", color=lightsteelblue1];
	"5th Edition" -> "6th Edition";
	"5th Edition" -> "PWB 1.0";
	"6th Edition" -> LSX;
	"6th Edition" -> "1 BSD";
	"6th Edition" -> "Mini Unix";
	"6th Edition" -> Wollongong;
	"6th Edition" -> Interdata;
	Interdata -> "Unix/TS 3.0";
	Interdata -> "PWB 2.0";
	Interdata -> "7th Edition";
	"7th Edition" -> "8th Edition";
	"7th Edition" -> "32V";
	"7th Edition" -> V7M;
	"7th Edition" -> "Ultrix-11";
	"7th Edition" -> Xenix;
	"7th Edition" -> "UniPlus+";
	V7M -> "Ultrix-11";
	"8th Edition" -> "9th Edition";
	"1 BSD" -> "2 BSD";
	"2 BSD" -> "2.8 BSD";
	"2.8 BSD" -> "Ultrix-11";
	"2.8 BSD" -> "2.9 BSD";
	"32V" -> "3 BSD";
	"3 BSD" -> "4 BSD";
	"4 BSD" -> "4.1 BSD";
	"4.1 BSD" -> "4.2 BSD";
	"4.1 BSD" -> "2.8 BSD";
	"4.1 BSD" -> "8th Edition";
	"4.2 BSD" -> "4.3 BSD";
	"4.2 BSD" -> "Ultrix-32";
	"PWB 1.0" -> "PWB 1.2";
	"PWB 1.0" -> "USG 1.0";
	"PWB 1.2" -> "PWB 2.0";
	"USG 1.0" -> "CB Unix 1";
	"USG 1.0" -> "USG 2.0";
	"CB Unix 1" -> "CB Unix 2";
	"CB Unix 2" -> "CB Unix 3";
	"CB Unix 3" -> "Unix/TS++";
	"CB Unix 3" -> "PDP-11 Sys V";
	"USG 2.0" -> "USG 3.0";
	"USG 3.0" -> "Unix/TS 3.0";
	"PWB 2.0" -> "Unix/TS 3.0";
	"Unix/TS 1.0" -> "Unix/TS 3.0";
	"Unix/TS 3.0" -> "TS 4.0";
	"Unix/TS++" -> "TS 4.0";
	"CB Unix 3" -> "TS 4.0";
	"TS 4.0" -> "System V.0";
	"System V.0" -> "System V.2";
	"System V.2" -> "System V.3";
}

Ejemplo de un organigrama empresarial

demo_graphviz_3.dotdownload
digraph Organigram {

	/* General Layout */
	rankdir = LR;

	/* Subgraph Branches */	

	Subgraph cluster_Branches {

		node [shape = square, fontsize = 8];

		BRANCHES [style = bold];
		Denrie [color = grey];
		Information [color = grey];
		"Quick ID" [color = grey];
		Instrument [color = grey];
		Biomaterial [color = grey];
		Quality [color = grey];
		Function [color = grey];
		Role [color = grey];


		style = dashed;
	}

	/* Subgraph Developers */	

	Subgraph cluster_Developers {

		node [shape = box, fontsize = 8];

		DEVELOPERS [style = bold];
		"Coordinating Committee" [color = grey];
		"Developers Working Groups" [color = grey];
		"Supporting Working Groups" [color = grey];
		"Community Representatives" [color = grey];
		"Scientific Community" [color = grey];

		style = dashed;
	}

	/* Subgraph Development ORGANIZATION */
	Subgraph cluster_ORGANIZATION {

		node [shape = box, fontsize = 8]

			"ORGANIZATION" [style = bold];
		"Mailinglists" [color = grey];
		"Conference Calls" [color = grey];
		Documents [color = grey];
		Workshops [color = grey];
		WIKI [color = grey];

		style = dashed;
	}

	/* Sub Cluster Design */
	Subgraph cluster_Design {

		node [shape = box, fontsize = 8]

			DESIGN [style = bold];
		"TOOLS" [color = grey];
		"Design Patterns" [color = grey];
		"Design Principles" [color = grey];
		"Design Process" [color = grey];
		"Policy" [color = grey];

		style = dashed;
	}

	/* Sub Evaluation */
	Subgraph cluster_Evaluation {

		node [shape = box, fontsize = 8]

			"OBI Evaluation" [color = grey];
		"Terms + Use Cases" [color = grey];

		style = dashed;
	}

	/* Relations */

	node [shape = box, style = filled, color = black, fontcolor = white, fontsize = 10];


	OBI -> BRANCHES;
	BRANCHES -> Denrie;
	BRANCHES -> Information;
	BRANCHES -> Instrument;
	BRANCHES -> Biomaterial;
	BRANCHES -> Quality;
	BRANCHES -> Function;
	BRANCHES -> Role;
	BRANCHES -> "Quick ID";

	OBI -> DEVELOPERS;
	DEVELOPERS -> "Coordinating Committee";
	DEVELOPERS -> "Developers Working Groups";
	DEVELOPERS -> "Supporting Working Groups";
	DEVELOPERS -> "Community Representatives";
	DEVELOPERS -> "Scientific Community";

	"Scientific Community" -> "Quick ID";
	"Community Representatives" -> "BRANCHES";
	"Supporting Working Groups" -> "BRANCHES";
	"Coordinating Committee" -> "BRANCHES";
	"Developers Working Groups" -> "BRANCHES";

	OBI -> ORGANIZATION;
	ORGANIZATION -> "Mailinglists";
	ORGANIZATION -> "Conference Calls";
	ORGANIZATION -> Documents;
	ORGANIZATION -> Workshops;
	ORGANIZATION -> WIKI;

	OBI -> DESIGN;
	DESIGN -> "Design Patterns";
	DESIGN -> "Design Principles";
	DESIGN -> TOOLS;
	DESIGN -> "Design Process";
	DESIGN -> Policy;

	"Design Process" -> "Terms + Use Cases";
	"Terms + Use Cases" ->"OBI Evaluation";
	"OBI Evaluation" -> DESIGN;
}

Ejemplo de una gráfica utilizando degradados de colores

demo_graphviz_4.dotdownload
digraph G {bgcolor="red:cyan" gradientangle=0

	subgraph cluster_0 {
		style=filled;
		color=lightgrey;
		fillcolor="blue:yellow";
		gradientangle=90;
		node [fillcolor="yellow:green" style=filled gradientangle=270] a0;
		node [fillcolor="green:red"] a1;
		node [fillcolor="red:cyan"] a2;
		node [fillcolor="cyan:blue"] a3;

		a0 -> a1 -> a2 -> a3;
		label = "process #1";
	}

	subgraph cluster_1 {
		node [fillcolor="yellow:magenta" 
			 style=filled gradientangle=270] b0;
		node [fillcolor="magenta:cyan"] b1;
		node [fillcolor="cyan:red"] b2;
		node [fillcolor="red:blue"] b3;

		b0 -> b1 -> b2 -> b3;
		label = "process #2";
		color=blue
		fillcolor="blue:yellow";
		style=filled;
		gradientangle=90;
	}
	start -> a0;
	start -> b0;
	a1 -> b3;
	b2 -> a3;
	a3 -> a0;
	a3 -> end;
	b3 -> end;

	start [shape=Mdiamond ,
		fillcolor="yellow:brown",
		gradientangle=90,
		style=radial];
	end [shape=Msquare,
		fillcolor="orange:blue",
		style=radial,
		gradientangle=90];
}

Referencias