nettracer3d 0.3.7__tar.gz → 0.3.9__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 (23) hide show
  1. {nettracer3d-0.3.7/src/nettracer3d.egg-info → nettracer3d-0.3.9}/PKG-INFO +1 -1
  2. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/pyproject.toml +1 -1
  3. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/nettracer.py +50 -2
  4. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/nettracer_gui.py +43 -12
  5. {nettracer3d-0.3.7 → nettracer3d-0.3.9/src/nettracer3d.egg-info}/PKG-INFO +1 -1
  6. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/LICENSE +0 -0
  7. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/README.md +0 -0
  8. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/setup.cfg +0 -0
  9. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/__init__.py +0 -0
  10. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/community_extractor.py +0 -0
  11. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/hub_getter.py +0 -0
  12. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/modularity.py +0 -0
  13. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/morphology.py +0 -0
  14. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/network_analysis.py +0 -0
  15. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/network_draw.py +0 -0
  16. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/node_draw.py +0 -0
  17. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/proximity.py +0 -0
  18. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/simple_network.py +0 -0
  19. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d/smart_dilate.py +0 -0
  20. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
  21. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
  22. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/src/nettracer3d.egg-info/requires.txt +0 -0
  23. {nettracer3d-0.3.7 → nettracer3d-0.3.9}/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.3.7
3
+ Version: 0.3.9
4
4
  Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
5
5
  Author-email: Liam McLaughlin <boom2449@gmail.com>
6
6
  Project-URL: User_Manual, https://drive.google.com/drive/folders/1fTkz3n4LN9_VxKRKC8lVQSlrz_wq0bVn?usp=drive_link
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nettracer3d"
3
- version = "0.3.7"
3
+ version = "0.3.9"
4
4
  authors = [
5
5
  { name="Liam McLaughlin", email="boom2449@gmail.com" },
6
6
  ]
@@ -23,8 +23,6 @@ except:
23
23
  from . import node_draw
24
24
  from . import network_draw
25
25
  from skimage.morphology import skeletonize_3d
26
- #from skimage.segmentation import watershed
27
- from skimage.feature import peak_local_max
28
26
  from concurrent.futures import ThreadPoolExecutor, as_completed
29
27
  from . import smart_dilate
30
28
  from . import modularity
@@ -864,6 +862,11 @@ def dilate_3D(tiff_array, dilated_x, dilated_y, dilated_z):
864
862
  """Internal method to dilate an array in 3D. Dilation this way is much faster than using a distance transform although the latter is theoretically more accurate.
865
863
  Arguments are an array, and the desired pixel dilation amounts in X, Y, Z."""
866
864
 
865
+
866
+ if dilated_x == 3 and dilated_y == 3 and dilated_z == 3:
867
+
868
+ return dilate_3D_old(tiff_array, dilated_x, dilated_y, dilated_z)
869
+
867
870
  def create_circular_kernel(diameter):
