Grafos creados con elementos SVG

Figura
Figura. Grafo (árbol) con SVG

Esta Herramienta de Web Tool Online sirve para crear grafos usando exclusivamente elementos SVG. Puede interactuar con el editor SVG traspasando el código SVG generado en la gráfica a ese editor y así poder realizar modificaciones en los elementos SVG de la gráfica. Otra posibilidad es traspasar el código al Parseador XML con objeto de verificar la corrección del SVG, pues en cualquier caso un SVG es un XML.

En la Figura puede ver un grafo generado con este editor. Realmente es un árbol, pues un grafo conexo sin ciclos es un árbol. En adelante hablaremos de grafos que incluye también a los árboles. Se observa que los nodos apuntan a sus padres. Para generarlo hemos utilizado la siguiente información para establecer los nodos:

[
  {"index": 0, "parent": -1},
  {"index": 1, "parent": 0},
  {"index": 2, "parent": 0},
  {"index": 3, "parent": 0},
  {"index": 4, "parent": 2},
  {"index": 5, "parent": 2},
  {"index": 6, "parent": 3},
  {"index": 7, "parent": 4}
]

Se trata de un Array donde cada objeto representa un nodo. Cada nodo tiene un indice (index) único. Serán cualesquiera números enteros no negativos, no necesariamente seguidos ni ordenados, pero en ningún caso repetidos. Cada nodo debe apuntar obligatoriamente a algún padre (parent). En esta cadena de enlaces tiene que haber uno o más nodos que sean los iniciales, llamado nodo raíz en caso de un árbol. Apuntarán al valor -1.

La disposición gráfica de los nodos y aristas se realiza de forma automática. Aunque es posible desplazar las líneas de las aristas usando alguna configuración para el nodo. Más abajo hablaremos de las configuraciones que particularizan la presentación.

Interfaz de la herramienta

Figura
Figura. Interfaz del editor de grafos con SVG

La información de nodos del primer ejemplo del apartado anterior se inserta en el área de texto del inicio de la herramienta como puede ver en la Figura. Pero por defecto no se pintan las flechas. Para ello hay que seleccionar la configuración marcador final con el valor arrow.

Existe la posibilidad de exportar el grafo en un archivo de texto, generándose lo siguiente para el ejemplo visto antes. Se trata de una representación JSON de un objeto que contiene dos propiedades. Una de ellas es nodes que contiene la información de los nodos. La otra es config que contiene la configuración general del grafo. Se puede exportar sólo las configuraciones que difieren de los valores iniciales, ahorrándonos así tamaño de archivo:

{
  "nodes": [
    {"index": 0, "parent": -1},
    {"index": 1, "parent": 0},
    {"index": 2, "parent": 0},
    {"index": 3, "parent": 0},
    {"index": 4, "parent": 2},
    {"index": 5, "parent": 2},
    {"index": 6, "parent": 3},
    {"index": 7, "parent": 4}
  ],
  "config": {
    "markerEnd": "arrow"
  }
}

Posteriormente podemos cargar ese archivo de texto e importar el grafo guardado.

Configuración del grafo

La configuración general establece propiedades para todo el grafo. En la siguiente tabla se resumen las configuraciones posibles en este momento. Es posible que se modifique en el futuro. En la herramienta también hay una ayuda que mostrará esta tabla con los valores actuales.

El código SVG puede ser modificado traspasando su contenido al Editor SVG usando el botón . En el editor SVG podemos realizar modificaciones en la propia gráfica, como corregir ubicaciones de elementos, cambiar colores, etc.

También puede traspasarse el código al Parseador XML para verificar la corrección del mismo usando el botón .

A continuación se muestra una lista con las configuraciones de la gráfica:

