nettracer3d 0.8.6__tar.gz → 0.8.8__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.

Potentially problematic release.


This version of nettracer3d might be problematic. Click here for more details.

Files changed (31) hide show
  1. {nettracer3d-0.8.6/src/nettracer3d.egg-info → nettracer3d-0.8.8}/PKG-INFO +2 -2
  2. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/README.md +1 -1
  3. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/pyproject.toml +1 -1
  4. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/nettracer_gui.py +104 -100
  5. nettracer3d-0.8.8/src/nettracer3d/painting.py +549 -0
  6. {nettracer3d-0.8.6 → nettracer3d-0.8.8/src/nettracer3d.egg-info}/PKG-INFO +2 -2
  7. nettracer3d-0.8.6/src/nettracer3d/painting.py +0 -375
  8. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/LICENSE +0 -0
  9. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/setup.cfg +0 -0
  10. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/__init__.py +0 -0
  11. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/cellpose_manager.py +0 -0
  12. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/community_extractor.py +0 -0
  13. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/excelotron.py +0 -0
  14. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/modularity.py +0 -0
  15. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/morphology.py +0 -0
  16. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/neighborhoods.py +0 -0
  17. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/nettracer.py +0 -0
  18. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/network_analysis.py +0 -0
  19. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/network_draw.py +0 -0
  20. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/node_draw.py +0 -0
  21. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/proximity.py +0 -0
  22. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/run.py +0 -0
  23. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/segmenter.py +0 -0
  24. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/segmenter_GPU.py +0 -0
  25. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/simple_network.py +0 -0
  26. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d/smart_dilate.py +0 -0
  27. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
  28. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
  29. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d.egg-info/entry_points.txt +0 -0
  30. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d.egg-info/requires.txt +0 -0
  31. {nettracer3d-0.8.6 → nettracer3d-0.8.8}/src/nettracer3d.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nettracer3d
3
- Version: 0.8.6
3
+ Version: 0.8.8
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/
@@ -110,6 +110,6 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
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 0.8.6 Updates --
113
+ -- Version 0.8.8 Updates --
114
114
 
115
115
  * See Documentation Once Updated
@@ -65,6 +65,6 @@ McLaughlin, L., Zhang, B., Sharma, S. et al. Three dimensional multiscalar neuro
65
65
 
66
66
  NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
67
67
 
68
- -- Version 0.8.6 Updates --
68
+ -- Version 0.8.8 Updates --
69
69
 
70
70
  * See Documentation Once Updated
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "nettracer3d"
3
- version = "0.8.6"
3
+ version = "0.8.8"
4
4
  authors = [
5
5
  { name="Liam McLaughlin", email="liamm@wustl.edu" },
6
6
  ]
@@ -2172,7 +2172,18 @@ class ImageViewerWindow(QMainWindow):
2172
2172
  if self.machine_window is not None:
2173
2173
  self.machine_window.silence_button()
2174
2174
  self.canvas.setCursor(Qt.CursorShape.CrossCursor)
2175
- if self.pan_mode or self.brush_mode:
2175
+ if (hasattr(self, 'virtual_draw_operations') and self.virtual_draw_operations) or \
2176
+ (hasattr(self, 'virtual_erase_operations') and self.virtual_erase_operations) or \
2177
+ (hasattr(self, 'current_operation') and self.current_operation):
2178
+ # Finish current operation first
2179
+ if hasattr(self, 'current_operation') and self.current_operation:
2180
+ self.pm.finish_current_virtual_operation()
2181
+ # Now convert to real data
2182
+ self.pm.convert_virtual_strokes_to_data()
2183
+ current_xlim = self.ax.get_xlim()
2184
+ current_ylim = self.ax.get_ylim()
2185
+ self.update_display(preserve_zoom=(current_xlim, current_ylim))
2186
+ if self.pan_mode:
2176
2187
  current_xlim = self.ax.get_xlim()
2177
2188
  current_ylim = self.ax.get_ylim()
2178
2189
  self.update_display(preserve_zoom=(current_xlim, current_ylim))
@@ -2189,6 +2200,7 @@ class ImageViewerWindow(QMainWindow):
2189
2200
  self.pan_mode = self.pan_button.isChecked()
