Parent Directory
|
Revision Log
Revision 1.1.1.1 - (view) (download) (as text)
1 : | sheradon | 1.1 | |
2 : | import string | ||
3 : | from pydot import * | ||
4 : | # Compbio tools we'll need: | ||
5 : | try: | ||
6 : | from KahOM.RecoElem import * | ||
7 : | from FaST.BssFactory import * | ||
8 : | except: | ||
9 : | #print 'Could not import KahOM modules.' | ||
10 : | pass | ||
11 : | |||
12 : | class unique: | ||
13 : | uniqueN = 100 | ||
14 : | def get(self): | ||
15 : | self.uniqueN = self.uniqueN + 1 | ||
16 : | return self.uniqueN | ||
17 : | uN = unique() | ||
18 : | recycling = {} | ||
19 : | |||
20 : | # ----------------- | ||
21 : | def makeDot(re): | ||
22 : | # ----------------- | ||
23 : | """Generates a pydot Dot graph structure from a recoElem. | ||
24 : | @type re: RecoElem | ||
25 : | @rtype: Dot | ||
26 : | """ | ||
27 : | global recycling | ||
28 : | recycling = {} | ||
29 : | degree = {} | ||
30 : | s = Dot(graph_name = 'graph%d' % uN.get(), type = 'digraph', rankdir = 'LR', \ | ||
31 : | label = re.Name, overlap = 'scale', fontsize = '12', nslimit = '2.0', mclimit = '2.0') | ||
32 : | |||
33 : | rxns = [] | ||
34 : | try: | ||
35 : | re.gatherReactions(rxns) # make list of reactions | ||
36 : | except: | ||
37 : | print 'makeDot failed: Could not gatherReactions from recoElem.' | ||
38 : | return None | ||
39 : | rxns = uniqueReactions(rxns) # remove duplicates | ||
40 : | |||
41 : | # Make nodes & edges for each reaction here... | ||
42 : | for rxn in rxns: | ||
43 : | |||
44 : | if rxn.Direction == '1' or rxn.Direction == 'forward': direction = 'forward' | ||
45 : | elif rxn.Direction == 'both': direction = 'both' | ||
46 : | |||
47 : | # Inputs | ||
48 : | into = Node('invis%d' % uN.get(), style = 'invis', fixedsize = 'true', height = '0', width = '0') | ||
49 : | s.add_node(into) | ||
50 : | for input in rxn.Inputs: | ||
51 : | nn = getNodeByLabel(input.Name) | ||
52 : | # If not created yet or it's a "non-connected" (common things e.g. ATP), make a new node | ||
53 : | if nn == None or not input.isConnected: | ||
54 : | label = string.replace(input.Name, ' ', r'\n') # break into multiple lines | ||
55 : | nn = Node("node%d" % uN.get(), label = label, shape = 'box') | ||
56 : | if input.isConnected: recycling[input.Name] = nn # reuse node | ||
57 : | else: nn.shape = 'plaintext' # or mark it as a 'multi' | ||
58 : | s.add_node(nn) | ||
59 : | degree[nn.get_name()] = 1 | ||
60 : | # Otherwise we keep the existing and increment its degree count | ||
61 : | else: degree[nn.get_name()] += 1 | ||
62 : | ne = Edge(nn.get_name(), into.get_name(), dir=direction) | ||
63 : | s.add_edge(ne) | ||
64 : | if input.isConnected: ne.weight = '2' | ||
65 : | else: ne.weight = '1' | ||
66 : | |||
67 : | # Outputs | ||
68 : | outof = Node('invis%d' % uN.get(), style = 'invis', fixedsize = 'true', height = '0', width = '0') | ||
69 : | s.add_node(outof) | ||
70 : | for output in rxn.Outputs: | ||
71 : | nn = getNodeByLabel(output.Name) | ||
72 : | # same drill as above... this is when we create a new node: | ||
73 : | if nn == None or not output.isConnected: | ||
74 : | label = string.replace(output.Name, ' ', r'\n') # break into multiple lines | ||
75 : | nn = Node('node%d' % uN.get(), label = label, shape = 'box') | ||
76 : | if output.isConnected: recycling[output.Name] = nn # reuse node | ||
77 : | else: nn.shape = 'plaintext' # or mark it as a 'multi' | ||
78 : | s.add_node(nn) | ||
79 : | degree[nn.get_name()] = 1 | ||
80 : | # Otherwise keep existing node, increment degree | ||
81 : | else: degree[nn.get_name()] += 1 | ||
82 : | ne = Edge(outof.get_name(), nn.get_name(), dir=direction) | ||
83 : | s.add_edge(ne) | ||
84 : | if output.isConnected: ne.weight = '2' | ||
85 : | else: ne.weight = '1' | ||
86 : | |||
87 : | # edge connecting inputs to outputs | ||
88 : | s.add_edge(Edge(into.get_name(), outof.get_name(), tooltip = rxn.asString(), label = '?', dir = direction)) | ||
89 : | |||
90 : | # OK, go through each node and adjust its size based on its degree. | ||
91 : | # That is, ones with tons of in/out activity will be bigger. | ||
92 : | for n in s.get_node_list(): | ||
93 : | if n.style == 'invis': continue | ||
94 : | try: | ||
95 : | # n.fontsize = 12 + 4*degree[n.get_name()] | ||
96 : | n.height = str(0.20 + 0.10 * degree[n.get_name()]) | ||
97 : | n.width = str(0.7 * string.atof(n.height) * max(map(len, string.split(n.label, r'\n')))) | ||
98 : | except KeyError: pass | ||
99 : | return s | ||
100 : | |||
101 : | |||
102 : | # -------------------------- | ||
103 : | def getNodeByLabel(label, recycling=recycling): | ||
104 : | # -------------------------- | ||
105 : | """Get a Node with this label, if it's been created. Note that the pydot.Graph built-in | ||
106 : | get_node(str) won't work because it takes a name (eg. node132), not label. | ||
107 : | @type label: string | ||
108 : | @rtype: Node | ||
109 : | """ | ||
110 : | try: return recycling[label] | ||
111 : | except: return None | ||
112 : | |||
113 : | # -------------------------- | ||
114 : | def uniqueReactions(rxns): | ||
115 : | # -------------------------- | ||
116 : | """Get rid of duplicates. Don't think it's very efficient because of | ||
117 : | the asString generation and rebuilding the list, but it's quick to write. | ||
118 : | @type: [Reaction] | ||
119 : | @rtype: [Reaction] | ||
120 : | """ | ||
121 : | umap = {} | ||
122 : | urxns = [] | ||
123 : | for r in rxns: | ||
124 : | umap[r.asString()] = r | ||
125 : | for key in umap.keys(): | ||
126 : | urxns.append(umap[key]) | ||
127 : | return urxns | ||
128 : | |||
129 : |
MCS Webmaster | ViewVC Help |
Powered by ViewVC 1.0.3 |