GrupoNombreTítuloValor inicialTipo valorChequeoValores
svgwvAncho ViewBox100Number/^(?:0|[1-9]\d*)$/[0 .. 10000]
hvAlto ViewBox100Number/^(?:0|[1-9]\d*)$/[0 .. 10000]
widthAncho SVG250Number/^(?:0|[1-9]\d*)$/[0 .. 10000]
heightAlto SVG250Number/^(?:0|[1-9]\d*)$/[0 .. 10000]
langIdiomaesString/^[a-z]+$/i[Text]
adjustAjustar SVGfalseBooleanValores alternativostrue | false
lineHeightAltura línea25Number/^(?:0|[1-9]\d*)$/[0 .. 10000]
precisionPrecisión2Number/^(?:0|[1-9]\d*)$/[0 .. 6]
classNameClase CSSString/^[a-zA-Z]+[\w-]*_$/[Text]
styleEstilo CSSString/^[\w\s.;:-]+$/[Text]
xmlnsXMLNShttp://www.w3.
org/2000/svg
SelectValores alternativos- | http://www.w3.org/2000/svg
nodesnodeColorColor nodowhiteString/^(?:#[a-fA-F\d]{3,6}|[a-z]+|(?:rgb|hsl)a?\s*\((?:\s*(?:0|0?\.\d+|[1-9]\d*\.?\d*)%?\s*(?:,|\)$)\s*){3,4}\)?)$/[Text]
nodeFontFamilyFuente nodoArialString/^(?:[a-z\s]+)$/i[Text]
nodeFontColorColor texto nodocurrentcolorString/^(?:#[a-fA-F\d]{3,6}|[a-z]+|(?:rgb|hsl)a?\s*\((?:\s*(?:0|0?\.\d+|[1-9]\d*\.?\d*)%?\s*(?:,|\)$)\s*){3,4}\)?)$/[Text]
nodeFontItalicTexto itálica nodofalseBooleanValores alternativostrue | false
nodeFontBoldTexto negrita nodofalseBooleanValores alternativostrue | false
lineslineColorColor líneacurrentcolorString/^(?:#[a-fA-F\d]{3,6}|[a-z]+|(?:rgb|hsl)a?\s*\((?:\s*(?:0|0?\.\d+|[1-9]\d*\.?\d*)%?\s*(?:,|\)$)\s*){3,4}\)?)$/[Text]
lineFontFamilyFuente aristaArialString/^(?:[a-z\s]+)$/i[Text]
lineFontColorColor texto aristacurrentcolorString/^(?:#[a-fA-F\d]{3,6}|[a-z]+|(?:rgb|hsl)a?\s*\((?:\s*(?:0|0?\.\d+|[1-9]\d*\.?\d*)%?\s*(?:,|\)$)\s*){3,4}\)?)$/[Text]
lineFontItalicTexto itálica aristafalseBooleanValores alternativostrue | false
lineFontBoldTexto negrita aristatrueBooleanValores alternativostrue | false
lineWidthAncho línea arista1Number/^(?:0|0?\.\d+|[1-9]\d*\.?\d*)$/[0 .. 10]
lineOffsetSeparación arista0String/^[+-]?(?:0|0?\.\d+|[1-9]\d*\.?\d*)(?:\s+[+-]?(?:0|0?\.\d+|[1-9]\d*\.?\d*))?$/[Text]
lineTextOffsetSeparación valor arista0String/^[+-]?(?:0|0?\.\d+|[1-9]\d*\.?\d*)(?:\s+[+-]?(?:0|0?\.\d+|[1-9]\d*\.?\d*))?$/[Text]
lineTextPositionPosición texto aristamiddle centralSelectValores alternativosstart text-before-edge | start central | start text-after-edge | middle text-before-edge | middle central | middle text-after-edge | end text-before-edge | end central | end text-after-edge
lineTextStrokeResalte texto aristatrueBooleanValores alternativostrue | false
lineDashRayado arista0Number/^(?:0|[1-9]\d*)$/[0 .. 10000]
markersmarkerStartMarcador iniciononeSelectValores alternativosnone | circle | arrow
markerEndMarcador finalnoneSelectValores alternativosnone | circle | arrow
markerSizeTamaño marcador2Number/^(?:0|0?\.\d+|[1-9]\d*\.?\d*)$/[0 .. 6]
markerReverseRelación ascendiente invertidafalseBooleanValores alternativostrue | false

Algunos detalles a tener en cuenta con la tabla anterior cuando pasemos la configuración en create({values, config}):

  • Columna Valor inicial: No es necesario pasar los valores por defecto.
  • Los valores como [1 .. 10] se refiere a un número entre esos dos valores. Con [Text] expresamos que puede incluirse cualquier texto, aunque se chequeará con una expresión regular.
  • Columna Chequeo: Los valores se chequean con expresiones regulares o bien con los valores alternativos de la columna Valores.
  • Si un valor no pasa el chequeo se utilizará el valor inicial.

Configuración del nodo

Figura
Figura. Grafo con SVG

En la Figura puede observar un grafo. La información de nodos se expone en el código a continuación de este párrafo. Las propiedades index y parent son obligatorias. Otras propiedades como value son opcionales. También pueden aplicarse todas las propiedades de la configuración general que afecten a nodos, líneas y marcadores.

Los nodos se encierran en un círculo. Su valor es el del índice a no ser que se especifique la propiedad value. Observe que el nodo con índice 1 tiene establecido "value":"X".

[
  {"index":0, "parent":-1},
  {"index":1, "value":"X", "parent":[
          {"index":0, "value":"A"}
      ]
  },
  {"index":2, "parent":[
         {"index":0, "value":"B"},
         {"index":1, "value":"C"}
      ]
  },
  {"index":3, "parent":[
         {"index":1, "value":"D"},
         {"index":4, "value":"E"}
      ]
  },
  {"index":4, "parent":[
         {"index":1, "value":"F"},
         2
      ]
  }
]

La propiedad parent es un Array con una colección de nodos donde apunta el nodo. Puede simplificarse con un número entero, como por ejemplo {"index":0, "parent":-1}, de tal forma que apunta a un único nodo cuyo índice es ese número. Si hemos de apuntar a varios nodos usaremos un Array, pudiendo combinar objetos y números, como el parent del nodo 4 en el código anterior. Ese nodo 4 apunta al 1 con una arista cuyo texto es "F" y también apunta al 2 sin más especificaciones.

Figura
Figura. Grafo con SVG: agregar arista que une nodos 4 y 0

Supongamos ahora que el nodo 4 también debe apuntar al 0. Sólo basta agregar un cero a la definición del nodo 4 del código anterior:

"parent":[{"index":1, "value":"F"}, 2, 0]

El resultado se muestra en la Figura.

Figura
Figura. Grafo con SVG: desplazar arista que une nodos 4 y 0

La arista que une el nodo 4 y el 0 cruza otros elementos. Existe la posibilidad de desplazar esa arista usando la propiedad lineOffset. Para ello sustituímos el 0 del código anterior por lo siguiente:

{"index":0, "lineOffset":1}

El resultado se muestra en la Figura.

La propiedad lineOffset es un String como H V donde H y V son números reales positivos o negativos para desplazar horizontal y verticalmente. Si sólo se pasa un número se aplicará al horizontal. Para sólo desplazar verticalmente pasaremos un cero en H. El desplazamiento es igual al radio de los círculos, valor que se calcula automáticamente.

Figura
Figura. Grafo con SVG: presentar flechas

Si seleccionamos la configuración para presentar marcadores finales en forma de flecha, vemos en la Figura que el nodo 4 apunta a los nodos 0, 1 y 2 (al nodo 1 le pusimos un valor "X"). Recuerde que esta configuración de flechas no es a nivel de nodo, sino a nivel general, aunque también puede configurarse cada flecha individualmente.

Figura
Figura. Grafo con SVG: invertir flecha de la arista que une 4 y 0

Podemos invertir el sentido de la flecha usando la propiedad markerReverse. Por defecto tiene el valor falso. Para invertir una flecha le daremos el valor verdadero:

{"index":0, "offset":"h1", "markerReverse":true}

El resultado se muestra en la Figura, donde se observa que la arista que une el 4 y el 0 tiene una flecha que apunta en la dirección inversa 0→4.

Figura
Figura. Grafo con SVG: desplazar texto "D"

Por último veamos la propiedad lineTextOffset. Observamos que el texto "D", que es el valor de la arista que une el nodo 3 con el 1, quedó automáticamente ubicado en un lugar que lo hace poco legible. Podemos desplazarlo usando el String "-0.75 0.25". Con dos valores el primero es el desplazamiento vertical y el segundo el horizontal. Con sólo un valor se aplicará al horizontal. Por lo tanto desplazamos 0.75 a la izquierda y 0.25 abajo. En el nodo 3 agregamos esta propiedad:

{"index":3, "parent":[{"index":1, "value":"D", "lineTextOffset":"-0.75 0.25"}, {"index":4, "value":"E"}]}

El resultado se muestra en la Figura. El JSON final de este ejemplo está accesible como muestra en la herramienta. El código final para importar es el siguiente:

{"nodes":[{"index":0,"parent":-1},
{"index":1,"value":"X","parent":[{"index":0,"value":"A"}]},
{"index":2,"parent":[{"index":0,"value":"B"},{"index":1,"value":"C"}]},
{"index":3,"parent":[{"index":1,"value":"D","lineTextOffset":"-0.75 0.25"},
{"index":4,"value":"E"}]},{"index":4,"parent":[{"index":1,"value":"F"},2,{"index":0,"lineOffset":1,"markerReverse":true}]}],
"config":{"markerEnd":"arrow"}}

Grafos no conexos

Figura
Figura. Varios grafos

Es posible representar un grafo no conexo compuesto de varios subgrafos. En la Figura se observan dos subgrafos no conectados. Para ello basta indicar los nodos raíces 0 y 3 que apuntan a un padre -1, como se observa en el código.

En cada nivel se ubican de forma automática los nodos, centrándolos en cada línea horizontal de nodos. En cualquier caso siempre existe la posibilidad de editar el grafo con el Editor SVG para modificar cualquier elemento.

[{"index":0, "parent":-1},
{"index":1, "parent":0},
{"index":2, "parent":0},
{"index":3, "parent":-1},
{"index":4, "parent":3},
{"index":5, "parent":3},
{"index":6, "parent":4},
{"index":7, "parent":4}]