Mike Daines

Viz.js 3.23.0 addressed some edge cases for graph objects. Attributes added to subgraphs would also show up on the root graph. Also, subgraphs specified without names would be given the name “undefined”; actually, Graphviz supports anonymous subgraphs.

This now works as expected:

{
  edges: [
    { tail: "a", head: "b" }
  ],
  subgraphs: [
    {
      graphAttributes: {
        cluster: true,
        bgcolor: "yellow"
      },
      nodes: [
        { name: "a" }
      ]
    },
    {
      graphAttributes: {
        cluster: true,
        bgcolor: "orange"
      },
      nodes: [
        { name: "b" }
      ]
    }
  ]
}

The equivalent in DOT:

digraph {
  a -> b
  {
    cluster = true
    bgcolor = yellow
    a
  }
  {
    cluster = true
    bgcolor = orange
    b
  }
}

The rendered graph:

What are graph objects?

Graph objects are a feature of Viz.js. Instead of writing graphs as DOT strings, you can use plain old JavaScript objects. This makes it easier to render models from your application as a graph.

Here’s a simplified example from Grammophone. This is a table representing the transitions between states of a parser. The keys represent symbols in the grammar, and the values are the destination index of the transition.

const table = [
  { "A": 1, "a": 2 },
  {},
  { "A": 3, "a": 4 },
  { "b": 5 },
  { "a": 4, "A": 6 },
  { "b": 7 },
  {}
];

I’d like to display this as a graph, with the items in the table shown as nodes, and the transitions shown as edges labeled by the symbols. Here’s what that might look like in DOT:

digraph {
  rankdir = LR
  0 -> 1 [label = A]
  0 -> 2 [label = a]
  # ...
}

The table can be converted to this representation using string concatenation or whatever, but it’s another type of template and content type to work with, and besides, what about quoting the labels? Especially since Grammophone accepts arbitrary quoted strings as symbols.

Constructing an object representing the graph clearly shows the relationship between the table and the graph, and avoids the need to explicitly quote the label attribute values.

function transform(table) {
  return {
    graphAttributes: {
      rankdir: "LR"
    },
    edges: table.flatMap((state, tail) => (
      Object.entries(state).map(([label, head]) => (
        {
          tail,
          head,
          attributes: {
            label
          }
        }
      ))
    ))
  };
}

Viz.js can render a graph using the output from this function. Under the hood, it uses the Graphviz library functions to construct the graph.

This is the rendered graph: