nettracer3d 0.5.3__tar.gz → 0.5.5__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.
Files changed (27) hide show
  1. {nettracer3d-0.5.3/src/nettracer3d.egg-info → nettracer3d-0.5.5}/PKG-INFO +7 -6
  2. nettracer3d-0.5.5/README.md +17 -0
  3. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/pyproject.toml +1 -1
  4. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/community_extractor.py +42 -0
  5. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/nettracer.py +23 -0
  6. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/nettracer_gui.py +556 -99
  7. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/segmenter.py +577 -80
  8. {nettracer3d-0.5.3 → nettracer3d-0.5.5/src/nettracer3d.egg-info}/PKG-INFO +7 -6
  9. nettracer3d-0.5.3/README.md +0 -16
  10. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/LICENSE +0 -0
  11. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/setup.cfg +0 -0
  12. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/__init__.py +0 -0
  13. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/hub_getter.py +0 -0
  14. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/modularity.py +0 -0
  15. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/morphology.py +0 -0
  16. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/network_analysis.py +0 -0
  17. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/network_draw.py +0 -0
  18. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/node_draw.py +0 -0
  19. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/proximity.py +0 -0
  20. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/run.py +0 -0
  21. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/simple_network.py +0 -0
  22. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d/smart_dilate.py +0 -0
  23. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
  24. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
  25. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d.egg-info/entry_points.txt +0 -0
  26. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d.egg-info/requires.txt +0 -0
  27. {nettracer3d-0.5.3 → nettracer3d-0.5.5}/src/nettracer3d.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: nettracer3d
3
- Version: 0.5.3
3
+ Version: 0.5.5
4
4
  Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
5
5
  Author-email: Liam McLaughlin <mclaughlinliam99@gmail.com>
6
6
  Project-URL: User_Tutorial, https://www.youtube.com/watch?v=cRatn5VTWDY
@@ -44,9 +44,10 @@ NetTracer3D is free to use/fork for academic/nonprofit use so long as citation i
44
44
 
45
45
  NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
46
46
 
47
- -- Version 0.5.3 updates --
47
+ -- Version 0.5.5 updates --
48
48
 
49
- 1. Improved calculate volumes method. Previous method used np.argwhere() to count voxels of labeled objects in parallel which was quite strenuous in large arrays with many objects. New method uses np.bincount() which uses optimized numpy C libraries to do the same.
50
- 2. scipy.ndimage.find_objects() method was replaced as the method to find bounding boxes for objects when searching for object neighborhoods for the morphological proximity network and the edge < > node interaction quantification. This new version should be substantially faster in big arrays with many labels. (Depending on how well this improves performance, I may reimplement the secondary network search algorithm, as a side-option, which uses the same parallel-search within subarray strategies, as opposed to the primary network search algorithm that uses distance transforms).
51
- 3. Image viewer window can now load in .nii format images, as well as .jpeg, .jpg, and .png. The nibabel library was added to the dependencies to enable .nii loading, although this is currently all it is used for (and the gui will still run without nibabel).
52
- 4. Fixed bug regarding deleting edge objects.
49
+ 1. When the highlight overlay is being used in big overlays (and therefore defaulting to the mini overlay), updated system to just make one 2d overlay that regenerates on slice movement. Decided this was better than having it sit in a bigger 3d array when said array wasn't being used for anything and had to be rebuilt on slice movement or 3d operations anyway.
50
+
51
+ 2. For the random forrest segmenter, added the option to segment by 2D slice instead of 3D. In short, the 3D version was very greedy with its RAM usage and essentially computes a set of feature maps for the target array that are equivalent dims. By default it makes 7 of these, so a 1 GB array is going to demand 7GB of RAM to store its feature maps. The 2D slice version segments by 2D slice instead, meaning it stores only feature maps for slices with actual slices on them for training the model, and then for predicting voxel foreground/background, it computes the feature maps for the current slice (admittedly in the threadpool so this is amplified by core amount in the CPU but generally speaking this will save a lot of RAM). The reason I made this segmenter is to give NetTracer3D all the bells and whistles to let a user do everything in one program, but admittedly there are more efficient ML segmenters out there, such as through FIJI's big data viewer which is a lot better at handling big arrays in memory. I considered a way to compute 3D feature maps one at a time, save them in chunks to hard mem, and then open them while doing the chunked total segmentation but frankly this would likely be too slow to want to use so I will just suggest using 2D slice segmenter if RAM runs low.
52
+
53
+ I do not anticipate any major updates for this project for the foreseeable future beyond bug fixes.
@@ -0,0 +1,17 @@
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
+
4
+ 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. More advanced documentation is coming down the line, but for now please see: https://www.youtube.com/watch?v=cRatn5VTWDY
5
+ for a video tutorial on using the GUI.
6
+
7
+ 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).
8
+
9
+ NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
10
+
11
+ -- Version 0.5.5 updates --
12
+
13
+ 1. When the highlight overlay is being used in big overlays (and therefore defaulting to the mini overlay), updated system to just make one 2d overlay that regenerates on slice movement. Decided this was better than having it sit in a bigger 3d array when said array wasn't being used for anything and had to be rebuilt on slice movement or 3d operations anyway.
14
+
15
+ 2. For the random forrest segmenter, added the option to segment by 2D slice instead of 3D. In short, the 3D version was very greedy with its RAM usage and essentially computes a set of feature maps for the target array that are equivalent dims. By default it makes 7 of these, so a 1 GB array is going to demand 7GB of RAM to store its feature maps. The 2D slice version segments by 2D slice instead, meaning it stores only feature maps for slices with actual slices on them for training the model, and then for predicting voxel foreground/background, it computes the feature maps for the current slice (admittedly in the threadpool so this is amplified by core amount in the CPU but generally speaking this will save a lot of RAM). The reason I made this segmenter is to give NetTracer3D all the bells and whistles to let a user do everything in one program, but admittedly there are more efficient ML segmenters out there, such as through FIJI's big data viewer which is a lot better at handling big arrays in memory. I considered a way to compute 3D feature maps one at a time, save them in chunks to hard mem, and then open them while doing the chunked total segmentation but frankly this would likely be too slow to want to use so I will just suggest using 2D slice segmenter if RAM runs low.
16
+
17
+ I do not anticipate any major updates for this project for the foreseeable future beyond bug fixes.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nettracer3d"
3
- version = "0.5.3"
3
+ version = "0.5.5"
4
4
  authors = [
5
5
  { name="Liam McLaughlin", email="mclaughlinliam99@gmail.com" },
6
6
  ]
