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 |
