nettracer3d 1.2.3__py3-none-any.whl → 1.2.5__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/filaments.py CHANGED
@@ -93,16 +93,24 @@ class VesselDenoiser:
93
93
  # A voxel contributes to surface area if any neighbor is different
94
94
  for axis in range(3):
95
95
  for direction in [-1, 1]:
96
- # Shift array to compare with neighbors
97
- shifted = np.roll(labeled, direction, axis=axis)
96
+ # Pad with zeros only on the axis we're checking
97
+ pad_width = [(1, 1) if i == axis else (0, 0) for i in range(3)]
98
+ padded = np.pad(labeled, pad_width, mode='constant', constant_values=0)
98
99
 
99
- # Find faces exposed to different label (including background)
100
- exposed_faces = (labeled != shifted) & (labeled > 0)
100
+ # Roll the padded array
101
+ shifted = np.roll(padded, direction, axis=axis)
102
+
103
+ # Extract the center region (original size) from shifted
104
+ slices = [slice(1, -1) if i == axis else slice(None) for i in range(3)]
105
+ shifted_cropped = shifted[tuple(slices)]
106
+
107
+ # Find exposed faces
108
+ exposed_faces = (labeled != shifted_cropped) & (labeled > 0)
101
109
 
102
- # Count exposed faces per label
103
110
  face_counts = np.bincount(labeled[exposed_faces],
104
111
  minlength=num_features + 1)
105
112
  surface_areas += face_counts
113
+ del padded
106
114
 
107
115
  # Calculate sphericity for each component
108
116
  # Sphericity = (surface area of sphere with same volume) / (actual surface area)
