nettracer3d 0.5.8__tar.gz → 0.6.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.5.8/src/nettracer3d.egg-info → nettracer3d-0.6.0}/PKG-INFO +3 -3
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/README.md +2 -2
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/pyproject.toml +1 -1
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/nettracer_gui.py +221 -198
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/segmenter.py +5 -2
- {nettracer3d-0.5.8 → nettracer3d-0.6.0/src/nettracer3d.egg-info}/PKG-INFO +3 -3
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/LICENSE +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/setup.cfg +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/__init__.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/community_extractor.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/hub_getter.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/modularity.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/morphology.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/nettracer.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/network_analysis.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/network_draw.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/node_draw.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/proximity.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/run.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/simple_network.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d/smart_dilate.py +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d.egg-info/SOURCES.txt +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d.egg-info/dependency_links.txt +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d.egg-info/entry_points.txt +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/src/nettracer3d.egg-info/requires.txt +0 -0
- {nettracer3d-0.5.8 → nettracer3d-0.6.0}/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
|
+
Version: 0.6.0
|
|
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,6 +44,6 @@ 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.
|
|
47
|
+
-- Version 0.6.0 updates --
|
|
48
48
|
|
|
49
|
-
1. Bug fixes
|
|
49
|
+
1. Bug fixes
|
|
@@ -8,6 +8,6 @@ NetTracer3D is free to use/fork for academic/nonprofit use so long as citation i
|
|
|
8
8
|
|
|
9
9
|
NetTracer3D was developed by Liam McLaughlin while working under Dr. Sanjay Jain at Washington University School of Medicine.
|
|
10
10
|
|
|
11
|
-
-- Version 0.
|
|
11
|
+
-- Version 0.6.0 updates --
|
|
12
12
|
|
|
13
|
-
1. Bug fixes
|
|
13
|
+
1. Bug fixes
|
|
@@ -840,7 +840,7 @@ class ImageViewerWindow(QMainWindow):
|
|
|
840
840
|
select_nodes.triggered.connect(lambda: self.handle_select_all(edges = False, nodes = True))
|
|
841
841
|
select_both.triggered.connect(lambda: self.handle_select_all(edges = True))
|
|
842
842
|
select_edges.triggered.connect(lambda: self.handle_select_all(edges = True, nodes = False))
|
|
843
|
-
if self.highlight_overlay is not None:
|
|
843
|
+
if self.highlight_overlay is not None or self.mini_overlay_data is not None:
|
|
844
844
|
highlight_select = context_menu.addAction("Add highlight in network selection")
|
|
845
845
|
highlight_select.triggered.connect(self.handle_highlight_select)
|
|
846
846
|
show_remove_menu.triggered.connect(self.handle_remove_points)
|
|
@@ -3514,206 +3514,211 @@ class ImageViewerWindow(QMainWindow):
|
|
|
3514
3514
|
def update_display(self, preserve_zoom=None, dims = None, called = False, reset_resize = False, begin_paint = False):
|
|
3515
3515
|
"""Update the display with currently visible channels and highlight overlay."""
|
|
3516
3516
|
|
|
3517
|
-
|
|
3518
|
-
# Store/update the static background with current zoom level
|
|
3519
|
-
self.static_background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
3517
|
+
try:
|
|
3520
3518
|
|
|
3519
|
+
if begin_paint:
|
|
3520
|
+
# Store/update the static background with current zoom level
|
|
3521
|
+
self.static_background = self.canvas.copy_from_bbox(self.ax.bbox)
|
|
3521
3522
|
|
|
3522
|
-
self.figure.clear()
|
|
3523
3523
|
|
|
3524
|
-
|
|
3525
|
-
active_channels = [i for i in range(4) if self.channel_data[i] is not None]
|
|
3526
|
-
if dims is None:
|
|
3527
|
-
if active_channels:
|
|
3528
|
-
dims = [(self.channel_data[i].shape[1:3] if len(self.channel_data[i].shape) >= 3 else
|
|
3529
|
-
self.channel_data[i].shape) for i in active_channels]
|
|
3530
|
-
min_height = min(d[0] for d in dims)
|
|
3531
|
-
min_width = min(d[1] for d in dims)
|
|
3532
|
-
else:
|
|
3533
|
-
min_height = 1
|
|
3534
|
-
min_width = 1
|
|
3535
|
-
else:
|
|
3536
|
-
min_height = dims[0]
|
|
3537
|
-
min_width = dims[1]
|
|
3524
|
+
self.figure.clear()
|
|
3538
3525
|
|
|
3539
|
-
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
# Store current zoom limits if they exist and weren't provided
|
|
3548
|
-
|
|
3549
|
-
current_xlim, current_ylim = preserve_zoom if preserve_zoom else (None, None)
|
|
3550
|
-
|
|
3551
|
-
# Define base colors for each channel with increased intensity
|
|
3552
|
-
base_colors = self.base_colors
|
|
3553
|
-
# Set only the axes (image area) background to black
|
|
3554
|
-
self.ax.set_facecolor('black')
|
|
3555
|
-
|
|
3556
|
-
# Display each visible channel
|
|
3557
|
-
for channel in range(4):
|
|
3558
|
-
if (self.channel_visible[channel] and
|
|
3559
|
-
self.channel_data[channel] is not None):
|
|
3560
|
-
|
|
3561
|
-
# Check if we're dealing with RGB data
|
|
3562
|
-
is_rgb = len(self.channel_data[channel].shape) == 4 and (self.channel_data[channel].shape[-1] == 3 or self.channel_data[channel].shape[-1] == 4)
|
|
3563
|
-
|
|
3564
|
-
if len(self.channel_data[channel].shape) == 3 and not is_rgb:
|
|
3565
|
-
current_image = self.channel_data[channel][self.current_slice, :, :]
|
|
3566
|
-
elif is_rgb:
|
|
3567
|
-
current_image = self.channel_data[channel][self.current_slice] # Already has RGB channels
|
|
3526
|
+
# Get active channels and their dimensions
|
|
3527
|
+
active_channels = [i for i in range(4) if self.channel_data[i] is not None]
|
|
3528
|
+
if dims is None:
|
|
3529
|
+
if active_channels:
|
|
3530
|
+
dims = [(self.channel_data[i].shape[1:3] if len(self.channel_data[i].shape) >= 3 else
|
|
3531
|
+
self.channel_data[i].shape) for i in active_channels]
|
|
3532
|
+
min_height = min(d[0] for d in dims)
|
|
3533
|
+
min_width = min(d[1] for d in dims)
|
|
3568
3534
|
else:
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
alpha=0.7)
|
|
3575
|
-
elif is_rgb and self.channel_data[channel].shape[-1] == 4:
|
|
3576
|
-
self.ax.imshow(current_image) #For images that already have an alpha value and RGB, don't update alpha
|
|
3535
|
+
min_height = 1
|
|
3536
|
+
min_width = 1
|
|
3537
|
+
else:
|
|
3538
|
+
min_height = dims[0]
|
|
3539
|
+
min_width = dims[1]
|
|
3577
3540
|
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3541
|
+
# Set axes limits before displaying any images
|
|
3542
|
+
self.ax.set_xlim(-0.5, min_width - 0.5)
|
|
3543
|
+
self.ax.set_ylim(min_height - 0.5, -0.5)
|
|
3544
|
+
|
|
3545
|
+
# Create subplot with tight layout and white figure background
|
|
3546
|
+
self.figure.patch.set_facecolor('white')
|
|
3547
|
+
self.ax = self.figure.add_subplot(111)
|
|
3548
|
+
|
|
3549
|
+
# Store current zoom limits if they exist and weren't provided
|
|
3550
|
+
|
|
3551
|
+
current_xlim, current_ylim = preserve_zoom if preserve_zoom else (None, None)
|
|
3552
|
+
|
|
3553
|
+
# Define base colors for each channel with increased intensity
|
|
3554
|
+
base_colors = self.base_colors
|
|
3555
|
+
# Set only the axes (image area) background to black
|
|
3556
|
+
self.ax.set_facecolor('black')
|
|
3557
|
+
|
|
3558
|
+
# Display each visible channel
|
|
3559
|
+
for channel in range(4):
|
|
3560
|
+
if (self.channel_visible[channel] and
|
|
3561
|
+
self.channel_data[channel] is not None):
|
|
3583
3562
|
|
|
3584
|
-
#
|
|
3585
|
-
|
|
3586
|
-
vmin = img_min
|
|
3587
|
-
vmax = img_min + 1
|
|
3588
|
-
else:
|
|
3589
|
-
vmin = img_min + (img_max - img_min) * self.channel_brightness[channel]['min']
|
|
3590
|
-
vmax = img_min + (img_max - img_min) * self.channel_brightness[channel]['max']
|
|
3563
|
+
# Check if we're dealing with RGB data
|
|
3564
|
+
is_rgb = len(self.channel_data[channel].shape) == 4 and (self.channel_data[channel].shape[-1] == 3 or self.channel_data[channel].shape[-1] == 4)
|
|
3591
3565
|
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3566
|
+
if len(self.channel_data[channel].shape) == 3 and not is_rgb:
|
|
3567
|
+
current_image = self.channel_data[channel][self.current_slice, :, :]
|
|
3568
|
+
elif is_rgb:
|
|
3569
|
+
current_image = self.channel_data[channel][self.current_slice] # Already has RGB channels
|
|
3595
3570
|
else:
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
if
|
|
3599
|
-
|
|
3600
|
-
f'custom_{channel}',
|
|
3601
|
-
[(0, 0, 0, 0), # transparent for 0
|
|
3602
|
-
(0.5, 1, 0.5, 1), # light green for 1
|
|
3603
|
-
(1, 0.5, 0.5, 1)] # light red for 2
|
|
3604
|
-
)
|
|
3571
|
+
current_image = self.channel_data[channel]
|
|
3572
|
+
|
|
3573
|
+
if is_rgb and self.channel_data[channel].shape[-1] == 3:
|
|
3574
|
+
# For RGB images, just display directly without colormap
|
|
3605
3575
|
self.ax.imshow(current_image,
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
interpolation='nearest',
|
|
3611
|
-
extent=(-0.5, min_width-0.5, min_height-0.5, -0.5))
|
|
3576
|
+
alpha=0.7)
|
|
3577
|
+
elif is_rgb and self.channel_data[channel].shape[-1] == 4:
|
|
3578
|
+
self.ax.imshow(current_image) #For images that already have an alpha value and RGB, don't update alpha
|
|
3579
|
+
|
|
3612
3580
|
else:
|
|
3613
|
-
#
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
[(0,0,0,0), (*color,1)]
|
|
3618
|
-
)
|
|
3581
|
+
# Regular channel processing with colormap
|
|
3582
|
+
# Calculate brightness/contrast limits from entire volume
|
|
3583
|
+
img_min = self.min_max[channel][0]
|
|
3584
|
+
img_max = self.min_max[channel][1]
|
|
3619
3585
|
|
|
3620
|
-
#
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
|
|
3637
|
-
|
|
3638
|
-
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
3647
|
-
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
# Draw line if both points are on current slice
|
|
3699
|
-
if z1 == z2 == self.current_slice:
|
|
3700
|
-
self.ax.plot([x1, x2], [y1, y2], 'r--', alpha=0.5)
|
|
3701
|
-
|
|
3702
|
-
if active_channels:
|
|
3703
|
-
self.ax.set_xlim(-0.5, min_width - 0.5)
|
|
3704
|
-
self.ax.set_ylim(min_height - 0.5, -0.5)
|
|
3586
|
+
# Calculate vmin and vmax, ensuring we don't get a zero range
|
|
3587
|
+
if img_min == img_max:
|
|
3588
|
+
vmin = img_min
|
|
3589
|
+
vmax = img_min + 1
|
|
3590
|
+
else:
|
|
3591
|
+
vmin = img_min + (img_max - img_min) * self.channel_brightness[channel]['min']
|
|
3592
|
+
vmax = img_min + (img_max - img_min) * self.channel_brightness[channel]['max']
|
|
3593
|
+
|
|
3594
|
+
# Normalize the image safely
|
|
3595
|
+
if vmin == vmax:
|
|
3596
|
+
normalized_image = np.zeros_like(current_image)
|
|
3597
|
+
else:
|
|
3598
|
+
normalized_image = np.clip((current_image - vmin) / (vmax - vmin), 0, 1)
|
|
3599
|
+
|
|
3600
|
+
if channel == 2 and self.machine_window is not None:
|
|
3601
|
+
custom_cmap = LinearSegmentedColormap.from_list(
|
|
3602
|
+
f'custom_{channel}',
|
|
3603
|
+
[(0, 0, 0, 0), # transparent for 0
|
|
3604
|
+
(0.5, 1, 0.5, 1), # light green for 1
|
|
3605
|
+
(1, 0.5, 0.5, 1)] # light red for 2
|
|
3606
|
+
)
|
|
3607
|
+
self.ax.imshow(current_image,
|
|
3608
|
+
cmap=custom_cmap,
|
|
3609
|
+
vmin=0,
|
|
3610
|
+
vmax=2,
|
|
3611
|
+
alpha=0.7,
|
|
3612
|
+
interpolation='nearest',
|
|
3613
|
+
extent=(-0.5, min_width-0.5, min_height-0.5, -0.5))
|
|
3614
|
+
else:
|
|
3615
|
+
# Create custom colormap with higher intensity
|
|
3616
|
+
color = base_colors[channel]
|
|
3617
|
+
custom_cmap = LinearSegmentedColormap.from_list(
|
|
3618
|
+
f'custom_{channel}',
|
|
3619
|
+
[(0,0,0,0), (*color,1)]
|
|
3620
|
+
)
|
|
3621
|
+
|
|
3622
|
+
# Display the image with slightly higher alpha
|
|
3623
|
+
self.ax.imshow(normalized_image,
|
|
3624
|
+
alpha=0.7,
|
|
3625
|
+
cmap=custom_cmap,
|
|
3626
|
+
vmin=0,
|
|
3627
|
+
vmax=1,
|
|
3628
|
+
extent=(-0.5, min_width-0.5, min_height-0.5, -0.5))
|
|
3629
|
+
|
|
3630
|
+
if self.preview and not called:
|
|
3631
|
+
self.create_highlight_overlay_slice(self.targs, bounds = self.bounds)
|
|
3632
|
+
|
|
3633
|
+
# Add highlight overlay if it exists
|
|
3634
|
+
if self.mini_overlay and self.highlight and self.machine_window is None:
|
|
3635
|
+
highlight_cmap = LinearSegmentedColormap.from_list(
|
|
3636
|
+
'highlight',
|
|
3637
|
+
[(0, 0, 0, 0), (1, 1, 0, 1)] # yellow
|
|
3638
|
+
)
|
|
3639
|
+
self.ax.imshow(self.mini_overlay_data,
|
|
3640
|
+
cmap=highlight_cmap,
|
|
3641
|
+
alpha=0.5)
|
|
3642
|
+
elif self.highlight_overlay is not None and self.highlight and self.machine_window is None:
|
|
3643
|
+
highlight_slice = self.highlight_overlay[self.current_slice]
|
|
3644
|
+
highlight_cmap = LinearSegmentedColormap.from_list(
|
|
3645
|
+
'highlight',
|
|
3646
|
+
[(0, 0, 0, 0), (1, 1, 0, 1)] # yellow
|
|
3647
|
+
)
|
|
3648
|
+
self.ax.imshow(highlight_slice,
|
|
3649
|
+
cmap=highlight_cmap,
|
|
3650
|
+
alpha=0.5)
|
|
3651
|
+
elif self.highlight_overlay is not None and self.highlight:
|
|
3652
|
+
highlight_slice = self.highlight_overlay[self.current_slice]
|
|
3653
|
+
highlight_cmap = LinearSegmentedColormap.from_list(
|
|
3654
|
+
'highlight',
|
|
3655
|
+
[(0, 0, 0, 0), # transparent for 0
|
|
3656
|
+
(1, 1, 0, 1), # bright yellow for 1
|
|
3657
|
+
(0, 0.7, 1, 1)] # cool blue for 2
|
|
3658
|
+
)
|
|
3659
|
+
self.ax.imshow(highlight_slice,
|
|
3660
|
+
cmap=highlight_cmap,
|
|
3661
|
+
vmin=0,
|
|
3662
|
+
vmax=2, # Important: set vmax to 2 to accommodate both values
|
|
3663
|
+
alpha=0.5)
|
|
3705
3664
|
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
self.ax.
|
|
3712
|
-
self.ax.
|
|
3713
|
-
|
|
3714
|
-
|
|
3665
|
+
|
|
3666
|
+
|
|
3667
|
+
|
|
3668
|
+
# Style the axes
|
|
3669
|
+
self.ax.set_xlabel('X')
|
|
3670
|
+
self.ax.set_ylabel('Y')
|
|
3671
|
+
self.ax.set_title(f'Slice {self.current_slice}')
|
|
3672
|
+
|
|
3673
|
+
# Make axis labels and ticks black for visibility against white background
|
|
3674
|
+
self.ax.xaxis.label.set_color('black')
|
|
3675
|
+
self.ax.yaxis.label.set_color('black')
|
|
3676
|
+
self.ax.title.set_color('black')
|
|
3677
|
+
self.ax.tick_params(colors='black')
|
|
3678
|
+
for spine in self.ax.spines.values():
|
|
3679
|
+
spine.set_color('black')
|
|
3680
|
+
|
|
3681
|
+
# Adjust the layout to ensure the plot fits well in the figure
|
|
3682
|
+
self.figure.tight_layout()
|
|
3683
|
+
|
|
3684
|
+
# Redraw measurement points and their labels
|
|
3685
|
+
for point in self.measurement_points:
|
|
3686
|
+
x1, y1, z1 = point['point1']
|
|
3687
|
+
x2, y2, z2 = point['point2']
|
|
3688
|
+
pair_idx = point['pair_index']
|
|
3689
|
+
|
|
3690
|
+
# Draw points and labels if they're on current slice
|
|
3691
|
+
if z1 == self.current_slice:
|
|
3692
|
+
self.ax.plot(x1, y1, 'yo', markersize=8)
|
|
3693
|
+
self.ax.text(x1, y1+5, str(pair_idx),
|
|
3694
|
+
color='white', ha='center', va='bottom')
|
|
3695
|
+
if z2 == self.current_slice:
|
|
3696
|
+
self.ax.plot(x2, y2, 'yo', markersize=8)
|
|
3697
|
+
self.ax.text(x2, y2+5, str(pair_idx),
|
|
3698
|
+
color='white', ha='center', va='bottom')
|
|
3699
|
+
|
|
3700
|
+
# Draw line if both points are on current slice
|
|
3701
|
+
if z1 == z2 == self.current_slice:
|
|
3702
|
+
self.ax.plot([x1, x2], [y1, y2], 'r--', alpha=0.5)
|
|
3715
3703
|
|
|
3716
|
-
|
|
3704
|
+
if active_channels:
|
|
3705
|
+
self.ax.set_xlim(-0.5, min_width - 0.5)
|
|
3706
|
+
self.ax.set_ylim(min_height - 0.5, -0.5)
|
|
3707
|
+
|
|
3708
|
+
if self.resizing:
|
|
3709
|
+
self.original_xlim = self.ax.get_xlim()
|
|
3710
|
+
self.original_ylim = self.ax.get_ylim()
|
|
3711
|
+
# Restore zoom limits if they existed
|
|
3712
|
+
if current_xlim is not None and current_ylim is not None:
|
|
3713
|
+
self.ax.set_xlim(current_xlim)
|
|
3714
|
+
self.ax.set_ylim(current_ylim)
|
|
3715
|
+
if reset_resize:
|
|
3716
|
+
self.resizing = False
|
|
3717
|
+
|
|
3718
|
+
self.canvas.draw()
|
|
3719
|
+
|
|
3720
|
+
except:
|
|
3721
|
+
pass
|
|
3717
3722
|
|
|
3718
3723
|
def update_display_slice(self, channel, preserve_zoom=None):
|
|
3719
3724
|
"""Ultra minimal update that only changes the paint channel's data"""
|
|
@@ -4818,7 +4823,7 @@ class Show3dDialog(QDialog):
|
|
|
4818
4823
|
if visible:
|
|
4819
4824
|
arrays_4d.append(channel)
|
|
4820
4825
|
|
|
4821
|
-
if self.parent().highlight_overlay is not None:
|
|
4826
|
+
if self.parent().highlight_overlay is not None or self.parent().mini_overlay_data is not None:
|
|
4822
4827
|
if self.parent().mini_overlay == True:
|
|
4823
4828
|
self.parent().create_highlight_overlay(node_indices = self.parent().clicked_values['nodes'], edge_indices = self.parent().clicked_values['edges'])
|
|
4824
4829
|
arrays_3d.append(self.parent().highlight_overlay)
|
|
@@ -5048,19 +5053,24 @@ class ShuffleDialog(QDialog):
|
|
|
5048
5053
|
target_data = self.parent().channel_data[accepted_target]
|
|
5049
5054
|
|
|
5050
5055
|
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
self.parent().highlight_overlay = n3d.binarize(target_data)
|
|
5054
|
-
else:
|
|
5055
|
-
self.parent().load_channel(accepted_mode, channel_data = target_data, data = True)
|
|
5056
|
+
try:
|
|
5057
|
+
if accepted_mode == 4:
|
|
5056
5058
|
|
|
5059
|
+
self.parent().highlight_overlay = n3d.binarize(target_data)
|
|
5060
|
+
else:
|
|
5061
|
+
self.parent().load_channel(accepted_mode, channel_data = target_data, data = True)
|
|
5062
|
+
except:
|
|
5063
|
+
pass
|
|
5057
5064
|
|
|
5058
5065
|
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5066
|
+
try:
|
|
5067
|
+
if accepted_target == 4:
|
|
5068
|
+
try:
|
|
5069
|
+
self.parent().highlight_overlay = n3d.binarize(active_data)
|
|
5070
|
+
except:
|
|
5071
|
+
self.parent().highlight_overlay = None
|
|
5072
|
+
except:
|
|
5073
|
+
pass
|
|
5064
5074
|
|
|
5065
5075
|
else:
|
|
5066
5076
|
self.parent().load_channel(accepted_target, channel_data = active_data, data = True)
|
|
@@ -5862,6 +5872,9 @@ class ResizeDialog(QDialog):
|
|
|
5862
5872
|
|
|
5863
5873
|
|
|
5864
5874
|
# Process highlight overlay if it exists
|
|
5875
|
+
if self.parent().mini_overlay_data is not None:
|
|
5876
|
+
self.parent().create_highlight_overlay(self.parent().clicked_values['nodes'], self.parent().clicked_values['edges'])
|
|
5877
|
+
|
|
5865
5878
|
if self.parent().highlight_overlay is not None:
|
|
5866
5879
|
self.parent().highlight_overlay = n3d.resize(self.parent().highlight_overlay, resize, order)
|
|
5867
5880
|
if my_network.search_region is not None:
|
|
@@ -5877,6 +5890,10 @@ class ResizeDialog(QDialog):
|
|
|
5877
5890
|
resized_data = n3d.upsample_with_padding(self.parent().channel_data[channel], original_shape = self.parent().original_shape)
|
|
5878
5891
|
self.parent().load_channel(channel, channel_data=resized_data, data=True, assign_shape = False)
|
|
5879
5892
|
|
|
5893
|
+
if self.parent().mini_overlay_data is not None:
|
|
5894
|
+
|
|
5895
|
+
self.parent().create_highlight_overlay(self.parent().clicked_values['nodes'], self.parent().clicked_values['edges'])
|
|
5896
|
+
|
|
5880
5897
|
|
|
5881
5898
|
# Process highlight overlay if it exists
|
|
5882
5899
|
if self.parent().highlight_overlay is not None:
|
|
@@ -6105,6 +6122,9 @@ class ThresholdDialog(QDialog):
|
|
|
6105
6122
|
if self.parent().volume_dict[self.parent().active_channel] is None:
|
|
6106
6123
|
self.parent().volumes()
|
|
6107
6124
|
|
|
6125
|
+
if self.parent().mini_overlay_data is not None:
|
|
6126
|
+
self.parent().mini_overlay_data = None
|
|
6127
|
+
|
|
6108
6128
|
thresh_window = ThresholdWindow(self.parent(), accepted_mode)
|
|
6109
6129
|
thresh_window.show() # Non-modal window
|
|
6110
6130
|
self.highlight_overlay = None
|
|
@@ -6128,6 +6148,8 @@ class ThresholdDialog(QDialog):
|
|
|
6128
6148
|
)
|
|
6129
6149
|
return
|
|
6130
6150
|
|
|
6151
|
+
if self.parent().mini_overlay_data is not None:
|
|
6152
|
+
self.parent().mini_overlay_data = None
|
|
6131
6153
|
|
|
6132
6154
|
self.parent().machine_window = MachineWindow(self.parent())
|
|
6133
6155
|
self.parent().machine_window.show() # Non-modal window
|
|
@@ -6774,6 +6796,7 @@ class ThresholdWindow(QMainWindow):
|
|
|
6774
6796
|
self.histo_list = self.parent().channel_data[self.parent().active_channel].flatten().tolist()
|
|
6775
6797
|
self.bounds = True
|
|
6776
6798
|
self.parent().bounds = True
|
|
6799
|
+
|
|
6777
6800
|
|
|
6778
6801
|
# Create matplotlib figure
|
|
6779
6802
|
fig = Figure(figsize=(5, 4))
|
|
@@ -1099,8 +1099,11 @@ class InteractiveSegmenter:
|
|
|
1099
1099
|
def cleanup(self):
|
|
1100
1100
|
"""Clean up GPU memory"""
|
|
1101
1101
|
if self.use_gpu:
|
|
1102
|
-
|
|
1103
|
-
|
|
1102
|
+
try:
|
|
1103
|
+
cp.get_default_memory_pool().free_all_blocks()
|
|
1104
|
+
torch.cuda.empty_cache()
|
|
1105
|
+
except:
|
|
1106
|
+
pass
|
|
1104
1107
|
|
|
1105
1108
|
def train_batch(self, foreground_array, speed = True, use_gpu = False, use_two = False):
|
|
1106
1109
|
"""Train directly on foreground and background arrays"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: nettracer3d
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
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,6 +44,6 @@ 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.
|
|
47
|
+
-- Version 0.6.0 updates --
|
|
48
48
|
|
|
49
|
-
1. Bug fixes
|
|
49
|
+
1. Bug fixes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|