Jump to content

XQuery/Graph Visualization with Graphviz

From Wikibooks, open books for an open world

Graphviz developed by AT&T provides a package of code for generating graph images from a text definition.

The input file in 'dot' format can be generated by an XQuery script with text output.

Motivation

[edit | edit source]

You want to create a graph to visualize complex structures such as taxonomies, object hierarchies or organizational hierarchies.

Database visualization

[edit | edit source]

A graphical representation of the relationships between employee and manager in the empdept example.

This script generates the dot format file, with employees as (implicit ) nodes and arcs from employee to manager to show managed by relationships.

The output is serialised as text. Serialisation strips out all XML tags so XML can be used to structure the output and there is no need to serialise each item. The Graphviz dot format uses { } curly brackets as delimiters so these need to be escaped (doubled) in XQuery.

let $dot :=
<graph>
  digraph {{
 { for $emp in //Emp
  let $mgr := //Emp[EmpNo = $emp/MgrNo]
  where exists($mgr)
  return
    concat( $emp/Ename, " -> ", $mgr/Ename, ";")
 }
  }}
</graph>
return element result {util:serialize($dot,"method=text")}

Generate dot file

To process dot format files with SVG, we can use a module such as this on <a href="https://github.com/KitWallace/xquery-graphviz">GitHub</>. Because this module uses the process:module, the script must run with db access rights.

gv:dot-to-svg($dot)

SVG image

This would look more like a typical organisational chart if the graph was reversed. Graphviz provides a wide range of controls over the content and appearance of the graph.

let $dot :=
<graph>
  digraph {{
  rankdir=BT;
 { for $emp in //Emp
  let $mgr := //Emp[EmpNo = $emp/MgrNo]
  where exists($mgr)
  return
    concat( $emp/Ename, " -> ", $mgr/Ename, ";")
 }
  }}
</graph>
return qv:dot-to-svg($dot)

SVG graph


Since Enames are not necessarily unique, it would be better to use the EmpNo as the node identifier and label the node with the name:

let $dot := 
<graph>
   digraph {{
   
  {for $emp in //Emp
  let $mgr := //Emp[EmpNo = $emp/MgrNo]
  return
      <emp>
       {$emp/EmpNo} [label="{$emp/Ename}"];
       {if ( exists($mgr))
       then  
          <arc>
            {$mgr/EmpNo}  -> {$emp/EmpNo} ;
          </arc>
       else ()
       }
     </emp>
  }
   }}
</graph>
return qv:dot-to-svg($dot)

SVG graph

Similarly, the Department/Employee Hierarchy can be graphed:

let $dot :=
<graph>
  digraph {{
  {for $dept in //Dept
  return 
  <dept>
        Company  -> {$dept/DeptNo} ;   
        {$dept/DeptNo} [ label="{$dept/Dname}" ];
        { for $emp in //Emp[DeptNo = $dept/DeptNo]
          return
             <emp>
                {$emp/EmpNo}  [label="{$emp/Ename}" ];
                {$dept/DeptNo}  -> {$emp/EmpNo} ;
              </emp>
        }
    </dept>
   }
  }}
</graph>
return qv:dot-to-svg($dot)

SVG graph