nettracer3d 0.7.4__py3-none-any.whl → 0.7.6__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.
Potentially problematic release.
This version of nettracer3d might be problematic. Click here for more details.
- nettracer3d/community_extractor.py +17 -39
- nettracer3d/modularity.py +41 -264
- nettracer3d/nettracer.py +7 -94
- nettracer3d/nettracer_gui.py +422 -205
- nettracer3d/network_analysis.py +0 -178
- nettracer3d/segmenter.py +9 -56
- nettracer3d/segmenter_GPU.py +856 -181
- nettracer3d/simple_network.py +2 -150
- {nettracer3d-0.7.4.dist-info → nettracer3d-0.7.6.dist-info}/METADATA +3 -6
- nettracer3d-0.7.6.dist-info/RECORD +21 -0
- {nettracer3d-0.7.4.dist-info → nettracer3d-0.7.6.dist-info}/WHEEL +1 -1
- nettracer3d/segmenter - Copy.py +0 -2097
- nettracer3d-0.7.4.dist-info/RECORD +0 -22
- {nettracer3d-0.7.4.dist-info → nettracer3d-0.7.6.dist-info}/entry_points.txt +0 -0
- {nettracer3d-0.7.4.dist-info → nettracer3d-0.7.6.dist-info}/licenses/LICENSE +0 -0
- {nettracer3d-0.7.4.dist-info → nettracer3d-0.7.6.dist-info}/top_level.txt +0 -0
|
@@ -8,7 +8,6 @@ from networkx.algorithms import community
|
|
|
8
8
|
from scipy import ndimage
|
|
9
9
|
from scipy.ndimage import zoom
|
|
10
10
|
from networkx.algorithms import community
|
|
11
|
-
from community import community_louvain
|
|
12
11
|
import random
|
|
13
12
|
from . import node_draw
|
|
14
13
|
|
|
@@ -229,38 +228,11 @@ def _isolate_connected(G, key = None):
|
|
|
229
228
|
return G0
|
|
230
229
|
|
|
231
230
|
|
|
232
|
-
def extract_mothers(nodes,
|
|
233
|
-
|
|
234
|
-
if type(nodes) == str:
|
|
235
|
-
nodes = tifffile.imread(nodes)
|
|
236
|
-
|
|
237
|
-
if np.unique(nodes) < 3:
|
|
238
|
-
structure_3d = np.ones((3, 3, 3), dtype=int)
|
|
239
|
-
nodes, num_nodes = ndimage.label(nodes, structure=structure_3d)
|
|
240
|
-
|
|
241
|
-
if type(excel_file_path) == str:
|
|
242
|
-
G, edge_weights = weighted_network(excel_file_path)
|
|
243
|
-
else:
|
|
244
|
-
G = excel_file_path
|
|
245
|
-
|
|
246
|
-
if not called:
|
|
247
|
-
|
|
248
|
-
if louvain:
|
|
249
|
-
# Apply the Louvain algorithm for community detection
|
|
250
|
-
partition = community_louvain.best_partition(G)
|
|
251
|
-
some_communities = set(partition.values())
|
|
252
|
-
else:
|
|
253
|
-
some_communities = list(nx.community.label_propagation_communities(G))
|
|
254
|
-
partition = {}
|
|
255
|
-
for i, community in enumerate(some_communities):
|
|
256
|
-
for node in community:
|
|
257
|
-
partition[node] = i + 1
|
|
258
|
-
else:
|
|
259
|
-
partition = louvain
|
|
260
|
-
some_communities = (partition.keys())
|
|
231
|
+
def extract_mothers(nodes, G, partition, centroid_dic = None, directory = None, ret_nodes = False, called = False):
|
|
261
232
|
|
|
262
233
|
|
|
263
234
|
my_nodes, intercom_connections, connected_coms = get_border_nodes(partition, G)
|
|
235
|
+
some_communities = partition.keys()
|
|
264
236
|
|
|
265
237
|
print(f"Number of intercommunity connections: {intercom_connections}")
|
|
266
238
|
print(f"{len(connected_coms)} communities with any connectivity of {len(some_communities)} communities")
|
|
@@ -390,10 +362,14 @@ def find_hub_nodes(G: nx.Graph, proportion: float = 0.1) -> List:
|
|
|
390
362
|
# Dictionary to store average path lengths for all nodes
|
|
391
363
|
avg_path_lengths: Dict[int, float] = {}
|
|
392
364
|
|
|
365
|
+
output = []
|
|
366
|
+
|
|
393
367
|
# Process each component separately
|
|
394
368
|
for component in components:
|
|
395
369
|
# Create subgraph for this component
|
|
396
370
|
subgraph = G.subgraph(component)
|
|
371
|
+
if not (len(subgraph.nodes()) * proportion >= 0.75): #Skip components that are too small
|
|
372
|
+
continue
|
|
397
373
|
|
|
398
374
|
# Calculate average shortest path length for each node in this component
|
|
399
375
|
for node in subgraph.nodes():
|
|
@@ -403,16 +379,18 @@ def find_hub_nodes(G: nx.Graph, proportion: float = 0.1) -> List:
|
|
|
403
379
|
avg_length = sum(path_lengths.values()) / (len(subgraph.nodes()) - 1)
|
|
404
380
|
avg_path_lengths[node] = avg_length
|
|
405
381
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
382
|
+
# Sort nodes by average path length (ascending)
|
|
383
|
+
sorted_nodes = sorted(avg_path_lengths.items(), key=lambda x: x[1])
|
|
384
|
+
|
|
385
|
+
# Calculate number of nodes to return
|
|
386
|
+
num_nodes = int(np.ceil(len(G.nodes()) * proportion))
|
|
387
|
+
|
|
388
|
+
# Return the top nodes (those with lowest average path lengths)
|
|
389
|
+
hub_nodes = [node for node, _ in sorted_nodes[:num_nodes]]
|
|
390
|
+
output.extend(hub_nodes)
|
|
391
|
+
avg_path_lengths: Dict[int, float] = {}
|
|
414
392
|
|
|
415
|
-
return
|
|
393
|
+
return output
|
|
416
394
|
|
|
417
395
|
def get_color_name_mapping():
|
|
418
396
|
"""Return a dictionary of common colors and their RGB values."""
|
nettracer3d/modularity.py
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
from networkx.algorithms import community
|
|
2
|
-
from community import community_louvain
|
|
3
2
|
import pandas as pd
|
|
4
3
|
import networkx as nx
|
|
5
4
|
import matplotlib.pyplot as plt
|
|
@@ -104,77 +103,8 @@ def read_excel_to_lists(file_path, sheet_name=0):
|
|
|
104
103
|
|
|
105
104
|
|
|
106
105
|
|
|
107
|
-
|
|
108
|
-
def louvain_mod_solo(G, edge_weights = None, identifier = None, directory_path = None):
|
|
109
|
-
|
|
110
|
-
if type(G) == str:
|
|
111
|
-
G, edge_weights = weighted_network(G)
|
|
112
|
-
|
|
113
|
-
if edge_weights is None:
|
|
114
|
-
edge_weights = get_edge_weights(G)
|
|
115
|
-
|
|
116
|
-
# Assuming G is your NetworkX graph
|
|
117
|
-
# Louvain community detection
|
|
118
|
-
partition = community_louvain.best_partition(G)
|
|
119
|
-
|
|
120
|
-
# Print modularity
|
|
121
|
-
modularity = community_louvain.modularity(partition, G)
|
|
122
|
-
number_of_nodes = G.number_of_nodes()
|
|
123
|
-
print("Modularity:", modularity)
|
|
124
|
-
num_components = nx.number_connected_components(G)
|
|
125
|
-
|
|
126
|
-
if directory_path:
|
|
127
|
-
with open(f'{directory_path}/{identifier} network stats.txt', 'a') as f:
|
|
128
|
-
f.write(f'\nlouvain full graph modularity: {modularity} constructed from {num_components} components containing {number_of_nodes} nodes')
|
|
129
|
-
f.close()
|
|
130
|
-
|
|
131
|
-
louvain_graph(edge_weights, identifier, directory_path)
|
|
132
|
-
|
|
133
|
-
def louvain_mod(G, edge_weights=None, identifier=None, geometric = False, geo_info = None, directory = None):
|
|
134
|
-
|
|
135
|
-
if type(G) == list:
|
|
136
|
-
num_edge = len(G[0])
|
|
137
|
-
else:
|
|
138
|
-
num_edge = None
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
if type(G) == str or type(G) == list:
|
|
142
|
-
G, edge_weights = network_analysis.weighted_network(G)
|
|
143
|
-
|
|
144
|
-
if edge_weights is None:
|
|
145
|
-
edge_weights = get_edge_weights(G)
|
|
146
|
-
|
|
147
|
-
connected_components = list(nx.connected_components(G))
|
|
148
|
-
num_nodes = float(G.number_of_nodes())
|
|
149
|
-
|
|
150
|
-
print("Number of nodes:", num_nodes)
|
|
151
|
-
print("Number of edges:", num_edge)
|
|
152
|
-
|
|
153
|
-
# Calculate the average degree connectivity
|
|
154
|
-
average_degree_connectivity = nx.average_degree_connectivity(G)
|
|
155
|
-
print("Average degree connectivity:", average_degree_connectivity)
|
|
156
|
-
|
|
157
|
-
# Calculate the average number of edges attached to a node
|
|
158
|
-
average_edges_per_node = num_nodes/num_edge
|
|
159
|
-
print("Average edges per node:", average_edges_per_node)
|
|
160
|
-
|
|
161
|
-
for i, component in enumerate(connected_components):
|
|
162
|
-
# Apply the Louvain community detection on the subgraph
|
|
163
|
-
partition = community_louvain.best_partition(G.subgraph(component))
|
|
164
|
-
|
|
165
|
-
# Calculate modularity
|
|
166
|
-
modularity = community_louvain.modularity(partition, G.subgraph(component))
|
|
167
|
-
num_nodes = len(component)
|
|
168
|
-
|
|
169
|
-
print(f"Louvain modularity for component with {num_nodes} nodes: {modularity}")
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
louvain_graph(edge_weights, identifier, directory, geometric, geo_info)
|
|
173
|
-
|
|
174
106
|
def show_communities_flex(G, master_list, normalized_weights, geo_info = None, geometric=False, directory=None, weighted=True, partition=None, style=0):
|
|
175
|
-
|
|
176
|
-
partition, normalized_weights, _ = community_partition(master_list, weighted=weighted, style=style)
|
|
177
|
-
print(partition)
|
|
107
|
+
|
|
178
108
|
if normalized_weights is None:
|
|
179
109
|
G, edge_weights = network_analysis.weighted_network(master_list)
|
|
180
110
|
|
|
@@ -276,13 +206,7 @@ def show_communities_flex(G, master_list, normalized_weights, geo_info = None, g
|
|
|
276
206
|
|
|
277
207
|
|
|
278
208
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
def community_partition(master_list, weighted = False, style = 0, dostats = True):
|
|
209
|
+
def community_partition(master_list, weighted = False, style = 0, dostats = True, seed = None):
|
|
286
210
|
|
|
287
211
|
def calculate_network_stats(G, communities):
|
|
288
212
|
"""
|
|
@@ -392,7 +316,7 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
392
316
|
|
|
393
317
|
return stats
|
|
394
318
|
|
|
395
|
-
def calculate_louvain_network_stats(G, partition):
|
|
319
|
+
def calculate_louvain_network_stats(G, partition, seed):
|
|
396
320
|
"""
|
|
397
321
|
Calculate comprehensive network statistics for the graph using Louvain community detection.
|
|
398
322
|
|
|
@@ -410,17 +334,10 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
410
334
|
"""
|
|
411
335
|
stats = {}
|
|
412
336
|
|
|
413
|
-
# Convert partition dict to communities list format
|
|
414
|
-
communities = []
|
|
415
|
-
max_community = max(partition.values())
|
|
416
|
-
for com_id in range(max_community + 1):
|
|
417
|
-
community_nodes = {node for node, com in partition.items() if com == com_id}
|
|
418
|
-
if community_nodes: # Only add non-empty communities
|
|
419
|
-
communities.append(community_nodes)
|
|
420
337
|
|
|
421
338
|
try:
|
|
422
339
|
# Overall network modularity using Louvain
|
|
423
|
-
stats['Modularity Entire Network'] =
|
|
340
|
+
stats['Modularity Entire Network'] = community.modularity(partition, G)
|
|
424
341
|
except:
|
|
425
342
|
pass
|
|
426
343
|
|
|
@@ -430,8 +347,8 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
430
347
|
if len(connected_components) > 1:
|
|
431
348
|
for i, component in enumerate(connected_components):
|
|
432
349
|
subgraph = G.subgraph(component)
|
|
433
|
-
subgraph_partition =
|
|
434
|
-
modularity =
|
|
350
|
+
subgraph_partition = nx.community.louvain_communities(G, weight='weight', seed = seed)
|
|
351
|
+
modularity = community.modularity(subgraph_partition, subgraph)
|
|
435
352
|
num_nodes = len(component)
|
|
436
353
|
stats[f'Modularity of component with {num_nodes} nodes'] = modularity
|
|
437
354
|
except:
|
|
@@ -523,7 +440,6 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
523
440
|
edge_weights = get_edge_weights(G)
|
|
524
441
|
|
|
525
442
|
if style == 1 and weighted:
|
|
526
|
-
|
|
527
443
|
G = nx.Graph()
|
|
528
444
|
|
|
529
445
|
# Find the maximum and minimum edge weights
|
|
@@ -540,33 +456,38 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
540
456
|
for edge, normalized_weight in normalized_weights.items():
|
|
541
457
|
G.add_edge(edge[0], edge[1], weight=normalized_weight)
|
|
542
458
|
|
|
543
|
-
#
|
|
544
|
-
|
|
459
|
+
# Replace Louvain with NetworkX's implementation
|
|
460
|
+
communities = list(nx.community.louvain_communities(G, weight='weight', seed = seed))
|
|
461
|
+
|
|
462
|
+
# Convert to the same format as community_louvain.best_partition
|
|
463
|
+
output = {}
|
|
464
|
+
for i, com in enumerate(communities):
|
|
465
|
+
for node in com:
|
|
466
|
+
output[node] = i + 1
|
|
545
467
|
|
|
546
468
|
if dostats:
|
|
469
|
+
stats = calculate_louvain_network_stats(G, communities, seed)
|
|
547
470
|
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
return partition, normalized_weights, stats
|
|
471
|
+
return output, normalized_weights, stats
|
|
552
472
|
|
|
553
473
|
elif style == 1:
|
|
554
|
-
|
|
555
474
|
edges = list(zip(master_list[0], master_list[1]))
|
|
556
|
-
|
|
557
475
|
G = nx.Graph()
|
|
558
|
-
|
|
559
476
|
G.add_edges_from(edges)
|
|
560
477
|
|
|
478
|
+
# Replace Louvain with NetworkX's implementation
|
|
479
|
+
communities = list(nx.community.louvain_communities(G, seed = seed))
|
|
561
480
|
|
|
562
|
-
#
|
|
563
|
-
|
|
481
|
+
# Convert to the same format as community_louvain.best_partition
|
|
482
|
+
output = {}
|
|
483
|
+
for i, com in enumerate(communities):
|
|
484
|
+
for node in com:
|
|
485
|
+
output[node] = i + 1
|
|
564
486
|
|
|
565
487
|
if dostats:
|
|
488
|
+
stats = calculate_louvain_network_stats(G, communities, seed)
|
|
566
489
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
return partition, None, stats
|
|
490
|
+
return output, None, stats
|
|
570
491
|
|
|
571
492
|
elif style == 0 and weighted:
|
|
572
493
|
|
|
@@ -586,6 +507,13 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
586
507
|
for edge, normalized_weight in normalized_weights.items():
|
|
587
508
|
G.add_edge(edge[0], edge[1], weight=normalized_weight)
|
|
588
509
|
|
|
510
|
+
if seed is not None:
|
|
511
|
+
import random
|
|
512
|
+
import numpy as np
|
|
513
|
+
# Set seeds
|
|
514
|
+
random.seed(seed)
|
|
515
|
+
np.random.seed(seed)
|
|
516
|
+
|
|
589
517
|
# Detect communities using label propagation
|
|
590
518
|
communities = list(community.label_propagation_communities(G))
|
|
591
519
|
output = {}
|
|
@@ -614,6 +542,14 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
614
542
|
|
|
615
543
|
|
|
616
544
|
# Detect communities using label propagation
|
|
545
|
+
|
|
546
|
+
if seed is not None:
|
|
547
|
+
import random
|
|
548
|
+
import numpy as np
|
|
549
|
+
# Set seeds
|
|
550
|
+
random.seed(seed)
|
|
551
|
+
np.random.seed(seed)
|
|
552
|
+
|
|
617
553
|
communities = list(community.label_propagation_communities(G))
|
|
618
554
|
output = {}
|
|
619
555
|
for i, com in enumerate(communities):
|
|
@@ -627,127 +563,6 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
627
563
|
return output, None, stats
|
|
628
564
|
|
|
629
565
|
|
|
630
|
-
|
|
631
|
-
def _louvain_mod_solo(G, edge_weights = None):
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
if type(G) == str:
|
|
635
|
-
G, edge_weights = weighted_network(G)
|
|
636
|
-
|
|
637
|
-
# Louvain community detection
|
|
638
|
-
partition = community_louvain.best_partition(G)
|
|
639
|
-
|
|
640
|
-
# modularity
|
|
641
|
-
modularity = community_louvain.modularity(partition, G)
|
|
642
|
-
|
|
643
|
-
print(f"Modularity is {modularity}")
|
|
644
|
-
|
|
645
|
-
return modularity
|
|
646
|
-
|
|
647
|
-
def _louvain_mod(G, edge_weights = None):
|
|
648
|
-
|
|
649
|
-
if type(G) == str:
|
|
650
|
-
G, edge_weights = weighted_network(G)
|
|
651
|
-
|
|
652
|
-
connected_components = list(nx.connected_components(G))
|
|
653
|
-
return_dict = {}
|
|
654
|
-
|
|
655
|
-
for i, component in enumerate(connected_components):
|
|
656
|
-
# Apply the Louvain community detection on the subgraph
|
|
657
|
-
partition = community_louvain.best_partition(G.subgraph(component))
|
|
658
|
-
|
|
659
|
-
# Calculate modularity
|
|
660
|
-
modularity = community_louvain.modularity(partition, G.subgraph(component))
|
|
661
|
-
num_nodes = len(component)
|
|
662
|
-
return_dict[num_nodes] = modularity
|
|
663
|
-
|
|
664
|
-
print(f"Louvain modularity for component with {num_nodes} nodes: {modularity}")
|
|
665
|
-
|
|
666
|
-
return return_dict
|
|
667
|
-
|
|
668
|
-
def louvain_graph(edge_weights, identifier, directory_path, geometric, geo_info):
|
|
669
|
-
G = nx.Graph()
|
|
670
|
-
|
|
671
|
-
# Find the maximum and minimum edge weights
|
|
672
|
-
max_weight = max(weight for edge, weight in edge_weights.items())
|
|
673
|
-
min_weight = min(weight for edge, weight in edge_weights.items())
|
|
674
|
-
|
|
675
|
-
if max_weight > 1:
|
|
676
|
-
# Normalize edge weights to the range [0.1, 1.0]
|
|
677
|
-
normalized_weights = {edge: 0.1 + 0.9 * ((weight - min_weight) / (max_weight - min_weight)) for edge, weight in edge_weights.items()}
|
|
678
|
-
else:
|
|
679
|
-
normalized_weights = {edge: 0.1 for edge, weight in edge_weights.items()}
|
|
680
|
-
|
|
681
|
-
# Add edges to the graph with normalized weights
|
|
682
|
-
for edge, normalized_weight in normalized_weights.items():
|
|
683
|
-
G.add_edge(edge[0], edge[1], weight=normalized_weight)
|
|
684
|
-
|
|
685
|
-
if geometric:
|
|
686
|
-
for node in list(G.nodes()):
|
|
687
|
-
if node not in geo_info[0]:
|
|
688
|
-
G.remove_node(node)
|
|
689
|
-
print(f"Removing node {node} from network visualization (no centroid - likely due to downsampling when finding centroids)")
|
|
690
|
-
|
|
691
|
-
# Perform Louvain community detection
|
|
692
|
-
partition = community_louvain.best_partition(G)
|
|
693
|
-
|
|
694
|
-
# Invert the partition dictionary to group nodes by their community
|
|
695
|
-
print(f"louvain_communities_initial: {partition}")
|
|
696
|
-
communities = {}
|
|
697
|
-
for node, community_id in partition.items():
|
|
698
|
-
communities.setdefault(community_id, []).append(node)
|
|
699
|
-
|
|
700
|
-
print(f"louvain_communities_after: {partition}")
|
|
701
|
-
|
|
702
|
-
# Prepare colors for each community
|
|
703
|
-
unique_communities = set(partition.values())
|
|
704
|
-
colors = [plt.cm.jet(i / len(unique_communities)) for i in range(len(unique_communities))]
|
|
705
|
-
|
|
706
|
-
if geometric:
|
|
707
|
-
|
|
708
|
-
pos, z_pos = simple_network.geometric_positions(geo_info[0], geo_info[1])
|
|
709
|
-
#nx.draw(G, pos, with_labels=True, font_color='black', font_weight='bold', node_size = node_sizes_list, node_color = node_color_list, alpha=0.8, font_size = 12)
|
|
710
|
-
|
|
711
|
-
# Draw the nodes, coloring them according to their community
|
|
712
|
-
for community_id, nodes in communities.items():
|
|
713
|
-
node_sizes_list = [z_pos[node] for node in nodes]
|
|
714
|
-
nx.draw_networkx_nodes(G, pos, nodelist=nodes, node_color=[colors[community_id]], node_size=node_sizes_list, alpha=0.8)
|
|
715
|
-
|
|
716
|
-
# Modify edge drawing to consider normalized weights
|
|
717
|
-
for edge in G.edges():
|
|
718
|
-
normalized_weight = G[edge[0]][edge[1]]['weight']
|
|
719
|
-
|
|
720
|
-
# Scale the width based on a constant factor (e.g., 5)
|
|
721
|
-
nx.draw_networkx_edges(G, pos, edgelist=[edge], width=5 * normalized_weight, edge_color='black')
|
|
722
|
-
|
|
723
|
-
# Optionally, draw node labels
|
|
724
|
-
nx.draw_networkx_labels(G, pos)
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
else:
|
|
728
|
-
# Position nodes using the spring layout
|
|
729
|
-
pos = nx.spring_layout(G)
|
|
730
|
-
|
|
731
|
-
# Draw the nodes, coloring them according to their community
|
|
732
|
-
for community_id, nodes in communities.items():
|
|
733
|
-
nx.draw_networkx_nodes(G, pos, nodelist=nodes, node_color=[colors[community_id]], node_size=100, alpha=0.8)
|
|
734
|
-
|
|
735
|
-
# Modify edge drawing to consider normalized weights
|
|
736
|
-
for edge in G.edges():
|
|
737
|
-
normalized_weight = G[edge[0]][edge[1]]['weight']
|
|
738
|
-
|
|
739
|
-
# Scale the width based on a constant factor (e.g., 5)
|
|
740
|
-
nx.draw_networkx_edges(G, pos, edgelist=[edge], width=5 * normalized_weight, edge_color='black')
|
|
741
|
-
|
|
742
|
-
# Optionally, draw node labels
|
|
743
|
-
nx.draw_networkx_labels(G, pos)
|
|
744
|
-
|
|
745
|
-
plt.axis('off')
|
|
746
|
-
if directory_path is not None:
|
|
747
|
-
plt.savefig(f'{directory_path}/community_louvain_network_plot.png')
|
|
748
|
-
|
|
749
|
-
plt.show()
|
|
750
|
-
|
|
751
566
|
def create_directory(directory_name):
|
|
752
567
|
try:
|
|
753
568
|
os.mkdir(directory_name)
|
|
@@ -782,43 +597,5 @@ def remove_small_components(G, threshold):
|
|
|
782
597
|
return G
|
|
783
598
|
|
|
784
599
|
|
|
785
|
-
def louvain_analysis_5x(G, excel_file, identifier, directory_path):
|
|
786
|
-
print("Performing Louvain Community Detection...")
|
|
787
|
-
df = pd.read_excel(excel_file)
|
|
788
|
-
G, edge_weights = weighted_network(excel_file)
|
|
789
|
-
threshold = find_threshold(G)
|
|
790
|
-
G = remove_small_components(G, threshold)
|
|
791
|
-
louvain_mod(G, identifier, directory_path)
|
|
792
|
-
louvain_graph(edge_weights, identifier, directory_path)
|
|
793
|
-
print("Done")
|
|
794
|
-
|
|
795
|
-
def louvain_analysis_20x(G, excel_file, identifier, directory_path):
|
|
796
|
-
print("Performing Louvain Community Detection...")
|
|
797
|
-
df = pd.read_excel(excel_file)
|
|
798
|
-
G, edge_weights = weighted_network(excel_file)
|
|
799
|
-
louvain_mod_20x(G, identifier, directory_path)
|
|
800
|
-
louvain_graph(edge_weights, identifier, directory_path)
|
|
801
|
-
print("Done")
|
|
802
|
-
|
|
803
|
-
|
|
804
600
|
if __name__ == "__main__":
|
|
805
|
-
|
|
806
|
-
is_5x = input("Is 5x? (Type Y for 5x): ")
|
|
807
|
-
if is_5x == 'Y':
|
|
808
|
-
|
|
809
|
-
df = pd.read_excel(excel_name)
|
|
810
|
-
identifier = "output"
|
|
811
|
-
directory_path = 'output'
|
|
812
|
-
create_directory(directory_path)
|
|
813
|
-
G, edge_weights = weighted_network(excel_name)
|
|
814
|
-
#threshold = find_threshold(G)
|
|
815
|
-
#G = remove_small_components(G, threshold)
|
|
816
|
-
louvain_mod_solo(G, edge_weights, identifier, directory_path)
|
|
817
|
-
|
|
818
|
-
else:
|
|
819
|
-
df = pd.read_excel(excel_name)
|
|
820
|
-
identifier = "output"
|
|
821
|
-
directory_path = 'output'
|
|
822
|
-
create_directory(directory_path)
|
|
823
|
-
G, edge_weights = weighted_network(excel_name)
|
|
824
|
-
louvain_mod(G, edge_weights, identifier, directory_path)
|
|
601
|
+
pass
|
nettracer3d/nettracer.py
CHANGED
|
@@ -3564,12 +3564,12 @@ class Network_3D:
|
|
|
3564
3564
|
|
|
3565
3565
|
#Some methods that may be useful:
|
|
3566
3566
|
|
|
3567
|
-
def community_partition(self, weighted = False, style = 0, dostats = True):
|
|
3567
|
+
def community_partition(self, weighted = False, style = 0, dostats = True, seed = None):
|
|
3568
3568
|
"""
|
|
3569
3569
|
Sets the communities attribute by splitting the network into communities
|
|
3570
3570
|
"""
|
|
3571
3571
|
|
|
3572
|
-
self._communities, self.normalized_weights, stats = modularity.community_partition(self._network_lists, weighted = weighted, style = style, dostats = dostats)
|
|
3572
|
+
self._communities, self.normalized_weights, stats = modularity.community_partition(self._network_lists, weighted = weighted, style = style, dostats = dostats, seed = seed)
|
|
3573
3573
|
|
|
3574
3574
|
return stats
|
|
3575
3575
|
|
|
@@ -4027,66 +4027,6 @@ class Network_3D:
|
|
|
4027
4027
|
self._communities, self.normalized_weights = modularity.show_communities_flex(self._network, self._network_lists, self.normalized_weights, geo_info = [self._node_centroids, self._nodes.shape], geometric = geometric, directory = directory, weighted = weighted, partition = partition, style = style)
|
|
4028
4028
|
|
|
4029
4029
|
|
|
4030
|
-
def show_communities(self, geometric = False, directory = None):
|
|
4031
|
-
"""
|
|
4032
|
-
Shows the network property, and some basic stats, as a graph where nodes are labelled by colors representing the community they belong to as determined by a label propogation algorithm. Does not support viewing edge weights.
|
|
4033
|
-
:param geoemtric: (Optional - Val = False; boolean). If False, node placement in the graph will be random. If True, nodes
|
|
4034
|
-
will be placed in their actual spatial location (from the original node segmentation) along the XY plane, using node_centroids.
|
|
4035
|
-
The node size will then represent the nodes Z location, with smaller nodes representing a larger Z value. If False, nodes will be placed randomly.
|
|
4036
|
-
:param directory: (Optional – Val = None; string). An optional string path to a directory to save the network plot image to. If not set, nothing will be saved.
|
|
4037
|
-
"""
|
|
4038
|
-
|
|
4039
|
-
if not geometric:
|
|
4040
|
-
|
|
4041
|
-
simple_network.show_community_network(self._network_lists, directory = directory)
|
|
4042
|
-
|
|
4043
|
-
else:
|
|
4044
|
-
simple_network.show_community_network(self._network_lists, geometric = True, geo_info = [self._node_centroids, self._nodes.shape], directory = directory)
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
def show_communities_louvain(self, geometric = False, directory = None):
|
|
4048
|
-
"""
|
|
4049
|
-
Shows the network property as a graph, and some basic stats, where nodes are labelled by colors representing the community they belong to as determined by a louvain algorithm. Supports viewing edge weights.
|
|
4050
|
-
:param geoemtric: (Optional - Val = False; boolean). If False, node placement in the graph will be random. If True, nodes
|
|
4051
|
-
will be placed in their actual spatial location (from the original node segmentation) along the XY plane, using node_centroids.
|
|
4052
|
-
The node size will then represent the nodes Z location, with smaller nodes representing a larger Z value. If False, nodes will be placed randomly.
|
|
4053
|
-
"""
|
|
4054
|
-
|
|
4055
|
-
if not geometric:
|
|
4056
|
-
|
|
4057
|
-
modularity.louvain_mod(self._network_lists, directory = directory)
|
|
4058
|
-
else:
|
|
4059
|
-
modularity.louvain_mod(self._network_lists, geometric = True, geo_info = [self._node_centroids, self._nodes.shape], directory = directory)
|
|
4060
|
-
|
|
4061
|
-
def louvain_modularity(self, solo_mod = False):
|
|
4062
|
-
"""
|
|
4063
|
-
Shows some basic stats of the network, including modularity (essentially strength of community structure), using a louvain algorithm that accounts for edge weights.
|
|
4064
|
-
:param solo_mod: (Optional - Val = False; boolean). If True, will return a singular modularity for the network, taking into
|
|
4065
|
-
account all disconnected components as pieces of a network. If False, will return the modularity of each singular disconnected component of the network with the number of nodes in the component as a key
|
|
4066
|
-
and the modularity of the component as a value.
|
|
4067
|
-
:returns: A dictionary containing the modularity for each disconnected component in the network, key-indexed by that component's node count, or a single modularity value accounting for all disconnected components of the network if the solo_mod param is True.
|
|
4068
|
-
"""
|
|
4069
|
-
|
|
4070
|
-
if not solo_mod:
|
|
4071
|
-
mod = modularity._louvain_mod(self._network)
|
|
4072
|
-
else:
|
|
4073
|
-
mod = modularity._louvain_mod_solo(self._network)
|
|
4074
|
-
|
|
4075
|
-
return mod
|
|
4076
|
-
|
|
4077
|
-
def modularity(self, solo_mod = False):
|
|
4078
|
-
"""
|
|
4079
|
-
Shows some basic stats of the network, including modularity (essentially strength of community structure), using a label propogation algorithm that does not consider edge weights.
|
|
4080
|
-
:param solo_mod: (Optional - Val = False; boolean). If True, will return a singular modularity for the network, taking into
|
|
4081
|
-
account all disconnected components as pieces of a network. If False, will return the modularity of each singular disconnected component of the network with the number of nodes in the component as a key
|
|
4082
|
-
and the modularity of the component as a value.
|
|
4083
|
-
:returns: A dictionary containing the modularity for each disconnected component in the network, key-indexed by that component's node count, or a single modularity value accounting for all disconnected components of the network if the solo_mod param is True.
|
|
4084
|
-
"""
|
|
4085
|
-
|
|
4086
|
-
modularity = simple_network.modularity(self._network, solo_mod = solo_mod)
|
|
4087
|
-
|
|
4088
|
-
return modularity
|
|
4089
|
-
|
|
4090
4030
|
|
|
4091
4031
|
def show_identity_network(self, geometric = False, directory = None):
|
|
4092
4032
|
"""
|
|
@@ -4149,7 +4089,7 @@ class Network_3D:
|
|
|
4149
4089
|
return G
|
|
4150
4090
|
|
|
4151
4091
|
|
|
4152
|
-
def isolate_mothers(self, directory = None, down_factor = 1,
|
|
4092
|
+
def isolate_mothers(self, directory = None, down_factor = 1, ret_nodes = False, called = False):
|
|
4153
4093
|
|
|
4154
4094
|
"""
|
|
4155
4095
|
Method to isolate 'mother' nodes of a network (in this case, this means nodes that exist betwixt communities), also generating overlays that relate this information to the 3D structure.
|
|
@@ -4163,7 +4103,7 @@ class Network_3D:
|
|
|
4163
4103
|
"""
|
|
4164
4104
|
|
|
4165
4105
|
if ret_nodes:
|
|
4166
|
-
mothers = community_extractor.extract_mothers(None, self._network,
|
|
4106
|
+
mothers = community_extractor.extract_mothers(None, self._network, self._communities, ret_nodes = True, called = called)
|
|
4167
4107
|
return mothers
|
|
4168
4108
|
else:
|
|
4169
4109
|
|
|
@@ -4172,9 +4112,9 @@ class Network_3D:
|
|
|
4172
4112
|
for item in self._node_centroids:
|
|
4173
4113
|
centroids[item] = np.round((self._node_centroids[item]) / down_factor)
|
|
4174
4114
|
nodes = downsample(self._nodes, down_factor)
|
|
4175
|
-
mothers, overlay = community_extractor.extract_mothers(nodes, self._network, directory = directory, centroid_dic = centroids,
|
|
4115
|
+
mothers, overlay = community_extractor.extract_mothers(nodes, self._network, self._communities, directory = directory, centroid_dic = centroids, called = called)
|
|
4176
4116
|
else:
|
|
4177
|
-
mothers, overlay = community_extractor.extract_mothers(self._nodes, self._network, centroid_dic = self._node_centroids, directory = directory,
|
|
4117
|
+
mothers, overlay = community_extractor.extract_mothers(self._nodes, self._network, self._communities, centroid_dic = self._node_centroids, directory = directory, called = called)
|
|
4178
4118
|
return mothers, overlay
|
|
4179
4119
|
|
|
4180
4120
|
|
|
@@ -4186,7 +4126,7 @@ class Network_3D:
|
|
|
4186
4126
|
|
|
4187
4127
|
hub_img = np.isin(self._nodes, hubs) * self._nodes
|
|
4188
4128
|
else:
|
|
4189
|
-
|
|
4129
|
+
hub_img = None
|
|
4190
4130
|
|
|
4191
4131
|
return hubs, hub_img
|
|
4192
4132
|
|
|
@@ -4248,33 +4188,6 @@ class Network_3D:
|
|
|
4248
4188
|
|
|
4249
4189
|
|
|
4250
4190
|
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
def extract_communities_louvain(self, directory = None, down_factor = 1, color_code = True):
|
|
4254
|
-
"""
|
|
4255
|
-
Method to generate overlays that relate community detection in a network to the 3D structure.
|
|
4256
|
-
Overlays include a grayscale image where nodes are assigned a grayscale value corresponding to their community, a numerical index where numbers are drawn at nodes corresponding to their community, and a
|
|
4257
|
-
color coded overlay where a nodes color corresponds to its community. Community detection will be done with louvain algorithm.
|
|
4258
|
-
These will be saved to the active directory if none is specified.
|
|
4259
|
-
:param directory: (Optional - Val = None; string). A path to a directory to save outputs.
|
|
4260
|
-
:param down_factor: (Optional - Val = 1; int). A factor to downsample nodes by while drawing overlays. Note this option REQUIRES node_centroids to already be set.
|
|
4261
|
-
:param color code: (Optional - Val = True; boolean). If set to False, the color-coded overlay will not be drawn.
|
|
4262
|
-
:returns: A dictionary where nodes are grouped by community.
|
|
4263
|
-
"""
|
|
4264
|
-
|
|
4265
|
-
if down_factor > 1:
|
|
4266
|
-
centroids = self._node_centroids.copy()
|
|
4267
|
-
for item in self._node_centroids:
|
|
4268
|
-
centroids[item] = np.round((self._node_centroids[item]) / down_factor)
|
|
4269
|
-
nodes = downsample(self._nodes, down_factor)
|
|
4270
|
-
partition = network_analysis.community_partition(nodes, self._network_lists, directory = directory, centroids = centroids, color_code = color_code)
|
|
4271
|
-
|
|
4272
|
-
else:
|
|
4273
|
-
partition = network_analysis.community_partition(self._nodes, self._network_lists, directory = directory, centroids = self._node_centroids, color_code = color_code)
|
|
4274
|
-
|
|
4275
|
-
return partition
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
4191
|
#Methods related to analysis:
|
|
4279
4192
|
|
|
4280
4193
|
def radial_distribution(self, radial_distance, directory = None):
|