nettracer3d 0.6.8__py3-none-any.whl → 0.7.0__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.
- nettracer3d/modularity.py +23 -24
- nettracer3d/morphology.py +14 -9
- nettracer3d/nettracer.py +271 -44
- nettracer3d/nettracer_gui.py +502 -64
- nettracer3d/proximity.py +376 -16
- nettracer3d/segmenter.py +87 -4
- nettracer3d/smart_dilate.py +23 -24
- {nettracer3d-0.6.8.dist-info → nettracer3d-0.7.0.dist-info}/METADATA +42 -9
- nettracer3d-0.7.0.dist-info/RECORD +20 -0
- {nettracer3d-0.6.8.dist-info → nettracer3d-0.7.0.dist-info}/WHEEL +1 -1
- nettracer3d-0.6.8.dist-info/RECORD +0 -20
- {nettracer3d-0.6.8.dist-info → nettracer3d-0.7.0.dist-info}/entry_points.txt +0 -0
- {nettracer3d-0.6.8.dist-info → nettracer3d-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {nettracer3d-0.6.8.dist-info → nettracer3d-0.7.0.dist-info}/top_level.txt +0 -0
nettracer3d/smart_dilate.py
CHANGED
|
@@ -188,11 +188,9 @@ def dilate_3D_dt(array, search_distance, xy_scaling=1.0, z_scaling=1.0, GPU = Fa
|
|
|
188
188
|
Returns:
|
|
189
189
|
Dilated 3D array
|
|
190
190
|
"""
|
|
191
|
-
if array.shape[0] == 1:
|
|
192
191
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
# Determine which dimension needs resampling
|
|
192
|
+
# Determine which dimension needs resampling. the moral of the story is read documentation before you do something unecessary.
|
|
193
|
+
"""
|
|
196
194
|
if (z_scaling > xy_scaling):
|
|
197
195
|
# Z dimension needs to be stretched
|
|
198
196
|
zoom_factor = [z_scaling/xy_scaling, 1, 1] # Scale factor for [z, y, x]
|
|
@@ -208,11 +206,11 @@ def dilate_3D_dt(array, search_distance, xy_scaling=1.0, z_scaling=1.0, GPU = Fa
|
|
|
208
206
|
zoom_factor = None
|
|
209
207
|
rev_factor = None
|
|
210
208
|
cardinal = xy_scaling
|
|
211
|
-
|
|
209
|
+
"""
|
|
212
210
|
|
|
213
211
|
# Resample the mask if needed
|
|
214
|
-
if zoom_factor:
|
|
215
|
-
array = ndimage.zoom(array, zoom_factor, order=0) # Use order=0 for binary masks
|
|
212
|
+
#if zoom_factor:
|
|
213
|
+
#array = ndimage.zoom(array, zoom_factor, order=0) # Use order=0 for binary masks
|
|
216
214
|
|
|
217
215
|
# Invert the array (find background)
|
|
218
216
|
inv = array < 1
|
|
@@ -220,22 +218,21 @@ def dilate_3D_dt(array, search_distance, xy_scaling=1.0, z_scaling=1.0, GPU = Fa
|
|
|
220
218
|
if GPU:
|
|
221
219
|
try:
|
|
222
220
|
print("Attempting on GPU...")
|
|
223
|
-
inv, indices = compute_distance_transform_GPU(inv, return_dists = True)
|
|
221
|
+
inv, indices = compute_distance_transform_GPU(inv, return_dists = True, sampling = [z_scaling, xy_scaling, xy_scaling])
|
|
224
222
|
except:
|
|
225
223
|
print("Failed, attempting on CPU...")
|
|
226
224
|
#Who would have seen this coming?:
|
|
227
|
-
inv, indices = compute_distance_transform(inv, return_dists = True)
|
|
225
|
+
inv, indices = compute_distance_transform(inv, return_dists = True, sampling = [z_scaling, xy_scaling, xy_scaling])
|
|
228
226
|
else:
|
|
229
|
-
inv, indices = compute_distance_transform(inv, return_dists = True)
|
|
227
|
+
inv, indices = compute_distance_transform(inv, return_dists = True, sampling = [z_scaling, xy_scaling, xy_scaling])
|
|
230
228
|
|
|
231
229
|
|
|
232
|
-
inv = inv * cardinal
|
|
230
|
+
#inv = inv * cardinal
|
|
233
231
|
|
|
234
232
|
# Threshold the distance transform to get dilated result
|
|
235
233
|
inv = inv <= search_distance
|
|
236
234
|
|
|
237
|
-
|
|
238
|
-
return inv.astype(np.uint8), indices, array, rev_factor
|
|
235
|
+
return inv.astype(np.uint8), indices, array
|
|
239
236
|
|
|
240
237
|
|
|
241
238
|
|
|
@@ -275,7 +272,7 @@ def smart_dilate(nodes, dilate_xy, dilate_z, directory = None, GPU = True, fast_
|
|
|
275
272
|
binary_nodes = binarize(nodes)
|
|
276
273
|
dilated_binary_nodes = dilate_3D(binary_nodes, dilate_xy, dilate_xy, dilate_z)
|
|
277
274
|
else:
|
|
278
|
-
dilated_binary_nodes, nearest_label_indices, nodes
|
|
275
|
+
dilated_binary_nodes, nearest_label_indices, nodes = dilate_3D_dt(nodes, use_dt_dil_amount, GPU = GPU, xy_scaling = xy_scale, z_scaling = z_scale)
|
|
279
276
|
binary_nodes = binarize(nodes)
|
|
280
277
|
|
|
281
278
|
# Step 3: Isolate the ring (binary dilated mask minus original binary mask)
|
|
@@ -352,8 +349,6 @@ def smart_dilate(nodes, dilate_xy, dilate_z, directory = None, GPU = True, fast_
|
|
|
352
349
|
if (dilated_nodes_with_labels.shape[1] < original_shape[1]) and fast_dil: #If downsample was used, upsample output
|
|
353
350
|
dilated_nodes_with_labels = nettracer.upsample_with_padding(dilated_nodes_with_labels, downsample_needed, original_shape)
|
|
354
351
|
dilated_nodes_with_labels = dilated_nodes_with_labels * dilated_mask
|
|
355
|
-
elif (dilated_nodes_with_labels.shape[1] != original_shape[1]) and not fast_dil:
|
|
356
|
-
dilated_nodes_with_labels = ndimage.zoom(dilated_nodes_with_labels, rev_factor, order=0)
|
|
357
352
|
|
|
358
353
|
if directory is not None:
|
|
359
354
|
try:
|
|
@@ -472,16 +467,17 @@ def smart_label(binary_array, label_array, directory = None, GPU = True, predown
|
|
|
472
467
|
|
|
473
468
|
return dilated_nodes_with_labels
|
|
474
469
|
|
|
475
|
-
def compute_distance_transform_GPU(nodes, return_dists = False):
|
|
470
|
+
def compute_distance_transform_GPU(nodes, return_dists = False, sampling = [1, 1, 1]):
|
|
476
471
|
is_pseudo_3d = nodes.shape[0] == 1
|
|
477
472
|
if is_pseudo_3d:
|
|
478
473
|
nodes = np.squeeze(nodes) # Convert to 2D for processing
|
|
474
|
+
del sampling[0]
|
|
479
475
|
|
|
480
476
|
# Convert numpy array to CuPy array
|
|
481
477
|
nodes_cp = cp.asarray(nodes)
|
|
482
478
|
|
|
483
479
|
# Compute the distance transform on the GPU
|
|
484
|
-
dists, nearest_label_indices = cpx.distance_transform_edt(nodes_cp, return_indices=True)
|
|
480
|
+
dists, nearest_label_indices = cpx.distance_transform_edt(nodes_cp, return_indices=True, sampling = sampling)
|
|
485
481
|
|
|
486
482
|
# Convert results back to numpy arrays
|
|
487
483
|
nearest_label_indices_np = cp.asnumpy(nearest_label_indices)
|
|
@@ -504,12 +500,13 @@ def compute_distance_transform_GPU(nodes, return_dists = False):
|
|
|
504
500
|
return dists, nearest_label_indices_np
|
|
505
501
|
|
|
506
502
|
|
|
507
|
-
def compute_distance_transform(nodes, return_dists = False):
|
|
503
|
+
def compute_distance_transform(nodes, return_dists = False, sampling = [1, 1, 1]):
|
|
508
504
|
is_pseudo_3d = nodes.shape[0] == 1
|
|
509
505
|
if is_pseudo_3d:
|
|
510
506
|
nodes = np.squeeze(nodes) # Convert to 2D for processing
|
|
507
|
+
del sampling[0]
|
|
511
508
|
|
|
512
|
-
dists, nearest_label_indices = distance_transform_edt(nodes, return_indices=True)
|
|
509
|
+
dists, nearest_label_indices = distance_transform_edt(nodes, return_indices=True, sampling = sampling)
|
|
513
510
|
|
|
514
511
|
if is_pseudo_3d:
|
|
515
512
|
# For 2D input, we get (2, H, W) but need (3, 1, H, W)
|
|
@@ -529,17 +526,18 @@ def compute_distance_transform(nodes, return_dists = False):
|
|
|
529
526
|
|
|
530
527
|
|
|
531
528
|
|
|
532
|
-
def compute_distance_transform_distance_GPU(nodes):
|
|
529
|
+
def compute_distance_transform_distance_GPU(nodes, sampling = [1, 1, 1]):
|
|
533
530
|
|
|
534
531
|
is_pseudo_3d = nodes.shape[0] == 1
|
|
535
532
|
if is_pseudo_3d:
|
|
536
533
|
nodes = np.squeeze(nodes) # Convert to 2D for processing
|
|
534
|
+
del sampling[0]
|
|
537
535
|
|
|
538
536
|
# Convert numpy array to CuPy array
|
|
539
537
|
nodes_cp = cp.asarray(nodes)
|
|
540
538
|
|
|
541
539
|
# Compute the distance transform on the GPU
|
|
542
|
-
distance = cpx.distance_transform_edt(nodes_cp)
|
|
540
|
+
distance = cpx.distance_transform_edt(nodes_cp, sampling = sampling)
|
|
543
541
|
|
|
544
542
|
# Convert results back to numpy arrays
|
|
545
543
|
distance = cp.asnumpy(distance)
|
|
@@ -550,14 +548,15 @@ def compute_distance_transform_distance_GPU(nodes):
|
|
|
550
548
|
return distance
|
|
551
549
|
|
|
552
550
|
|
|
553
|
-
def compute_distance_transform_distance(nodes):
|
|
551
|
+
def compute_distance_transform_distance(nodes, sampling = [1, 1, 1]):
|
|
554
552
|
|
|
555
553
|
is_pseudo_3d = nodes.shape[0] == 1
|
|
556
554
|
if is_pseudo_3d:
|
|
557
555
|
nodes = np.squeeze(nodes) # Convert to 2D for processing
|
|
556
|
+
del sampling[0]
|
|
558
557
|
|
|
559
558
|
# Fallback to CPU if there's an issue with GPU computation
|
|
560
|
-
distance = distance_transform_edt(nodes)
|
|
559
|
+
distance = distance_transform_edt(nodes, sampling = sampling)
|
|
561
560
|
if is_pseudo_3d:
|
|
562
561
|
np.expand_dims(distance, axis = 0)
|
|
563
562
|
return distance
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
|
|
5
|
-
Author-email: Liam McLaughlin <
|
|
6
|
-
Project-URL:
|
|
5
|
+
Author-email: Liam McLaughlin <liamm@wustl.edu>
|
|
6
|
+
Project-URL: Documentation, https://nettracer3d.readthedocs.io/en/latest/
|
|
7
|
+
Project-URL: Video_Tutorial, https://www.youtube.com/watch?v=cRatn5VTWDY
|
|
7
8
|
Project-URL: Reference_Citation_For_Use, https://doi.org/10.1101/2024.07.29.605633
|
|
8
9
|
Classifier: Programming Language :: Python :: 3
|
|
9
10
|
Classifier: License :: Other/Proprietary License
|
|
10
11
|
Classifier: Operating System :: OS Independent
|
|
11
|
-
Requires-Python:
|
|
12
|
+
Requires-Python: ==3.11
|
|
12
13
|
Description-Content-Type: text/markdown
|
|
13
14
|
License-File: LICENSE
|
|
14
15
|
Requires-Dist: numpy==1.26.4
|
|
@@ -38,16 +39,48 @@ Dynamic: license-file
|
|
|
38
39
|
|
|
39
40
|
NetTracer3D is a python package developed for both 2D and 3D analysis of microscopic images in the .tif file format. It supports generation of 3D networks showing the relationships between objects (or nodes) in three dimensional space, either based on their own proximity or connectivity via connecting objects such as nerves or blood vessels. In addition to these functionalities are several advanced 3D data processing algorithms, such as labeling of branched structures or abstraction of branched structures into networks. Note that nettracer3d uses segmented data, which can be segmented from other softwares such as ImageJ and imported into NetTracer3D, although it does offer its own segmentation via intensity and volumetric thresholding, or random forest machine learning segmentation. NetTracer3D currently has a fully functional GUI. To use the GUI, after installing the nettracer3d package via pip, enter the command 'nettracer3d' in your command prompt:
|
|
40
41
|
|
|
42
|
+
--- Documentation ---
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
Please see: https://nettracer3d.readthedocs.io/en/latest/
|
|
45
|
+
|
|
46
|
+
--- Installation ---
|
|
47
|
+
|
|
48
|
+
To install nettracer3d, simply install Python and use this command in your command terminal:
|
|
49
|
+
|
|
50
|
+
pip install nettracer3d
|
|
51
|
+
|
|
52
|
+
I recommend installing the program as an Anaconda package to ensure its modules are work together on your specific system:
|
|
53
|
+
(Install anaconda at the link below, set up a new python env for nettracer3d, then use the same pip command).
|
|
54
|
+
|
|
55
|
+
https://www.anaconda.com/download?utm_source=anacondadocs&utm_medium=documentation&utm_campaign=download&utm_content=installwindows
|
|
56
|
+
|
|
57
|
+
nettracer3d mostly utilizes the CPU for processing and visualization, although it does have a few GPU-aided options. If you would like to use the GPU for these, you will need an NVIDIA GPU and a corresponding CUDA toolkit which can be installed here:
|
|
58
|
+
https://developer.nvidia.com/cuda-toolkit
|
|
59
|
+
|
|
60
|
+
To install nettracer3d with associated GPU-supporting packages, please use:
|
|
61
|
+
|
|
62
|
+
If your CUDA toolkit is version 11: pip install nettracer3d[CUDA11]
|
|
63
|
+
If your CUDA toolkit is version 12: pip install nettracer3d[CUDA12]
|
|
64
|
+
If you just want the entire cupy library: pip install nettracer3d[cupy]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
This gui is built from the PyQt6 package and therefore may not function on dockers or virtual envs that are unable to support PyQt6 displays.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
For a (slightly outdated) video tutorial on using the GUI: https://www.youtube.com/watch?v=cRatn5VTWDY
|
|
44
71
|
|
|
45
72
|
NetTracer3D is free to use/fork for academic/nonprofit use so long as citation is provided, and is available for commercial use at a fee (see license file for information).
|
|
46
73
|
|
|
47
74
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
48
75
|
|
|
49
|
-
-- Version 0.
|
|
76
|
+
-- Version 0.7.0 Updates --
|
|
77
|
+
|
|
78
|
+
1. Added new function in 'Analyze -> Stats -> Cluster Analysis'
|
|
79
|
+
* This function allows the user to create a ripley's K or H function to compare the relative clustering of two types of nodes, or of one type of node vs itself.
|
|
50
80
|
|
|
51
|
-
|
|
81
|
+
2. Added new function in 'Analyze -> Randomize -> Scramble Nodes'
|
|
82
|
+
* This function randomly rearranges the node (centroids) for comparison with other centroid-using methods, as a possible way to demonstrate non-random behavior.
|
|
83
|
+
* The randomize menu is likewise new and the 'Generate Equivalent Random Network' method was moved there.
|
|
52
84
|
|
|
53
|
-
|
|
85
|
+
3. Bug fixes.
|
|
86
|
+
* Importantly fixed a bug with dt-based dilation not working in 2D, which I had accidentally introduced recently.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
nettracer3d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
nettracer3d/community_extractor.py,sha256=5v9SCCLX3P1RX0fjPVKH5NHMFkMolZ5BTe0bR_a67xg,24479
|
|
3
|
+
nettracer3d/modularity.py,sha256=FH3GpTHorRNkdQULe-2DWgFE3i0_u__hrao7Nx_6Ge4,30249
|
|
4
|
+
nettracer3d/morphology.py,sha256=kEzuzBxHHpWt3o_LHMXYJGJT8-Z_dEP99QpZjOkavzE,19742
|
|
5
|
+
nettracer3d/nettracer.py,sha256=dnnWEr9xpzoxV-NqLJm4DAFmZJ25CSjhA85AR_LT8Qc,218452
|
|
6
|
+
nettracer3d/nettracer_gui.py,sha256=jeqsjaLGdaXdPcuy3Z3iEVnaOvyGDTEjD8uVkoNPFtk,426501
|
|
7
|
+
nettracer3d/network_analysis.py,sha256=q1q7lxtA3lebxitfC_jfiT9cnpYXJw4q0Oy2_-Aj8qE,48068
|
|
8
|
+
nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
|
|
9
|
+
nettracer3d/node_draw.py,sha256=k3sCTfUCJs3aH1C1q1gTNxDz9EAQbBd1hsUIJajxRx8,9823
|
|
10
|
+
nettracer3d/proximity.py,sha256=2Fj1UTKDEFBf7r1SgWXhiSINOTMjP4G5_Egu58l2zTk,24756
|
|
11
|
+
nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
|
|
12
|
+
nettracer3d/segmenter.py,sha256=gJS2AXqHhnw29cbzIxAah2LsrE7_7XnzG7mYSAovZ4I,87847
|
|
13
|
+
nettracer3d/simple_network.py,sha256=fP1gkDdtQcHruEZpUdasKdZeVacoLOxKhR3bY0L1CAQ,15426
|
|
14
|
+
nettracer3d/smart_dilate.py,sha256=MNFz-7P56OFwkNx2N24SH4gV0kL3KwzmZvAxg-T7f3U,25781
|
|
15
|
+
nettracer3d-0.7.0.dist-info/licenses/LICENSE,sha256=gM207DhJjWrxLuEWXl0Qz5ISbtWDmADfjHp3yC2XISs,888
|
|
16
|
+
nettracer3d-0.7.0.dist-info/METADATA,sha256=AqntVh2fF1VwxjLMongf_L9JpmNuZSO2irf_sFXrHvE,4955
|
|
17
|
+
nettracer3d-0.7.0.dist-info/WHEEL,sha256=SmOxYU7pzNKBqASvQJ7DjX3XGUF92lrGhMb3R6_iiqI,91
|
|
18
|
+
nettracer3d-0.7.0.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
|
|
19
|
+
nettracer3d-0.7.0.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
|
|
20
|
+
nettracer3d-0.7.0.dist-info/RECORD,,
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
nettracer3d/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
-
nettracer3d/community_extractor.py,sha256=5v9SCCLX3P1RX0fjPVKH5NHMFkMolZ5BTe0bR_a67xg,24479
|
|
3
|
-
nettracer3d/modularity.py,sha256=V1f3s_vGd8EuVz27mzq6ycIGr0BWIpH7c7NU4QjgAHU,30247
|
|
4
|
-
nettracer3d/morphology.py,sha256=P7hH9qpDBs0JtMSd95NmrvqoyD8BVq3AjAYv-MWoS_Y,19498
|
|
5
|
-
nettracer3d/nettracer.py,sha256=HDU7z9UOpc2rK1tp-gV7vum27NBNVe8CmfZEeJ7lDBc,209469
|
|
6
|
-
nettracer3d/nettracer_gui.py,sha256=Uo7INQF89Jb5YioqAjH25Qxxk2rMA9Y5J2hZ35s8ySU,409270
|
|
7
|
-
nettracer3d/network_analysis.py,sha256=q1q7lxtA3lebxitfC_jfiT9cnpYXJw4q0Oy2_-Aj8qE,48068
|
|
8
|
-
nettracer3d/network_draw.py,sha256=F7fw6Pcf4qWOhdKwLmhwqWdschbDlHzwCVolQC9imeU,14117
|
|
9
|
-
nettracer3d/node_draw.py,sha256=k3sCTfUCJs3aH1C1q1gTNxDz9EAQbBd1hsUIJajxRx8,9823
|
|
10
|
-
nettracer3d/proximity.py,sha256=B9DfbYMzxdlksQTY6EjyGi8iSQ54RZ5OEqfze2IOrBo,10916
|
|
11
|
-
nettracer3d/run.py,sha256=xYeaAc8FCx8MuzTGyL3NR3mK7WZzffAYAH23bNRZYO4,127
|
|
12
|
-
nettracer3d/segmenter.py,sha256=NcNeLSfg3ox-CfnUajT1E2iDqDkv5H6zSJOK_L5N4YI,85020
|
|
13
|
-
nettracer3d/simple_network.py,sha256=fP1gkDdtQcHruEZpUdasKdZeVacoLOxKhR3bY0L1CAQ,15426
|
|
14
|
-
nettracer3d/smart_dilate.py,sha256=ISZR6v52zf-MwhGx-JTfTOP8uo7pNGt-GJj7ydeuMAo,25587
|
|
15
|
-
nettracer3d-0.6.8.dist-info/licenses/LICENSE,sha256=gM207DhJjWrxLuEWXl0Qz5ISbtWDmADfjHp3yC2XISs,888
|
|
16
|
-
nettracer3d-0.6.8.dist-info/METADATA,sha256=-uaII8GnsHBV7nt_rmSlntFKv9QCDujtfhSEd_OuKVM,3523
|
|
17
|
-
nettracer3d-0.6.8.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
|
18
|
-
nettracer3d-0.6.8.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
|
|
19
|
-
nettracer3d-0.6.8.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
|
|
20
|
-
nettracer3d-0.6.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|