2

I have a file (see status variable in the code below) that I want to convert into a flowchart (attached). My python script converts "status" into a dictionary. How do I convert that dictionary into a flowchart or a graphic? my code:

status = """
Object car {
Name honda;
From Richland;
To Seattle;
Distance 160;
Configuration road_travel;
}

Object bus {
Name greyhound;
From pasco;
To richland;
Distance 15;
Configuration road_travel;
}

Object aeroplane {
Name united;
From miami_airport;
To pasco;
Distance 1000;
Configuration air_travel;
}

Object train {
Name gas_train;
From beach;
To miami_airport;
Distance 30;
Configuration train_travel;
}
"""
sale_number = ''

sales = collections.defaultdict(list)

for line in status.split('\n'):
    line = line.strip()
    if line.startswith("set"):
         continue
    elif (line.startswith("Object") or line.startswith("object")):
         sale_number = line.split(' ')[1].strip()
    elif not line or line.isspace() :
         continue
    else:
         # you can also use a regular expression here
         sales[sale_number].append(line.split())

for sale in sales:
    print sale+str(dict(sales[sale][:-1]))

and this generates:

car{'To': 'Seattle;', 'Configuration': 'road_travel;', 'From': 'Richland;', 'Name': 'honda;', 'Distance': '160;'}
train{'To': 'miami_airport;', 'Configuration': 'train_travel;', 'From': 'beach;', 'Name': 'gas_train;', 'Distance': '30;'}
aeroplane{'To': 'pasco;', 'Configuration': 'air_travel;', 'From': 'miami_airport;', 'Name': 'united;', 'Distance': '1000;'}
bus{'To': 'richland;', 'Configuration': 'road_travel;', 'From': 'pasco;', 'Name': 'greyhound;', 'Distance': '15;'}

and I want to convert the above python output into a picture that looks something like below. I don't want to do it manually using Giffy or MS-Visio because my practical cases have about 1000 objects (this example has 4 objects in "status") flow_chart of above dictionary

smci
  • 32,567
  • 20
  • 113
  • 146
Nikhil Gupta
  • 551
  • 10
  • 28
  • @Jivan The way I have been doing is I wrote a python script that converts the file with content in "status" into a .dot file, then I import it into graphviz to visualize it. As the number of objects increase, this gets huge and complicated, so I thought to convert the content into a graphic eliminating graphviz approach. So far I converted the file content into dictionaries and I want to import "key" and "values" into tkinter or D3 or some other visualization library (python or javascript) but I am not sure how that can be done. – Nikhil Gupta Dec 28 '14 at 03:13
  • @Jivan I also tried using "pydot" library following the examples in http://pythonhaven.wordpress.com/2009/12/09/generating_graphs_with_pydot/ but a lot of it involved hard-coding which is not helpful in this problem – Nikhil Gupta Dec 28 '14 at 03:18

2 Answers2

1

Focusing just on converting your weirdly-formatted status string into a dict is hard enough couldn't you have it in a more sensible, popular format like JSON?

import re
def Status2dict(status):
    result = {}
    current = {}
    lines = status.splitlines()
    for line in lines:
        line = line.strip()
        if not line: 
            continue
        mo = re.match(r'Object (\w+) {', line)
        if mo:
            curk = mo.group(1)
            current = {curk: {}}
        elif re.match('}', line):
            result.update(current)
            current = {}
        else:
            mo = re.match(r'(\w+)\s+([\w\s]+);', line)
            if not mo:
                raise ValueError('cannot match {!r}'.format(line))
            current[curk][mo.group(1)] = mo.group(2)
    if current:
        result.update(current)
    return result

import pprint    
pprint.pprint(Status2dict(status))

This code tries to be marginally robust on small variations from the inferred syntax, you may want to dial that up or down, depending. But, it should be better than nothing.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • I tried this. It is not working. `current` dictionary is always empty so never entering the `if current` case. First line is `Object car {` and since `current` is empty and there is no `}` it hits the `else` and again doing a `re.match` and failing because `{` is not in it. and so nothing is ever written to `curk`. can you please take a look? – Nikhil Gupta Dec 28 '14 at 07:13
  • commenting `if current` eliminated the error and generated a JSON file generated the output I added to your answer. Why did you use `if current` check? – Nikhil Gupta Dec 28 '14 at 08:05
  • 1
    @SrinGupta , fixed indentation now. You're right that the `if current:` check is supererogatory as `result.update({})` is a no-op anyway, eliminating it now for simplicity. – Alex Martelli Dec 28 '14 at 15:53
  • I have a question: if my object name has `_`, the program fails. So, I changed the first `mo=re.match(...)` but looks like I am doing something horribly wrong and not able to match if the object name has any underscores. (NOTE: I changed the first `mo` similar to second `mo`... an example of what i mean is: if the object line looks like: `object aeroplane_unit_crew` or `object bus_set etc`. – Nikhil Gupta Feb 01 '15 at 20:22
  • To match only `Object` lines which are not `Object _ {` could be done in many simple ways, but it's not clear what you want to occur to the rest of that block in such cases. Comments are cramped: best to edit the Q, showing exactly the code you're using now, what it does, what you'd like it to do instead; even better would be to accept this A, which **does** solve the Q you posed after all!, and open a new one for this new issue. – Alex Martelli Feb 01 '15 at 20:29
0

If you already got the code converting to dot file, you can use the tk export of graphviz to visualise your graph on a tkinter canvas. You could give a look at this other question for other libraries.

dot -Ttk output tcl code like this

# a
$c create oval 5.33 53.33 77.33 5.33 -fill white -width 1 -outline black -tags {1node1}
$c create text 41.33 30.3 -text {a} -fill black -font {"Times" 14} -tags {0node1}
# c
$c create oval 53.33 149.33 125.33 101.33 -fill white -width 1 -outline black -tags {1node2}
$c create text 89.33 126.3 -text {c} -fill black -font {"Times" 14} -tags {0node2}
#(...)

You can display it on a tkinter canvas by calling the tcl interpreter as in this example:

from Tkinter import *
import subprocess

graph = "digraph g { a-> c ; b -> c ; c -> d }"

ps = subprocess.Popen(('dot', '-Ttk'),stdin=subprocess.PIPE, stdout=subprocess.PIPE)
out, err = ps.communicate(input=graph)

canvas = Canvas()
canvas.pack(expand=YES, fill=BOTH)

#the output of graphiz assume thazt the canvas in variable $c
out = "set c .{}\n".format(canvas._name) + out
#tk.eval expect command one by one
map(canvas.tk.eval, out.split("\n"))

canvas.mainloop()
Community
  • 1
  • 1
FabienAndre
  • 4,514
  • 25
  • 38
  • As of now I have been doing something similar. I wrote a python script to convert the "status" into a .dot file, then I import into GraphVIZ to get the flowchart/graph but I am trying to get away from that. After some reading, I thought by converting that to `JSON`, I can then somehow visualize it in D3 or using some python library because eventually I want to convert it into an interactive graphic. – Nikhil Gupta Dec 29 '14 at 01:03