2190
2201
  if self.pan_mode:
2191
2202
 
2203
+
2192
2204
  self.zoom_button.setChecked(False)
2193
2205
  self.pen_button.setChecked(False)
2194
2206
  self.zoom_mode = False
@@ -2196,13 +2208,42 @@ class ImageViewerWindow(QMainWindow):
2196
2208
  self.threed = False
2197
2209
  self.last_change = None
2198
2210
  self.brush_mode = False
2199
- if self.machine_window is not None:
2200
- self.machine_window.silence_button()
2201
- self.canvas.setCursor(Qt.CursorShape.OpenHandCursor)
2202
- if self.brush_mode:
2211
+ if (hasattr(self, 'virtual_draw_operations') and self.virtual_draw_operations) or \
2212
+ (hasattr(self, 'virtual_erase_operations') and self.virtual_erase_operations) or \
2213
+ (hasattr(self, 'current_operation') and self.current_operation):
2214
+ # Finish current operation first
2215
+ if hasattr(self, 'current_operation') and self.current_operation:
2216
+ self.pm.finish_current_virtual_operation()
2217
+ # Now convert to real data
2218
+ self.pm.convert_virtual_strokes_to_data()
2203
2219
  current_xlim = self.ax.get_xlim()
2204
2220
  current_ylim = self.ax.get_ylim()
2205
2221
  self.update_display(preserve_zoom=(current_xlim, current_ylim))
2222
+ if self.machine_window is not None:
2223
+ self.machine_window.silence_button()
2224
+ self.canvas.setCursor(Qt.CursorShape.OpenHandCursor)
2225
+
2226
+ if self.pan_background_image is None:
2227
+
2228
+ if self.machine_window is not None:
2229
+ if self.machine_window.segmentation_worker is not None:
2230
+ if not self.machine_window.segmentation_worker._paused:
2231
+ self.resume = True
2232
+ self.machine_window.segmentation_worker.pause()
2233
+
2234
+ # Store current channel visibility state
2235
+ self.pre_pan_channel_state = self.channel_visible.copy()
2236
+
2237
+ # Create static background from currently visible channels
2238
+ self.create_pan_background()
2239
+
2240
+ # Hide all channels and show only the background
2241
+ self.channel_visible = [False] * 4
2242
+ self.is_pan_preview = True
2243
+
2244
+ # Update display to show only background
2245
+ self.update_display_pan_mode()
2246
+
2206
2247
  else:
2207
2248
  current_xlim = self.ax.get_xlim()
2208
2249
  current_ylim = self.ax.get_ylim()
@@ -2229,8 +2270,6 @@ class ImageViewerWindow(QMainWindow):
2229
2270
  else:
2230
2271
  channel = 2
2231
2272
 
2232
- self.pm.initiate_paint_session(channel, current_xlim, current_ylim)
2233
-
2234
2273
  if self.pan_mode:
2235
2274
  current_xlim = self.ax.get_xlim()
2236
2275
  current_ylim = self.ax.get_ylim()
@@ -2242,6 +2281,14 @@ class ImageViewerWindow(QMainWindow):
2242
2281
  self.zoom_mode = False
2243
2282
  self.update_brush_cursor()
2244
2283
  else:
2284
+ if (hasattr(self, 'virtual_draw_operations') and self.virtual_draw_operations) or \
2285
+ (hasattr(self, 'virtual_erase_operations') and self.virtual_erase_operations) or \
2286
+ (hasattr(self, 'current_operation') and self.current_operation):
2287
+ # Finish current operation first
2288
+ if hasattr(self, 'current_operation') and self.current_operation:
2289
+ self.pm.finish_current_virtual_operation()
2290
+ # Now convert to real data
2291
+ self.pm.convert_virtual_strokes_to_data()
2245
2292
  # Get current zoom and do display update
2246
2293
  current_xlim = self.ax.get_xlim()
2247
2294
  current_ylim = self.ax.get_ylim()
@@ -2495,29 +2542,7 @@ class ImageViewerWindow(QMainWindow):
2495
2542
 
2496
2543
  self.panning = True
2497
2544
  self.pan_start = (event.xdata, event.ydata)