868
871
  """Create a 2D circular kernel with a given radius.
869
872
 
@@ -4182,6 +4185,51 @@ class Network_3D:
4182
4185
 
4183
4186
  return array
4184
4187
 
4188
+ def community_id_info(self):
4189
+ def invert_dict(d):
4190
+ inverted = {}
4191
+ for key, value in d.items():
4192
+ inverted.setdefault(value, []).append(key)
4193
+ return inverted
4194
+
4195
+ community_dict = invert_dict(self.communities)
4196
+ summation = 0
4197
+ id_set = set(self.node_identities.values())
4198
+ output = {sort: 0 for sort in id_set}
4199
+ template = copy.deepcopy(output)
4200
+
4201
+ for community in community_dict:
4202
+ counter = copy.deepcopy(template)
4203
+ nodes = community_dict[community]
4204
+ size = len(nodes)
4205
+ summation += size
4206
+
4207
+ # Count identities in this community
4208
+ for node in nodes:
4209
+ counter[self.node_identities[node]] += 1
4210
+
4211
+ # Convert to proportions within this community and weight by size
4212
+ for sort in counter:
4213
+ if size > 0: # Avoid division by zero
4214
+ counter[sort] = (counter[sort]) * size # proportion * size
4215
+
4216
+ # Add to running totals
4217
+ for sort, weighted_count in counter.items():
4218
+ output[sort] = output.get(sort, 0) + weighted_count
4219
+
4220
+ # Normalize by total size
4221
+ dictsum = 0
4222
+ for sort in output:
4223
+ output[sort] = output[sort]/summation
4224
+ dictsum += output[sort]
4225
+
4226
+ for sort in output:
4227
+ output[sort] = output[sort]/dictsum
4228
+
4229
+ return output
4230
+
4231
+
4232
+
4185
4233
 
4186
4234
  def kd_network(self, distance = 100, targets = None):
4187
4235
 
@@ -167,6 +167,7 @@ class ImageViewerWindow(QMainWindow):
167
167
  self.zoom_button.setFixedSize(40, 40)
168
168
  self.zoom_button.clicked.connect(self.toggle_zoom_mode)
169
169
  control_layout.addWidget(self.zoom_button)
170
+ self.resizing = False
170
171
 
171
172
  self.pan_button = QPushButton("✋")
172
173
  self.pan_button.setCheckable(True)
@@ -1783,8 +1784,10 @@ class ImageViewerWindow(QMainWindow):
1783
1784
  network_menu = analysis_menu.addMenu("Network")
1784
1785
  netshow_action = network_menu.addAction("Show Network")
1785
1786
  netshow_action.triggered.connect(self.show_netshow_dialog)
1786
- partition_action = network_menu.addAction("Community Partition + Community Stats")
1787
+ partition_action = network_menu.addAction("Community Partition +Generic Community Stats")
1787
1788
  partition_action.triggered.connect(self.show_partition_dialog)
1789
+ com_identity_action = network_menu.addAction("Identity Makeup of Network Communities (Weighted avg by community size)")
1790
+ com_identity_action.triggered.connect(self.handle_com_id)
1788
1791
  stats_menu = analysis_menu.addMenu("Stats")
1789
1792
  allstats_action = stats_menu.addAction("Calculate Generic Network Stats")
1790
1793
  allstats_action.triggered.connect(self.stats)
@@ -2797,8 +2800,12 @@ class ImageViewerWindow(QMainWindow):
2797
2800
  def update_slice(self):
2798
2801
  """Queue a slice update when slider moves."""
2799
2802
  # Store current view settings
2800
- current_xlim = self.ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
2801
- current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
2803
+ if not self.resizing:
2804
+ current_xlim = self.ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
2805
+ current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
2806
+ else:
2807
+ current_xlim = None
2808
+ current_ylim = None
2802
2809
 
2803
2810
  # Store the pending slice and view settings
2804
2811
  self.pending_slice = (self.slice_slider.value(), (current_xlim, current_ylim))
@@ -2855,11 +2862,8 @@ class ImageViewerWindow(QMainWindow):
2855
2862
  self.ax = self.figure.add_subplot(111)
2856
2863
 
2857
2864
  # Store current zoom limits if they exist and weren't provided
2858
- if preserve_zoom is None and hasattr(self, 'ax'):
2859
- current_xlim = self.ax.get_xlim() if self.ax.get_xlim() != (0, 1) else None
2860
- current_ylim = self.ax.get_ylim() if self.ax.get_ylim() != (0, 1) else None
2861
- else:
2862
- current_xlim, current_ylim = preserve_zoom if preserve_zoom else (None, None)
2865
+
2866
+ current_xlim, current_ylim = preserve_zoom if preserve_zoom else (None, None)
2863
2867
 
2864
2868
  # Define base colors for each channel with increased intensity
2865
2869
  base_colors = self.base_colors
@@ -2934,10 +2938,7 @@ class ImageViewerWindow(QMainWindow):
2934
2938
  cmap=highlight_cmap,
2935
2939
  alpha=0.5)
2936
2940
 
2937
- # Restore zoom limits if they existed
2938
- if current_xlim is not None and current_ylim is not None:
2939
- self.ax.set_xlim(current_xlim)
2940
- self.ax.set_ylim(current_ylim)
2941
+
2941
2942
 
2942
2943
  # Style the axes
2943
2944
  self.ax.set_xlabel('X')
@@ -2978,8 +2979,17 @@ class ImageViewerWindow(QMainWindow):
2978
2979
  if active_channels:
2979
2980
  self.ax.set_xlim(-0.5, min_width - 0.5)
2980
2981
  self.ax.set_ylim(min_height - 0.5, -0.5)
2982
+
2983
+ if self.resizing:
2984
+ self.original_xlim = self.ax.get_xlim()
2985
+ self.original_ylim = self.ax.get_ylim()
2986
+ # Restore zoom limits if they existed
2987
+ if current_xlim is not None and current_ylim is not None:
2988
+ self.ax.set_xlim(current_xlim)
2989
+ self.ax.set_ylim(current_ylim)
2981
2990
 
2982
2991
  self.canvas.draw()
2992
+
2983
2993
  def show_netshow_dialog(self):
2984
2994
  dialog = NetShowDialog(self)
2985
2995
  dialog.exec()
@@ -2988,6 +2998,21 @@ class ImageViewerWindow(QMainWindow):
2988
2998
  dialog = PartitionDialog(self)
2989
2999
  dialog.exec()
2990
3000
 
3001
+ def handle_com_id(self):
3002
+ if my_network.node_identities is None:
3003
+ print("Node identities must be set")
3004
+
3005
+ if my_network.communities is None:
3006
+ self.show_partition_dialog()
3007
+
3008
+ if my_network.communities is None:
3009
+ return
3010
+
3011
+ info = my_network.community_id_info()
3012
+
3013
+ self.format_for_upperright_table(info, 'Node Identity Type', 'Weighted Proportion in Communities', 'Weighted Average of Community Makeup')
3014
+
3015
+
2991
3016
  def show_radial_dialog(self):
2992
3017
  dialog = RadialDialog(self)
2993
3018
  dialog.exec()
@@ -4360,6 +4385,8 @@ class PartitionDialog(QDialog):
4360
4385
  except Exception as e:
4361
4386
  print(f"Error creating communities: {e}")
4362
4387
 
4388
+
4389
+
4363
4390
  class RadialDialog(QDialog):
4364
4391
 
4365
4392
  def __init__(self, parent=None):
@@ -4956,6 +4983,7 @@ class ResizeDialog(QDialog):
4956
4983
 
4957
4984
  def run_resize(self, undo = False):
4958
4985
  try:
4986
+ self.parent().resizing = True
4959
4987
  # Get parameters
4960
4988
  try:
4961
4989
  resize = float(self.resize.text()) if self.resize.text() else None
@@ -5104,6 +5132,7 @@ class ResizeDialog(QDialog):
5104
5132
 
5105
5133
  self.parent().update_display()
5106
5134
  self.reset_fields()
5135
+ self.parent().resizing = False
5107
5136
  self.accept()
5108
5137
 
5109
5138
  except Exception as e:
@@ -6034,6 +6063,7 @@ class GenNodesDialog(QDialog):
6034
6063
  )
6035
6064
 
6036
6065
  if down_factor > 0 and not self.called:
6066
+ self.parent().resizing = True
6037
6067
 
6038
6068
  my_network.edges = n3d.downsample(my_network.edges, down_factor, order = order)
6039
6069
  my_network.xy_scale = my_network.xy_scale * down_factor
@@ -6061,6 +6091,7 @@ class GenNodesDialog(QDialog):
6061
6091
 
6062
6092
 
6063
6093
  self.parent().update_display()
6094
+ self.parent().resizing = False
6064
6095
  self.accept()
6065
6096
 
6066
6097
  except Exception as e:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: nettracer3d
3
- Version: 0.3.7
3
+ Version: 0.3.9
4
4
  Summary: Scripts for intializing and analyzing networks from segmentations of three dimensional images.
5
5
  Author-email: Liam McLaughlin <boom2449@gmail.com>
6
6
  Project-URL: User_Manual, https://drive.google.com/drive/folders/1fTkz3n4LN9_VxKRKC8lVQSlrz_wq0bVn?usp=drive_link
File without changes
File without changes
File without changes