@@ -9,6 +9,7 @@ from scipy import ndimage
9
9
  from scipy.ndimage import zoom
10
10
  from networkx.algorithms import community
11
11
  from community import community_louvain
12
+ import random
12
13
  from . import node_draw
13
14
 
14
15
 
@@ -781,6 +782,47 @@ def generate_distinct_colors(n_colors: int) -> List[Tuple[int, int, int]]:
781
782
  colors.append(rgb)
782
783
  return colors
783
784
 
785
+ def assign_node_colors(node_list: List[int], labeled_array: np.ndarray) -> Tuple[np.ndarray, Dict[int, str]]:
786
+ """
787
+ Assign distinct colors to nodes and create an RGBA image.
788
+
789
+ Args:
790
+ node_list: List of node IDs
791
+ labeled_array: 3D numpy array with labels corresponding to node IDs
792
+
793
+ Returns:
794
+ Tuple of (RGBA-coded numpy array (H, W, D, 4), dictionary mapping nodes to color names)
795
+ """
796
+
797
+ # Sort communities by size (descending)
798
+ sorted_nodes= sorted(node_list, reverse=True)
799
+
800
+ # Generate distinct colors
801
+ colors = generate_distinct_colors(len(node_list))
802
+ random.shuffle(colors) #Randomly sorted to make adjacent structures likely stand out
803
+
804
+ # Convert RGB colors to RGBA by adding alpha channel
805
+ colors_rgba = [(r, g, b, 255) for r, g, b in colors] # Full opacity for colored regions
806
+
807
+ # Create mapping from community to color
808
+ node_to_color = {node: colors_rgba[i] for i, node in enumerate(sorted_nodes)}
809
+
810
+ # Create RGBA array (initialize with transparent background)
811
+ rgba_array = np.zeros((*labeled_array.shape, 4), dtype=np.uint8)
812
+
813
+ # Assign colors to each voxel based on its label
814
+ for label in np.unique(labeled_array):
815
+ if label in node_to_color: # Skip background (usually label 0)
816
+ mask = labeled_array == label
817
+ for i in range(4): # RGBA channels
818
+ rgba_array[mask, i] = node_to_color[label][i]
819
+
820
+ # Convert the RGB portion of community_to_color back to RGB for color naming
821
+ node_to_color_rgb = {k: tuple(v[:3]) for k, v in node_to_color.items()}
822
+ node_to_color_names = convert_node_colors_to_names(node_to_color_rgb)
823
+
824
+ return rgba_array, node_to_color_names
825
+
784
826
  def assign_community_colors(community_dict: Dict[int, int], labeled_array: np.ndarray) -> Tuple[np.ndarray, Dict[int, str]]:
785
827
  """
786
828
  Assign distinct colors to communities and create an RGBA image.
@@ -4091,6 +4091,29 @@ class Network_3D:
4091
4091
 
4092
4092
 
4093
4093
  return image, output
4094
+
4095
+ def node_to_color(self, down_factor = None, mode = 0):
4096
+
4097
+ if mode == 0:
4098
+ array = self._nodes
4099
+ elif mode == 1:
4100
+ array = self._edges
4101
+
4102
+ items = list(np.unique(array))
4103
+ if 0 in items:
4104
+ del items[0]
4105
+
4106
+
4107
+ if down_factor is not None:
4108
+ original_shape = array.shape
4109
+ array = downsample(array, down_factor)
4110
+
4111
+ array, output = community_extractor.assign_node_colors(items, array)
4112
+
4113
+ if down_factor is not None:
4114
+ array = upsample_with_padding(array, down_factor, original_shape)
4115
+
4116
+ return array, output
4094
4117
 
4095
4118
 
4096
4119