nettracer3d/nettracer.py CHANGED
@@ -750,35 +750,37 @@ def estimate_object_radii(labeled_array, gpu=False, n_jobs=None, xy_scale = 1, z
750
750
 
751
751
  def get_surface_areas(labeled, xy_scale=1, z_scale=1):
752
752
  labels = np.unique(labeled)
753
- labels = labels[labels > 0] # Remove background label
753
+ labels = labels[labels > 0]
754
754
  max_label = int(np.max(labeled))
755
755
 
756
- # Size array to accommodate highest label value
757
756
  surface_areas = np.zeros(max_label + 1, dtype=np.float64)
758
757
 
759
- # Check each of 6 face directions (±x, ±y, ±z)
760
758
  for axis in range(3):
761
- # Determine face area based on axis (anisotropic scaling)
762
- if axis == 2: # z-axis: face is in xy plane
759
+ if axis == 2:
763
760
  face_area = xy_scale * xy_scale
764
- else: # x or y axis: face is perpendicular to xy plane
761
+ else:
765
762
  face_area = xy_scale * z_scale
766
763
 
767
764
  for direction in [-1, 1]:
768
- # Shift array to compare with neighbors
769
- shifted = np.roll(labeled, direction, axis=axis)
765
+ # Pad with zeros only on the axis we're checking
766
+ pad_width = [(1, 1) if i == axis else (0, 0) for i in range(3)]
767
+ padded = np.pad(labeled, pad_width, mode='constant', constant_values=0)
768
+
769
+ # Roll the padded array
770
+ shifted = np.roll(padded, direction, axis=axis)
770
771
 
771
- # Find faces exposed to different label (including background)
772
- exposed_faces = (labeled != shifted) & (labeled > 0)
772
+ # Extract the center region (original size) from shifted
773
+ slices = [slice(1, -1) if i == axis else slice(None) for i in range(3)]
774
+ shifted_cropped = shifted[tuple(slices)]
775
+
776
+ # Find exposed faces
777
+ exposed_faces = (labeled != shifted_cropped) & (labeled > 0)
773
778
 
774
- # Count exposed faces per label
775
779
  face_counts = np.bincount(labeled[exposed_faces],
776
780
  minlength=max_label + 1)
777
781
  surface_areas += face_counts * face_area
778
782
 
779
- # Create dictionary mapping label to surface area
780
783
  result = {int(label): float(surface_areas[label]) for label in labels}
781
-
782
784
  return result
783
785
 
784
786
  def break_and_label_skeleton(skeleton, peaks = 1, branch_removal = 0, comp_dil = 0, max_vol = 0, directory = None, return_skele = False, nodes = None, compute = True, unify = False, xy_scale = 1, z_scale = 1):
@@ -5560,14 +5562,14 @@ class Network_3D:
5560
5562
  except:
5561
5563
  pass
5562
5564
 
5563
- title1 = f'Neighborhood Distribution of Nodes in Network from Nodes: {root}'
5564
- title2 = f'Neighborhood Distribution of Nodes in Network from Nodes {root} as a proportion of total nodes of that ID'
5565
+ title1 = f'Neighborhood Distribution of Nodes in Network from Node Type: {root}'
5566
+ title2 = f'Neighborhood Distribution of Nodes in Network from Node Type {root} as a Proportion (# neighbors with ID x / Total # ID x)'
5565
5567
 
5566
5568
 
5567
5569
  elif mode == 1: #Search neighborhoods morphologically, obtain densities
5568
5570
  neighborhood_dict, total_dict, densities = morphology.search_neighbor_ids(self._nodes, targets, node_identities, neighborhood_dict, total_dict, search, self._xy_scale, self._z_scale, root, fastdil = fastdil)
5569
- title1 = f'Volumetric Neighborhood Distribution of Nodes in image that are {search} from nodes: {root}'
5570
- title2 = f'Density Distribution of Nodes in image that are {search} from Nodes {root} as a proportion of total node volume of that ID'
5571
+ title1 = f'Volumetric Neighborhood Distribution of Nodes in image that are {search} from Node Type: {root}'
5572
+ title2 = f'Density Distribution of Nodes in image that are {search} from Node Type {root} as a proportion (Vol neighors with ID x / Total vol ID x)'
5571
5573
 
5572
5574
 
5573
5575
  for identity in neighborhood_dict:
@@ -5578,7 +5580,7 @@ class Network_3D:
5578
5580
  network_analysis.create_bar_graph(proportion_dict, title2, "Node Identity", "Proportion", directory=directory)
5579
5581
 
5580
5582
  try:
5581
- network_analysis.create_bar_graph(densities, f'Relative Density of Node Identities with {search} from nodes {root}', "Node Identity", "Density Search/Density Total", directory=directory)
5583
+ network_analysis.create_bar_graph(densities, f'Relative Density of Node Identities with {search} from Node Type {root}', "Node Identity", "Density within search region/Density within entire image", directory=directory)
5582
5584
  except:
5583
5585
  densities = None
5584
5586
 
@@ -6233,14 +6235,14 @@ class Network_3D:
6233
6235
  if proportional:
6234
6236
 
6235
6237
  identities2, id_set2 = self.community_id_info_per_com(proportional = True)
6236
- output = neighborhoods.plot_dict_heatmap(identities2, id_set2, title = "Neighborhood Heatmap by Proportional Composition of Nodes in Neighborhood vs All Nodes")
6238
+ output = neighborhoods.plot_dict_heatmap(identities2, id_set2, title = "Neighborhood Heatmap by Proportional Composition of Nodes in Neighborhood vs All Nodes in Image")
6237
6239
  matrixes.append(output)
6238
6240
 
6239
6241
  identities3 = {}
6240
6242
  for iden in identities2:
6241
6243
  identities3[iden] = identities2[iden]/len_dict[iden][1]
6242
6244
 
6243
- 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)
6245
+ output = neighborhoods.plot_dict_heatmap(identities3, id_set2, title = "Over/Underrepresentation of Node Identities per Neighborhood (val < 1 = underrepresented, val > 1 = overrepresented)", center_at_one = True)
6244
6246
  matrixes.append(output)
6245
6247
 
6246
6248
  return len_dict, matrixes, id_set
@@ -10090,7 +10090,7 @@ class NeighborIdentityDialog(QDialog):
10090
10090
  self.root = None
10091
10091
 
10092
10092
  self.mode = QComboBox()
10093
- self.mode.addItems(["From Network - Based on Absolute Connectivity", "Use Labeled Nodes - Based on Morphological Neighborhood Densities"])
10093
+ self.mode.addItems(["From Network - Quantifies Neighbors Based on Adjacent Network Connections", "Use Labeled Nodes - Quantifies Neighbors Volume of Neighbor Within Search Region"])
10094
10094
  self.mode.setCurrentIndex(0)
10095
10095
  layout.addRow("Mode", self.mode)
10096
10096
 
@@ -1,10 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nettracer3d
3
- Version: 1.2.3
3
+ Version: 1.2.5
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/
7
- Project-URL: Video_Tutorial, https://www.youtube.com/watch?v=cRatn5VTWDY
8
7
  Project-URL: Reference_Citation_For_Use, https://doi.org/10.1101/2024.07.29.605633
