nettracer3d 0.8.9__py3-none-any.whl → 0.9.1__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/cellpose_manager.py +22 -11
- nettracer3d/modularity.py +24 -9
- nettracer3d/neighborhoods.py +153 -30
- nettracer3d/nettracer.py +321 -54
- nettracer3d/nettracer_gui.py +1095 -478
- nettracer3d/proximity.py +101 -48
- nettracer3d/segmenter.py +514 -372
- nettracer3d/segmenter_GPU.py +434 -281
- {nettracer3d-0.8.9.dist-info → nettracer3d-0.9.1.dist-info}/METADATA +7 -4
- nettracer3d-0.9.1.dist-info/RECORD +25 -0
- nettracer3d-0.8.9.dist-info/RECORD +0 -25
- {nettracer3d-0.8.9.dist-info → nettracer3d-0.9.1.dist-info}/WHEEL +0 -0
- {nettracer3d-0.8.9.dist-info → nettracer3d-0.9.1.dist-info}/entry_points.txt +0 -0
- {nettracer3d-0.8.9.dist-info → nettracer3d-0.9.1.dist-info}/licenses/LICENSE +0 -0
- {nettracer3d-0.8.9.dist-info → nettracer3d-0.9.1.dist-info}/top_level.txt +0 -0
nettracer3d/nettracer.py
CHANGED
|
@@ -500,7 +500,7 @@ def _upsample_3d_array(data, factor, original_shape):
|
|
|
500
500
|
else:
|
|
501
501
|
trimmed_rows = trimmed_planes[:, sub_before[1]:-sub_after[1], :]
|
|
502
502
|
|
|
503
|
-
# Remove
|
|
503
|
+
# Remove columns from the beginning and end
|
|
504
504
|
if sub_dims[2] == 0:
|
|
505
505
|
trimmed_array = trimmed_rows
|
|
506
506
|
else:
|
|
@@ -508,6 +508,101 @@ def _upsample_3d_array(data, factor, original_shape):
|
|
|
508
508
|
|
|
509
509
|
return trimmed_array
|
|
510
510
|
|
|
511
|
+
|
|
512
|
+
def remove_branches_new(skeleton, length):
|
|
513
|
+
"""Used to compensate for overly-branched skeletons resulting from the scipy 3d skeletonization algorithm"""
|
|
514
|
+
def find_coordinate_difference(arr):
|
|
515
|
+
try:
|
|
516
|
+
arr[1,1,1] = 0
|
|
517
|
+
# Find the indices of non-zero elements
|
|
518
|
+
indices = np.array(np.nonzero(arr)).T
|
|
519
|
+
|
|
520
|
+
# Calculate the difference
|
|
521
|
+
diff = np.array([1,1,1]) - indices[0]
|
|
522
|
+
|
|
523
|
+
return diff
|
|
524
|
+
except:
|
|
525
|
+
return None
|
|
526
|
+
|
|
527
|
+
skeleton = np.pad(skeleton, pad_width=1, mode='constant', constant_values=0) #Add black planes over the 3d space to avoid index errors
|
|
528
|
+
image_copy = np.copy(skeleton)
|
|
529
|
+
|
|
530
|
+
# Find all endpoints ONCE at the beginning
|
|
531
|
+
nonzero_coords = np.transpose(np.nonzero(image_copy))
|
|
532
|
+
endpoints = []
|
|
533
|
+
nubs = []
|
|
534
|
+
|
|
535
|
+
for x, y, z in nonzero_coords:
|
|
536
|
+
mini = image_copy[x-1:x+2, y-1:y+2, z-1:z+2]
|
|
537
|
+
nearby_sum = np.sum(mini)
|
|
538
|
+
threshold = 2 * image_copy[x, y, z]
|
|
539
|
+
|
|
540
|
+
if nearby_sum <= threshold:
|
|
541
|
+
endpoints.append((x, y, z))
|
|
542
|
+
|
|
543
|
+
x, y, z = endpoints[0]
|
|
544
|
+
original_val = image_copy[x, y, z]
|
|
545
|
+
|
|
546
|
+
# Process each endpoint individually for nub assessment
|
|
547
|
+
for start_x, start_y, start_z in endpoints:
|
|
548
|
+
|
|
549
|
+
# Trace the branch from this endpoint, removing points as we go
|
|
550
|
+
branch_coords = []
|
|
551
|
+
current_coord = (start_x, start_y, start_z)
|
|
552
|
+
nub_reached = False
|
|
553
|
+
|
|
554
|
+
for step in range(length):
|
|
555
|
+
x, y, z = current_coord
|
|
556
|
+
|
|
557
|
+
# Store original value and coordinates
|
|
558
|
+
branch_coords.append((x, y, z))
|
|
559
|
+
|
|
560
|
+
# Remove this point temporarily
|
|
561
|
+
image_copy[x, y, z] = 0
|
|
562
|
+
|
|
563
|
+
# If we've reached the maximum length without hitting a nub, break
|
|
564
|
+
if step == length - 1:
|
|
565
|
+
break
|
|
566
|
+
|
|
567
|
+
# Find next coordinate in the branch
|
|
568
|
+
mini = image_copy[x-1:x+2, y-1:y+2, z-1:z+2]
|
|
569
|
+
dif = find_coordinate_difference(mini.copy())
|
|
570
|
+
if dif is None:
|
|
571
|
+
break
|
|
572
|
+
|
|
573
|
+
next_coord = (x - dif[0], y - dif[1], z - dif[2])
|
|
574
|
+
|
|
575
|
+
# Check if next coordinate is valid and exists
|
|
576
|
+
nx, ny, nz = next_coord
|
|
577
|
+
|
|
578
|
+
# Check if next point is a nub (has more neighbors than expected)
|
|
579
|
+
next_mini = image_copy[nx-1:nx+2, ny-1:ny+2, nz-1:nz+2]
|
|
580
|
+
next_nearby_sum = np.sum(next_mini)
|
|
581
|
+
next_threshold = 2 * image_copy[nx, ny, nz]
|
|
582
|
+
|
|
583
|
+
if next_nearby_sum > next_threshold:
|
|
584
|
+
nub_reached = True
|
|
585
|
+
nubs.append(next_coord)
|
|
586
|
+
nubs.append(current_coord) # Note, if we don't add the current coord here (and restore it below), the behavior of this method can be changed to trim branches beneath previous branches, which could be neat but its somewhat unpredictable so I opted out of it.
|
|
587
|
+
image_copy[x, y, z] = original_val
|
|
588
|
+
#image_copy[nx, ny, nz] = 0
|
|
589
|
+
break
|
|
590
|
+
|
|
591
|
+
current_coord = next_coord
|
|
592
|
+
|
|
593
|
+
# If no nub was reached, restore all the points we removed
|
|
594
|
+
if not nub_reached:
|
|
595
|
+
for i, (bx, by, bz) in enumerate(branch_coords):
|
|
596
|
+
image_copy[bx, by, bz] = original_val
|
|
597
|
+
# If nub was reached, points stay removed (branch is eliminated)
|
|
598
|
+
|
|
599
|
+
for item in nubs: #The nubs are endpoints of length = 1. They appear a bit different in the array so we just note when one is created and remove them all at the end in a batch.
|
|
600
|
+
image_copy[item[0], item[1], item[2]] = 0 # Removing the nub itself leaves a hole in the skeleton but for branchpoint detection that doesn't matter, which is why it behaves this way. To fill the hole, one option is to dilate once then erode/skeletonize again, but we want to avoid making anything that looks like local branching so I didn't bother.
|
|
601
|
+
|
|
602
|
+
# Remove padding and return
|
|
603
|
+
image_copy = (image_copy[1:-1, 1:-1, 1:-1]).astype(np.uint8)
|
|
604
|
+
return image_copy
|
|
605
|
+
|
|
511
606
|
def remove_branches(skeleton, length):
|
|
512
607
|
"""Used to compensate for overly-branched skeletons resulting from the scipy 3d skeletonization algorithm"""
|
|
513
608
|
|
|
@@ -532,6 +627,7 @@ def remove_branches(skeleton, length):
|
|
|
532
627
|
x, y, z = nonzero_coords[0]
|
|
533
628
|
threshold = 2 * skeleton[x, y, z]
|
|
534
629
|
nubs = []
|
|
630
|
+
|
|
535
631
|
|
|
536
632
|
for b in range(length):
|
|
537
633
|
|
|
@@ -628,6 +724,8 @@ def break_and_label_skeleton(skeleton, peaks = 1, branch_removal = 0, comp_dil =
|
|
|
628
724
|
else:
|
|
629
725
|
broken_skele = None
|
|
630
726
|
|
|
727
|
+
#old_skeleton = copy.deepcopy(skeleton) # The skeleton might get modified in label_vertices so we can make a preserved copy of it to use later
|
|
728
|
+
|
|
631
729
|
if nodes is None:
|
|
632
730
|
|
|
633
731
|
verts = label_vertices(skeleton, peaks = peaks, branch_removal = branch_removal, comp_dil = comp_dil, max_vol = max_vol, return_skele = return_skele)
|
|
@@ -637,6 +735,8 @@ def break_and_label_skeleton(skeleton, peaks = 1, branch_removal = 0, comp_dil =
|
|
|
637
735
|
|
|
638
736
|
verts = invert_array(verts)
|
|
639
737
|
|
|
738
|
+
#skeleton = old_skeleton
|
|
739
|
+
|
|
640
740
|
image_copy = skeleton * verts
|
|
641
741
|
|
|
642
742
|
|
|
@@ -1031,10 +1131,93 @@ def remove_trunk(edges, num_iterations=1):
|
|
|
1031
1131
|
|
|
1032
1132
|
return edges
|
|
1033
1133
|
|
|
1034
|
-
def
|
|
1134
|
+
def get_all_label_coords(labeled_array, background=0):
|
|
1135
|
+
"""
|
|
1136
|
+
Get coordinates for all labels using single pass method.
|
|
1137
|
+
|
|
1138
|
+
Parameters:
|
|
1139
|
+
-----------
|
|
1140
|
+
labeled_array : numpy.ndarray
|
|
1141
|
+
Labeled array with integer labels
|
|
1142
|
+
background : int, optional
|
|
1143
|
+
Background label to exclude (default: 0)
|
|
1144
|
+
|
|
1145
|
+
Returns:
|
|
1146
|
+
--------
|
|
1147
|
+
dict : {label: coordinates_array}
|
|
1148
|
+
Dictionary mapping each label to its coordinate array
|
|
1149
|
+
"""
|
|
1150
|
+
coords_dict = {}
|
|
1151
|
+
|
|
1152
|
+
# Get all non-background coordinates at once
|
|
1153
|
+
all_coords = np.argwhere(labeled_array != background)
|
|
1154
|
+
|
|
1155
|
+
if len(all_coords) == 0:
|
|
1156
|
+
return coords_dict
|
|
1157
|
+
|
|
1158
|
+
# Get the label values at those coordinates
|
|
1159
|
+
labels_at_coords = labeled_array[tuple(all_coords.T)]
|
|
1160
|
+
|
|
1161
|
+
# Group by label
|
|
1162
|
+
unique_labels = np.unique(labels_at_coords)
|
|
1163
|
+
for label in unique_labels:
|
|
1164
|
+
mask = labels_at_coords == label
|
|
1165
|
+
coords_dict[label] = all_coords[mask]
|
|
1166
|
+
|
|
1167
|
+
return coords_dict
|
|
1168
|
+
|
|
1169
|
+
def approx_boundaries(array, iden_set = None, node_identities = None, keep_labels = False):
|
|
1170
|
+
|
|
1171
|
+
"""Hollows out an array, can do it for only a set number of identities. Returns coords as dict if labeled or as 1d numpy array if binary is desired"""
|
|
1172
|
+
|
|
1173
|
+
if node_identities is not None:
|
|
1174
|
+
|
|
1175
|
+
nodes = []
|
|
1176
|
+
|
|
1177
|
+
for node in node_identities:
|
|
1178
|
+
|
|
1179
|
+
if node_identities[node] in iden_set: #Filter out only idens we need
|
|
1180
|
+
nodes.append(node)
|
|
1181
|
+
|
|
1182
|
+
mask = np.isin(array, nodes)
|
|
1183
|
+
|
|
1184
|
+
if keep_labels:
|
|
1185
|
+
|
|
1186
|
+
array = array * mask
|
|
1187
|
+
else:
|
|
1188
|
+
array = mask
|
|
1189
|
+
del mask
|
|
1190
|
+
|
|
1191
|
+
from skimage.segmentation import find_boundaries
|
|
1192
|
+
|
|
1193
|
+
borders = find_boundaries(array, mode='thick')
|
|
1194
|
+
array = array * borders
|
|
1195
|
+
del borders
|
|
1196
|
+
if not keep_labels:
|
|
1197
|
+
return np.argwhere(array != 0)
|
|
1198
|
+
else:
|
|
1199
|
+
return get_all_label_coords(array)
|
|
1200
|
+
|
|
1201
|
+
|
|
1202
|
+
|
|
1203
|
+
def hash_inners(search_region, inner_edges, GPU = False):
|
|
1035
1204
|
"""Internal method used to help sort out inner edge connections. The inner edges of the array will not differentiate between what nodes they contact if those nodes themselves directly touch each other.
|
|
1036
1205
|
This method allows these elements to be efficiently seperated from each other"""
|
|
1037
1206
|
|
|
1207
|
+
from skimage.segmentation import find_boundaries
|
|
1208
|
+
|
|
1209
|
+
borders = find_boundaries(search_region, mode='thick')
|
|
1210
|
+
|
|
1211
|
+
inner_edges = inner_edges * borders #And as a result, we can mask out only 'inner edges' that themselves exist within borders
|
|
1212
|
+
|
|
1213
|
+
inner_edges = dilate_3D_old(inner_edges, 3, 3, 3) #Not sure if dilating is necessary. Want to ensure that the inner edge pieces still overlap with the proper nodes after the masking.
|
|
1214
|
+
|
|
1215
|
+
return inner_edges
|
|
1216
|
+
|
|
1217
|
+
def hash_inners_old(search_region, inner_edges, GPU = True):
|
|
1218
|
+
"""Internal method used to help sort out inner edge connections. The inner edges of the array will not differentiate between what nodes they contact if those nodes themselves directly touch each other.
|
|
1219
|
+
This method allows these elements to be efficiently seperated from each other. Originally this was implemented using the gaussian blur because i didn't yet realize skimage could do the same more efficiently."""
|
|
1220
|
+
|
|
1038
1221
|
print("Performing gaussian blur to hash inner edges.")
|
|
1039
1222
|
|
|
1040
1223
|
blurred_search = smart_dilate.gaussian(search_region, GPU = GPU)
|
|
@@ -2170,6 +2353,9 @@ def label_vertices(array, peaks = 0, branch_removal = 0, comp_dil = 0, max_vol =
|
|
|
2170
2353
|
|
|
2171
2354
|
array = skeletonize(array)
|
|
2172
2355
|
|
|
2356
|
+
if return_skele:
|
|
2357
|
+
old_skeleton = copy.deepcopy(array) # The skeleton might get modified in label_vertices so we can make a preserved copy of it to use later
|
|
2358
|
+
|
|
2173
2359
|
if branch_removal > 0:
|
|
2174
2360
|
array = remove_branches(array, branch_removal)
|
|
2175
2361
|
|
|
@@ -2235,7 +2421,7 @@ def label_vertices(array, peaks = 0, branch_removal = 0, comp_dil = 0, max_vol =
|
|
|
2235
2421
|
|
|
2236
2422
|
if return_skele:
|
|
2237
2423
|
|
|
2238
|
-
return labeled_image,
|
|
2424
|
+
return labeled_image, old_skeleton
|
|
2239
2425
|
|
|
2240
2426
|
else:
|
|
2241
2427
|
|
|
@@ -5306,7 +5492,7 @@ class Network_3D:
|
|
|
5306
5492
|
neighborhoods.visualize_cluster_composition_umap(self.node_centroids, None, id_dictionary = self.node_identities, graph_label = "Node ID", title = 'UMAP Visualization of Node Centroids')
|
|
5307
5493
|
|
|
5308
5494
|
|
|
5309
|
-
def community_id_info_per_com(self, umap = False, label =
|
|
5495
|
+
def community_id_info_per_com(self, umap = False, label = 0, limit = 0, proportional = False, neighbors = None):
|
|
5310
5496
|
|
|
5311
5497
|
community_dict = invert_dict(self.communities)
|
|
5312
5498
|
summation = 0
|
|
@@ -5395,7 +5581,19 @@ class Network_3D:
|
|
|
5395
5581
|
if umap:
|
|
5396
5582
|
from . import neighborhoods
|
|
5397
5583
|
|
|
5398
|
-
|
|
5584
|
+
|
|
5585
|
+
if self.communities is not None and label == 2:
|
|
5586
|
+
neighbor_group = {}
|
|
5587
|
+
for node, com in self.communities.items():
|
|
5588
|
+
neighbor_group[com] = neighbors[node]
|
|
5589
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, neighborhoods = neighbor_group)
|
|
5590
|
+
elif label == 1:
|
|
5591
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = True)
|
|
5592
|
+
else:
|
|
5593
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = False)
|
|
5594
|
+
|
|
5595
|
+
|
|
5596
|
+
#neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = label)
|
|
5399
5597
|
|
|
5400
5598
|
return output, id_set
|
|
5401
5599
|
|
|
@@ -5668,75 +5866,141 @@ class Network_3D:
|
|
|
5668
5866
|
pass
|
|
5669
5867
|
|
|
5670
5868
|
|
|
5671
|
-
def nearest_neighbors_avg(self, root, targ, xy_scale = 1, z_scale = 1, num = 1, heatmap = False, threed = True, numpy = False, quant = False):
|
|
5869
|
+
def nearest_neighbors_avg(self, root, targ, xy_scale = 1, z_scale = 1, num = 1, heatmap = False, threed = True, numpy = False, quant = False, centroids = True):
|
|
5672
5870
|
|
|
5673
|
-
def
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5871
|
+
def distribute_points_uniformly(n, shape, z_scale, xy_scale, num, is_2d=False):
|
|
5872
|
+
|
|
5873
|
+
from scipy.spatial import KDTree
|
|
5874
|
+
|
|
5875
|
+
if n <= 1:
|
|
5876
|
+
return 0
|
|
5877
|
+
|
|
5878
|
+
# Calculate total positions and sampling step
|
|
5879
|
+
total_positions = np.prod(shape)
|
|
5880
|
+
if n >= total_positions:
|
|
5881
|
+
# If we want more points than positions, just return scaled unit distance
|
|
5882
|
+
return xy_scale if is_2d else min(z_scale, xy_scale)
|
|
5679
5883
|
|
|
5680
|
-
|
|
5681
|
-
|
|
5884
|
+
# Create uniformly spaced indices
|
|
5885
|
+
indices = np.linspace(0, total_positions - 1, n, dtype=int)
|
|
5682
5886
|
|
|
5683
|
-
|
|
5684
|
-
|
|
5887
|
+
# Convert flat indices to coordinates
|
|
5888
|
+
coords = []
|
|
5889
|
+
for idx in indices:
|
|
5890
|
+
coord = np.unravel_index(idx, shape)
|
|
5891
|
+
if len(shape) == 3:
|
|
5892
|
+
# Apply scaling: [z, y, x] with respective scales
|
|
5893
|
+
scaled_coord = [coord[0] * z_scale, coord[1] * xy_scale, coord[2] * xy_scale]
|
|
5894
|
+
elif len(shape) == 2:
|
|
5895
|
+
# Apply scaling: [y, x] with xy_scale
|
|
5896
|
+
scaled_coord = [coord[0] * xy_scale, coord[1] * xy_scale]
|
|
5897
|
+
coords.append(scaled_coord)
|
|
5685
5898
|
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5899
|
+
coords = np.array(coords)
|
|
5900
|
+
|
|
5901
|
+
# Build KDTree
|
|
5902
|
+
tree = KDTree(coords)
|
|
5903
|
+
|
|
5904
|
+
# Pick a point near the middle of the array
|
|
5905
|
+
middle_idx = len(coords) // 2
|
|
5906
|
+
query_point = coords[middle_idx]
|
|
5907
|
+
|
|
5908
|
+
# Find the num+1 nearest neighbors (including the point itself)
|
|
5909
|
+
distances, indices = tree.query(query_point, k=num+1)
|
|
5910
|
+
|
|
5911
|
+
# Exclude the point itself (distance 0) and get the actual neighbors
|
|
5912
|
+
neighbor_distances = distances[1:num+1]
|
|
5913
|
+
|
|
5914
|
+
if num == n:
|
|
5915
|
+
neighbor_distances[-1] = neighbor_distances[-2]
|
|
5916
|
+
|
|
5917
|
+
avg_distance = np.mean(neighbor_distances)
|
|
5696
5918
|
|
|
5697
|
-
|
|
5919
|
+
|
|
5920
|
+
return avg_distance
|
|
5698
5921
|
|
|
5699
|
-
|
|
5922
|
+
do_borders = not centroids
|
|
5700
5923
|
|
|
5701
|
-
|
|
5924
|
+
if centroids:
|
|
5925
|
+
root_set = []
|
|
5702
5926
|
|
|
5703
|
-
|
|
5927
|
+
compare_set = []
|
|
5704
5928
|
|
|
5705
|
-
|
|
5706
|
-
compare_set = root_set
|
|
5707
|
-
title = "Nearest Neighbors Between Nodes Heatmap"
|
|
5929
|
+
if root is None:
|
|
5708
5930
|
|
|
5709
|
-
|
|
5931
|
+
root_set = list(self.node_centroids.keys())
|
|
5932
|
+
compare_set = root_set
|
|
5933
|
+
title = "Nearest Neighbors Between Nodes Heatmap"
|
|
5934
|
+
|
|
5935
|
+
else:
|
|
5710
5936
|
|
|
5711
|
-
|
|
5937
|
+
title = f"Nearest Neighbors of ID {targ} from ID {root} Heatmap"
|
|
5712
5938
|
|
|
5713
|
-
|
|
5939
|
+
for node, iden in self.node_identities.items():
|
|
5714
5940
|
|
|
5715
|
-
|
|
5941
|
+
if iden == root:
|
|
5716
5942
|
|
|
5717
|
-
|
|
5943
|
+
root_set.append(node)
|
|
5718
5944
|
|
|
5719
|
-
|
|
5945
|
+
elif (iden == targ) or (targ == 'All Others (Excluding Self)'):
|
|
5720
5946
|
|
|
5721
|
-
|
|
5947
|
+
compare_set.append(node)
|
|
5722
5948
|
|
|
5723
|
-
|
|
5949
|
+
if root == targ:
|
|
5950
|
+
|
|
5951
|
+
compare_set = root_set
|
|
5952
|
+
if len(compare_set) - 1 < num:
|
|
5953
|
+
|
|
5954
|
+
num = len(compare_set) - 1
|
|
5955
|
+
|
|
5956
|
+
print(f"Error: Not enough neighbor nodes for requested number of neighbors. Using max available neighbors: {num}")
|
|
5957
|
+
|
|
5724
5958
|
|
|
5725
|
-
compare_set
|
|
5726
|
-
if len(compare_set) - 1 < num:
|
|
5959
|
+
if len(compare_set) < num:
|
|
5727
5960
|
|
|
5728
|
-
num = len(compare_set)
|
|
5961
|
+
num = len(compare_set)
|
|
5729
5962
|
|
|
5730
5963
|
print(f"Error: Not enough neighbor nodes for requested number of neighbors. Using max available neighbors: {num}")
|
|
5731
|
-
|
|
5732
5964
|
|
|
5733
|
-
|
|
5965
|
+
avg, output = proximity.average_nearest_neighbor_distances(self.node_centroids, root_set, compare_set, xy_scale=self.xy_scale, z_scale=self.z_scale, num = num, do_borders = do_borders)
|
|
5734
5966
|
|
|
5735
|
-
|
|
5967
|
+
else:
|
|
5968
|
+
if heatmap:
|
|
5969
|
+
root_set = []
|
|
5970
|
+
compare_set = []
|
|
5971
|
+
if root is None:
|
|
5736
5972
|
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5973
|
+
root_set = list(self.node_centroids.keys())
|
|
5974
|
+
compare_set = root_set
|
|
5975
|
+
else:
|
|
5976
|
+
for node, iden in self.node_identities.items():
|
|
5977
|
+
|
|
5978
|
+
if iden == root:
|
|
5979
|
+
|
|
5980
|
+
root_set.append(node)
|
|
5981
|
+
|
|
5982
|
+
elif (iden == targ) or (targ == 'All Others (Excluding Self)'):
|
|
5983
|
+
|
|
5984
|
+
compare_set.append(node)
|
|
5985
|
+
|
|
5986
|
+
if root is None:
|
|
5987
|
+
title = "Nearest Neighbors Between Nodes Heatmap"
|
|
5988
|
+
root_set_neigh = approx_boundaries(self.nodes, keep_labels = True)
|
|
5989
|
+
compare_set_neigh = approx_boundaries(self.nodes, keep_labels = False)
|
|
5990
|
+
else:
|
|
5991
|
+
title = f"Nearest Neighbors of ID {targ} from ID {root} Heatmap"
|
|
5992
|
+
|
|
5993
|
+
root_set_neigh = approx_boundaries(self.nodes, [root], self.node_identities, keep_labels = True)
|
|
5994
|
+
|
|
5995
|
+
if targ == 'All Others (Excluding Self)':
|
|
5996
|
+
compare_set_neigh = set(self.node_identities.values())
|
|
5997
|
+
compare_set_neigh.remove(root)
|
|
5998
|
+
targ = compare_set_neigh
|
|
5999
|
+
else:
|
|
6000
|
+
targ = [targ]
|
|
6001
|
+
|
|
6002
|
+
compare_set_neigh = approx_boundaries(self.nodes, targ, self.node_identities, keep_labels = False)
|
|
6003
|
+
avg, output = proximity.average_nearest_neighbor_distances(self.node_centroids, root_set_neigh, compare_set_neigh, xy_scale=self.xy_scale, z_scale=self.z_scale, num = num, do_borders = do_borders)
|
|
5740
6004
|
|
|
5741
6005
|
if quant:
|
|
5742
6006
|
try:
|
|
@@ -5778,8 +6042,7 @@ class Network_3D:
|
|
|
5778
6042
|
else:
|
|
5779
6043
|
is_2d = False
|
|
5780
6044
|
|
|
5781
|
-
pred =
|
|
5782
|
-
#pred = avg
|
|
6045
|
+
pred = distribute_points_uniformly(len(compare_set), bounds, self.z_scale, self.xy_scale, num = num, is_2d = is_2d)
|
|
5783
6046
|
|
|
5784
6047
|
node_intensity = {}
|
|
5785
6048
|
import math
|
|
@@ -5787,18 +6050,22 @@ class Network_3D:
|
|
|
5787
6050
|
|
|
5788
6051
|
for node in root_set:
|
|
5789
6052
|
node_intensity[node] = math.log(pred/output[node])
|
|
6053
|
+
#print(output[node])
|
|
5790
6054
|
node_centroids[node] = self.node_centroids[node]
|
|
5791
6055
|
|
|
5792
6056
|
if numpy:
|
|
5793
6057
|
|
|
5794
6058
|
overlay = neighborhoods.create_node_heatmap(node_intensity, node_centroids, shape = shape, is_3d=threed, labeled_array = self.nodes, colorbar_label="Clustering Intensity", title = title)
|
|
5795
6059
|
|
|
5796
|
-
return avg, output, overlay, quant_overlay
|
|
6060
|
+
return avg, output, overlay, quant_overlay, pred
|
|
5797
6061
|
|
|
5798
6062
|
else:
|
|
5799
6063
|
neighborhoods.create_node_heatmap(node_intensity, node_centroids, shape = shape, is_3d=threed, labeled_array = None, colorbar_label="Clustering Intensity", title = title)
|
|
5800
6064
|
|
|
5801
|
-
|
|
6065
|
+
else:
|
|
6066
|
+
pred = None
|
|
6067
|
+
|
|
6068
|
+
return avg, output, quant_overlay, pred
|
|
5802
6069
|
|
|
5803
6070
|
|
|
5804
6071
|
|