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.

Files changed (31) hide show
  1. {nettracer3d-1.0.8/src/nettracer3d.egg-info → nettracer3d-1.1.0}/PKG-INFO +3 -4
  2. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/README.md +2 -3
  3. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/pyproject.toml +1 -1
  4. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/morphology.py +108 -17
  5. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/nettracer.py +67 -13
  6. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/nettracer_gui.py +453 -156
  7. {nettracer3d-1.0.8 → nettracer3d-1.1.0/src/nettracer3d.egg-info}/PKG-INFO +3 -4
  8. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/LICENSE +0 -0
  9. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/setup.cfg +0 -0
  10. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/__init__.py +0 -0
  11. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/cellpose_manager.py +0 -0
  12. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/community_extractor.py +0 -0
  13. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/excelotron.py +0 -0
  14. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/modularity.py +0 -0
  15. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/neighborhoods.py +0 -0
  16. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/network_analysis.py +0 -0
  17. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/network_draw.py +0 -0
  18. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/node_draw.py +0 -0
  19. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/painting.py +0 -0
  20. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/proximity.py +0 -0
  21. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/run.py +0 -0
  22. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/segmenter.py +0 -0
  23. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/segmenter_GPU.py +0 -0
  24. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/simple_network.py +0 -0
  25. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/smart_dilate.py +0 -0
  26. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d/stats.py +0 -0
  27. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
  28. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
  29. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/entry_points.txt +0 -0
  30. {nettracer3d-1.0.8 → nettracer3d-1.1.0}/src/nettracer3d.egg-info/requires.txt +0 -0
  31. {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.8
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.8 Updates --
113
+ -- Version 1.1.0 Updates --
114
114
 
115
- * Minor bug fixes, updates
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.8 Updates --
68
+ -- Version 1.1.0 Updates --
69
69
 
70
- * Minor bug fixes, updates
71
- * Added significance testing menu
70
+ * Bug Fix
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nettracer3d"
3
- version = "1.0.8"
3
+ version = "1.1.0"
4
4
  authors = [
5
5
  { name="Liam McLaughlin", email="liamm@wustl.edu" },
6
6
  ]
@@ -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
- args = [edge_array, label_array]
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
- tifffile.imwrite(f"{filename}", self._nodes)
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
- tifffile.imwrite(f"{directory}/{filename}", self._nodes)
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
- tifffile.imwrite(f"{filename}", self._network_overlay)
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
- tifffile.imwrite(f"{directory}/{filename}", self._network_overlay)
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
- tifffile.imwrite(f"{filename}", self._id_overlay)
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
- tifffile.imwrite(f"{directory}/{filename}", self._id_overlay)
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 voxel_scalings")
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