9
8
  Classifier: Programming Language :: Python :: 3
10
9
  Classifier: License :: Other/Proprietary License
@@ -51,7 +50,7 @@ Please see: https://nettracer3d.readthedocs.io/en/latest/
51
50
 
52
51
  --- Installation ---
53
52
 
54
- To install nettracer3d, simply install Python and use this command in your command terminal:
53
+ To install nettracer3d, simply install Python. Make sure the Python installation installs pip, and that both Python and pip are available on your PATH. Next, use this command in your command terminal:
55
54
 
56
55
  pip install nettracer3d
57
56
 
@@ -60,6 +59,10 @@ I recommend installing the program as an Anaconda package to ensure its modules
60
59
 
61
60
  https://www.anaconda.com/download?utm_source=anacondadocs&utm_medium=documentation&utm_campaign=download&utm_content=installwindows
62
61
 
62
+ Alternatively, you can download a compiled .exe of version 1.2.4 here: https://doi.org/10.5281/zenodo.17873800
63
+
64
+ Unzip the folder, then double click the NetTracer3D executable to run the program. Note that this version will be missing a few features compared to the Python package, namely the 3D display and the ability to print updates to the command window. It will also not be updated as often.
65
+
63
66
  Optional Packages
64
67
  ~~~~~~~~~~~~~~~~~~
