Implementing a Custom Graph Parser

We're focusing on Roamer and custom visualizations so we're phasing out support for this library. If you have questions or concerns, please contact us.

If you're using a special format to represent your graph data, you'll need to create your own graph parser. Fortunately, this is pretty straightforward. You just need to implement the IGraphParser interface which requires a single method, parse.

package
{
  import com.asterisq.graph.*;
 
  import flash.events.Event;
 
  public class CustomGraphParser
      extends GraphParser
  {
    /**
     * Creates a new graph parser.
     */
    public function CustomGraphParser()
    {
    }
 
    /**
     * Writes the data to the given graph.
     */
    override public function parse(
        graph:IGraph, data:*):void
    {
      // parsing code here
    }
  }
}

The parse method takes two arguments: the IGraph instance to which the parsed graph data will be added and the data to be parsed. In this example we'll read a list of nodes and edges from an XML file and add them to the graph. Here's our sample data.

<?xml version="1.0" encoding="UTF-8"?>
<graph_data>
  <nodes>
    <node id="n0" label="Jerry" color="green" />
    <node id="n1" label="Louise" color="red" />
  </nodes>
  <edges>
    <edge id="e0"
      tail_node_id="n0"
      head_node_id="n1"
      thickness="4" />
  </edges>
</graph_data>

As you can see, the nodes have IDs, labels, and colors, and the edges have IDs, tail and head node IDs, and a thickness value. We're going to parse all this information and add it to the graph.

override public function parse(
    graph:IGraph, data:*):void
{
  var xmlData:XML = XML(data);
 
  // first parse the nodes
  for each (var nodeElem:XML in xmlData.nodes.node)
  {
    // store the label and color in an Object
    var nodeData:Object =
    {
      label: String(nodeElem.@label),
      color: String(nodeElem.@color)
    };
 
    // add the node and its data to the graph
    graph.addNode(String(nodeElem.@id), nodeData);
  }
 
  // now parse the edges
  for each (var edgeElem:XML in xmlData.edges.edge)
  {
    // store the thickness in an Object
    var edgeData:Object =
    {
      thickness: Number(edgeElem.@thickness)
    };
 
    // add the edge and its data
    graph.addEdge(
      String(edgeElem.@id),
      String(edgeElem.@tail_node_id),
      String(edgeElem.@head_node_id),
      edgeData);
  }
}

Our new parse method iterates through each of the <node> elements in the XML and adds a node to the graph. The label and color attributes are pulled from the <node> element and saved in an Object.

Once the nodes are in, it does basically the same thing with edges. The ordering here is actually significant because if the nodes referenced by the edges haven't already been added, addEdge will throw reference errors.

The label, color, and thickness values will now be available from INode and IEdge instances via the getDataProperty method or the data property. For example, the node renderer might use the code below to determine what color to give the node.

override protected function updateDisplayList(
    w:Number, h:Number):void
{
  super.updateDisplayList(w, h);
 
  // read the color string from the node
  var colorValue:String = node.data.color;
  // or: node.getDataProperty('color');
 
  var color:Number;
  switch (colorValue.toLowerCase())
  {
    case 'red':
      color = 0xff0000;
      break;
 
    case 'green':
      color = 0x00ff00;
      break;
 
    default:
      color = 0x999999;
  }
 
  var g:Graphics = graphics;
  g.clear();
  g.beginFill(color);
  g.drawCircle(0, 0, 20);
  g.endFill();
}

The node renderer grabs the string color value from the node and uses a switch statement to figure out the color as a number. Then it draws a circle filled with that color. You can find out more about custom renderers in the node renderer tutorial and the edge renderer tutorial.

Now you can create custom parsers for your own graph data formats. If you haven't already, you might want to learn about using graph parsers.