2498
-
2499
- if self.pan_background_image is None:
2500
-
2501
- if self.machine_window is not None:
2502
- if self.machine_window.segmentation_worker is not None:
2503
- if not self.machine_window.segmentation_worker._paused:
2504
- self.resume = True
2505
- self.machine_window.segmentation_worker.pause()
2506
-
2507
- # Store current channel visibility state
2508
- self.pre_pan_channel_state = self.channel_visible.copy()
2509
-
2510
- # Create static background from currently visible channels
2511
- self.create_pan_background()
2512
-
2513
- # Hide all channels and show only the background
2514
- self.channel_visible = [False] * 4
2515
- self.is_pan_preview = True
2516
-
2517
- # Update display to show only background
2518
- self.update_display_pan_mode()
2519
- else:
2520
- self.canvas.setCursor(Qt.CursorShape.ClosedHandCursor)
2545
+ self.canvas.setCursor(Qt.CursorShape.ClosedHandCursor)
2521
2546
 
2522
2547
 
2523
2548
  elif self.brush_mode:
@@ -2525,21 +2550,16 @@ class ImageViewerWindow(QMainWindow):
2525
2550
  if event.inaxes != self.ax:
2526
2551
  return
2527
2552
 
2528
- """
2529
- try:
2530
- if self.machine_window is not None and not self.machine_window.segmentation_worker._paused:
2531
- current_xlim = self.ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
2532
- current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
2553
+ current_xlim = self.ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
2554
+ current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
2533
2555
 
2534
- if self.pen_button.isChecked():
2535
- channel = self.active_channel
2536
- else:
2537
- channel = 2
2556
+ if self.pen_button.isChecked():
2557
+ channel = self.active_channel
2558
+ else:
2559
+ channel = 2
2560
+
2561
+ self.pm.initiate_paint_session(channel, current_xlim, current_ylim)
2538
2562
 
2539
- self.pm.initiate_paint_session(channel, current_xlim, current_ylim)
2540
- except:
2541
- pass
2542
- """
2543
2563
 
2544
2564
  if event.button == 1 or event.button == 3:
2545
2565
  if self.machine_window is not None:
@@ -2555,7 +2575,7 @@ class ImageViewerWindow(QMainWindow):
2555
2575
  current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
2556
2576
 
2557
2577
  if event.button == 1 and getattr(self, 'can', False):
2558
- self.update_display(preserve_zoom=(current_xlim, current_ylim), skip_paint_reinit = True)
2578
+ self.update_display(preserve_zoom=(current_xlim, current_ylim))
2559
2579
  self.handle_can(x, y)
2560
2580
  return
2561
2581
 
@@ -2965,7 +2985,7 @@ class ImageViewerWindow(QMainWindow):
2965
2985
  if z1 == z2 == self.current_slice:
2966
2986
  self.ax.plot([x1, x2], [y1, y2], 'r--', alpha=0.5)
2967
2987
 
2968
- self.canvas.setCursor(Qt.CursorShape.ClosedHandCursor)
2988
+ #self.canvas.setCursor(Qt.CursorShape.ClosedHandCursor)
2969
2989
 
2970
2990
  self.canvas.draw_idle()
2971
2991
 
@@ -3121,24 +3141,26 @@ class ImageViewerWindow(QMainWindow):
3121
3141
 
3122
3142
  if not hasattr(self, 'zoom_changed'):
3123
3143
  self.zoom_changed = False
3124
-
3144
+
3125
3145
  self.canvas.draw()
3126
3146
 
3127
3147
  # Handle brush mode cleanup with paint session management
3128
3148
  if self.brush_mode and hasattr(self, 'painting') and self.painting:
3149
+
3150
+ self.pm.connect_virtual_paint_points()
3151
+ self.pm.update_virtual_paint_display()
3152
+
3153
+
3129
3154
  # Finish current operation
3155
+ self.pm.finish_current_stroke()
3130
3156
  self.pm.finish_current_virtual_operation()
3131
3157
 
3132
3158
  # Reset last position for next stroke
3133
- self.last_virtual_pos = None
3159
+ #self.last_virtual_pos = None
3134
3160
 
3135
3161
  # End this stroke but keep session active for continuous painting
3136
3162
  self.painting = False