65
68
  I recommend including Napari (Chi-Li Chiu, Nathan Clack, the napari community, napari: a Python Multi-Dimensional Image Viewer Platform for the Research Community, Microscopy and Microanalysis, Volume 28, Issue S1, 1 August 2022, Pages 1576–1577, https://doi.org/10.1017/S1431927622006328) in the download as well, which allows NetTracer3D to use 3D displays. The standard package only comes with its native 2D slice display window.
@@ -101,17 +104,14 @@ While not related to NetTracer3D, if you want to use Cellpose3 (for which GPU-us
101
104
  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.
102
105
 
103
106
 
104
- For a (slightly outdated) video tutorial on using the GUI: https://www.youtube.com/watch?v=cRatn5VTWDY
105
-
106
- 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).
107
- The current citation is here:
107
+ NetTracer3D is freely available for academic and nonprofit use and can obtained from pip (pip install nettracer3d), provided that citation is included in any abstract, paper, or presentation utilizing NetTracer3D.
108
108
 
109
- McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neurovascular nephron connectivity map of the human kidney across the lifespan. Nat Commun 16, 5161 (2025). https://doi.org/10.1038/s41467-025-60435-8
109
+ (The official paper to cite is coming soon)
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.2.3 Updates --
113
+ -- Version 1.2.5 Updates --
114
114
 
115
- * Tweaked the 'branch unification params' - now hard rejects any sharp forks in the branches so branches will mostly be straight.
115
+ * Updated readme, license
116
116
 
117
117
 
@@ -3,12 +3,12 @@ nettracer3d/branch_stitcher.py,sha256=gyDVPUnApS2jmlIglJoRVEVY8WXLqwpr0_8rNdvy9u
3
3
  nettracer3d/cellpose_manager.py,sha256=NfRqW6Zl7yRU4qHCS_KjmR0R6QANSSgCO0_dr-eivxg,6694
4
4
  nettracer3d/community_extractor.py,sha256=rPXXWwMX05mfD_ogULEouLy8CST-aOaoSw45NhloKVg,31754
5
5
  nettracer3d/excelotron.py,sha256=aNof6k-DgMxVyFgsl3ltSCxG4vZW49cuvCBzfzhYhUY,75072
6
- nettracer3d/filaments.py,sha256=-gUoiXg4n5qTHhGvzh1gkLeDjStECRGbaGpau_NGVRM,43280
6
+ nettracer3d/filaments.py,sha256=ks3-ThdHRKu5hPk04R_YHAmVpwCqXraR0LWW0VRlAts,43693
7
7
  nettracer3d/modularity.py,sha256=pborVcDBvICB2-g8lNoSVZbIReIBlfeBmjFbPYmtq7Y,22443
8
8
  nettracer3d/morphology.py,sha256=QlBPsJAswBoinjZuouNwEfGEGwclvenlZ1Vmo288QLo,23287
9
9
  nettracer3d/neighborhoods.py,sha256=Bje77gWzXRIYyXkDlnFQnbUALnIt8dheLXHVFQsAKuc,53156
10
- nettracer3d/nettracer.py,sha256=JaoNXP67vLzaw6HUQ6mtB7qye1U92wZDJYI3vEpsDS4,294237
11
- nettracer3d/nettracer_gui.py,sha256=AKXT_4M-wuuijPzj6XfMV6fYKQ0WJYW0A_YdcO7kfYc,741978
10
+ nettracer3d/nettracer.py,sha256=9iQ51fvYUNsHA90lZd4cEVz_4AZZToTy22SjJoZNPHY,294254
11
+ nettracer3d/nettracer_gui.py,sha256=oStQZCqzi_nDFq8NKjMA1n0cuMv77gKekOd6XQFO5H4,742021
12
12
  nettracer3d/network_analysis.py,sha256=kBzsVaq4dZkMe0k-VGvQIUvM-tK0ZZ8bvb-wtsugZRQ,46150
13
13
  nettracer3d/network_draw.py,sha256=Uw0w1MoFiYMirkdM_XDAfy_m5_MoVaZkkGpoYzN9_-c,14259
14
14
  nettracer3d/node_draw.py,sha256=LeSftKJiNGkC7cpBJuf8Y9JeTUaUjcD6I2byclmZCb4,10484
@@ -21,9 +21,9 @@ nettracer3d/simple_network.py,sha256=dkG4jpc4zzdeuoaQobgGfL3PNo6N8dGKQ5hEEubFIvA
21
21
  nettracer3d/smart_dilate.py,sha256=gtL7hxzae93PJQsGLnUrwQ6Wb0evnHHREh0rHyUh_48,28644
22
22
  nettracer3d/stats.py,sha256=0YwrVLeEvll3PlbL5-0_9dstldr48PvxJrQm-PiC8jY,36607
23
23
  nettracer3d/tutorial.py,sha256=cUxiBf5RaBTtr9uJ2qoxZjRkcAY8mrvS9_LEqiwoxLc,153564
24
- nettracer3d-1.2.3.dist-info/licenses/LICENSE,sha256=jnNT-yBeIAKAHpYthPvLeqCzJ6nSurgnKmloVnfsjCI,764
25
- nettracer3d-1.2.3.dist-info/METADATA,sha256=rVv3ho6njj9VWX6XrKz0ri1mHYBwo_zO8Mb7d7XHBaM,7110
26
- nettracer3d-1.2.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
- nettracer3d-1.2.3.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
28
- nettracer3d-1.2.3.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
29
- nettracer3d-1.2.3.dist-info/RECORD,,
24
+ nettracer3d-1.2.5.dist-info/licenses/LICENSE,sha256=_Wg4zyCtT18lXBCXRov17IEop_-7z1OFo6o3JTzQj3g,568
25
+ nettracer3d-1.2.5.dist-info/METADATA,sha256=KGky4Y1X3pHgoykGd-SaJkp6x4faTeH6K-uh2r7wvL0,7164
26
+ nettracer3d-1.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
27
+ nettracer3d-1.2.5.dist-info/entry_points.txt,sha256=Nx1rr_0QhJXDBHAQg2vcqCzLMKBzSHfwy3xwGkueVyc,53
28
+ nettracer3d-1.2.5.dist-info/top_level.txt,sha256=zsYy9rZwirfCEOubolhee4TyzqBAL5gSUeFMzhFTX8c,12
29
+ nettracer3d-1.2.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
- NetTracer3D is freely available for academic and nonprofit use and can be obtained from Liam McLaughlin (boom2449@gmail.com) OR at pip (pip install nettracer3d), provided that the following citation is included in any abstract, paper, or presentation utilizing NetTracer3D:
1
+ NetTracer3D is freely available for academic and nonprofit use and can be obtained from Liam McLaughlin (boom2449@gmail.com) OR at pip (pip install nettracer3d), provided that citation is included in any abstract, paper, or presentation utilizing NetTracer3D.
2
2
 
3
- McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neurovascular nephron connectivity map of the human kidney across the lifespan. Nat Commun 16, 5161 (2025). https://doi.org/10.1038/s41467-025-60435-8
3
+ (The official paper to cite is coming soon)
4
4
 
5
5
  Commercial use is available for a fee. Copyright © is held by Washington University. Please direct all commercial requests for licensing, information, and limited evaluation copies to Washington University's Office of Technology Management at OTM@wustl.edu.