NAME
Graph::Simple - Render graphs as ASCII or HTML
SYNOPSIS
use Graph::Simple;
my $graph = Graph::Simple->new();
my $bonn = Graph::Simple::Node->new(
name => 'Bonn',
border => 'solid 1px black',
);
my $berlin = Graph::Simple::Node->new(
name => 'Berlin',
);
$graph->add_edge ($bonn, $berlin);
$graph->layout();
print $graph->as_ascii( );
# prints:
# +------+ +--------+
# | Bonn | --> | Berlin |
# +------+ +--------+
# raw HTML section
print $graph->as_html( );
# complete HTML page (with CSS)
print $graph->as_html_page( );
# creating a graph from a textual description
use Graph::Simple::Parser;
my $parser = Graph::Simple::Parser->new();
my $graph = $parser->from_text(
"[ Bonn ] => [ Berlin ] \n".
"[ Bonn ] => [ Rostock ]"
);
print $graph->as_ascii( );
# Outputs something like:
# +------+ +---------+
# | Bonn | --> | Rostock |
# +------+ +---------+
# |
# |
# v
# +--------+
# | Berlin |
# +--------+
DESCRIPTION
Graph::Simple
lets you generate graphs consisting of various shaped boxes connected with arrows.
Be default it works on a grid (manhattan layout), and thus the output is most usefull for flow charts, network diagrams, or hirarchy trees.
Input
Apart from driving the module with Perl code, you can also use Graph::Simple::Parser
to parse simple graph descriptions like:
[ Bonn ] --> [ Berlin ]
[ Frankfurt ] <=> [ Dresden ]
[ Bonn ] --> [ Frankfurt ]
See EXAMPLES for how this might be rendered.
Output
The output can be done in various styles:
- ASCII ART
-
Uses things like
+
,-
<
and|
to render the boxes. - BOX ART
-
Uses the extended ASCII characters to draw seamless boxes.
- HTML
-
HTML tables with CSS making everything "pretty".
EXAMPLES
The following examples are given in the simple text format that is understood by Graph::Simple::Parser.
If you see no ASCII/HTML graph output in the following examples, then your pod2html
or pod2txt
converter did not recognize the special graph paragraphs.
You can use the converters in examples/
in this distribution to generate a pretty page with nice graph "drawings" from this document.
You can also see many different examples at:
http://bloodgate.com/perl/graph/
One node
The most simple graph (apart from the empty one :) is a graph consisting of only one node:
Two nodes
A simple graph consisting of two nodes, linked together by a directed edge:
Three nodes
A graph consisting of three nodes, and both are linked from the first:
Two not connected graphs
A graph consisting of two seperate parts, both of them not connected to each other:
Three nodes, interlinked
A graph consisting of three nodes, and two of the are connected from the first node:
Different edge styles
A graph consisting of a couple of nodes, linked with the different possible edge styles.
More examples at:
http://bloodgate.com/perl/graph/
METHODS
Graph::Simple
supports the following methods:
new()
use Graph::Simple;
my $graph = Graph::Simple->new( );
Creates a new, empty Graph::Simple
object.
Takes optinal a hash reference with a list of options. The following are valid options:
debug if true, enables debug output
attribute()
my $value = $graph->attribute( $class, $name );
Return the value of attribute $name
from class $class
.
Example:
my $color = $graph->attribute( 'node', 'color' );
set_attribute()
$graph->set_attribute( $class, $name, $val );
Sets a given attribute named $name
to the new value $val
in the class specified in $class
.
Example:
$graph->set_attribute( 'graph', 'gid', '123' );
The class can be one of graph
, edge
, node
or group
. The last three can also have subclasses like in node.subclassname
.
set_attributes()
$graph->set_attributes( $class, $att );
Given a class name in $class
and a hash of mappings between attribute names and values in $att
, will set all these attributes.
The class can be one of graph
, edge
, node
or group
. The last three can also have subclasses like in node.subclassname
.
Example:
$graph->set_attributes( 'node', { color => 'red', background => 'none' } );
score()
my $score = $graph->score();
Returns the score of the graph, or undef if layout() has not yet been called.
Higher scores are better, although you cannot compare scores for different graphs. The score should only be used to compare different layouts of the same graph against each other:
my $max = undef;
$graph->randomize();
my $seed = $graph->seed();
$graph->layout();
$max = $graph->score();
for (1..10)
{
$graph->randomize(); # select random seed
$graph->layout(); # layout with that seed
if ($graph->score() > $max)
{
$max = $graph->score(); # store the new max store
$seed = $graph->seed(); # and it's seed
}
}
# redo the best layout
$graph->seed($seed);
$graph->layout();
error()
my $error = $graph->error();
Returns the last error. Optionally, takes an error message to be set.
$graph->error( 'Expected Foo, but found Bar.' );
layout()
Creates the internal structures to layout the graph. This will be done behind the scenes of you call any of the as_FOO
methods.
as_ascii()
print $graph->as_ascii();
Return the graph layout in ASCII art.
as_html()
print $graph->as_html();
Return the graph layout as HTML section. See css() to get the CSS section to go with that HTML code. If you want a complete HTML page then use as_html_page().
as_html_page()
print $graph->as_html_page();
Return the graph layout as HTML complete with headers, CSS section and footer. Can be viewed in the browser of your choice.
css()
my $css = $graph->css();
Return CSS code for that graph. See as_html().
as_txt()
print $graph->as_txt();
Return the graph as a textual representation, that can be parsed with Graph::Simple::Parser
back to a graph.
This does not call layout() since the actual text representation is more a dump of the grpah, then a certain layout.
add_edge()
$graph->add_edge( $x, $y, $edge);
$graph->add_edge( $x, $y);
Add an edge between nodes X and Y. The optional edge object defines the style of the edge, if not present, a default object will be used.
$x
and $y
should be objects of Graph::Simple::Node, while $edge
should be Graph::Simple::Edge.
add_vertex()
$graph->add_vertex( $x );
Add a single node X to the graph. $x
should be a Graph::Simple::Node.
vertices()
my $vertices = $graph->vertices();
In scalar context, returns the number of nodes/vertices the graph has. In list context returns a list of all vertices (as their unique keys). See also nodes().
nodes()
my $nodes = $graph->nodes();
In scalar context, returns the number of nodes/vertices the graph has. In list context returns a list of all the node objects (as reference).
sorted_nodes()
my $nodes = $graph->sorted_nodes();
In scalar context, returns the number of nodes/vertices the graph has. In list context returns a list of all the node objects (as reference), sorted by their internal ID number (e.g. the order they have been inserted).
node()
my $node = $graph->node('node name');
Return node by name (case sensitive). Returns undef of the node couldn't be found.
edge()
my $edge = $graph->edge( $node1, $node2 );
Return edge object between nodes $node1
and $node2
. Both nodes can be either names or Graph::Simple::Node
objects.
id()
my $graph_id = $graph->id();
$graph->id('123');
Returns the id of the graph. You can also set a new ID with this routine. The default is ''.
The graph's ID is used to generate unique CSS classes for each graph, in the case you want to have more than one graph in an HTML page.
EXPORT
Exports nothing.
SEE ALSO
Graph::Layout::Aesthetic, Graph and Graph::Simple::Parser.
There is also an very old, unrelated project from ca. 1995, which does something similiar. See http://rw4.cs.uni-sb.de/users/sander/html/gsvcg1.html.
Testcases and more examples under:
http://bloodgate.com/perl/graph/.
LIMITATIONS
This module is a proof-of-concept and has currently some serious limitations. Hopefully further development will lift these.
Syntax
See http://bloodgate.com/perl/graph/ for limits of the syntax. Mostly this are limitations in the parser, which cannot yet handle the following features:
Paths
- No crossing
-
Currently edges (paths from node to node) cannot cross each other. This limits the kind of graphs you can do quite seriously.
- No bends
-
All nodes must be in straight line of sight (up, down, left or right) of each other - a bend cannot yet be generated. So the following graph outputs are not yet possible:
+------+ +--------+ | Bonn | --> | Berlin | +------+ +--------+ | | | | | v | +---------+ +--------> | Potsdam | +---------+ +------+ +--------+ +--------+ | Bonn | --> | Berlin | -- > | Kassel | +------+ +--------+ +--------+ | ^ | | | | | | +-----------------------------+
Since the
long edges
feature is already implemented, this should be easy to add. - No joints
-
Currently it is not possible that an edge joins another edge like this:
+------+ +--------+ +-----------+ | Bonn | --> | Berlin | --> | Magdeburg | +------+ +--------+ +-----------+ | | | | | | | | v | v +---------+ +-----------------------> | Potsdam | +---------+
This means each node can have at most 4 edges leading to or from it.
All the flaws with the edges can be corrected easily, but there was simple not enough time for that yet.
Distances
Nodes are always placed 2 cells away from each other. If this fails, the node will be placed a random distance away, and this will usually cause the path tracing code to not find an edge between the two nodes.
Placement
Currently the node placement is dependend on the order the nodes were inserted into the graph. In reality it should start with nodes having no or little incoming edges and then progress to nodes with more incoming edges.
Grouping
Grouping of nodes is not yet implemented.
Recursion
Theoretically, a node could contain an entire second graph. Practially, this is not yet implemented.
Layouter
The layouter is quite simple, and buggy. Once the syntax and feature set are complete, it will be rewritten.
LICENSE
This library is free software; you can redistribute it and/or modify it under the same terms of the GPL. See the LICENSE file for information.
AUTHOR
Copyright (C) 2004 - 2005 by Tels http://bloodgate.com