1
votes

I couldn't install pygraphviz on my Windows 10 system so as a workaround I am trying to store the states and transitions of the FSM in a separate graph. For example:

from transitions import Machine
from graphviz import Digraph

class Matter(object):
    pass

# The states
states=['hungry', 'satisfied', 'full', 'sick']

# And some transitions between states. 
transitions = [
     { 'trigger': 'eat', 'source': 'hungry', 'dest': 'satisfied' },
     { 'trigger': 'eat', 'source': 'satisfied', 'dest': 'full' },
     { 'trigger': 'eat', 'source': 'full', 'dest': 'sick' },
     { 'trigger': 'rest', 'source': ['satisfied', 'full', 'sick'], 'dest': 
      'hungry' }]


# Initialize
machine = Matter()
fsm = Machine(machine, states=states, transitions=transitions, initial=states[0])
dot = Digraph(comment='FSM')

src = machine.state

for event in transitions:
    machine.trigger(event['trigger'])
    dst = machine.state
    dot.edge(src,dst,event['trigger'])
    src = dst

print (dot)

Here my graph doesn't include all the possible transitions and includes only the sequential transitions.

Output:

digraph {
    hungry -> satisfied [label=eat]
    satisfied -> full [label=eat]
    full -> sick [label=eat]
    sick -> hungry [label=rest]
}

As you can see the multiple state transitions are not present in the graph. Is there a way I can trigger all the transitions and store it in the graph or do I have to write a custom code for all of this to work.

1

1 Answers

1
votes

transitions organises transitions in events. An Event may contain several transitions, again organised in a dictionary. To achieve what you desire, first iterate over the event dictionary (key is the trigger name and value is the Event itself) to get the events. Then, iterate over Event.transitions (key is the source state and value is a list of applicable Transition objects) to get a list of transitions. Now, iterate over this list to get the source and destination of each transition. You can use the trigger name as a label if you like:

from transitions import Machine
from graphviz import Digraph


class Matter(object):
    pass


# The states
states = ['hungry', 'satisfied', 'full', 'sick']

# And some transitions between states.
transitions = [{'trigger': 'eat', 'source': 'hungry', 'dest': 'satisfied'},
               {'trigger': 'eat', 'source': 'satisfied', 'dest': 'full'},
               {'trigger': 'eat', 'source': 'full', 'dest': 'sick'},
               {'trigger': 'rest', 'source': ['satisfied', 'full', 'sick'],
                'dest': 'hungry'}]


# Initialize
machine = Matter()
fsm = Machine(machine, states=states, transitions=transitions, initial=states[0],
              auto_transitions=False)
dot = Digraph(comment='FSM')

for label, event in fsm.events.items():
    for event_transitions in event.transitions.values():
        for transition in event_transitions:
            dot.edge(transition.source, transition.dest, label)
print(dot)

Output:

// FSM
digraph {
    hungry -> satisfied [label=eat]
    satisfied -> full [label=eat]
    full -> sick [label=eat]
    satisfied -> hungry [label=rest]
    full -> hungry [label=rest]
    sick -> hungry [label=rest]
}

I also added auto_transitions=False to your Machine. This way transitions will not generate auto transitions (to_<state_name>) which would otherwise clutter your graph. Of course, you can tinker with auto_transitions=True or try to filter auto transitions from the graph as done in transitions' diagrams extension.