nettracer3d 0.6.8__tar.gz → 0.7.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.
- {nettracer3d-0.6.8/src/nettracer3d.egg-info → nettracer3d-0.7.0}/PKG-INFO +42 -9
- nettracer3d-0.7.0/README.md +47 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/pyproject.toml +5 -4
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/modularity.py +23 -24
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/morphology.py +14 -9
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/nettracer.py +271 -44
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/nettracer_gui.py +502 -64
- nettracer3d-0.7.0/src/nettracer3d/proximity.py +649 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/segmenter.py +87 -4
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/smart_dilate.py +23 -24
- {nettracer3d-0.6.8 → nettracer3d-0.7.0/src/nettracer3d.egg-info}/PKG-INFO +42 -9
- nettracer3d-0.6.8/README.md +0 -15
- nettracer3d-0.6.8/src/nettracer3d/proximity.py +0 -289
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/LICENSE +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/setup.cfg +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/__init__.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/community_extractor.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/network_analysis.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/network_draw.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/node_draw.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/run.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d/simple_network.py +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d.egg-info/entry_points.txt +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d.egg-info/requires.txt +0 -0
- {nettracer3d-0.6.8 → nettracer3d-0.7.0}/src/nettracer3d.egg-info/top_level.txt +0 -0
|
@@ -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,47 @@
|
|
|
1
|
+
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:
|
|
2
|
+
|
|
3
|
+
--- Documentation ---
|
|
4
|
+
|
|
5
|
+
Please see: https://nettracer3d.readthedocs.io/en/latest/
|
|
6
|
+
|
|
7
|
+
--- Installation ---
|
|
8
|
+
|
|
9
|
+
To install nettracer3d, simply install Python and use this command in your command terminal:
|
|
10
|
+
|
|
11
|
+
pip install nettracer3d
|
|
12
|
+
|
|
13
|
+
I recommend installing the program as an Anaconda package to ensure its modules are work together on your specific system:
|
|
14
|
+
(Install anaconda at the link below, set up a new python env for nettracer3d, then use the same pip command).
|
|
15
|
+
|
|
16
|
+
https://www.anaconda.com/download?utm_source=anacondadocs&utm_medium=documentation&utm_campaign=download&utm_content=installwindows
|
|
17
|
+
|
|
18
|
+
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:
|
|
19
|
+
https://developer.nvidia.com/cuda-toolkit
|
|
20
|
+
|
|
21
|
+
To install nettracer3d with associated GPU-supporting packages, please use:
|
|
22
|
+
|
|
23
|
+
If your CUDA toolkit is version 11: pip install nettracer3d[CUDA11]
|
|
24
|
+
If your CUDA toolkit is version 12: pip install nettracer3d[CUDA12]
|
|
25
|
+
If you just want the entire cupy library: pip install nettracer3d[cupy]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
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.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
For a (slightly outdated) video tutorial on using the GUI: https://www.youtube.com/watch?v=cRatn5VTWDY
|
|
32
|
+
|
|
33
|
+
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).
|
|
34
|
+
|
|
35
|
+
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
36
|
+
|
|
37
|
+
-- Version 0.7.0 Updates --
|
|
38
|
+
|
|
39
|
+
1. Added new function in 'Analyze -> Stats -> Cluster Analysis'
|
|
40
|
+
* 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.
|
|
41
|
+
|
|
42
|
+
2. Added new function in 'Analyze -> Randomize -> Scramble Nodes'
|
|
43
|
+
* This function randomly rearranges the node (centroids) for comparison with other centroid-using methods, as a possible way to demonstrate non-random behavior.
|
|
44
|
+
* The randomize menu is likewise new and the 'Generate Equivalent Random Network' method was moved there.
|
|
45
|
+
|
|
46
|
+
3. Bug fixes.
|
|
47
|
+
* Importantly fixed a bug with dt-based dilation not working in 2D, which I had accidentally introduced recently.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "nettracer3d"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
authors = [
|
|
5
|
-
{ name="Liam McLaughlin", email="
|
|
5
|
+
{ name="Liam McLaughlin", email="liamm@wustl.edu" },
|
|
6
6
|
]
|
|
7
7
|
description = "Scripts for intializing and analyzing networks from segmentations of three dimensional images."
|
|
8
8
|
|
|
@@ -27,7 +27,7 @@ dependencies = [
|
|
|
27
27
|
]
|
|
28
28
|
|
|
29
29
|
readme = "README.md"
|
|
30
|
-
requires-python = "
|
|
30
|
+
requires-python = "==3.11"
|
|
31
31
|
classifiers = [
|
|
32
32
|
"Programming Language :: Python :: 3",
|
|
33
33
|
"License :: Other/Proprietary License",
|
|
@@ -49,5 +49,6 @@ cupy = [
|
|
|
49
49
|
nettracer3d = "nettracer3d.run:main"
|
|
50
50
|
|
|
51
51
|
[project.urls]
|
|
52
|
-
|
|
52
|
+
Documentation = "https://nettracer3d.readthedocs.io/en/latest/"
|
|
53
|
+
Video_Tutorial = "https://www.youtube.com/watch?v=cRatn5VTWDY"
|
|
53
54
|
Reference_Citation_For_Use = "https://doi.org/10.1101/2024.07.29.605633"
|
|
@@ -446,31 +446,11 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
446
446
|
except:
|
|
447
447
|
pass
|
|
448
448
|
|
|
449
|
-
try:
|
|
450
|
-
# Per-community statistics
|
|
451
|
-
for i, com in enumerate(communities):
|
|
452
|
-
subgraph = G.subgraph(com)
|
|
453
|
-
|
|
454
|
-
# Basic community metrics
|
|
455
|
-
stats[f'Community {i+1} Density'] = nx.density(subgraph)
|
|
456
|
-
stats[f'Community {i+1} Conductance'] = nx.conductance(G, com)
|
|
457
|
-
stats[f'Community {i+1} Avg Clustering'] = nx.average_clustering(subgraph)
|
|
458
|
-
|
|
459
|
-
# Degree centrality
|
|
460
|
-
degree_cent = nx.degree_centrality(subgraph)
|
|
461
|
-
stats[f'Community {i+1} Avg Degree Centrality'] = np.mean(list(degree_cent.values()))
|
|
462
|
-
|
|
463
|
-
# Average path length (only for connected subgraphs)
|
|
464
|
-
if nx.is_connected(subgraph):
|
|
465
|
-
stats[f'Community {i+1} Avg Path Length'] = nx.average_shortest_path_length(subgraph)
|
|
466
|
-
except:
|
|
467
|
-
pass
|
|
468
|
-
|
|
469
|
-
try:
|
|
449
|
+
#try:
|
|
470
450
|
# Add some Louvain-specific statistics
|
|
471
|
-
stats['Partition Resolution'] = 1.0 # Default resolution parameter
|
|
472
|
-
except:
|
|
473
|
-
pass
|
|
451
|
+
#stats['Partition Resolution'] = 1.0 # Default resolution parameter
|
|
452
|
+
#except:
|
|
453
|
+
#pass
|
|
474
454
|
try:
|
|
475
455
|
stats['Number of Iterations'] = len(set(partition.values()))
|
|
476
456
|
except:
|
|
@@ -514,6 +494,25 @@ def community_partition(master_list, weighted = False, style = 0, dostats = True
|
|
|
514
494
|
except:
|
|
515
495
|
pass
|
|
516
496
|
|
|
497
|
+
try:
|
|
498
|
+
# Per-community statistics
|
|
499
|
+
for i, com in enumerate(communities):
|
|
500
|
+
subgraph = G.subgraph(com)
|
|
501
|
+
|
|
502
|
+
# Basic community metrics
|
|
503
|
+
stats[f'Community {i+1} Density'] = nx.density(subgraph)
|
|
504
|
+
stats[f'Community {i+1} Conductance'] = nx.conductance(G, com)
|
|
505
|
+
stats[f'Community {i+1} Avg Clustering'] = nx.average_clustering(subgraph)
|
|
506
|
+
|
|
507
|
+
# Degree centrality
|
|
508
|
+
degree_cent = nx.degree_centrality(subgraph)
|
|
509
|
+
stats[f'Community {i+1} Avg Degree Centrality'] = np.mean(list(degree_cent.values()))
|
|
510
|
+
|
|
511
|
+
# Average path length (only for connected subgraphs)
|
|
512
|
+
if nx.is_connected(subgraph):
|
|
513
|
+
stats[f'Community {i+1} Avg Path Length'] = nx.average_shortest_path_length(subgraph)
|
|
514
|
+
except:
|
|
515
|
+
pass
|
|
517
516
|
|
|
518
517
|
return stats
|
|
519
518
|
|
|
@@ -354,6 +354,7 @@ def process_object_cpu(label, objects, labeled_array, xy_scale = 1, z_scale = 1)
|
|
|
354
354
|
mask = (subarray == label)
|
|
355
355
|
|
|
356
356
|
|
|
357
|
+
"""
|
|
357
358
|
# Determine which dimension needs resampling
|
|
358
359
|
if (z_scale > xy_scale) and mask.shape[0] != 1:
|
|
359
360
|
# Z dimension needs to be stretched
|
|
@@ -371,13 +372,13 @@ def process_object_cpu(label, objects, labeled_array, xy_scale = 1, z_scale = 1)
|
|
|
371
372
|
# Resample the mask if needed
|
|
372
373
|
if zoom_factor:
|
|
373
374
|
mask = ndimage.zoom(mask, zoom_factor, order=0) # Use order=0 for binary masks
|
|
374
|
-
|
|
375
|
+
"""
|
|
375
376
|
|
|
376
377
|
# Compute distance transform on the smaller mask
|
|
377
|
-
dist_transform = compute_distance_transform_distance(mask)
|
|
378
|
+
dist_transform = compute_distance_transform_distance(mask, sampling = [z_scale, xy_scale, xy_scale])
|
|
378
379
|
|
|
379
380
|
# Filter out small values near the edge to focus on more central regions
|
|
380
|
-
radius = np.max(dist_transform)
|
|
381
|
+
radius = np.max(dist_transform)
|
|
381
382
|
|
|
382
383
|
return label, radius
|
|
383
384
|
|
|
@@ -474,6 +475,7 @@ def estimate_object_radii_gpu(labeled_array, xy_scale = 1, z_scale = 1):
|
|
|
474
475
|
# Create binary mask for this object (directly on GPU)
|
|
475
476
|
mask_gpu = (labeled_array_gpu[tuple(padded_slices)] == label)
|
|
476
477
|
|
|
478
|
+
"""
|
|
477
479
|
# Determine which dimension needs resampling
|
|
478
480
|
if (z_scale > xy_scale) and mask_gpu.shape[0] != 1:
|
|
479
481
|
# Z dimension needs to be stretched
|
|
@@ -491,11 +493,12 @@ def estimate_object_radii_gpu(labeled_array, xy_scale = 1, z_scale = 1):
|
|
|
491
493
|
# Resample the mask if needed
|
|
492
494
|
if zoom_factor:
|
|
493
495
|
mask_gpu = cpx.zoom(mask_gpu, zoom_factor, order=0) # Use order=0 for binary masks
|
|
496
|
+
"""
|
|
494
497
|
|
|
495
498
|
# Compute distance transform on GPU
|
|
496
|
-
dist_transform_gpu = compute_distance_transform_distance_GPU(mask_gpu)
|
|
499
|
+
dist_transform_gpu = compute_distance_transform_distance_GPU(mask_gpu, sampling = [z_scale, xy_scale, xy_scale])
|
|
497
500
|
|
|
498
|
-
radius = float(cp.max(dist_transform_gpu).get())
|
|
501
|
+
radius = float(cp.max(dist_transform_gpu).get())
|
|
499
502
|
|
|
500
503
|
|
|
501
504
|
# Store the radius and the scaled radius
|
|
@@ -510,14 +513,15 @@ def estimate_object_radii_gpu(labeled_array, xy_scale = 1, z_scale = 1):
|
|
|
510
513
|
print(f"GPU calculation failed, trying CPU instead -> {e}")
|
|
511
514
|
return estimate_object_radii_cpu(labeled_array)
|
|
512
515
|
|
|
513
|
-
def compute_distance_transform_distance_GPU(nodes):
|
|
516
|
+
def compute_distance_transform_distance_GPU(nodes, sampling = [1,1,1]):
|
|
514
517
|
|
|
515
518
|
is_pseudo_3d = nodes.shape[0] == 1
|
|
516
519
|
if is_pseudo_3d:
|
|
517
520
|
nodes = cp.squeeze(nodes) # Convert to 2D for processing
|
|
521
|
+
del sampling[0]
|
|
518
522
|
|
|
519
523
|
# Compute the distance transform on the GPU
|
|
520
|
-
distance = cpx.distance_transform_edt(nodes)
|
|
524
|
+
distance = cpx.distance_transform_edt(nodes, sampling = sampling)
|
|
521
525
|
|
|
522
526
|
if is_pseudo_3d:
|
|
523
527
|
cp.expand_dims(distance, axis = 0)
|
|
@@ -525,14 +529,15 @@ def compute_distance_transform_distance_GPU(nodes):
|
|
|
525
529
|
return distance
|
|
526
530
|
|
|
527
531
|
|
|
528
|
-
def compute_distance_transform_distance(nodes):
|
|
532
|
+
def compute_distance_transform_distance(nodes, sampling = [1,1,1]):
|
|
529
533
|
|
|
530
534
|
is_pseudo_3d = nodes.shape[0] == 1
|
|
531
535
|
if is_pseudo_3d:
|
|
532
536
|
nodes = np.squeeze(nodes) # Convert to 2D for processing
|
|
537
|
+
del sampling[0]
|
|
533
538
|
|
|
534
539
|
# Fallback to CPU if there's an issue with GPU computation
|
|
535
|
-
distance = ndimage.distance_transform_edt(nodes)
|
|
540
|
+
distance = ndimage.distance_transform_edt(nodes, sampling = sampling)
|
|
536
541
|
if is_pseudo_3d:
|
|
537
542
|
np.expand_dims(distance, axis = 0)
|
|
538
543
|
return distance
|