nettracer3d 0.8.1__py3-none-any.whl → 0.8.3__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 +161 -0
- nettracer3d/community_extractor.py +169 -23
- nettracer3d/neighborhoods.py +222 -23
- nettracer3d/nettracer.py +166 -68
- nettracer3d/nettracer_gui.py +584 -266
- nettracer3d/network_analysis.py +222 -230
- nettracer3d/proximity.py +191 -30
- {nettracer3d-0.8.1.dist-info → nettracer3d-0.8.3.dist-info}/METADATA +44 -12
- {nettracer3d-0.8.1.dist-info → nettracer3d-0.8.3.dist-info}/RECORD +13 -12
- {nettracer3d-0.8.1.dist-info → nettracer3d-0.8.3.dist-info}/WHEEL +0 -0
- {nettracer3d-0.8.1.dist-info → nettracer3d-0.8.3.dist-info}/entry_points.txt +0 -0
- {nettracer3d-0.8.1.dist-info → nettracer3d-0.8.3.dist-info}/licenses/LICENSE +0 -0
- {nettracer3d-0.8.1.dist-info → nettracer3d-0.8.3.dist-info}/top_level.txt +0 -0
nettracer3d/nettracer.py
CHANGED
|
@@ -348,6 +348,11 @@ def create_and_save_dataframe(pairwise_connections, excel_filename = None):
|
|
|
348
348
|
|
|
349
349
|
#General supporting methods below:
|
|
350
350
|
|
|
351
|
+
def invert_dict(d):
|
|
352
|
+
inverted = {}
|
|
353
|
+
for key, value in d.items():
|
|
354
|
+
inverted.setdefault(value, []).append(key)
|
|
355
|
+
return inverted
|
|
351
356
|
|
|
352
357
|
def invert_array(array):
|
|
353
358
|
"""Internal method used to flip node array indices. 0 becomes 255 and vice versa."""
|
|
@@ -1484,6 +1489,13 @@ def remove_zeros(input_list):
|
|
|
1484
1489
|
return result_array
|
|
1485
1490
|
|
|
1486
1491
|
|
|
1492
|
+
def overlay_arrays_simple(edge_labels_1, edge_labels_2):
|
|
1493
|
+
"""
|
|
1494
|
+
Superimpose edge_labels_2 on top of edge_labels_1 without any offset.
|
|
1495
|
+
Where edge_labels_2 > 0, use those values directly.
|
|
1496
|
+
"""
|
|
1497
|
+
mask = edge_labels_1 > 0
|
|
1498
|
+
return np.where(mask, edge_labels_1, edge_labels_2)
|
|
1487
1499
|
|
|
1488
1500
|
def combine_edges(edge_labels_1, edge_labels_2):
|
|
1489
1501
|
"""
|
|
@@ -1616,7 +1628,7 @@ def downsample(data, factor, directory=None, order=0):
|
|
|
1616
1628
|
return data
|
|
1617
1629
|
|
|
1618
1630
|
|
|
1619
|
-
def otsu_binarize(image_array):
|
|
1631
|
+
def otsu_binarize(image_array, non_bool = False):
|
|
1620
1632
|
|
|
1621
1633
|
"""Automated binarize method for seperating the foreground"""
|
|
1622
1634
|
|
|
@@ -1624,6 +1636,10 @@ def otsu_binarize(image_array):
|
|
|
1624
1636
|
|
|
1625
1637
|
threshold = threshold_otsu(image_array)
|
|
1626
1638
|
binary_mask = image_array > threshold
|
|
1639
|
+
|
|
1640
|
+
if non_bool:
|
|
1641
|
+
binary_mask = binary_mask * 255
|
|
1642
|
+
|
|
1627
1643
|
return binary_mask
|
|
1628
1644
|
|
|
1629
1645
|
def binarize(arrayimage, directory = None):
|
|
@@ -1814,12 +1830,6 @@ def label_branches(array, peaks = 0, branch_removal = 0, comp_dil = 0, max_vol =
|
|
|
1814
1830
|
|
|
1815
1831
|
def fix_branches_network(array, G, communities, fix_val = None):
|
|
1816
1832
|
|
|
1817
|
-
def invert_dict(d):
|
|
1818
|
-
inverted = {}
|
|
1819
|
-
for key, value in d.items():
|
|
1820
|
-
inverted.setdefault(value, []).append(key)
|
|
1821
|
-
return inverted
|
|
1822
|
-
|
|
1823
1833
|
def get_degree_threshold(community_degrees):
|
|
1824
1834
|
degrees = np.array(community_degrees, dtype=float)
|
|
1825
1835
|
hist, bins = np.histogram(degrees, bins='auto')
|
|
@@ -3893,11 +3903,6 @@ class Network_3D:
|
|
|
3893
3903
|
|
|
3894
3904
|
def com_to_node(self, targets = None):
|
|
3895
3905
|
|
|
3896
|
-
def invert_dict(d):
|
|
3897
|
-
inverted = {}
|
|
3898
|
-
for key, value in d.items():
|
|
3899
|
-
inverted.setdefault(value, []).append(key)
|
|
3900
|
-
return inverted
|
|
3901
3906
|
|
|
3902
3907
|
def update_array(array_3d, value_dict, targets = None):
|
|
3903
3908
|
ref_array = copy.deepcopy(array_3d)
|
|
@@ -4831,9 +4836,9 @@ class Network_3D:
|
|
|
4831
4836
|
(z1, y1, x1), (z2, y2, x2) = bounds
|
|
4832
4837
|
z1, y1, x1 = int(z1), int(y1), int(x1)
|
|
4833
4838
|
z2, y2, x2 = int(z2), int(y2), int(x2)
|
|
4834
|
-
z_range = np.arange(z1, z2 + 1)
|
|
4835
|
-
y_range = np.arange(y1, y2 + 1)
|
|
4836
|
-
x_range = np.arange(x1, x2 + 1)
|
|
4839
|
+
z_range = np.arange(z1, z2 + 1 )
|
|
4840
|
+
y_range = np.arange(y1, y2 + 1 )
|
|
4841
|
+
x_range = np.arange(x1, x2 + 1 )
|
|
4837
4842
|
z_grid, y_grid, x_grid = np.meshgrid(z_range, y_range, x_range, indexing='ij')
|
|
4838
4843
|
del z_range
|
|
4839
4844
|
del y_range
|
|
@@ -4896,11 +4901,6 @@ class Network_3D:
|
|
|
4896
4901
|
|
|
4897
4902
|
def community_id_info(self):
|
|
4898
4903
|
|
|
4899
|
-
def invert_dict(d):
|
|
4900
|
-
inverted = {}
|
|
4901
|
-
for key, value in d.items():
|
|
4902
|
-
inverted.setdefault(value, []).append(key)
|
|
4903
|
-
return inverted
|
|
4904
4904
|
|
|
4905
4905
|
community_dict = invert_dict(self.communities)
|
|
4906
4906
|
summation = 0
|
|
@@ -4938,13 +4938,7 @@ class Network_3D:
|
|
|
4938
4938
|
|
|
4939
4939
|
return output
|
|
4940
4940
|
|
|
4941
|
-
def community_id_info_per_com(self, umap = False, label = False):
|
|
4942
|
-
|
|
4943
|
-
def invert_dict(d):
|
|
4944
|
-
inverted = {}
|
|
4945
|
-
for key, value in d.items():
|
|
4946
|
-
inverted.setdefault(value, []).append(key)
|
|
4947
|
-
return inverted
|
|
4941
|
+
def community_id_info_per_com(self, umap = False, label = False, limit = 0, proportional = False):
|
|
4948
4942
|
|
|
4949
4943
|
community_dict = invert_dict(self.communities)
|
|
4950
4944
|
summation = 0
|
|
@@ -4954,62 +4948,122 @@ class Network_3D:
|
|
|
4954
4948
|
id_dict[iden] = i
|
|
4955
4949
|
|
|
4956
4950
|
output = {}
|
|
4951
|
+
umap_dict = {}
|
|
4957
4952
|
|
|
4958
|
-
|
|
4953
|
+
if not proportional:
|
|
4959
4954
|
|
|
4960
|
-
|
|
4955
|
+
for community in community_dict:
|
|
4961
4956
|
|
|
4962
|
-
|
|
4963
|
-
size = len(nodes)
|
|
4957
|
+
counter = np.zeros(len(id_set))
|
|
4964
4958
|
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4959
|
+
nodes = community_dict[community]
|
|
4960
|
+
size = len(nodes)
|
|
4961
|
+
|
|
4962
|
+
# Count identities in this community
|
|
4963
|
+
for node in nodes:
|
|
4964
|
+
counter[id_dict[self.node_identities[node]]] += 1 # Keep them as arrays
|
|
4965
|
+
|
|
4966
|
+
for i in range(len(counter)): # Translate them into proportions out of 1
|
|
4967
|
+
|
|
4968
|
+
counter[i] = counter[i]/size
|
|
4969
|
+
|
|
4970
|
+
output[community] = counter #Assign the finding here
|
|
4968
4971
|
|
|
4969
|
-
|
|
4972
|
+
if size >= limit:
|
|
4973
|
+
umap_dict[community] = counter
|
|
4970
4974
|
|
|
4971
|
-
|
|
4975
|
+
else:
|
|
4976
|
+
idens = invert_dict(self.node_identities)
|
|
4977
|
+
iden_count = {}
|
|
4978
|
+
template = {}
|
|
4979
|
+
node_count = len(list(self.communities.keys()))
|
|
4980
|
+
|
|
4981
|
+
|
|
4982
|
+
for iden in id_set:
|
|
4983
|
+
template[iden] = 0
|
|
4984
|
+
|
|
4985
|
+
for iden, nodes in idens.items():
|
|
4986
|
+
iden_count[iden] = len(nodes)
|
|
4987
|
+
|
|
4988
|
+
for community in community_dict:
|
|
4989
|
+
|
|
4990
|
+
iden_tracker = copy.deepcopy(template)
|
|
4991
|
+
|
|
4992
|
+
nodes = community_dict[community]
|
|
4993
|
+
size = len(nodes)
|
|
4994
|
+
counter = np.zeros(len(id_set))
|
|
4995
|
+
|
|
4996
|
+
for node in nodes:
|
|
4997
|
+
iden_tracker[self.node_identities[node]] += 1
|
|
4998
|
+
|
|
4999
|
+
i = 0
|
|
5000
|
+
|
|
5001
|
+
if not umap: # External calls just get the proportion for now
|
|
5002
|
+
|
|
5003
|
+
for iden, val in iden_tracker.items(): # Translate them into proportions of total number of that node of all nodes of that ID
|
|
5004
|
+
|
|
5005
|
+
counter[i] = (val/iden_count[iden])
|
|
5006
|
+
i += 1
|
|
5007
|
+
|
|
5008
|
+
output[community] = counter #Assign the finding here
|
|
5009
|
+
|
|
5010
|
+
if size >= limit:
|
|
5011
|
+
umap_dict[community] = counter
|
|
5012
|
+
|
|
5013
|
+
else: # Internal calls for the umap get the relative proportion, demonstrating overrepresentation per community
|
|
5014
|
+
|
|
5015
|
+
|
|
5016
|
+
for iden, val in iden_tracker.items(): # Translate them into proportions of total number of that node of all nodes of that ID
|
|
5017
|
+
|
|
5018
|
+
counter[i] = (val/iden_count[iden])/(size/node_count) # The proportion of that ID in the community vs all of that ID divided by the proportion of that community size vs all the nodes
|
|
5019
|
+
i += 1
|
|
5020
|
+
|
|
5021
|
+
output[community] = counter #Assign the finding here
|
|
5022
|
+
|
|
5023
|
+
if size >= limit:
|
|
5024
|
+
umap_dict[community] = counter
|
|
4972
5025
|
|
|
4973
|
-
output[community] = counter #Assign the finding here
|
|
4974
5026
|
|
|
4975
5027
|
if umap:
|
|
4976
5028
|
from . import neighborhoods
|
|
4977
|
-
|
|
5029
|
+
|
|
5030
|
+
neighborhoods.visualize_cluster_composition_umap(umap_dict, id_set, label = label)
|
|
4978
5031
|
|
|
4979
5032
|
return output, id_set
|
|
4980
5033
|
|
|
4981
5034
|
|
|
4982
|
-
def assign_neighborhoods(self, seed, count, limit = None, prev_coms = None):
|
|
5035
|
+
def assign_neighborhoods(self, seed, count, limit = None, prev_coms = None, proportional = False, mode = 0):
|
|
4983
5036
|
|
|
4984
5037
|
from . import neighborhoods
|
|
4985
5038
|
|
|
4986
|
-
def invert_dict(d):
|
|
4987
|
-
inverted = {}
|
|
4988
|
-
for key, value in d.items():
|
|
4989
|
-
inverted.setdefault(value, []).append(key)
|
|
4990
|
-
return inverted
|
|
4991
|
-
|
|
4992
5039
|
if prev_coms is not None:
|
|
4993
5040
|
self.communities = copy.deepcopy(prev_coms)
|
|
4994
5041
|
|
|
4995
5042
|
identities, _ = self.community_id_info_per_com()
|
|
4996
5043
|
|
|
5044
|
+
zero_group = {}
|
|
5045
|
+
|
|
5046
|
+
|
|
4997
5047
|
if limit is not None:
|
|
4998
5048
|
|
|
4999
5049
|
coms = invert_dict(self.communities)
|
|
5000
5050
|
|
|
5001
|
-
zero_group = {}
|
|
5002
5051
|
|
|
5003
5052
|
for com, nodes in coms.items():
|
|
5004
5053
|
|
|
5005
5054
|
if len(nodes) < limit:
|
|
5006
5055
|
|
|
5007
|
-
zero_group[com] = 0
|
|
5008
|
-
|
|
5009
5056
|
del identities[com]
|
|
5010
5057
|
|
|
5058
|
+
if count > len(identities):
|
|
5059
|
+
print(f"Requested neighborhoods too large for available communities. Using {len(identities)} neighborhoods (max for these coms)")
|
|
5060
|
+
count = len(identities)
|
|
5011
5061
|
|
|
5012
|
-
|
|
5062
|
+
|
|
5063
|
+
if mode == 0:
|
|
5064
|
+
clusters = neighborhoods.cluster_arrays(identities, count, seed = seed)
|
|
5065
|
+
elif mode == 1:
|
|
5066
|
+
clusters = neighborhoods.cluster_arrays_dbscan(identities, seed = seed)
|
|
5013
5067
|
|
|
5014
5068
|
coms = {}
|
|
5015
5069
|
|
|
@@ -5021,19 +5075,60 @@ class Network_3D:
|
|
|
5021
5075
|
|
|
5022
5076
|
coms[com] = i + 1
|
|
5023
5077
|
|
|
5024
|
-
|
|
5025
|
-
coms.update(zero_group)
|
|
5078
|
+
copy_dict = copy.deepcopy(self.communities)
|
|
5026
5079
|
|
|
5027
|
-
for node, com in
|
|
5080
|
+
for node, com in copy_dict.items():
|
|
5081
|
+
|
|
5082
|
+
try:
|
|
5083
|
+
|
|
5084
|
+
self.communities[node] = coms[com]
|
|
5085
|
+
|
|
5086
|
+
except:
|
|
5087
|
+
del self.communities[node]
|
|
5088
|
+
zero_group[node] = 0
|
|
5089
|
+
|
|
5090
|
+
self.com_by_size()
|
|
5091
|
+
|
|
5092
|
+
|
|
5093
|
+
if len(zero_group) > 0:
|
|
5094
|
+
self.communities.update(zero_group)
|
|
5028
5095
|
|
|
5029
|
-
self.communities[node] = coms[com]
|
|
5030
5096
|
|
|
5031
5097
|
identities, id_set = self.community_id_info_per_com()
|
|
5032
5098
|
|
|
5033
|
-
|
|
5099
|
+
len_dict = {}
|
|
5100
|
+
|
|
5101
|
+
coms = invert_dict(self.communities)
|
|
5102
|
+
node_count = len(list(self.communities.keys()))
|
|
5103
|
+
|
|
5104
|
+
for com, nodes in coms.items():
|
|
5105
|
+
|
|
5106
|
+
len_dict[com] = len(nodes)/node_count
|
|
5107
|
+
|
|
5108
|
+
matrixes = []
|
|
5109
|
+
|
|
5110
|
+
output = neighborhoods.plot_dict_heatmap(identities, id_set, title = "Neighborhood Heatmap by Proportional Composition Per Neighborhood")
|
|
5111
|
+
|
|
5112
|
+
matrixes.append(output)
|
|
5113
|
+
|
|
5114
|
+
if proportional:
|
|
5115
|
+
|
|
5116
|
+
identities2, id_set2 = self.community_id_info_per_com(proportional = True)
|
|
5117
|
+
output = neighborhoods.plot_dict_heatmap(identities2, id_set2, title = "Neighborhood Heatmap by Proportional Composition of Nodes in Neighborhood vs All Nodes")
|
|
5118
|
+
matrixes.append(output)
|
|
5119
|
+
|
|
5120
|
+
identities3 = {}
|
|
5121
|
+
for iden in identities2:
|
|
5122
|
+
identities3[iden] = identities2[iden]/len_dict[iden]
|
|
5123
|
+
|
|
5124
|
+
output = neighborhoods.plot_dict_heatmap(identities3, id_set2, title = "Neighborhood Heatmap by Proportional Composition of Nodes in Neighborhood vs All Nodes Divided by Neighborhood Total Proportion of All Nodes (val < 1 = underrepresented, val > 1 = overrepresented)", center_at_one = True)
|
|
5125
|
+
matrixes.append(output)
|
|
5126
|
+
|
|
5127
|
+
return len_dict, matrixes, id_set
|
|
5128
|
+
|
|
5034
5129
|
|
|
5035
5130
|
|
|
5036
|
-
def kd_network(self, distance = 100, targets = None, make_array = False):
|
|
5131
|
+
def kd_network(self, distance = 100, targets = None, make_array = False, max_neighbors = None):
|
|
5037
5132
|
|
|
5038
5133
|
centroids = copy.deepcopy(self._node_centroids)
|
|
5039
5134
|
|
|
@@ -5054,14 +5149,20 @@ class Network_3D:
|
|
|
5054
5149
|
centroids[node] = [centroid[0], centroid[1] * refactor, centroid[2] * refactor]
|
|
5055
5150
|
|
|
5056
5151
|
|
|
5057
|
-
neighbors = proximity.find_neighbors_kdtree(distance, targets = targets, centroids = centroids)
|
|
5152
|
+
neighbors = proximity.find_neighbors_kdtree(distance, targets = targets, centroids = centroids, max_neighbors = max_neighbors)
|
|
5153
|
+
|
|
5154
|
+
print("Creating Dataframe")
|
|
5058
5155
|
|
|
5059
5156
|
network = create_and_save_dataframe(neighbors)
|
|
5060
5157
|
|
|
5158
|
+
print("Converting df to network")
|
|
5159
|
+
|
|
5061
5160
|
self._network_lists = network_analysis.read_excel_to_lists(network)
|
|
5062
5161
|
|
|
5063
5162
|
#self._network is a networkx graph that stores the connections
|
|
5064
5163
|
|
|
5164
|
+
print("Removing Edge Weights")
|
|
5165
|
+
|
|
5065
5166
|
self.remove_edge_weights()
|
|
5066
5167
|
|
|
5067
5168
|
if make_array:
|
|
@@ -5072,7 +5173,7 @@ class Network_3D:
|
|
|
5072
5173
|
|
|
5073
5174
|
def community_cells(self, size = 32, xy_scale = 1, z_scale = 1):
|
|
5074
5175
|
|
|
5075
|
-
def
|
|
5176
|
+
def revert_dict(d):
|
|
5076
5177
|
inverted = {}
|
|
5077
5178
|
for key, value_list in d.items():
|
|
5078
5179
|
for value in value_list:
|
|
@@ -5090,18 +5191,12 @@ class Network_3D:
|
|
|
5090
5191
|
|
|
5091
5192
|
com_dict = proximity.partition_objects_into_cells(self.node_centroids, (size_z, size_x, size_x))
|
|
5092
5193
|
|
|
5093
|
-
self.communities =
|
|
5194
|
+
self.communities = revert_dict(com_dict)
|
|
5094
5195
|
|
|
5095
5196
|
def community_heatmap(self, num_nodes = None, is3d = True, numpy = False):
|
|
5096
5197
|
|
|
5097
5198
|
import math
|
|
5098
5199
|
|
|
5099
|
-
def invert_dict(d):
|
|
5100
|
-
inverted = {}
|
|
5101
|
-
for key, value in d.items():
|
|
5102
|
-
inverted.setdefault(value, []).append(key)
|
|
5103
|
-
return inverted
|
|
5104
|
-
|
|
5105
5200
|
if num_nodes == None:
|
|
5106
5201
|
|
|
5107
5202
|
try:
|
|
@@ -5227,14 +5322,17 @@ class Network_3D:
|
|
|
5227
5322
|
compare_set = root_set
|
|
5228
5323
|
if len(compare_set) - 1 < num:
|
|
5229
5324
|
|
|
5230
|
-
|
|
5231
|
-
|
|
5325
|
+
num = len(compare_set) - 1
|
|
5326
|
+
|
|
5327
|
+
print(f"Error: Not enough neighbor nodes for requested number of neighbors. Using max available neighbors: {num}")
|
|
5328
|
+
|
|
5232
5329
|
|
|
5233
5330
|
if len(compare_set) < num:
|
|
5234
5331
|
|
|
5235
|
-
|
|
5236
|
-
return
|
|
5332
|
+
num = len(compare_set)
|
|
5237
5333
|
|
|
5334
|
+
print(f"Error: Not enough neighbor nodes for requested number of neighbors. Using max available neighbors: {num}")
|
|
5335
|
+
|
|
5238
5336
|
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)
|
|
5239
5337
|
|
|
5240
5338
|
if heatmap:
|