NetAnalyzer 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,200 @@
1
+ import os
2
+ import re
3
+ import sys
4
+ import graphviz
5
+ import json
6
+ import base64
7
+ import igraph as ig
8
+ from igraph.layout import Layout
9
+ import matplotlib as mpl
10
+ import random
11
+ import numpy as np
12
+ import pickle
13
+ from py_report_html import Py_report_html
14
+ class Net_plotter:
15
+
16
+ TEMPLATES = os.path.join(os.path.dirname(__file__), 'templates')
17
+
18
+ def __init__(self, net_data, options={}):
19
+
20
+ self.group_nodes = net_data['group_nodes']
21
+ self.reference_nodes = net_data['reference_nodes']
22
+ self.graph = net_data['graph']
23
+ self.layers = net_data['layers']
24
+
25
+ if options['method'] == 'graphviz':
26
+ self.plot_dot(options)
27
+ if options['method'] == 'igraph':
28
+ self.plot_igraph(options)
29
+ elif options['method'] == 'cyt_app':
30
+ self.plot_cyt_app(options)
31
+ else:
32
+ container = {'net_data' : {'group_nodes' : self.group_nodes, 'reference_nodes' : self.reference_nodes, 'graph' : self.graph, 'layers' : self.layers}}
33
+ template = open(os.path.join(Net_plotter.TEMPLATES, 'network.txt')).read()
34
+ report = Py_report_html(container, os.path.basename(options['output_file']), True, True)
35
+ report.build(template, build_options=options)
36
+ report.write(options['output_file'] + '.html')
37
+
38
+ def get_node_layer(self, node_id):
39
+ return self.graph.nodes(data=True)[node_id]['layer']
40
+
41
+ ## GRAPHVIZ
42
+ ##############################################################
43
+ def plot_dot(self, user_options = {}): # input keys: layout
44
+ # Watch out: Node ids must be with no ":".
45
+ options = {'layout': "sfdp"}
46
+ options.update(user_options)
47
+ graphviz_colors = ['lightsteelblue1', 'lightyellow1', 'lightgray', 'orchid2']
48
+ palette = {}
49
+ for layer in self.layers: palette[layer] = graphviz_colors.pop(0)
50
+ graph = graphviz.Graph('graph')
51
+ graph.attr(overlap = 'false', outputorder='edgesfirst')
52
+ for e in self.graph.edges:
53
+ l0 = self.get_node_layer(e[0])
54
+ graph.node(f'"{e[0]}"', '', style = 'filled', fillcolor = palette[l0])
55
+ l1 = self.get_node_layer(e[1])
56
+ graph.node(f'"{e[1]}"', '', style = 'filled', fillcolor = palette[l1])
57
+ graph.edge(f'"{e[0]}"', f'"{e[1]}"')
58
+
59
+ for nodeID in self.reference_nodes: graph.node(f'"{nodeID}"', '', style = 'filled', fillcolor = 'firebrick1')
60
+ graphviz_border_colors = ['blue', 'darkorange', 'red', 'olivedrab4']
61
+ for groupID, gNodes in self.group_nodes.items():
62
+ border_color = graphviz_border_colors.pop(0)
63
+ for nodeID in gNodes: graph.node(f'"{nodeID}"', '', color = border_color, penwidth = '10')
64
+ graph.render(outfile= options['output_file'] + '.png', format='png', engine = options['layout'])
65
+
66
+ ## IGRAPH
67
+ ##########################################################################
68
+ def plot_igraph(self, user_options = {}):
69
+ random.seed(1234)
70
+ ig_net = ig.Graph.from_networkx(self.graph)
71
+ net_edge_weight = ig_net.es['weight']
72
+ newMax= np.percentile(net_edge_weight, 90)
73
+ #net_edge_weight = [ f"rgba(0.5,0.5,0.5,{round(w/newMax, 3)})" for w in net_edge_weight ]
74
+ norm_net_edge_weight = [ ]
75
+ for w in net_edge_weight:
76
+ normalized = round(w/newMax, 3)
77
+ if normalized > 1: normalized = 1
78
+ norm_net_edge_weight.append(f"rgba(0.7,0.7,0.7,{normalized})")
79
+ cmap=mpl.colormaps['Pastel1']
80
+ node_ids = ig_net.vs['_nx_name']
81
+ node_base_color = list(cmap(0))
82
+ node_base_color[3] = 0.25
83
+ node_base_color = tuple(node_base_color)
84
+ node_colors = [node_base_color] * len(node_ids)
85
+ # Node color
86
+ count = 1
87
+ for groupID, gNodes in self.group_nodes.items():
88
+ color = cmap(count)
89
+ for n in gNodes:
90
+ idx = node_ids.index(n)
91
+ node_colors[idx] = color
92
+ count += 1
93
+
94
+ # Node order: tag each node with a int that says in which order mut be plotted. 0 is the first node to be plotted and N node the last (so the first in the image)
95
+ node_order=[0] * len(node_ids)
96
+ node_count = len(node_ids) -1
97
+ node_dict = {}
98
+ for groupID, gNodes in self.group_nodes.items():
99
+ for n in gNodes:
100
+ node_dict[n] = node_count
101
+ node_count -= 1
102
+ for i,n_id in enumerate(node_ids):
103
+ order = node_dict.get(n_id)
104
+ if order == None:
105
+ order = node_count
106
+ node_count -= 1
107
+ node_order[i] = order
108
+ opts = {
109
+ 'bbox' : (2400, 2400),
110
+ 'vertex_size' : 7,
111
+ 'layout' : "drl",
112
+ 'edge_color' : norm_net_edge_weight,
113
+ 'vertex_color': node_colors,
114
+ 'vertex_order': node_order
115
+ }
116
+ opts.update(user_options)
117
+ layout = self.get_igraph_layout(node_ids, ig_net, opts.pop('layout'), opts)
118
+ ig.plot(ig_net, layout=layout, target=user_options['output_file'] + '.png', **opts)
119
+
120
+ def get_igraph_layout(self, node_ids, igraph_obj, layout_name, opts):
121
+ layout = None
122
+ load_path = opts.get('load')
123
+ if load_path != None:
124
+ sorted_coords = []
125
+ with open(load_path, 'rb') as file:
126
+ tagged_coordinates = pickle.load(file)
127
+ for nodeID in node_ids: # Reorder file loaded layout with the current node ordering in the igraph object
128
+ coords = tagged_coordinates.get(nodeID)
129
+ if coords != None: sorted_coords.append(coords)
130
+ layout = Layout(sorted_coords) # Create layout objet from reordered loaded node coords
131
+ else:
132
+ layout_custom_opts = {}
133
+ custom_opts_string = opts.get('custom_opts')
134
+ if layout_custom_opts != None: layout_custom_opts = eval(re.sub(';', ',', custom_opts_string))
135
+ layout = igraph_obj.layout(layout_name, **layout_custom_opts)
136
+ save_path = opts.get('save')
137
+ if save_path != None:
138
+ tagged_coordinates = {}
139
+ for i, n in enumerate(node_ids):
140
+ tagged_coordinates[n] = layout[i]
141
+ with open(save_path, 'wb') as file: pickle.dump(tagged_coordinates, file)
142
+ return layout
143
+
144
+ ## CYTOSCAPE APP
145
+ ###########################################################################
146
+ def plot_cyt_app(self, user_options = {}):
147
+ options = {}
148
+ options.update(user_options)
149
+
150
+ group_nodes = {}
151
+ for groupID, gNodes in self.group_nodes.items():
152
+ for gNode in gNodes:
153
+ group_nodes[gNode] = groupID
154
+
155
+ node_cyt_ids = {}
156
+ nodes = []
157
+ count = 0
158
+ for node in self.graph.nodes:
159
+ self.cyt_app_add_node(nodes, count, node, group_nodes)
160
+ node_cyt_ids[node] = str(count)
161
+ count += 1
162
+ edges = self.cyt_app_add_edges(node_cyt_ids, count)
163
+ cys_net = {
164
+ 'elements' : {
165
+ 'nodes' : nodes,
166
+ 'edges' : edges
167
+ }
168
+ }
169
+ with open(options['output_file'] + '.cyjs', 'w') as f: f.write(json.dumps(cys_net, indent=4))
170
+
171
+ def cyt_app_add_node(self, nodes, count, node, group_nodes):
172
+ cyt_node = {
173
+ 'data' : {
174
+ 'id' : str(count),
175
+ 'name' : node
176
+ }
177
+ }
178
+ cyt_node['data']['type'] = self.get_node_layer(node)
179
+ if len(self.reference_nodes) > 0:
180
+ cyt_node['data']['ref'] = 'y' if node in self.reference_nodes else 'n'
181
+ if len(group_nodes) > 0:
182
+ query = group_nodes[node]
183
+ if query != None: cyt_node['data']['group'] = query
184
+ nodes.append(cyt_node)
185
+
186
+ def cyt_app_add_edges(self, node_ids, count):
187
+ edges = []
188
+ for e in self.graph.edges:
189
+ edges.append({
190
+ 'data' : {
191
+ 'id' : str(count),
192
+ 'source' : node_ids[e[0]],
193
+ 'target' : node_ids[e[1]],
194
+ "interaction" : "-",
195
+ "weight" : 1.0
196
+ }
197
+ })
198
+ count +=1
199
+ return edges
200
+ ###########################################################################