3137
3163
 
3138
- current_xlim = self.ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
3139
- current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
3140
-
3141
- self.update_display(preserve_zoom=(current_xlim, current_ylim), continue_paint = True)
3142
3164
 
3143
3165
  if self.resume:
3144
3166
  self.machine_window.segmentation_worker.resume()
@@ -3264,7 +3286,6 @@ class ImageViewerWindow(QMainWindow):
3264
3286
 
3265
3287
  self.zoom_changed = False # Flag that zoom has changed
3266
3288
 
3267
-
3268
3289
 
3269
3290
  self.canvas.draw()
3270
3291
 
@@ -5110,6 +5131,14 @@ class ImageViewerWindow(QMainWindow):
5110
5131
  """Actually perform the slice update after debounce delay."""
5111
5132
  if self.pending_slice is not None:
5112
5133
  slice_value, view_settings = self.pending_slice
5134
+ if (hasattr(self, 'virtual_draw_operations') and self.virtual_draw_operations) or \
5135
+ (hasattr(self, 'virtual_erase_operations') and self.virtual_erase_operations) or \
5136
+ (hasattr(self, 'current_operation') and self.current_operation):
5137
+ # Finish current operation first
5138
+ if hasattr(self, 'current_operation') and self.current_operation:
5139
+ self.pm.finish_current_virtual_operation()
5140
+ # Now convert to real data
5141
+ self.pm.convert_virtual_strokes_to_data()
5113
5142
  self.current_slice = slice_value
5114
5143
  if self.mini_overlay == True: #If we are rendering the highlight overlay for selected values one at a time.
5115
5144
  self.create_mini_overlay(node_indices = self.clicked_values['nodes'], edge_indices = self.clicked_values['edges'])
@@ -5133,7 +5162,7 @@ class ImageViewerWindow(QMainWindow):
5133
5162
 
5134
5163
 
5135
5164
 
5136
- def update_display(self, preserve_zoom=None, dims = None, called = False, reset_resize = False, continue_paint = False, skip_paint_reinit = False):
5165
+ def update_display(self, preserve_zoom=None, dims = None, called = False, reset_resize = False):
5137
5166
  """Update the display with currently visible channels and highlight overlay."""
5138
5167
  try:
5139
5168
  self.figure.clear()
@@ -5163,17 +5192,17 @@ class ImageViewerWindow(QMainWindow):
5163
5192
  self.restore_channels = []
5164
5193
  except:
5165
5194
  pass
5166
- if not continue_paint:
5167
- self.static_background = None
5168
5195
 
5169
- if self.machine_window is None:
5170
- try:
5171
- self.channel_data[4][self.current_slice, :, :] = n3d.overlay_arrays_simple(self.channel_data[self.temp_chan][self.current_slice, :, :], self.channel_data[4][self.current_slice, :, :])
5172
- self.load_channel(self.temp_chan, self.channel_data[4], data = True, end_paint = True)
5173
- self.channel_data[4] = None
5174
- self.channel_visible[4] = False
5175
- except:
5176
- pass
5196
+ self.static_background = None
5197
+
5198
+ if self.machine_window is None:
5199
+ try:
5200
+ self.channel_data[4][self.current_slice, :, :] = n3d.overlay_arrays_simple(self.channel_data[self.temp_chan][self.current_slice, :, :], self.channel_data[4][self.current_slice, :, :])
5201
+ self.load_channel(self.temp_chan, self.channel_data[4], data = True, end_paint = True)
5202
+ self.channel_data[4] = None
5203
+ self.channel_visible[4] = False
5204
+ except:
5205
+ pass
5177
5206
 
5178
5207
  # Get active channels and their dimensions
5179
5208
  active_channels = [i for i in range(4) if self.channel_data[i] is not None]
@@ -5404,17 +5433,6 @@ class ImageViewerWindow(QMainWindow):
5404
5433
 
5405
5434
  self.canvas.draw()
5406
5435
 
5407
- if self.brush_mode and not skip_paint_reinit:
5408
- # Get current zoom to preserve it
5409
- current_xlim = self.ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
5410
- current_ylim = self.ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
5411
-
5412
- if self.pen_button.isChecked():
5413
- channel = self.active_channel
5414
- else:
5415
- channel = 2
5416
-
5417
- self.pm.initiate_paint_session(channel, current_xlim, current_ylim)
5418
5436
 
