viernes, 6 de julio de 2012

Usar Graphviz desde Java

Graphviz es una herramienta que agrupa varios programas que generan distintos tipos de grafos a partir de archivos con un lenguaje definido. o tambien a travez de una api. (ejemplo de uso de graphviz desde C# para dibujar árbol binario, ejemplo de graphviz para dibujar un arbol B)

primero te descargas el paquete de graphviz y lo instalas
http://www.graphviz.org/Download_windows.php 

eso crea en archivos de programa una carpeta

C:\Archivos de programa\Graphviz 2.28\bin

ahi estan los ejecutables que nos interesan, en este caso por lo que planteas vamos a usar dot.exe que es para dibujar grafos dirigidos jerarquicos.

algo mas del lenguaje dot

http://www.graphviz.org/Documentation/dotguide.pdf

un ejemplo de grafo simple

grafo1.txt

Código:
digraph G
{
    node1;
    node2;
    node3;

    node1 -> node2 [label="linea1"];
    node1 -> node3 [label="linea2"];
    node2 -> node3 [label="linea3"];
}





lunes, 2 de julio de 2012

C# Dibujar Arbol Binario Graphviz

Para continuar con Graphviz, esta vez desde C#,

en este pequeño ejemplo, voy a implementar una forma simple de dibujar un Arbol Binario usando Graphviz y en especifico, Dot.

Como base para entender el funcionamiento general de Graphviz, hace tiempo hice un post hablando mas en detalle del proceso usando Java (Usar GraphViz en Java)

Para que este ejemplo funcione, es necesario tener instalado GraphViz con la carpeta "bin" de GraphViz como parte de la variable Path de Windows (esto para poder invocar Dot.exe usando solo el nombre del binario, el mismo caso que para los ejecutables Javac o Java en el Path)

Para no entrar en los detalles del codigo de un Arbol Binario, he tomado como base el ejemplo publicado en Code Project (http://www.codeproject.com/Articles/18976/A-simple-Binary-Search-Tree-written-in-C)


TBinarySTree bt = new TBinarySTree();
bt.insert ("Bill", 3.14);
bt.insert ("John". 2.71);


Dicho ejemplo resulta muy conveniente, ya que con un par de ajustes mínimos, se presta para generar su representación en el formato de grafo que utiliza Dot para dibujar.

dichos ajustes son.

1) Agregar un ToString() a la clase del Nodo, para que cada Nodo pueda generar un String que lo represente, en este caso solo usando la propiedad Name.

public class TTreeNode {
           public string name;
           public double value; 
           public TTreeNode left, right;
           
        // Constructor  to create a single node 
        public TTreeNode (string name, double d) {
              this.name = name;
              value = d;
              left = null;
              right = null;
           }

        public override string ToString()
        {
            return string.Format("\"{0}\"", name);
        }
    }

2) Exponer en el Arbol un metodo para acceder al Nodo Raiz de dicho Arbol. 

public class TBinarySTree
    {
        // Implements:

        // count()
        // clear()
        // insert()
        // delete()
        // findSymbol()
        //
        // Usage:
        //
        //  TBinarySTree bt = new TBinarySTree();
        //  bt.insert ("Bill", "3.14");
        //  bt.insert ("John". 2.71");
        //  etc.
        //  node = bt.findSymbol ("Bill");
        //  WriteLine ("Node value = {0}\n", node.value);
        //

        private TTreeNode root;     // Points to the root of the tree
        private int _count = 0;

        public TTreeNode GetRoot()
        {
            return root;
        }

Luego un par de metodos para generar la representacion de cada nodo y sus relaciones en lenguaje para Dot

        public static string ToDotGraph(TBinarySTree tree) {
            StringBuilder b = new StringBuilder();
            b.Append("digraph G {" + Environment.NewLine);
            b.Append(ToDot(tree.GetRoot()));            
            b.Append("}");
            return b.ToString();
        }


        public static string ToDot(TTreeNode node) {
            StringBuilder b = new StringBuilder();
            if (node.left != null) {
                b.AppendFormat("{0}->{1}{2}", node.ToString(), node.left.ToString(), Environment.NewLine);
                b.Append(ToDot(node.left));
            }

            if (node.right != null) {
                b.AppendFormat("{0}->{1}{2}", node.ToString(), node.right.ToString(), Environment.NewLine);
                b.Append(ToDot(node.right));
            }
            return b.ToString();
        }


El programa que use para demostrar el ejemplo, Genera un grafo aleatorio con mas de 10 nodos, y luego genera un archivo txt en la carpeta de ejecucion con el codigo para Graphviz que representa al grafo, invoca a dot para generar una imagen JPG y abrirla luego con el visor predeterminado,

demo



por ejemplo:




Descargar Codigo Fuente