Dotx Elixir dot parser v0.3.1 Dotx View Source

This library is a DOT parser and generator. Main functions are encode/1 and decode/1 (usable also via to_string and the String.Chars protocol).

The structure of type graph() allows easy handling of decoding dot graph, the principle is that the structure is exactly homogeneous with a dot graph :

  • it contains all inherited attributes for nodes, edges and subgraphs (*_attrs)
  • it contains attrs of itself in addition of the id
  • it is a recursive structure containing children: either subgraph or node or edge
  • and edge can be from and to nodes but also subgraph (a->{c d}) or other edge (a->c->d). They are edge shorthands which are actually sugars to define lists of node->node edges.

The structure is usable by itself, but subgraph tree, edge shorthands and attribute inheritance make it non trivial to handle. So to help you manage this complexity Dotx provides helper functions :

  • flatten/1 create unitary edge for every DOT shortand (inline edge a->b->c or graph edge {a b}->c) so all edges are expanded to get only node->node edges (a->b a->c b->c)
  • spread_attributes/1 spread default attributes from graph/subgraphs tree to all children handling inheritance of attributes, but keeping original graph structure.
  • identify/1 add an identifier to all graph and subgraph without id in original graph : xN where N is the index of the subgraph in the order of appearance in the file.
  • to_nodes/1 returns a flat databases of nodes and graphs containing additional special attributes to preserve the graph informations ("graph","edges_from","parent","children"), and where all inherited attributes are filled.
  • to_edges/1 returns a flat databases of edges and graphs containing additional special attributes to preserve the graph informations ("graph","parent","children") and where the from and to fields are filled with complete node structures with inherited attributes.
  • to_digraph/1 returns an erlang digraph structure where vertices are nodes id. This allows you to use :digraph_utils module to do complex graph computations.

Link to this section Summary

Types

A dotnode is the leaf structure of the graph: only an id and its attributes as a free map.

An edge is a link between nodes (from:,to:), it has attributes which are set by itself or inherited (see graph())

see edge() : an edge with raw dotnode(), after Dotx.flatten all edges are flatedge()

The main structure containing all parsed info from a DOT graph :

An id type is a value in DOT : either a simple string or an HTML string. The %Dotx.HTML{} allows you to match the latter.

A nodeid type is a either a simple node id ["myid"] or a node id with a port : ["myid","myport"]

see graph() : same as graph without graph type specification

Functions

Main lib function: parse a DOT graph to get a Dotx.Graph structure

Same as decode/1 but with an BadArgument error if DOT file is not valid

Main lib function: same as to_string(graph), encode (pretty) graph as a DOT binary string

flatten all dot edge shortcuts (a->{b c}->d became a->b a->c b->d c->d), so that all Dotx.Edge have only Dotx.Node in both sides (from and to).

Give an id to all graph and subgraph if none are given : { a { b c } } became subgraph x0 { a subgraph x1 { b c } }

Spread all inherited attributes (nodes|edges|graphs)_attrs or graphs to descendants attrs

Create an erlang :digraph structure from graph (see erlang doc) where vertices are nodeid(). This allows to easily use :digraph and :digraph_utils handlers to go through the graph and make complex analysis of the graph.

Other variant of to_nodes/1 : fill edges and nodes with all inherited attributes and also with a "graph" attribute. But instead of returning nodes with edges filled in attribute edges_from, it returns the list of all edges where all nodes in from and to are fully filled %Dotx.Node{} structures.

Returns a flat databases of nodes and graphs containing additional special attributes to preserve the graph informations ("graph","edges_from","parent","children"), and where all inherited attributes are filled :

Link to this section Types

Link to this type

dotnode() View Source
dotnode() :: %Dotx.Node{attrs: %{optional(id()) => id()}, id: nodeid()}

A dotnode is the leaf structure of the graph: only an id and its attributes as a free map.

Link to this type

edge() View Source
edge() :: %Dotx.Edge{
  attrs: %{optional(id()) => id()},
  bidir: boolean(),
  from: dotnode() | subgraph(edge()),
  to: dotnode() | subgraph(edge()) | edge()
}

An edge is a link between nodes (from:,to:), it has attributes which are set by itself or inherited (see graph())

to can be another edge (a->b->c->d) to inline multiple edges or subgraph {a b}->{c d} as a shortcut to a->c a->d b->c b->d. You can use Dotx.flatten/1 to expand edges and get only flatedge() with link between raw nodes.

Link to this type

flatedge() View Source
flatedge() :: %Dotx.Edge{
  attrs: %{optional(id()) => id()},
  bidir: boolean(),
  from: dotnode(),
  to: dotnode()
}

see edge() : an edge with raw dotnode(), after Dotx.flatten all edges are flatedge()

Link to this type