5419
5437
  except:
5420
5438
  import traceback
@@ -9770,18 +9788,6 @@ class MachineWindow(QMainWindow):
9770
9788
 
9771
9789
  self.parent().pm = painting.PaintManager(parent = self.parent())
9772
9790
 
9773
- # Start virtual paint session
9774
- # Get current zoom to preserve it
9775
- current_xlim = self.parent().ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
9776
- current_ylim = self.parent().ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
9777
-
9778
- if self.parent().pen_button.isChecked():
9779
- channel = self.parent().active_channel
9780
- else:
9781
- channel = 2
9782
-
9783
- self.parent().pm.initiate_paint_session(channel, current_xlim, current_ylim)
9784
-
9785
9791
  self.parent().pan_button.setChecked(False)
9786
9792
  self.parent().zoom_button.setChecked(False)
9787
9793
  if self.parent().pan_mode:
@@ -9809,6 +9815,15 @@ class MachineWindow(QMainWindow):
9809
9815
  # Wait a bit for cleanup
9810
9816
  time.sleep(0.1)
9811
9817
 
9818
+ if (hasattr(self.parent(), 'virtual_draw_operations') and self.parent().virtual_draw_operations) or \
9819
+ (hasattr(self.parent(), 'virtual_erase_operations') and self.parent().virtual_erase_operations) or \
9820
+ (hasattr(self.parent(), 'current_operation') and self.parent().current_operation):
9821
+ # Finish current operation first
9822
+ if hasattr(self.parent(), 'current_operation') and self.parent().current_operation:
9823
+ self.parent().pm.finish_current_virtual_operation()
9824
+ # Now convert to real data
9825
+ self.parent().pm.convert_virtual_strokes_to_data()
9826
+
9812
9827
  self.previewing = True
9813
9828
  try:
9814
9829
  try:
@@ -9852,7 +9867,7 @@ class MachineWindow(QMainWindow):
9852
9867
  return
9853
9868
  else:
9854
9869
  self.segmentation_worker = SegmentationWorker(self.parent().highlight_overlay, self.segmenter, self.use_gpu, self.use_two, self.previewing, self, self.mem_lock)
9855
- self.segmentation_worker.chunk_processed.connect(lambda: self.update_display(skip_paint_reinit = True)) # Just update display
9870
+ self.segmentation_worker.chunk_processed.connect(self.update_display) # Just update display
9856
9871
  current_xlim = self.parent().ax.get_xlim()
9857
9872
  current_ylim = self.parent().ax.get_ylim()
9858
9873
  try:
@@ -9905,7 +9920,7 @@ class MachineWindow(QMainWindow):
9905
9920
 
9906
9921
  return changed
9907
9922
 
9908
- def update_display(self, skip_paint_reinit = False):
9923
+ def update_display(self):
9909
9924
  if not hasattr(self, '_last_update'):
9910
9925
  self._last_update = 0
9911
9926
 
@@ -9932,18 +9947,7 @@ class MachineWindow(QMainWindow):
9932
9947
 
9933
9948
  if not self.parent().painting:
9934
9949
  # Only update if view limits are valid
9935
- self.parent().update_display(preserve_zoom=(current_xlim, current_ylim), skip_paint_reinit = skip_paint_reinit)
9936
-
9937
- if self.parent().brush_mode:
9938
- current_xlim = self.parent().ax.get_xlim() if hasattr(self, 'ax') and self.ax.get_xlim() != (0, 1) else None
9939
- current_ylim = self.parent().ax.get_ylim() if hasattr(self, 'ax') and self.ax.get_ylim() != (0, 1) else None
9940
-
9941
- if self.parent().pen_button.isChecked():
9942
- channel = self.parent().active_channel
9943
- else:
9944
- channel = 2
9945
-
9946
- self.parent().pm.initiate_paint_session(channel, current_xlim, current_ylim)
9950
+ self.parent().update_display(preserve_zoom=(current_xlim, current_ylim))
9947
9951
 
9948
9952
  self._last_update = current_time
9949
9953
  except Exception as e: