nettracer3d 1.0.8__tar.gz → 1.1.0__tar.gz
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-1.0.8/src/nettracer3d.egg-info → nettracer3d-1.1.0}/PKG-INFO +3 -4
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/README.md +2 -3
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/pyproject.toml +1 -1
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/morphology.py +108 -17
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/nettracer.py +67 -13
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/nettracer_gui.py +453 -156
- {nettracer3d-1.0.8 → nettracer3d-1.1.0/src/nettracer3d.egg-info}/PKG-INFO +3 -4
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/LICENSE +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/setup.cfg +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/__init__.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/cellpose_manager.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/community_extractor.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/excelotron.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/modularity.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/neighborhoods.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/network_analysis.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/network_draw.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/node_draw.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/painting.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/proximity.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/run.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/segmenter.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/segmenter_GPU.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/simple_network.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/smart_dilate.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/stats.py +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/entry_points.txt +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/requires.txt +0 -0
- {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 1.0
|
|
3
|
+
Version: 1.1.0
|
|
4
4
|
Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
|
|
5
5
|
Author-email: Liam McLaughlin <liamm@wustl.edu>
|
|
6
6
|
Project-URL: Documentation, https://nettracer3d.readthedocs.io/en/latest/
|
|
@@ -110,7 +110,6 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
|
|
|
110
110
|
|
|
111
111
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
112
112
|
|
|
113
|
-
-- Version 1.0
|
|
113
|
+
-- Version 1.1.0 Updates --
|
|
114
114
|
|
|
115
|
-
*
|
|
116
|
-
* Added significance testing menu
|
|
115
|
+
* Bug Fix
|
|
@@ -65,7 +65,6 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
|
|
|
65
65
|
|
|
66
66
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
67
67
|
|
|
68
|
-
-- Version 1.0
|
|
68
|
+
-- Version 1.1.0 Updates --
|
|
69
69
|
|
|
70
|
-
*
|
|
71
|
-
* Added significance testing menu
|
|
70
|
+
* Bug Fix
|
|
@@ -65,7 +65,7 @@ def reslice_3d_array(args):
|
|
|
65
65
|
return resliced_array
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
def _get_node_edge_dict(label_array, edge_array, label, dilate_xy, dilate_z, cores = 0, search = 0, fastdil = False, xy_scale = 1, z_scale = 1):
|
|
68
|
+
def _get_node_edge_dict(label_array, edge_array, label, dilate_xy, dilate_z, cores = 0, search = 0, fastdil = False, length = False, xy_scale = 1, z_scale = 1):
|
|
69
69
|
"""Internal method used for the secondary algorithm to find pixel involvement of nodes around an edge."""
|
|
70
70
|
|
|
71
71
|
# Create a boolean mask where elements with the specified label are True
|
|
@@ -74,24 +74,25 @@ def _get_node_edge_dict(label_array, edge_array, label, dilate_xy, dilate_z, cor
|
|
|
74
74
|
|
|
75
75
|
if cores == 0: #For getting the volume of objects. Cores presumes you want the 'core' included in the interaction.
|
|
76
76
|
edge_array = edge_array * dil_array # Filter the edges by the label in question
|
|
77
|
-
label_array = np.count_nonzero(dil_array)
|
|
78
|
-
edge_array = np.count_nonzero(edge_array) # For getting the interacting skeleton
|
|
79
|
-
|
|
80
77
|
elif cores == 1: #Cores being 1 presumes you do not want to 'core' included in the interaction
|
|
81
78
|
label_array = dil_array - label_array
|
|
82
79
|
edge_array = edge_array * label_array
|
|
83
|
-
label_array = np.count_nonzero(label_array)
|
|
84
|
-
edge_array = np.count_nonzero(edge_array) # For getting the interacting skeleton
|
|
85
|
-
|
|
86
80
|
elif cores == 2: #Presumes you want skeleton within the core but to only 'count' the stuff around the core for volumes... because of imaging artifacts, perhaps
|
|
87
81
|
edge_array = edge_array * dil_array
|
|
88
82
|
label_array = dil_array - label_array
|
|
89
|
-
label_array = np.count_nonzero(label_array)
|
|
90
|
-
edge_array = np.count_nonzero(edge_array) # For getting the interacting skeleton
|
|
91
83
|
|
|
84
|
+
label_count = np.count_nonzero(label_array) * xy_scale * xy_scale * z_scale
|
|
92
85
|
|
|
93
|
-
|
|
94
|
-
|
|
86
|
+
if not length:
|
|
87
|
+
edge_count = np.count_nonzero(edge_array) * xy_scale * xy_scale * z_scale # For getting the interacting skeleton
|
|
88
|
+
else:
|
|
89
|
+
edge_count = calculate_skeleton_lengths(
|
|
90
|
+
edge_array,
|
|
91
|
+
xy_scale=xy_scale,
|
|
92
|
+
z_scale=z_scale
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
args = [edge_count, label_count]
|
|
95
96
|
|
|
96
97
|
return args
|
|
97
98
|
|
|
@@ -115,7 +116,7 @@ def process_label(args):
|
|
|
115
116
|
|
|
116
117
|
|
|
117
118
|
|
|
118
|
-
def create_node_dictionary(nodes, edges, num_nodes, dilate_xy, dilate_z, cores=0, search = 0, fastdil = False, xy_scale = 1, z_scale = 1):
|
|
119
|
+
def create_node_dictionary(nodes, edges, num_nodes, dilate_xy, dilate_z, cores=0, search = 0, fastdil = False, length = False, xy_scale = 1, z_scale = 1):
|
|
119
120
|
"""Modified to pre-compute all bounding boxes using find_objects"""
|
|
120
121
|
node_dict = {}
|
|
121
122
|
array_shape = nodes.shape
|
|
@@ -135,20 +136,20 @@ def create_node_dictionary(nodes, edges, num_nodes, dilate_xy, dilate_z, cores=0
|
|
|
135
136
|
# Process results in parallel
|
|
136
137
|
for label, sub_nodes, sub_edges in results:
|
|
137
138
|
executor.submit(create_dict_entry, node_dict, label, sub_nodes, sub_edges,
|
|
138
|
-
dilate_xy, dilate_z, cores, search, fastdil, xy_scale, z_scale)
|
|
139
|
+
dilate_xy, dilate_z, cores, search, fastdil, length, xy_scale, z_scale)
|
|
139
140
|
|
|
140
141
|
return node_dict
|
|
141
142
|
|
|
142
|
-
def create_dict_entry(node_dict, label, sub_nodes, sub_edges, dilate_xy, dilate_z, cores = 0, search = 0, fastdil = False, xy_scale = 1, z_scale = 1):
|
|
143
|
+
def create_dict_entry(node_dict, label, sub_nodes, sub_edges, dilate_xy, dilate_z, cores = 0, search = 0, fastdil = False, length = False, xy_scale = 1, z_scale = 1):
|
|
143
144
|
"""Internal method used for the secondary algorithm to pass around args in parallel."""
|
|
144
145
|
|
|
145
146
|
if label is None:
|
|
146
147
|
pass
|
|
147
148
|
else:
|
|
148
|
-
node_dict[label] = _get_node_edge_dict(sub_nodes, sub_edges, label, dilate_xy, dilate_z, cores = cores, search = search, fastdil = fastdil, xy_scale = xy_scale, z_scale = z_scale)
|
|
149
|
+
node_dict[label] = _get_node_edge_dict(sub_nodes, sub_edges, label, dilate_xy, dilate_z, cores = cores, search = search, fastdil = fastdil, length = length, xy_scale = xy_scale, z_scale = z_scale)
|
|
149
150
|
|
|
150
151
|
|
|
151
|
-
def quantify_edge_node(nodes, edges, search = 0, xy_scale = 1, z_scale = 1, cores = 0, resize = None, save = True, skele = False, fastdil = False):
|
|
152
|
+
def quantify_edge_node(nodes, edges, search = 0, xy_scale = 1, z_scale = 1, cores = 0, resize = None, save = True, skele = False, length = False, auto = True, fastdil = False):
|
|
152
153
|
|
|
153
154
|
def save_dubval_dict(dict, index_name, val1name, val2name, filename):
|
|
154
155
|
|
|
@@ -168,6 +169,9 @@ def quantify_edge_node(nodes, edges, search = 0, xy_scale = 1, z_scale = 1, core
|
|
|
168
169
|
edges = tifffile.imread(edges)
|
|
169
170
|
|
|
170
171
|
if skele:
|
|
172
|
+
if auto:
|
|
173
|
+
edges = nettracer.skeletonize(edges)
|
|
174
|
+
edges = nettracer.fill_holes_3d(edges)
|
|
171
175
|
edges = nettracer.skeletonize(edges)
|
|
172
176
|
else:
|
|
173
177
|
edges = nettracer.binarize(edges)
|
|
@@ -188,7 +192,7 @@ def quantify_edge_node(nodes, edges, search = 0, xy_scale = 1, z_scale = 1, core
|
|
|
188
192
|
dilate_xy, dilate_z = 0, 0
|
|
189
193
|
|
|
190
194
|
|
|
191
|
-
edge_quants = create_node_dictionary(nodes, edges, num_nodes, dilate_xy, dilate_z, cores = cores, search = search, fastdil = fastdil, xy_scale = xy_scale, z_scale = z_scale) #Find which edges connect which nodes and put them in a dictionary.
|
|
195
|
+
edge_quants = create_node_dictionary(nodes, edges, num_nodes, dilate_xy, dilate_z, cores = cores, search = search, fastdil = fastdil, length = length, xy_scale = xy_scale, z_scale = z_scale) #Find which edges connect which nodes and put them in a dictionary.
|
|
192
196
|
|
|
193
197
|
if save:
|
|
194
198
|
|
|
@@ -199,6 +203,93 @@ def quantify_edge_node(nodes, edges, search = 0, xy_scale = 1, z_scale = 1, core
|
|
|
199
203
|
return edge_quants
|
|
200
204
|
|
|
201
205
|
|
|
206
|
+
# Helper methods for counting the lens of skeletons:
|
|
207
|
+
|
|
208
|
+
def calculate_skeleton_lengths(skeleton_binary, xy_scale=1.0, z_scale=1.0):
|
|
209
|
+
"""
|
|
210
|
+
Calculate total length of all skeletons in a 3D binary image.
|
|
211
|
+
|
|
212
|
+
skeleton_binary: 3D boolean array where True = skeleton voxel
|
|
213
|
+
xy_scale, z_scale: physical units per voxel
|
|
214
|
+
"""
|
|
215
|
+
# Find all skeleton voxels
|
|
216
|
+
skeleton_coords = np.argwhere(skeleton_binary)
|
|
217
|
+
|
|
218
|
+
if len(skeleton_coords) == 0:
|
|
219
|
+
return 0.0
|
|
220
|
+
|
|
221
|
+
# Create a mapping from coordinates to indices for fast lookup
|
|
222
|
+
coord_to_idx = {tuple(coord): idx for idx, coord in enumerate(skeleton_coords)}
|
|
223
|
+
|
|
224
|
+
# Build adjacency graph
|
|
225
|
+
adjacency_list = build_adjacency_graph(skeleton_coords, coord_to_idx, skeleton_binary.shape)
|
|
226
|
+
|
|
227
|
+
# Calculate lengths using scaled distances
|
|
228
|
+
total_length = calculate_graph_length(skeleton_coords, adjacency_list, xy_scale, z_scale)
|
|
229
|
+
|
|
230
|
+
return total_length
|
|
231
|
+
|
|
232
|
+
def build_adjacency_graph(skeleton_coords, coord_to_idx, shape):
|
|
233
|
+
"""Build adjacency list for skeleton voxels using 26-connectivity."""
|
|
234
|
+
adjacency_list = [[] for _ in range(len(skeleton_coords))]
|
|
235
|
+
|
|
236
|
+
# 26-connectivity offsets (all combinations of -1,0,1 except 0,0,0)
|
|
237
|
+
offsets = []
|
|
238
|
+
for dz in [-1, 0, 1]:
|
|
239
|
+
for dy in [-1, 0, 1]:
|
|
240
|
+
for dx in [-1, 0, 1]:
|
|
241
|
+
if not (dx == 0 and dy == 0 and dz == 0):
|
|
242
|
+
offsets.append((dz, dy, dx))
|
|
243
|
+
|
|
244
|
+
for idx, coord in enumerate(skeleton_coords):
|
|
245
|
+
z, y, x = coord
|
|
246
|
+
|
|
247
|
+
# Check all 26 neighbors
|
|
248
|
+
for dz, dy, dx in offsets:
|
|
249
|
+
nz, ny, nx = z + dz, y + dy, x + dx
|
|
250
|
+
|
|
251
|
+
# Check bounds
|
|
252
|
+
if (0 <= nz < shape[0] and
|
|
253
|
+
0 <= ny < shape[1] and
|
|
254
|
+
0 <= nx < shape[2]):
|
|
255
|
+
|
|
256
|
+
neighbor_coord = (nz, ny, nx)
|
|
257
|
+
if neighbor_coord in coord_to_idx:
|
|
258
|
+
neighbor_idx = coord_to_idx[neighbor_coord]
|
|
259
|
+
adjacency_list[idx].append(neighbor_idx)
|
|
260
|
+
|
|
261
|
+
return adjacency_list
|
|
262
|
+
|
|
263
|
+
def calculate_graph_length(skeleton_coords, adjacency_list, xy_scale, z_scale):
|
|
264
|
+
"""Calculate total length by summing distances between adjacent voxels."""
|
|
265
|
+
total_length = 0.0
|
|
266
|
+
processed_edges = set()
|
|
267
|
+
|
|
268
|
+
for idx, neighbors in enumerate(adjacency_list):
|
|
269
|
+
coord = skeleton_coords[idx]
|
|
270
|
+
|
|
271
|
+
for neighbor_idx in neighbors:
|
|
272
|
+
# Avoid double-counting edges
|
|
273
|
+
edge = tuple(sorted([idx, neighbor_idx]))
|
|
274
|
+
if edge in processed_edges:
|
|
275
|
+
continue
|
|
276
|
+
processed_edges.add(edge)
|
|
277
|
+
|
|
278
|
+
neighbor_coord = skeleton_coords[neighbor_idx]
|
|
279
|
+
|
|
280
|
+
# Calculate scaled distance
|
|
281
|
+
dz = (coord[0] - neighbor_coord[0]) * z_scale
|
|
282
|
+
dy = (coord[1] - neighbor_coord[1]) * xy_scale
|
|
283
|
+
dx = (coord[2] - neighbor_coord[2]) * xy_scale
|
|
284
|
+
|
|
285
|
+
distance = np.sqrt(dx*dx + dy*dy + dz*dz)
|
|
286
|
+
total_length += distance
|
|
287
|
+
|
|
288
|
+
return total_length
|
|
289
|
+
|
|
290
|
+
# End helper methods
|
|
291
|
+
|
|
292
|
+
|
|
202
293
|
|
|
203
294
|
def calculate_voxel_volumes(array, xy_scale=1, z_scale=1):
|
|
204
295
|
"""
|
|
@@ -3143,6 +3143,15 @@ class Network_3D:
|
|
|
3143
3143
|
Can be called on a Network_3D object to save the nodes property to hard mem as a tif. It will save to the active directory if none is specified.
|
|
3144
3144
|
:param directory: (Optional - Val = None; String). The path to an indended directory to save the nodes to.
|
|
3145
3145
|
"""
|
|
3146
|
+
if self._nodes is not None:
|
|
3147
|
+
imagej_metadata = {
|
|
3148
|
+
'spacing': self.z_scale,
|
|
3149
|
+
'slices': self._nodes.shape[0],
|
|
3150
|
+
'channels': 1,
|
|
3151
|
+
'axes': 'ZYX'
|
|
3152
|
+
}
|
|
3153
|
+
resolution_value = 1.0 / self.xy_scale if self.xy_scale != 0 else 1
|
|
3154
|
+
|
|
3146
3155
|
if filename is None:
|
|
3147
3156
|
filename = "labelled_nodes.tif"
|
|
3148
3157
|
elif not filename.endswith(('.tif', '.tiff')):
|
|
@@ -3151,13 +3160,19 @@ class Network_3D:
|
|
|
3151
3160
|
if self._nodes is not None:
|
|
3152
3161
|
if directory is None:
|
|
3153
3162
|
try:
|
|
3154
|
-
|
|
3163
|
+
if len(self._nodes.shape) == 3:
|
|
3164
|
+
tifffile.imwrite(f"{filename}", self._nodes, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3165
|
+
else:
|
|
3166
|
+
tifffile.imwrite(f"{filename}", self._nodes)
|
|
3155
3167
|
print(f"Nodes saved to {filename}")
|
|
3156
3168
|
except Exception as e:
|
|
3157
3169
|
print("Could not save nodes")
|
|
3158
3170
|
if directory is not None:
|
|
3159
3171
|
try:
|
|
3160
|
-
|
|
3172
|
+
if len(self._nodes.shape) == 3:
|
|
3173
|
+
tifffile.imwrite(f"{directory}/{filename}", self._nodes, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3174
|
+
else:
|
|
3175
|
+
tifffile.imwrite(f"{directory}/{filename}")
|
|
3161
3176
|
print(f"Nodes saved to {directory}/{filename}")
|
|
3162
3177
|
except Exception as e:
|
|
3163
3178
|
print(f"Could not save nodes to {directory}")
|
|
@@ -3170,6 +3185,16 @@ class Network_3D:
|
|
|
3170
3185
|
:param directory: (Optional - Val = None; String). The path to an indended directory to save the edges to.
|
|
3171
3186
|
"""
|
|
3172
3187
|
|
|
3188
|
+
if self._edges is not None:
|
|
3189
|
+
imagej_metadata = {
|
|
3190
|
+
'spacing': self.z_scale,
|
|
3191
|
+
'slices': self._edges.shape[0],
|
|
3192
|
+
'channels': 1,
|
|
3193
|
+
'axes': 'ZYX'
|
|
3194
|
+
}
|
|
3195
|
+
|
|
3196
|
+
resolution_value = 1.0 / self.xy_scale if self.xy_scale != 0 else 1
|
|
3197
|
+
|
|
3173
3198
|
if filename is None:
|
|
3174
3199
|
filename = "labelled_edges.tif"
|
|
3175
3200
|
elif not filename.endswith(('.tif', '.tiff')):
|
|
@@ -3177,11 +3202,11 @@ class Network_3D:
|
|
|
3177
3202
|
|
|
3178
3203
|
if self._edges is not None:
|
|
3179
3204
|
if directory is None:
|
|
3180
|
-
tifffile.imwrite(f"{filename}", self._edges)
|
|
3205
|
+
tifffile.imwrite(f"{filename}", self._edges, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3181
3206
|
print(f"Edges saved to {filename}")
|
|
3182
3207
|
|
|
3183
3208
|
if directory is not None:
|
|
3184
|
-
tifffile.imwrite(f"{directory}/{filename}", self._edges)
|
|
3209
|
+
tifffile.imwrite(f"{directory}/{filename}", self._edges, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3185
3210
|
print(f"Edges saved to {directory}/{filename}")
|
|
3186
3211
|
|
|
3187
3212
|
if self._edges is None:
|
|
@@ -3337,6 +3362,14 @@ class Network_3D:
|
|
|
3337
3362
|
|
|
3338
3363
|
def save_network_overlay(self, directory = None, filename = None):
|
|
3339
3364
|
|
|
3365
|
+
if self._network_overlay is not None:
|
|
3366
|
+
imagej_metadata = {
|
|
3367
|
+
'spacing': self.z_scale,
|
|
3368
|
+
'slices': self._network_overlay.shape[0],
|
|
3369
|
+
'channels': 1,
|
|
3370
|
+
'axes': 'ZYX'
|
|
3371
|
+
}
|
|
3372
|
+
resolution_value = 1.0 / self.xy_scale if self.xy_scale != 0 else 1
|
|
3340
3373
|
|
|
3341
3374
|
if filename is None:
|
|
3342
3375
|
filename = "overlay_1.tif"
|
|
@@ -3345,15 +3378,30 @@ class Network_3D:
|
|
|
3345
3378
|
|
|
3346
3379
|
if self._network_overlay is not None:
|
|
3347
3380
|
if directory is None:
|
|
3348
|
-
|
|
3381
|
+
if len(self._network_overlay.shape) == 3:
|
|
3382
|
+
tifffile.imwrite(f"{filename}", self._network_overlay, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3383
|
+
else:
|
|
3384
|
+
tifffile.imwrite(f"{filename}", self._network_overlay)
|
|
3349
3385
|
print(f"Network overlay saved to {filename}")
|
|
3350
3386
|
|
|
3351
3387
|
if directory is not None:
|
|
3352
|
-
|
|
3388
|
+
if len(self._network_overlay.shape) == 3:
|
|
3389
|
+
tifffile.imwrite(f"{directory}/{filename}", self._network_overlay, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3390
|
+
else:
|
|
3391
|
+
tifffile.imwrite(f"{directory}/{filename}", self._network_overlay)
|
|
3353
3392
|
print(f"Network overlay saved to {directory}/{filename}")
|
|
3354
3393
|
|
|
3355
3394
|
def save_id_overlay(self, directory = None, filename = None):
|
|
3356
3395
|
|
|
3396
|
+
if self._id_overlay is not None:
|
|
3397
|
+
imagej_metadata = {
|
|
3398
|
+
'spacing': self.z_scale,
|
|
3399
|
+
'slices': self._id_overlay.shape[0],
|
|
3400
|
+
'channels': 1,
|
|
3401
|
+
'axes': 'ZYX'
|
|
3402
|
+
}
|
|
3403
|
+
resolution_value = 1.0 / self.xy_scale if self.xy_scale != 0 else 1
|
|
3404
|
+
|
|
3357
3405
|
if filename is None:
|
|
3358
3406
|
filename = "overlay_2.tif"
|
|
3359
3407
|
if not filename.endswith(('.tif', '.tiff')):
|
|
@@ -3361,11 +3409,17 @@ class Network_3D:
|
|
|
3361
3409
|
|
|
3362
3410
|
if self._id_overlay is not None:
|
|
3363
3411
|
if directory is None:
|
|
3364
|
-
|
|
3412
|
+
if len(self._id_overlay.shape) == 3:
|
|
3413
|
+
tifffile.imwrite(f"{filename}", self._id_overlay, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3414
|
+
else:
|
|
3415
|
+
tifffile.imwrite(f"{filename}", self._id_overlay, imagej=True)
|
|
3365
3416
|
print(f"Network overlay saved to {filename}")
|
|
3366
3417
|
|
|
3367
3418
|
if directory is not None:
|
|
3368
|
-
|
|
3419
|
+
if len(self._id_overlay.shape) == 3:
|
|
3420
|
+
tifffile.imwrite(f"{directory}/{filename}", self._id_overlay, imagej=True, metadata=imagej_metadata, resolution=(resolution_value, resolution_value))
|
|
3421
|
+
else:
|
|
3422
|
+
tifffile.imwrite(f"{directory}/{filename}", self._id_overlay)
|
|
3369
3423
|
print(f"ID overlay saved to {directory}/{filename}")
|
|
3370
3424
|
|
|
3371
3425
|
|
|
@@ -3488,7 +3542,7 @@ class Network_3D:
|
|
|
3488
3542
|
|
|
3489
3543
|
if file_path is not None:
|
|
3490
3544
|
self._xy_scale, self_z_scale = read_scalings(file_path)
|
|
3491
|
-
print("Succesfully loaded voxel_scalings")
|
|
3545
|
+
print(f"Succesfully loaded voxel_scalings; values overriden to xy_scale: {self.xy_scale}, z_scale: {self.z_scale}")
|
|
3492
3546
|
return
|
|
3493
3547
|
|
|
3494
3548
|
items = directory_info(directory)
|
|
@@ -3497,11 +3551,11 @@ class Network_3D:
|
|
|
3497
3551
|
if item == 'voxel_scalings.txt':
|
|
3498
3552
|
if directory is not None:
|
|
3499
3553
|
self._xy_scale, self._z_scale = read_scalings(f"{directory}/{item}")
|
|
3500
|
-
print("Succesfully loaded voxel_scalings")
|
|
3554
|
+
print(f"Succesfully loaded voxel_scalings; values overriden to xy_scale: {self.xy_scale}, z_scale: {self.z_scale}")
|
|
3501
3555
|
return
|
|
3502
3556
|
else:
|
|
3503
3557
|
self._xy_scale, self._z_scale = read_scalings(item)
|
|
3504
|
-
print("Succesfully loaded
|
|
3558
|
+
print(f"Succesfully loaded voxel_scaling; values overriden to xy_scale: {self.xy_scale}, z_scale: {self.z_scale}s")
|
|
3505
3559
|
return
|
|
3506
3560
|
|
|
3507
3561
|
print("Could not find voxel scalings. They must be in the specified directory and named 'voxel_scalings.txt'")
|
|
@@ -5403,9 +5457,9 @@ class Network_3D:
|
|
|
5403
5457
|
|
|
5404
5458
|
|
|
5405
5459
|
|
|
5406
|
-
def interactions(self, search = 0, cores = 0, resize = None, save = False, skele = False, fastdil = False):
|
|
5460
|
+
def interactions(self, search = 0, cores = 0, resize = None, save = False, skele = False, length = False, auto = True, fastdil = False):
|
|
5407
5461
|
|
|
5408
|
-
return morphology.quantify_edge_node(self._nodes, self._edges, search = search, xy_scale = self._xy_scale, z_scale = self._z_scale, cores = cores, resize = resize, save = save, skele = skele, fastdil = fastdil)
|
|
5462
|
+
return morphology.quantify_edge_node(self._nodes, self._edges, search = search, xy_scale = self._xy_scale, z_scale = self._z_scale, cores = cores, resize = resize, save = save, skele = skele, length = length, auto = auto, fastdil = fastdil)
|
|
5409
5463
|
|
|
5410
5464
|
|
|
5411
5465
|
|