Adds methods to draw PetriNet and StateGraph instances using GraphViz.

For example, let's first define a Petri net:

>>> import snakes.plugins
>>> snakes.plugins.load('gv', 'snakes.nets', 'nets')
<module ...>
>>> from nets import *
>>> n = PetriNet('N')
>>> n.add_place(Place('p00', [0]))
>>> n.add_transition(Transition('t10'))
>>> n.add_place(Place('p11'))
>>> n.add_transition(Transition('t01'))
>>> n.add_input('p00', 't10', Variable('x'))
>>> n.add_output('p11', 't10', Expression('x+1'))
>>> n.add_input('p11', 't01', Variable('y'))
>>> n.add_output('p00', 't01', Expression('y-1'))

Thanks to plugin gv, we can draw it using the various engines of GraphViz; we can also draw the state graph:

>>> for engine in ('neato', 'dot', 'circo', 'twopi', 'fdp') :
...     n.draw(',test-gv-%s.png' % engine, engine=engine)
Graph(...)
Graph(...)
Graph(...)
Graph(...)
Graph(...)
>>> s = StateGraph(n)
>>> s.build()
>>> s.draw(',test-gv-graph.png')

The plugin also allows to layout the nodes without drawing the net (this is only available for PetriNet, not for StateGraph). We first move every node to position (-100, -100); then, we layout the net; finally, we check that every node has indeed been moved away from where we had put it:

>>> for node in n.node() :
...     node.pos.moveto(-100, -100)
>>> all(node.pos.x == node.pos.y == -100 for node in n.node())
True
>>> n.layout()
>>> any(node.pos.x == node.pos.y == -100 for node in n.node())
False
Note: setting nodes position has no influence on how a net is drawn: GraphViz will redo the layout in any case. Method layout is here just in the case you would need a layout of your nets.
Note: this plugin depens on plugins pos and clusters (that are automatically loaded)

Extensions

Class PetriNet

class PetriNet (module.PetriNet) :

An extension with methods draw and layout

Method PetriNet.draw

def draw (self, filename, engine="dot", debug=False,
          graph_attr=None, cluster_attr=None,
          place_attr=None, trans_attr=None, arc_attr=None) : ...

Draw the Petri net to a picture file. How the net is rendered can be controlled using the arguments ..._attr. For instance, to draw place in red with names in uppercase, and hide True guards, we can proceed as follows:

>>> import snakes.plugins
>>> snakes.plugins.load('gv', 'snakes.nets', 'nets')
<module ...>
>>> from nets import *
>>> n = PetriNet('N')
>>> n.add_place(Place('p'))
>>> n.add_transition(Transition('t'))
>>> n.add_input('p', 't', Value(dot))
>>> def draw_place (place, attr) :
...     attr['label'] = place.name.upper()
...     attr['color'] = '#FF0000'
>>> def draw_transition (trans, attr) :
...     if str(trans.guard) == 'True' :
...         attr['label'] = trans.name
...     else :
...         attr['label'] = '%s\n%s' % (trans.name, trans.guard)
>>> n.draw(',net-with-colors.png',
...        place_attr=draw_place, trans_attr=draw_transition)
Graph(...)
Call API

Method PetriNet.layout

def layout (self, xscale=1.0, yscale=1.0, engine="dot",
            debug=False, graph_attr=None, cluster_attr=None,
            place_attr=None, trans_attr=None, arc_attr=None) : ...

Layout the nodes of the Petri net by calling GraphViz and reading back the picture it creates. The effect is to change attributes pos (see plugin pos) for every node according to the positions calculated by GraphViz.

Call API

Class StateGraph

class StateGraph (module.StateGraph) :

An extension with a method draw

Method StateGraph.draw

def draw (self, filename, engine="dot", debug=False,
          node_attr=None, edge_attr=None, graph_attr=None) : ...

Draw the state graph to a picture file.

Call API