graph(edgetype) View Source
graph(edgetype) :: %Dotx.Graph{
  attrs: %{optional(id()) => id()},
  children: [dotnode() | edgetype | subgraph(edgetype)],
  edges_attrs: %{optional(id()) => id()},
  graphs_attrs: %{optional(id()) => id()},
  id: nil | id(),
  nodes_attrs: %{optional(id()) => id()},
  strict: boolean(),
  type: :graph | :digraph
}

The main structure containing all parsed info from a DOT graph :

  • strict is true if the strict prefix is present
  • type is :digraph if graph is a directed graph, :graph otherwise
  • attrs are the attributes of the graph itself : any key-values are allowed
  • (nodes|edges|graphs)_attrs are attributes which all subelements (respectively node, edge or subgraph) will inherited (node [key=value] in DOT)
  • children is the list of childs : dot, edge or subgraph
Link to this type

id() View Source
id() :: binary() | %Dotx.HTML{html: binary()}

An id type is a value in DOT : either a simple string or an HTML string. The %Dotx.HTML{} allows you to match the latter.

A nodeid type is a either a simple node id ["myid"] or a node id with a port : ["myid","myport"]

Link to this type

nodes_db() View Source
nodes_db() ::
  {nodes :: %{optional(nodeid()) => node()},
   graphs :: %{optional(id()) => graph()}}

Link to this type

subgraph(edgetype) View Source
subgraph(edgetype) :: %Dotx.SubGraph{
  attrs: %{optional(id()) => id()},
  children: [dotnode() | edgetype | subgraph(edgetype)],
  edges_attrs: %{optional(id()) => id()},
  graphs_attrs: %{optional(id()) => id()},
  id: nil | id(),
  nodes_attrs: %{optional(id()) => id()}
}

see graph() : same as graph without graph type specification

Link to this section Functions

Link to this function

decode(bin) View Source
decode(binary()) :: {:ok, graph(edge())} | {:error, msg :: binary()}

Main lib function: parse a DOT graph to get a Dotx.Graph structure

Same as decode/1 but with an BadArgument error if DOT file is not valid

Main lib function: same as to_string(graph), encode (pretty) graph as a DOT binary string

flatten all dot edge shortcuts (a->{b c}->d became a->b a->c b->d c->d), so that all Dotx.Edge have only Dotx.Node in both sides (from and to).

Link to this function

identify(graph) View Source
identify(graph(edge())) :: graph(edge())

Give an id to all graph and subgraph if none are given : { a { b c } } became subgraph x0 { a subgraph x1 { b c } }

Link to this function

spread_attributes(graph) View Source
spread_attributes(graph()) :: graph()

Spread all inherited attributes (nodes|edges|graphs)_attrs or graphs to descendants attrs

Link to this function

to_digraph(graph) View Source
to_digraph(graph()) :: :digraph.graph()

Create an erlang :digraph structure from graph (see erlang doc) where vertices are nodeid(). This allows to easily use :digraph and :digraph_utils handlers to go through the graph and make complex analysis of the graph.

Link to this function

to_edges(graph_or_nodesdb) View Source
to_edges(graph() | nodes_db()) ::
  {edges :: [flatedge()], graphs :: %{optional(id()) => graph()}}

Other variant of to_nodes/1 : fill edges and nodes with all inherited attributes and also with a "graph" attribute. But instead of returning nodes with edges filled in attribute edges_from, it returns the list of all edges where all nodes in from and to are fully filled %Dotx.Node{} structures.

  • The function actually call to_nodes/1 so you can put to_nodes/1 result as parameter to avoid doing heavy computation 2 times.
  • all rules for graphs, nodes and edges fullfilment are the same as to_nodes/1
Link to this function

to_nodes(graph) View Source
to_nodes(graph()) :: nodes_db()

Returns a flat databases of nodes and graphs containing additional special attributes to preserve the graph informations ("graph","edges_from","parent","children"), and where all inherited attributes are filled :

  • identify/1 is called to ensure every subgraph has an id
  • flatten/1 is called to ensure that every unitary edges are expanded from DOT shorthands.

For nodes returned :

  • the attrs are filled with inherited attributes from parent subgraphs nodes_attrs (node [k=v])
  • "graph" attribute is added to each node and contains the identifier of the subgraph owning the node (the deepest subgraph containing the node in the DOT graph tree)
  • "edges_from" attribute is added to every node and contains the list of %Dotx.Edge{} from this node in the graph. For these edges structures :

    • the "graph" is also filled (the graph owning the edge is not necessary the one owning the nodes on both sides)
    • the attrs are filled with inherited attributes from parent subgraphs edges_attrs (edge [k=v])
    • the from and to %Dotx.Node contains only id, attributes attrs are not set to avoid redundancy of data with parent nodes data.

For graphs returned :

  • the attrs are filled with inherited attributes from parent subgraphs graphs_attrs (graph [k=v])
  • the "parent" attribute is added containing parent graph id in the subgraph tree
  • the "children" attribute is added containing childs graph id list in the subgraph tree
  • the :children is set to empty list [] to only use the graph structure to get attributes and not nodes and edges already present in the nodes map returned.