Mercurial > repos > shellac > sam_consensus_v3
comparison env/lib/python3.9/site-packages/networkx/readwrite/pajek.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 """ | |
2 ***** | |
3 Pajek | |
4 ***** | |
5 Read graphs in Pajek format. | |
6 | |
7 This implementation handles directed and undirected graphs including | |
8 those with self loops and parallel edges. | |
9 | |
10 Format | |
11 ------ | |
12 See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm | |
13 for format information. | |
14 | |
15 """ | |
16 | |
17 import warnings | |
18 | |
19 import networkx as nx | |
20 from networkx.utils import open_file | |
21 | |
22 __all__ = ["read_pajek", "parse_pajek", "generate_pajek", "write_pajek"] | |
23 | |
24 | |
25 def generate_pajek(G): | |
26 """Generate lines in Pajek graph format. | |
27 | |
28 Parameters | |
29 ---------- | |
30 G : graph | |
31 A Networkx graph | |
32 | |
33 References | |
34 ---------- | |
35 See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm | |
36 for format information. | |
37 """ | |
38 if G.name == "": | |
39 name = "NetworkX" | |
40 else: | |
41 name = G.name | |
42 # Apparently many Pajek format readers can't process this line | |
43 # So we'll leave it out for now. | |
44 # yield '*network %s'%name | |
45 | |
46 # write nodes with attributes | |
47 yield f"*vertices {G.order()}" | |
48 nodes = list(G) | |
49 # make dictionary mapping nodes to integers | |
50 nodenumber = dict(zip(nodes, range(1, len(nodes) + 1))) | |
51 for n in nodes: | |
52 # copy node attributes and pop mandatory attributes | |
53 # to avoid duplication. | |
54 na = G.nodes.get(n, {}).copy() | |
55 x = na.pop("x", 0.0) | |
56 y = na.pop("y", 0.0) | |
57 try: | |
58 id = int(na.pop("id", nodenumber[n])) | |
59 except ValueError as e: | |
60 e.args += ( | |
61 ( | |
62 "Pajek format requires 'id' to be an int()." | |
63 " Refer to the 'Relabeling nodes' section." | |
64 ), | |
65 ) | |
66 raise | |
67 nodenumber[n] = id | |
68 shape = na.pop("shape", "ellipse") | |
69 s = " ".join(map(make_qstr, (id, n, x, y, shape))) | |
70 # only optional attributes are left in na. | |
71 for k, v in na.items(): | |
72 if isinstance(v, str) and v.strip() != "": | |
73 s += f" {make_qstr(k)} {make_qstr(v)}" | |
74 else: | |
75 warnings.warn( | |
76 f"Node attribute {k} is not processed. {('Empty attribute' if isinstance(v, str) else 'Non-string attribute')}." | |
77 ) | |
78 yield s | |
79 | |
80 # write edges with attributes | |
81 if G.is_directed(): | |
82 yield "*arcs" | |
83 else: | |
84 yield "*edges" | |
85 for u, v, edgedata in G.edges(data=True): | |
86 d = edgedata.copy() | |
87 value = d.pop("weight", 1.0) # use 1 as default edge value | |
88 s = " ".join(map(make_qstr, (nodenumber[u], nodenumber[v], value))) | |
89 for k, v in d.items(): | |
90 if isinstance(v, str) and v.strip() != "": | |
91 s += f" {make_qstr(k)} {make_qstr(v)}" | |
92 else: | |
93 warnings.warn( | |
94 f"Edge attribute {k} is not processed. {('Empty attribute' if isinstance(v, str) else 'Non-string attribute')}." | |
95 ) | |
96 yield s | |
97 | |
98 | |
99 @open_file(1, mode="wb") | |
100 def write_pajek(G, path, encoding="UTF-8"): | |
101 """Write graph in Pajek format to path. | |
102 | |
103 Parameters | |
104 ---------- | |
105 G : graph | |
106 A Networkx graph | |
107 path : file or string | |
108 File or filename to write. | |
109 Filenames ending in .gz or .bz2 will be compressed. | |
110 | |
111 Examples | |
112 -------- | |
113 >>> G = nx.path_graph(4) | |
114 >>> nx.write_pajek(G, "test.net") | |
115 | |
116 Warnings | |
117 -------- | |
118 Optional node attributes and edge attributes must be non-empty strings. | |
119 Otherwise it will not be written into the file. You will need to | |
120 convert those attributes to strings if you want to keep them. | |
121 | |
122 References | |
123 ---------- | |
124 See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm | |
125 for format information. | |
126 """ | |
127 for line in generate_pajek(G): | |
128 line += "\n" | |
129 path.write(line.encode(encoding)) | |
130 | |
131 | |
132 @open_file(0, mode="rb") | |
133 def read_pajek(path, encoding="UTF-8"): | |
134 """Read graph in Pajek format from path. | |
135 | |
136 Parameters | |
137 ---------- | |
138 path : file or string | |
139 File or filename to write. | |
140 Filenames ending in .gz or .bz2 will be uncompressed. | |
141 | |
142 Returns | |
143 ------- | |
144 G : NetworkX MultiGraph or MultiDiGraph. | |
145 | |
146 Examples | |
147 -------- | |
148 >>> G = nx.path_graph(4) | |
149 >>> nx.write_pajek(G, "test.net") | |
150 >>> G = nx.read_pajek("test.net") | |
151 | |
152 To create a Graph instead of a MultiGraph use | |
153 | |
154 >>> G1 = nx.Graph(G) | |
155 | |
156 References | |
157 ---------- | |
158 See http://vlado.fmf.uni-lj.si/pub/networks/pajek/doc/draweps.htm | |
159 for format information. | |
160 """ | |
161 lines = (line.decode(encoding) for line in path) | |
162 return parse_pajek(lines) | |
163 | |
164 | |
165 def parse_pajek(lines): | |
166 """Parse Pajek format graph from string or iterable. | |
167 | |
168 Parameters | |
169 ---------- | |
170 lines : string or iterable | |
171 Data in Pajek format. | |
172 | |
173 Returns | |
174 ------- | |
175 G : NetworkX graph | |
176 | |
177 See Also | |
178 -------- | |
179 read_pajek() | |
180 | |
181 """ | |
182 import shlex | |
183 | |
184 # multigraph=False | |
185 if isinstance(lines, str): | |
186 lines = iter(lines.split("\n")) | |
187 lines = iter([line.rstrip("\n") for line in lines]) | |
188 G = nx.MultiDiGraph() # are multiedges allowed in Pajek? assume yes | |
189 labels = [] # in the order of the file, needed for matrix | |
190 while lines: | |
191 try: | |
192 l = next(lines) | |
193 except: # EOF | |
194 break | |
195 if l.lower().startswith("*network"): | |
196 try: | |
197 label, name = l.split(None, 1) | |
198 except ValueError: | |
199 # Line was not of the form: *network NAME | |
200 pass | |
201 else: | |
202 G.graph["name"] = name | |
203 elif l.lower().startswith("*vertices"): | |
204 nodelabels = {} | |
205 l, nnodes = l.split() | |
206 for i in range(int(nnodes)): | |
207 l = next(lines) | |
208 try: | |
209 splitline = [ | |
210 x.decode("utf-8") for x in shlex.split(str(l).encode("utf-8")) | |
211 ] | |
212 except AttributeError: | |
213 splitline = shlex.split(str(l)) | |
214 id, label = splitline[0:2] | |
215 labels.append(label) | |
216 G.add_node(label) | |
217 nodelabels[id] = label | |
218 G.nodes[label]["id"] = id | |
219 try: | |
220 x, y, shape = splitline[2:5] | |
221 G.nodes[label].update( | |
222 {"x": float(x), "y": float(y), "shape": shape} | |
223 ) | |
224 except: | |
225 pass | |
226 extra_attr = zip(splitline[5::2], splitline[6::2]) | |
227 G.nodes[label].update(extra_attr) | |
228 elif l.lower().startswith("*edges") or l.lower().startswith("*arcs"): | |
229 if l.lower().startswith("*edge"): | |
230 # switch from multidigraph to multigraph | |
231 G = nx.MultiGraph(G) | |
232 if l.lower().startswith("*arcs"): | |
233 # switch to directed with multiple arcs for each existing edge | |
234 G = G.to_directed() | |
235 for l in lines: | |
236 try: | |
237 splitline = [ | |
238 x.decode("utf-8") for x in shlex.split(str(l).encode("utf-8")) | |
239 ] | |
240 except AttributeError: | |
241 splitline = shlex.split(str(l)) | |
242 | |
243 if len(splitline) < 2: | |
244 continue | |
245 ui, vi = splitline[0:2] | |
246 u = nodelabels.get(ui, ui) | |
247 v = nodelabels.get(vi, vi) | |
248 # parse the data attached to this edge and put in a dictionary | |
249 edge_data = {} | |
250 try: | |
251 # there should always be a single value on the edge? | |
252 w = splitline[2:3] | |
253 edge_data.update({"weight": float(w[0])}) | |
254 except: | |
255 pass | |
256 # if there isn't, just assign a 1 | |
257 # edge_data.update({'value':1}) | |
258 extra_attr = zip(splitline[3::2], splitline[4::2]) | |
259 edge_data.update(extra_attr) | |
260 # if G.has_edge(u,v): | |
261 # multigraph=True | |
262 G.add_edge(u, v, **edge_data) | |
263 elif l.lower().startswith("*matrix"): | |
264 G = nx.DiGraph(G) | |
265 adj_list = ( | |
266 (labels[row], labels[col], {"weight": int(data)}) | |
267 for (row, line) in enumerate(lines) | |
268 for (col, data) in enumerate(line.split()) | |
269 if int(data) != 0 | |
270 ) | |
271 G.add_edges_from(adj_list) | |
272 | |
273 return G | |
274 | |
275 | |
276 def make_qstr(t): | |
277 """Returns the string representation of t. | |
278 Add outer double-quotes if the string has a space. | |
279 """ | |
280 if not isinstance(t, str): | |
281 t = str(t) | |
282 if " " in t: | |
283 t = f'"{t}"' | |
284 return t |