comparison env/lib/python3.7/site-packages/galaxy/util/simplegraph.py @ 0:26e78fe6e8c4 draft

"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
author shellac
date Sat, 02 May 2020 07:14:21 -0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:26e78fe6e8c4
1 """
2 Fencepost-simple graph structure implementation.
3 """
4 # Currently (2013.7.12) only used in easing the parsing of graph datatype data.
5
6 from collections import OrderedDict
7
8
9 class SimpleGraphNode(object):
10 """
11 Node representation.
12 """
13
14 def __init__(self, index, **data):
15 """
16 :param index: index of this node in some parent list
17 :type index: int
18 :param data: any extra data that needs to be saved
19 :type data: (variadic dictionary)
20 """
21 # a bit application specific (could be 'id')
22 self.index = index
23 self.data = data
24
25
26 class SimpleGraphEdge(object):
27 """
28 Edge representation.
29 """
30
31 def __init__(self, source_index, target_index, **data):
32 """
33 :param source_index: index of the edge's source node in some parent list
34 :type source_index: int
35 :param target_index: index of the edge's target node in some parent list
36 :type target_index: int
37 :param data: any extra data that needs to be saved
38 :type data: (variadic dictionary)
39 """
40 self.source_index = source_index
41 self.target_index = target_index
42 self.data = data
43
44
45 class SimpleGraph(object):
46 """
47 Each node is unique (by id) and stores its own index in the node list/odict.
48 Each edge is represented as two indeces into the node list/odict.
49 Both nodes and edges allow storing extra information if needed.
50
51 Allows:
52 multiple edges between two nodes
53 self referential edges (an edge from a node to itself)
54
55 These graphs are not specifically directed but since source and targets on the
56 edges are listed - it could easily be used that way.
57 """
58
59 def __init__(self, nodes=None, edges=None):
60 # use an odict so that edge indeces actually match the final node list indeces
61 self.nodes = nodes or OrderedDict()
62 self.edges = edges or []
63
64 def add_node(self, node_id, **data):
65 """
66 Adds a new node only if it doesn't already exist.
67 :param node_id: some unique identifier
68 :type node_id: (hashable)
69 :param data: any extra data that needs to be saved
70 :type data: (variadic dictionary)
71 :returns: the new node
72 """
73 if node_id in self.nodes:
74 return self.nodes[node_id]
75 node_index = len(self.nodes)
76 new_node = SimpleGraphNode(node_index, **data)
77 self.nodes[node_id] = new_node
78 return new_node
79
80 def add_edge(self, source_id, target_id, **data):
81 """
82 Adds a new node only if it doesn't already exist.
83 :param source_id: the id of the source node
84 :type source_id: (hashable)
85 :param target_id: the id of the target node
86 :type target_id: (hashable)
87 :param data: any extra data that needs to be saved for the edge
88 :type data: (variadic dictionary)
89 :returns: the new node
90
91 ..note: that, although this will create new nodes if necessary, there's
92 no way to pass `data` to them - so if you need to assoc. more data with
93 the nodes, use `add_node` first.
94 """
95 # adds target_id to source_id's edge list
96 # adding source_id and/or target_id to nodes if not there already
97 if source_id not in self.nodes:
98 self.add_node(source_id)
99 if target_id not in self.nodes:
100 self.add_node(target_id)
101 new_edge = SimpleGraphEdge(self.nodes[source_id].index, self.nodes[target_id].index, **data)
102 self.edges.append(new_edge)
103 return new_edge
104
105 def gen_node_dicts(self):
106 """
107 Returns a generator that yields node dictionaries in the form:
108 { 'id': <the nodes unique id>, 'data': <any additional node data> }
109 """
110 for node_id, node in self.nodes.items():
111 yield {'id': node_id, 'data': node.data}
112
113 def gen_edge_dicts(self):
114 """
115 Returns a generator that yields node dictionaries in the form::
116
117 {
118 'source': <the index of the source node in the graph's node list>,
119 'target': <the index of the target node in the graph's node list>,
120 'data' : <any additional edge data>
121 }
122 """
123 for edge in self.edges:
124 yield {'source': edge.source_index, 'target': edge.target_index, 'data': edge.data}
125
126 def as_dict(self):
127 """
128 Returns a dictionary of the form::
129
130 { 'nodes': <a list of node dictionaries>, 'edges': <a list of node dictionaries> }
131 """
132 return {'nodes': list(self.gen_node_dicts()), 'edges': list(self.gen_edge_dicts())}