nettracer3d 0.7.6__py3-none-any.whl → 0.7.7__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/community_extractor.py +13 -29
- nettracer3d/excelotron.py +1669 -0
- nettracer3d/modularity.py +6 -9
- nettracer3d/neighborhoods.py +223 -0
- nettracer3d/nettracer.py +314 -13
- nettracer3d/nettracer_gui.py +583 -46
- nettracer3d/proximity.py +89 -9
- nettracer3d/smart_dilate.py +20 -15
- {nettracer3d-0.7.6.dist-info → nettracer3d-0.7.7.dist-info}/METADATA +4 -3
- nettracer3d-0.7.7.dist-info/RECORD +23 -0
- {nettracer3d-0.7.6.dist-info → nettracer3d-0.7.7.dist-info}/WHEEL +1 -1
- nettracer3d-0.7.6.dist-info/RECORD +0 -21
- {nettracer3d-0.7.6.dist-info → nettracer3d-0.7.7.dist-info}/entry_points.txt +0 -0
- {nettracer3d-0.7.6.dist-info → nettracer3d-0.7.7.dist-info}/licenses/LICENSE +0 -0
- {nettracer3d-0.7.6.dist-info → nettracer3d-0.7.7.dist-info}/top_level.txt +0 -0
nettracer3d/nettracer_gui.py
CHANGED
|
@@ -5,7 +5,7 @@ from PyQt6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QG
|
|
|
5
5
|
QFormLayout, QLineEdit, QPushButton, QFileDialog,
|
|
6
6
|
QLabel, QComboBox, QMessageBox, QTableView, QInputDialog,
|
|
7
7
|
QMenu, QTabWidget, QGroupBox)
|
|
8
|
-
from PyQt6.QtCore import (QPoint, Qt, QAbstractTableModel, QTimer, QThread, pyqtSignal)
|
|
8
|
+
from PyQt6.QtCore import (QPoint, Qt, QAbstractTableModel, QTimer, QThread, pyqtSignal, QObject, QCoreApplication)
|
|
9
9
|
import numpy as np
|
|
10
10
|
import time
|
|
11
11
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
|
|
@@ -26,6 +26,7 @@ from concurrent.futures import ThreadPoolExecutor
|
|
|
26
26
|
from functools import partial
|
|
27
27
|
from nettracer3d import segmenter
|
|
28
28
|
from nettracer3d import segmenter_GPU
|
|
29
|
+
from nettracer3d import excelotron
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
|
|
@@ -409,6 +410,11 @@ class ImageViewerWindow(QMainWindow):
|
|
|
409
410
|
self.mini_overlay = False # If the program is currently drawing the overlay by frame this will be true
|
|
410
411
|
self.mini_overlay_data = None #Actual data for mini overlay
|
|
411
412
|
self.mini_thresh = (500*500*500) # Array volume to start using mini overlays for
|
|
413
|
+
self.shape = None
|
|
414
|
+
|
|
415
|
+
self.excel_manager = ExcelotronManager(self)
|
|
416
|
+
self.excel_manager.data_received.connect(self.handle_excel_data)
|
|
417
|
+
self.prev_coms = None
|
|
412
418
|
|
|
413
419
|
def start_left_scroll(self):
|
|
414
420
|
"""Start scrolling left when left arrow is pressed."""
|
|
@@ -2680,6 +2686,8 @@ class ImageViewerWindow(QMainWindow):
|
|
|
2680
2686
|
load_action.triggered.connect(lambda checked, ch=i: self.load_channel(ch))
|
|
2681
2687
|
load_action = load_menu.addAction("Load Network")
|
|
2682
2688
|
load_action.triggered.connect(self.load_network)
|
|
2689
|
+
load_action = load_menu.addAction("Load From Excel Helper")
|
|
2690
|
+
load_action.triggered.connect(self.launch_excelotron)
|
|
2683
2691
|
misc_menu = load_menu.addMenu("Load Misc Properties")
|
|
2684
2692
|
load_action = misc_menu.addAction("Load Node IDs")
|
|
2685
2693
|
load_action.triggered.connect(lambda: self.load_misc('Node Identities'))
|
|
@@ -2696,10 +2704,14 @@ class ImageViewerWindow(QMainWindow):
|
|
|
2696
2704
|
network_menu = analysis_menu.addMenu("Network")
|
|
2697
2705
|
netshow_action = network_menu.addAction("Show Network")
|
|
2698
2706
|
netshow_action.triggered.connect(self.show_netshow_dialog)
|
|
2699
|
-
partition_action = network_menu.addAction("Community Partition +Generic Community Stats")
|
|
2707
|
+
partition_action = network_menu.addAction("Community Partition + Generic Community Stats")
|
|
2700
2708
|
partition_action.triggered.connect(self.show_partition_dialog)
|
|
2701
|
-
com_identity_action = network_menu.addAction("Identity Makeup of Network Communities (
|
|
2709
|
+
com_identity_action = network_menu.addAction("Identity Makeup of Network Communities (and UMAP)")
|
|
2702
2710
|
com_identity_action.triggered.connect(self.handle_com_id)
|
|
2711
|
+
com_neighbor_action = network_menu.addAction("Convert Network Communities into Neighborhoods?")
|
|
2712
|
+
com_neighbor_action.triggered.connect(self.handle_com_neighbor)
|
|
2713
|
+
com_cell_action = network_menu.addAction("Create Communities Based on Cuboidal Proximity Cells?")
|
|
2714
|
+
com_cell_action.triggered.connect(self.handle_com_cell)
|
|
2703
2715
|
stats_menu = analysis_menu.addMenu("Stats")
|
|
2704
2716
|
allstats_action = stats_menu.addAction("Calculate Generic Network Stats")
|
|
2705
2717
|
allstats_action.triggered.connect(self.stats)
|
|
@@ -2768,6 +2780,8 @@ class ImageViewerWindow(QMainWindow):
|
|
|
2768
2780
|
thresh_action.triggered.connect(self.show_thresh_dialog)
|
|
2769
2781
|
mask_action = image_menu.addAction("Mask Channel")
|
|
2770
2782
|
mask_action.triggered.connect(self.show_mask_dialog)
|
|
2783
|
+
crop_action = image_menu.addAction("Crop Channels")
|
|
2784
|
+
crop_action.triggered.connect(self.show_crop_dialog)
|
|
2771
2785
|
type_action = image_menu.addAction("Channel dtype")
|
|
2772
2786
|
type_action.triggered.connect(self.show_type_dialog)
|
|
2773
2787
|
skeletonize_action = image_menu.addAction("Skeletonize")
|
|
@@ -3135,6 +3149,11 @@ class ImageViewerWindow(QMainWindow):
|
|
|
3135
3149
|
dialog = MaskDialog(self)
|
|
3136
3150
|
dialog.exec()
|
|
3137
3151
|
|
|
3152
|
+
def show_crop_dialog(self):
|
|
3153
|
+
"""Show the crop dialog"""
|
|
3154
|
+
dialog = CropDialog(self)
|
|
3155
|
+
dialog.exec()
|
|
3156
|
+
|
|
3138
3157
|
def show_type_dialog(self):
|
|
3139
3158
|
"""Show the type dialog"""
|
|
3140
3159
|
try:
|
|
@@ -3553,6 +3572,103 @@ class ImageViewerWindow(QMainWindow):
|
|
|
3553
3572
|
f"Failed to load network: {str(e)}"
|
|
3554
3573
|
)
|
|
3555
3574
|
|
|
3575
|
+
def launch_excelotron(self):
|
|
3576
|
+
"""Method to launch Excelotron - call this from a button or menu"""
|
|
3577
|
+
self.excel_manager.launch()
|
|
3578
|
+
|
|
3579
|
+
def close_excelotron(self):
|
|
3580
|
+
"""Method to close Excelotron"""
|
|
3581
|
+
self.excel_manager.close()
|
|
3582
|
+
|
|
3583
|
+
def handle_excel_data(self, data_dict, property_name):
|
|
3584
|
+
"""Handle data received from Excelotron"""
|
|
3585
|
+
print(f"Received data for property: {property_name}")
|
|
3586
|
+
print(f"Data keys: {list(data_dict.keys())}")
|
|
3587
|
+
|
|
3588
|
+
if property_name == 'Node Centroids':
|
|
3589
|
+
|
|
3590
|
+
try:
|
|
3591
|
+
|
|
3592
|
+
ys = data_dict['Y']
|
|
3593
|
+
xs = data_dict['X']
|
|
3594
|
+
if 'Numerical IDs' in data_dict:
|
|
3595
|
+
nodes = data_dict['Numerical IDs']
|
|
3596
|
+
else:
|
|
3597
|
+
nodes = np.arange(1, len(ys) + 1)
|
|
3598
|
+
|
|
3599
|
+
|
|
3600
|
+
if 'Z' in data_dict:
|
|
3601
|
+
zs = data_dict['Z']
|
|
3602
|
+
else:
|
|
3603
|
+
zs = np.zeros(len(ys))
|
|
3604
|
+
|
|
3605
|
+
centroids = {}
|
|
3606
|
+
|
|
3607
|
+
for i in range(len(nodes)):
|
|
3608
|
+
|
|
3609
|
+
centroids[nodes[i]] = [int(zs[i]), int(ys[i]), int(xs[i])]
|
|
3610
|
+
|
|
3611
|
+
my_network.node_centroids = centroids
|
|
3612
|
+
|
|
3613
|
+
self.format_for_upperright_table(my_network.node_centroids, 'NodeID', ['Z', 'Y', 'X'], 'Node Centroids')
|
|
3614
|
+
|
|
3615
|
+
print("Centroids succesfully set")
|
|
3616
|
+
|
|
3617
|
+
except Exception as e:
|
|
3618
|
+
print(f"Error: {e}")
|
|
3619
|
+
|
|
3620
|
+
elif property_name == 'Node Identities':
|
|
3621
|
+
|
|
3622
|
+
try:
|
|
3623
|
+
|
|
3624
|
+
idens = data_dict['Identity Column']
|
|
3625
|
+
|
|
3626
|
+
if 'Numerical IDs' in data_dict:
|
|
3627
|
+
nodes = data_dict['Numerical IDs']
|
|
3628
|
+
else:
|
|
3629
|
+
nodes = np.arange(1, len(idens) + 1)
|
|
3630
|
+
|
|
3631
|
+
identities = {}
|
|
3632
|
+
|
|
3633
|
+
|
|
3634
|
+
for i in range(len(nodes)):
|
|
3635
|
+
|
|
3636
|
+
identities[nodes[i]] = str(idens[i])
|
|
3637
|
+
|
|
3638
|
+
my_network.node_identities = identities
|
|
3639
|
+
|
|
3640
|
+
self.format_for_upperright_table(my_network.node_identities, 'NodeID', 'Identity', title = 'Node Identities')
|
|
3641
|
+
|
|
3642
|
+
print("Identities succesfully set")
|
|
3643
|
+
|
|
3644
|
+
except Exception as e:
|
|
3645
|
+
print(f"Error: {e}")
|
|
3646
|
+
|
|
3647
|
+
elif property_name == 'Node Communities':
|
|
3648
|
+
|
|
3649
|
+
try:
|
|
3650
|
+
|
|
3651
|
+
coms = data_dict['Community Identifier']
|
|
3652
|
+
|
|
3653
|
+
if 'Numerical IDs' in data_dict:
|
|
3654
|
+
nodes = data_dict['Numerical IDs']
|
|
3655
|
+
else:
|
|
3656
|
+
nodes = np.arange(1, len(coms) + 1)
|
|
3657
|
+
|
|
3658
|
+
communities = {}
|
|
3659
|
+
|
|
3660
|
+
for i in range(len(nodes)):
|
|
3661
|
+
|
|
3662
|
+
communities[nodes[i]] = [str(coms[i])]
|
|
3663
|
+
|
|
3664
|
+
my_network.communities = communities
|
|
3665
|
+
|
|
3666
|
+
self.format_for_upperright_table(my_network.communities, 'NodeID', 'CommunityID', title = 'Community Partition')
|
|
3667
|
+
|
|
3668
|
+
print("Communities succesfully set")
|
|
3669
|
+
|
|
3670
|
+
except Exception as e:
|
|
3671
|
+
print(f"Error: {e}")
|
|
3556
3672
|
|
|
3557
3673
|
|
|
3558
3674
|
def set_active_channel(self, index):
|
|
@@ -3783,6 +3899,8 @@ class ImageViewerWindow(QMainWindow):
|
|
|
3783
3899
|
except:
|
|
3784
3900
|
pass
|
|
3785
3901
|
|
|
3902
|
+
self.shape = self.channel_data[channel_index].shape
|
|
3903
|
+
|
|
3786
3904
|
self.update_display(reset_resize = reset_resize)
|
|
3787
3905
|
|
|
3788
3906
|
|
|
@@ -4283,19 +4401,19 @@ class ImageViewerWindow(QMainWindow):
|
|
|
4283
4401
|
dialog.exec()
|
|
4284
4402
|
|
|
4285
4403
|
def handle_com_id(self):
|
|
4286
|
-
if my_network.node_identities is None:
|
|
4287
|
-
print("Node identities must be set")
|
|
4288
4404
|
|
|
4289
|
-
|
|
4290
|
-
|
|
4405
|
+
dialog = ComIdDialog(self)
|
|
4406
|
+
dialog.exec()
|
|
4291
4407
|
|
|
4292
|
-
|
|
4293
|
-
return
|
|
4408
|
+
def handle_com_neighbor(self):
|
|
4294
4409
|
|
|
4295
|
-
|
|
4410
|
+
dialog = ComNeighborDialog(self)
|
|
4411
|
+
dialog.exec()
|
|
4296
4412
|
|
|
4297
|
-
|
|
4413
|
+
def handle_com_cell(self):
|
|
4298
4414
|
|
|
4415
|
+
dialog = ComCellDialog(self)
|
|
4416
|
+
dialog.exec()
|
|
4299
4417
|
|
|
4300
4418
|
def show_radial_dialog(self):
|
|
4301
4419
|
dialog = RadialDialog(self)
|
|
@@ -4346,6 +4464,21 @@ class ImageViewerWindow(QMainWindow):
|
|
|
4346
4464
|
dialog = CodeDialog(self, sort = sort)
|
|
4347
4465
|
dialog.exec()
|
|
4348
4466
|
|
|
4467
|
+
def closeEvent(self, event):
|
|
4468
|
+
"""Override closeEvent to close all windows when main window closes"""
|
|
4469
|
+
|
|
4470
|
+
# Close all Qt windows
|
|
4471
|
+
QApplication.closeAllWindows()
|
|
4472
|
+
|
|
4473
|
+
# Close all matplotlib figures
|
|
4474
|
+
plt.close('all')
|
|
4475
|
+
|
|
4476
|
+
# Accept the close event
|
|
4477
|
+
event.accept()
|
|
4478
|
+
|
|
4479
|
+
# Force quit the application
|
|
4480
|
+
QCoreApplication.quit()
|
|
4481
|
+
|
|
4349
4482
|
|
|
4350
4483
|
|
|
4351
4484
|
#TABLE RELATED:
|
|
@@ -5542,10 +5675,15 @@ class Show3dDialog(QDialog):
|
|
|
5542
5675
|
layout.addRow("Downsample Factor (Optional to speed up display):", self.downsample)
|
|
5543
5676
|
|
|
5544
5677
|
# Network Overlay checkbox (default True)
|
|
5545
|
-
self.cubic = QPushButton("
|
|
5678
|
+
self.cubic = QPushButton("Cubic")
|
|
5546
5679
|
self.cubic.setCheckable(True)
|
|
5547
5680
|
self.cubic.setChecked(False)
|
|
5548
5681
|
layout.addRow("Use cubic downsample (Slower but preserves shape better potentially)?", self.cubic)
|
|
5682
|
+
|
|
5683
|
+
self.box = QPushButton("Box")
|
|
5684
|
+
self.box.setCheckable(True)
|
|
5685
|
+
self.box.setChecked(False)
|
|
5686
|
+
layout.addRow("Include bounding box?", self.box)
|
|
5549
5687
|
|
|
5550
5688
|
# Add Run button
|
|
5551
5689
|
run_button = QPushButton("Show 3D")
|
|
@@ -5564,6 +5702,7 @@ class Show3dDialog(QDialog):
|
|
|
5564
5702
|
downsample = None
|
|
5565
5703
|
|
|
5566
5704
|
cubic = self.cubic.isChecked()
|
|
5705
|
+
box = self.box.isChecked()
|
|
5567
5706
|
|
|
5568
5707
|
if cubic:
|
|
5569
5708
|
order = 3
|
|
@@ -5596,7 +5735,7 @@ class Show3dDialog(QDialog):
|
|
|
5596
5735
|
arrays_3d.append(self.parent().highlight_overlay)
|
|
5597
5736
|
colors.append(color_template[4])
|
|
5598
5737
|
|
|
5599
|
-
n3d.show_3d(arrays_3d, arrays_4d, down_factor = downsample, order = order, xy_scale = my_network.xy_scale, z_scale = my_network.z_scale, colors = colors)
|
|
5738
|
+
n3d.show_3d(arrays_3d, arrays_4d, down_factor = downsample, order = order, xy_scale = my_network.xy_scale, z_scale = my_network.z_scale, colors = colors, box = box)
|
|
5600
5739
|
|
|
5601
5740
|
self.accept()
|
|
5602
5741
|
|
|
@@ -5972,7 +6111,7 @@ class PartitionDialog(QDialog):
|
|
|
5972
6111
|
dostats = self.stats.isChecked()
|
|
5973
6112
|
|
|
5974
6113
|
try:
|
|
5975
|
-
seed = int(self.seed.text()) if self.seed.text() else
|
|
6114
|
+
seed = int(self.seed.text()) if self.seed.text() else 42
|
|
5976
6115
|
except:
|
|
5977
6116
|
seed = None
|
|
5978
6117
|
|
|
@@ -5993,6 +6132,184 @@ class PartitionDialog(QDialog):
|
|
|
5993
6132
|
except Exception as e:
|
|
5994
6133
|
print(f"Error creating communities: {e}")
|
|
5995
6134
|
|
|
6135
|
+
class ComIdDialog(QDialog):
|
|
6136
|
+
|
|
6137
|
+
def __init__(self, parent=None):
|
|
6138
|
+
|
|
6139
|
+
super().__init__(parent)
|
|
6140
|
+
self.setWindowTitle("Select Mode")
|
|
6141
|
+
self.setModal(True)
|
|
6142
|
+
|
|
6143
|
+
layout = QFormLayout(self)
|
|
6144
|
+
|
|
6145
|
+
self.mode = QComboBox()
|
|
6146
|
+
self.mode.addItems(["Average Identities Per Community", "Weighted Average Identity of All Communities", ])
|
|
6147
|
+
self.mode.setCurrentIndex(0)
|
|
6148
|
+
layout.addRow("Mode", self.mode)
|
|
6149
|
+
|
|
6150
|
+
# umap checkbox (default True)
|
|
6151
|
+
self.umap = QPushButton("UMAP")
|
|
6152
|
+
self.umap.setCheckable(True)
|
|
6153
|
+
self.umap.setChecked(True)
|
|
6154
|
+
layout.addRow("Generate UMAP?:", self.umap)
|
|
6155
|
+
|
|
6156
|
+
# weighted checkbox (default True)
|
|
6157
|
+
self.label = QPushButton("Label")
|
|
6158
|
+
self.label.setCheckable(True)
|
|
6159
|
+
self.label.setChecked(False)
|
|
6160
|
+
layout.addRow("If using above - label UMAP points?:", self.label)
|
|
6161
|
+
|
|
6162
|
+
|
|
6163
|
+
# Add Run button
|
|
6164
|
+
run_button = QPushButton("Get Community ID Info")
|
|
6165
|
+
run_button.clicked.connect(self.run)
|
|
6166
|
+
layout.addWidget(run_button)
|
|
6167
|
+
|
|
6168
|
+
def run(self):
|
|
6169
|
+
|
|
6170
|
+
try:
|
|
6171
|
+
|
|
6172
|
+
if my_network.node_identities is None:
|
|
6173
|
+
print("Node identities must be set")
|
|
6174
|
+
|
|
6175
|
+
if my_network.communities is None:
|
|
6176
|
+
self.parent().show_partition_dialog()
|
|
6177
|
+
|
|
6178
|
+
if my_network.communities is None:
|
|
6179
|
+
return
|
|
6180
|
+
|
|
6181
|
+
mode = self.mode.currentIndex()
|
|
6182
|
+
|
|
6183
|
+
umap = self.umap.isChecked()
|
|
6184
|
+
label = self.label.isChecked()
|
|
6185
|
+
|
|
6186
|
+
if mode == 1:
|
|
6187
|
+
|
|
6188
|
+
info = my_network.community_id_info()
|
|
6189
|
+
|
|
6190
|
+
self.parent().format_for_upperright_table(info, 'Node Identity Type', 'Weighted Proportion in Communities', 'Weighted Average of Community Makeup')
|
|
6191
|
+
|
|
6192
|
+
else:
|
|
6193
|
+
|
|
6194
|
+
info, names = my_network.community_id_info_per_com(umap = umap, label = label)
|
|
6195
|
+
|
|
6196
|
+
self.parent().format_for_upperright_table(info, 'Community', names, 'Average of Community Makeup')
|
|
6197
|
+
|
|
6198
|
+
self.accept()
|
|
6199
|
+
|
|
6200
|
+
except Exception as e:
|
|
6201
|
+
|
|
6202
|
+
print(f"Error: {e}")
|
|
6203
|
+
|
|
6204
|
+
|
|
6205
|
+
|
|
6206
|
+
class ComNeighborDialog(QDialog):
|
|
6207
|
+
|
|
6208
|
+
def __init__(self, parent=None):
|
|
6209
|
+
|
|
6210
|
+
super().__init__(parent)
|
|
6211
|
+
self.setWindowTitle("Reassign Communities Based on Identity Similarity?")
|
|
6212
|
+
self.setModal(True)
|
|
6213
|
+
|
|
6214
|
+
layout = QFormLayout(self)
|
|
6215
|
+
|
|
6216
|
+
self.neighborcount = QLineEdit("5")
|
|
6217
|
+
layout.addRow("Num Neighborhoods:", self.neighborcount)
|
|
6218
|
+
|
|
6219
|
+
self.seed = QLineEdit("")
|
|
6220
|
+
layout.addRow("Clustering Seed:", self.seed)
|
|
6221
|
+
|
|
6222
|
+
self.limit = QLineEdit("")
|
|
6223
|
+
layout.addRow("Min Community Size to be grouped (Smaller communities will be placed in neighborhood 0 - does not apply if empty)", self.limit)
|
|
6224
|
+
|
|
6225
|
+
# Add Run button
|
|
6226
|
+
run_button = QPushButton("Get Neighborhoods (Note this overwrites current communities - save your coms first)")
|
|
6227
|
+
run_button.clicked.connect(self.run)
|
|
6228
|
+
layout.addWidget(run_button)
|
|
6229
|
+
|
|
6230
|
+
def run(self):
|
|
6231
|
+
|
|
6232
|
+
try:
|
|
6233
|
+
|
|
6234
|
+
if my_network.node_identities is None:
|
|
6235
|
+
print("Node identities must be set")
|
|
6236
|
+
|
|
6237
|
+
if my_network.communities is None:
|
|
6238
|
+
self.parent().show_partition_dialog()
|
|
6239
|
+
|
|
6240
|
+
if my_network.communities is None:
|
|
6241
|
+
return
|
|
6242
|
+
|
|
6243
|
+
seed = float(self.seed.text()) if self.seed.text().strip() else 42
|
|
6244
|
+
|
|
6245
|
+
limit = int(self.limit.text()) if self.limit.text().strip() else None
|
|
6246
|
+
|
|
6247
|
+
|
|
6248
|
+
neighborcount = int(self.neighborcount.text()) if self.neighborcount.text().strip() else 5
|
|
6249
|
+
|
|
6250
|
+
if self.parent().prev_coms is None:
|
|
6251
|
+
|
|
6252
|
+
self.parent().prev_coms = copy.deepcopy(my_network.communities)
|
|
6253
|
+
my_network.assign_neighborhoods(seed, neighborcount, limit = limit)
|
|
6254
|
+
else:
|
|
6255
|
+
my_network.assign_neighborhoods(seed, neighborcount, limit = limit, prev_coms = self.parent().prev_coms)
|
|
6256
|
+
|
|
6257
|
+
self.parent().format_for_upperright_table(my_network.communities, 'NodeID', 'NeighborhoodID', title = 'Neighborhood Partition')
|
|
6258
|
+
|
|
6259
|
+
print("Neighborhoods have been assigned to communities based on similarity")
|
|
6260
|
+
|
|
6261
|
+
self.accept()
|
|
6262
|
+
|
|
6263
|
+
except Exception as e:
|
|
6264
|
+
|
|
6265
|
+
print(f"Error assigning neighborhoods: {e}")
|
|
6266
|
+
|
|
6267
|
+
class ComCellDialog(QDialog):
|
|
6268
|
+
|
|
6269
|
+
def __init__(self, parent=None):
|
|
6270
|
+
|
|
6271
|
+
super().__init__(parent)
|
|
6272
|
+
self.setWindowTitle("Assign Communities Based on Proximity Within Cuboidal Cells?")
|
|
6273
|
+
self.setModal(True)
|
|
6274
|
+
|
|
6275
|
+
layout = QFormLayout(self)
|
|
6276
|
+
|
|
6277
|
+
self.size = QLineEdit("")
|
|
6278
|
+
layout.addRow("Cell Size:", self.size)
|
|
6279
|
+
|
|
6280
|
+
# Add Run button
|
|
6281
|
+
run_button = QPushButton("Get Neighborhoods (Note this overwrites current communities - save your coms first)")
|
|
6282
|
+
run_button.clicked.connect(self.run)
|
|
6283
|
+
layout.addWidget(run_button)
|
|
6284
|
+
|
|
6285
|
+
def run(self):
|
|
6286
|
+
|
|
6287
|
+
try:
|
|
6288
|
+
|
|
6289
|
+
size = int(self.size.text()) if self.size.text().strip() else None
|
|
6290
|
+
|
|
6291
|
+
if size is None:
|
|
6292
|
+
return
|
|
6293
|
+
|
|
6294
|
+
if my_network.node_centroids is None:
|
|
6295
|
+
self.parent().show_centroid_dialog()
|
|
6296
|
+
if my_network.node_centroids is None:
|
|
6297
|
+
return
|
|
6298
|
+
|
|
6299
|
+
my_network.community_cells(size = size)
|
|
6300
|
+
|
|
6301
|
+
self.parent().format_for_upperright_table(my_network.communities, 'NodeID', 'CommunityID')
|
|
6302
|
+
|
|
6303
|
+
self.accept()
|
|
6304
|
+
|
|
6305
|
+
except Exception as e:
|
|
6306
|
+
|
|
6307
|
+
print(f"Error: {e}")
|
|
6308
|
+
|
|
6309
|
+
|
|
6310
|
+
|
|
6311
|
+
|
|
6312
|
+
|
|
5996
6313
|
|
|
5997
6314
|
|
|
5998
6315
|
class RadialDialog(QDialog):
|
|
@@ -7316,7 +7633,7 @@ class SLabelDialog(QDialog):
|
|
|
7316
7633
|
try:
|
|
7317
7634
|
|
|
7318
7635
|
# Update both the display data and the network object
|
|
7319
|
-
binary_array = sdl.smart_label(binary_array, label_array, directory = None, GPU = GPU, predownsample = down_factor)
|
|
7636
|
+
binary_array = sdl.smart_label(binary_array, label_array, directory = None, GPU = GPU, predownsample = down_factor, remove_template = True)
|
|
7320
7637
|
|
|
7321
7638
|
label_array = sdl.invert_array(label_array)
|
|
7322
7639
|
|
|
@@ -7433,12 +7750,101 @@ class ThresholdDialog(QDialog):
|
|
|
7433
7750
|
msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No)
|
|
7434
7751
|
return msg.exec() == QMessageBox.StandardButton.Yes
|
|
7435
7752
|
|
|
7753
|
+
class ExcelotronManager(QObject):
|
|
7754
|
+
# Signal to emit when data is received from Excelotron
|
|
7755
|
+
data_received = pyqtSignal(dict, str) # dictionary, property_name
|
|
7756
|
+
|
|
7757
|
+
def __init__(self, parent=None):
|
|
7758
|
+
super().__init__(parent)
|
|
7759
|
+
self.excelotron_window = None
|
|
7760
|
+
self.last_data = None
|
|
7761
|
+
self.last_property = None
|
|
7762
|
+
|
|
7763
|
+
def launch(self):
|
|
7764
|
+
"""Launch the Excelotron window"""
|
|
7765
|
+
|
|
7766
|
+
if self.excelotron_window is None:
|
|
7767
|
+
ExcelGUIClass = excelotron.main(standalone=False)
|
|
7768
|
+
self.excelotron_window = ExcelGUIClass()
|
|
7769
|
+
self.excelotron_window.data_exported.connect(self._on_data_exported)
|
|
7770
|
+
# Connect to both close event and destroyed signal
|
|
7771
|
+
self.excelotron_window.destroyed.connect(self._on_window_destroyed)
|
|
7772
|
+
self.excelotron_window.closeEvent = self._create_close_handler(self.excelotron_window.closeEvent)
|
|
7773
|
+
self.excelotron_window.show()
|
|
7774
|
+
else:
|
|
7775
|
+
self.excelotron_window.raise_()
|
|
7776
|
+
self.excelotron_window.activateWindow()
|
|
7777
|
+
|
|
7778
|
+
def _create_close_handler(self, original_close_event):
|
|
7779
|
+
"""Create a close event handler that cleans up properly"""
|
|
7780
|
+
def close_handler(event):
|
|
7781
|
+
self._cleanup_window()
|
|
7782
|
+
original_close_event(event)
|
|
7783
|
+
return close_handler
|
|
7784
|
+
|
|
7785
|
+
def close(self):
|
|
7786
|
+
"""Close the Excelotron window"""
|
|
7787
|
+
if self.excelotron_window is not None:
|
|
7788
|
+
self.excelotron_window.close()
|
|
7789
|
+
self._cleanup_window()
|
|
7790
|
+
|
|
7791
|
+
def _cleanup_window(self):
|
|
7792
|
+
"""Properly cleanup the window reference"""
|
|
7793
|
+
if self.excelotron_window is not None:
|
|
7794
|
+
try:
|
|
7795
|
+
# Disconnect all signals to prevent issues
|
|
7796
|
+
self.excelotron_window.data_exported.disconnect()
|
|
7797
|
+
self.excelotron_window.destroyed.disconnect()
|
|
7798
|
+
except:
|
|
7799
|
+
pass # Ignore if already disconnected
|
|
7800
|
+
|
|
7801
|
+
# Schedule for deletion
|
|
7802
|
+
self.excelotron_window.deleteLater()
|
|
7803
|
+
self.excelotron_window = None
|
|
7804
|
+
|
|
7805
|
+
def is_open(self):
|
|
7806
|
+
"""Check if Excelotron window is open"""
|
|
7807
|
+
is_open = self.excelotron_window is not None
|
|
7808
|
+
return is_open
|
|
7809
|
+
|
|
7810
|
+
def _on_data_exported(self, data_dict, property_name):
|
|
7811
|
+
"""Internal slot to handle data from Excelotron"""
|
|
7812
|
+
self.last_data = data_dict
|
|
7813
|
+
self.last_property = property_name
|
|
7814
|
+
# Re-emit the signal for parent to handle
|
|
7815
|
+
self.data_received.emit(data_dict, property_name)
|
|
7816
|
+
|
|
7817
|
+
def _on_window_destroyed(self):
|
|
7818
|
+
"""Handle when the Excelotron window is destroyed/closed"""
|
|
7819
|
+
self.excelotron_window = None
|
|
7820
|
+
|
|
7821
|
+
def get_last_data(self):
|
|
7822
|
+
"""Get the last exported data"""
|
|
7823
|
+
return self.last_data, self.last_property
|
|
7436
7824
|
|
|
7437
7825
|
class MachineWindow(QMainWindow):
|
|
7438
7826
|
|
|
7439
7827
|
def __init__(self, parent=None, GPU = False):
|
|
7440
7828
|
super().__init__(parent)
|
|
7441
7829
|
|
|
7830
|
+
if self.parent().active_channel == 0:
|
|
7831
|
+
if self.parent().channel_data[0] is not None:
|
|
7832
|
+
try:
|
|
7833
|
+
active_data = self.parent().channel_data[0]
|
|
7834
|
+
act_channel = 0
|
|
7835
|
+
except:
|
|
7836
|
+
active_data = self.parent().channel_data[1]
|
|
7837
|
+
act_channel = 1
|
|
7838
|
+
else:
|
|
7839
|
+
active_data = self.parent().channel_data[1]
|
|
7840
|
+
act_channel = 1
|
|
7841
|
+
|
|
7842
|
+
try:
|
|
7843
|
+
array1 = np.zeros_like(active_data).astype(np.uint8)
|
|
7844
|
+
except:
|
|
7845
|
+
print("No data in nodes channel")
|
|
7846
|
+
return
|
|
7847
|
+
|
|
7442
7848
|
self.setWindowTitle("Threshold")
|
|
7443
7849
|
|
|
7444
7850
|
# Create central widget and layout
|
|
@@ -7460,25 +7866,6 @@ class MachineWindow(QMainWindow):
|
|
|
7460
7866
|
|
|
7461
7867
|
self.parent().pen_button.setEnabled(False)
|
|
7462
7868
|
|
|
7463
|
-
|
|
7464
|
-
if self.parent().active_channel == 0:
|
|
7465
|
-
if self.parent().channel_data[0] is not None:
|
|
7466
|
-
try:
|
|
7467
|
-
active_data = self.parent().channel_data[0]
|
|
7468
|
-
act_channel = 0
|
|
7469
|
-
except:
|
|
7470
|
-
active_data = self.parent().channel_data[1]
|
|
7471
|
-
act_channel = 1
|
|
7472
|
-
else:
|
|
7473
|
-
active_data = self.parent().channel_data[1]
|
|
7474
|
-
act_channel = 1
|
|
7475
|
-
|
|
7476
|
-
try:
|
|
7477
|
-
array1 = np.zeros_like(active_data).astype(np.uint8)
|
|
7478
|
-
except:
|
|
7479
|
-
print("No data in nodes channel")
|
|
7480
|
-
return
|
|
7481
|
-
|
|
7482
7869
|
array3 = np.zeros_like(active_data).astype(np.uint8)
|
|
7483
7870
|
self.parent().highlight_overlay = array3 #Clear this out for the segmenter to use
|
|
7484
7871
|
|
|
@@ -8863,6 +9250,91 @@ class MaskDialog(QDialog):
|
|
|
8863
9250
|
except Exception as e:
|
|
8864
9251
|
print(f"Error masking: {e}")
|
|
8865
9252
|
|
|
9253
|
+
class CropDialog(QDialog):
|
|
9254
|
+
|
|
9255
|
+
def __init__(self, parent=None):
|
|
9256
|
+
|
|
9257
|
+
try:
|
|
9258
|
+
|
|
9259
|
+
super().__init__(parent)
|
|
9260
|
+
self.setWindowTitle("Crop Image?")
|
|
9261
|
+
self.setModal(True)
|
|
9262
|
+
|
|
9263
|
+
layout = QFormLayout(self)
|
|
9264
|
+
|
|
9265
|
+
self.xmin = QLineEdit("0")
|
|
9266
|
+
layout.addRow("X Min", self.xmin)
|
|
9267
|
+
|
|
9268
|
+
self.xmax = QLineEdit(f"{self.parent().shape[2]}")
|
|
9269
|
+
layout.addRow("X Max", self.xmax)
|
|
9270
|
+
|
|
9271
|
+
self.ymin = QLineEdit("0")
|
|
9272
|
+
layout.addRow("Y Min", self.ymin)
|
|
9273
|
+
|
|
9274
|
+
self.ymax = QLineEdit(f"{self.parent().shape[1]}")
|
|
9275
|
+
layout.addRow("Y Max", self.ymax)
|
|
9276
|
+
|
|
9277
|
+
self.zmin = QLineEdit("0")
|
|
9278
|
+
layout.addRow("Z Min", self.zmin)
|
|
9279
|
+
|
|
9280
|
+
self.zmax = QLineEdit(f"{self.parent().shape[0]}")
|
|
9281
|
+
layout.addRow("Z Max", self.zmax)
|
|
9282
|
+
|
|
9283
|
+
# Add Run button
|
|
9284
|
+
run_button = QPushButton("Run")
|
|
9285
|
+
run_button.clicked.connect(self.run)
|
|
9286
|
+
layout.addRow(run_button)
|
|
9287
|
+
|
|
9288
|
+
except:
|
|
9289
|
+
pass
|
|
9290
|
+
|
|
9291
|
+
def run(self):
|
|
9292
|
+
|
|
9293
|
+
try:
|
|
9294
|
+
|
|
9295
|
+
xmin = int(self.xmin.text()) if self.xmin.text() else 0
|
|
9296
|
+
ymin = int(self.ymin.text()) if self.ymin.text() else 0
|
|
9297
|
+
zmin = int(self.zmin.text()) if self.zmin.text() else 0
|
|
9298
|
+
xmax = int(self.xmax.text()) if self.xmax.text() else self.parent().shape[2]
|
|
9299
|
+
ymax = int(self.ymax.text()) if self.xmax.text() else self.parent().shape[1]
|
|
9300
|
+
zmax = int(self.zmax.text()) if self.xmax.text() else self.parent().shape[0]
|
|
9301
|
+
|
|
9302
|
+
args = xmin, ymin, zmin, xmax, ymax, zmax
|
|
9303
|
+
|
|
9304
|
+
for i, array in enumerate(self.parent().channel_data):
|
|
9305
|
+
|
|
9306
|
+
if array is None:
|
|
9307
|
+
|
|
9308
|
+
continue
|
|
9309
|
+
|
|
9310
|
+
else:
|
|
9311
|
+
|
|
9312
|
+
array = self.reslice_3d_array(array, args)
|
|
9313
|
+
|
|
9314
|
+
self.parent().load_channel(i, array, data = True)
|
|
9315
|
+
|
|
9316
|
+
self.accept()
|
|
9317
|
+
|
|
9318
|
+
except Exception as e:
|
|
9319
|
+
|
|
9320
|
+
print(f"Error cropping: {e}")
|
|
9321
|
+
|
|
9322
|
+
|
|
9323
|
+
|
|
9324
|
+
|
|
9325
|
+
|
|
9326
|
+
|
|
9327
|
+
|
|
9328
|
+
|
|
9329
|
+
def reslice_3d_array(self, array, args):
|
|
9330
|
+
"""Internal method used for the secondary algorithm to reslice subarrays around nodes."""
|
|
9331
|
+
|
|
9332
|
+
x_start, y_start, z_start, x_end, y_end, z_end = args
|
|
9333
|
+
|
|
9334
|
+
# Reslice the array
|
|
9335
|
+
array = array[z_start:z_end+1, y_start:y_end+1, x_start:x_end+1]
|
|
9336
|
+
|
|
9337
|
+
return array
|
|
8866
9338
|
|
|
8867
9339
|
|
|
8868
9340
|
class TypeDialog(QDialog):
|
|
@@ -9226,6 +9698,12 @@ class CentroidNodeDialog(QDialog):
|
|
|
9226
9698
|
|
|
9227
9699
|
layout = QFormLayout(self)
|
|
9228
9700
|
|
|
9701
|
+
# Add mode selection dropdown
|
|
9702
|
+
self.mode_selector = QComboBox()
|
|
9703
|
+
self.mode_selector.addItems(["Starting at 0", "Starting at Min Centroids (will transpose centroids)"])
|
|
9704
|
+
self.mode_selector.setCurrentIndex(0) # Default to Mode 1
|
|
9705
|
+
layout.addRow("Execution Mode:", self.mode_selector)
|
|
9706
|
+
|
|
9229
9707
|
# Add Run button
|
|
9230
9708
|
run_button = QPushButton("Run Node Generation? (Will override current nodes). Note it is presumed your nodes begin at 1, not 0.")
|
|
9231
9709
|
run_button.clicked.connect(self.run_nodes)
|
|
@@ -9255,7 +9733,18 @@ class CentroidNodeDialog(QDialog):
|
|
|
9255
9733
|
)
|
|
9256
9734
|
return
|
|
9257
9735
|
|
|
9258
|
-
|
|
9736
|
+
mode = self.mode_selector.currentIndex()
|
|
9737
|
+
|
|
9738
|
+
if mode == 0:
|
|
9739
|
+
|
|
9740
|
+
my_network.nodes = my_network.centroid_array()
|
|
9741
|
+
|
|
9742
|
+
else:
|
|
9743
|
+
|
|
9744
|
+
my_network.nodes, my_network.centroids = my_network.centroid_array(clip = True)
|
|
9745
|
+
|
|
9746
|
+
self.parent().format_for_upperright_table(my_network.node_centroids, 'NodeID', ['Z', 'Y', 'X'], 'Node Centroids')
|
|
9747
|
+
|
|
9259
9748
|
|
|
9260
9749
|
self.parent().load_channel(0, channel_data = my_network.nodes, data = True)
|
|
9261
9750
|
|
|
@@ -9338,7 +9827,13 @@ class GenNodesDialog(QDialog):
|
|
|
9338
9827
|
# Auto checkbox
|
|
9339
9828
|
self.auto = QPushButton("Auto")
|
|
9340
9829
|
self.auto.setCheckable(True)
|
|
9341
|
-
|
|
9830
|
+
try:
|
|
9831
|
+
if my_network.edges.shape[0] == 1:
|
|
9832
|
+
self.auto.setChecked(False)
|
|
9833
|
+
else:
|
|
9834
|
+
self.auto.setChecked(True)
|
|
9835
|
+
except:
|
|
9836
|
+
self.auto.setChecked(True)
|
|
9342
9837
|
rec_layout.addWidget(QLabel("Attempt to Auto Correct Skeleton Looping:"), 1, 0)
|
|
9343
9838
|
rec_layout.addWidget(self.auto, 1, 1)
|
|
9344
9839
|
|
|
@@ -9503,10 +9998,10 @@ class BranchDialog(QDialog):
|
|
|
9503
9998
|
correction_layout = QGridLayout()
|
|
9504
9999
|
|
|
9505
10000
|
# Branch Fix checkbox
|
|
9506
|
-
self.fix = QPushButton("Auto-Correct
|
|
10001
|
+
self.fix = QPushButton("Auto-Correct 1")
|
|
9507
10002
|
self.fix.setCheckable(True)
|
|
9508
10003
|
self.fix.setChecked(False)
|
|
9509
|
-
correction_layout.addWidget(QLabel("
|
|
10004
|
+
correction_layout.addWidget(QLabel("Auto-Correct Branches by Collapsing Busy Neighbors: "), 0, 0)
|
|
9510
10005
|
correction_layout.addWidget(self.fix, 0, 1)
|
|
9511
10006
|
|
|
9512
10007
|
# Fix value
|
|
@@ -9518,6 +10013,12 @@ class BranchDialog(QDialog):
|
|
|
9518
10013
|
self.seed = QLineEdit('')
|
|
9519
10014
|
correction_layout.addWidget(QLabel("Random seed for auto correction (int - optional):"), 2, 0)
|
|
9520
10015
|
correction_layout.addWidget(self.seed, 2, 1)
|
|
10016
|
+
|
|
10017
|
+
self.fix2 = QPushButton("Auto-Correct 2")
|
|
10018
|
+
self.fix2.setCheckable(True)
|
|
10019
|
+
self.fix2.setChecked(True)
|
|
10020
|
+
correction_layout.addWidget(QLabel("Auto-Correct Branches by Collapsing Internal Labels: "), 3, 0)
|
|
10021
|
+
correction_layout.addWidget(self.fix2, 3, 1)
|
|
9521
10022
|
|
|
9522
10023
|
correction_group.setLayout(correction_layout)
|
|
9523
10024
|
main_layout.addWidget(correction_group)
|
|
@@ -9587,6 +10088,7 @@ class BranchDialog(QDialog):
|
|
|
9587
10088
|
GPU = self.GPU.isChecked()
|
|
9588
10089
|
cubic = self.cubic.isChecked()
|
|
9589
10090
|
fix = self.fix.isChecked()
|
|
10091
|
+
fix2 = self.fix2.isChecked()
|
|
9590
10092
|
fix_val = float(self.fix_val.text()) if self.fix_val.text() else None
|
|
9591
10093
|
seed = int(self.seed.text()) if self.seed.text() else None
|
|
9592
10094
|
|
|
@@ -9603,6 +10105,25 @@ class BranchDialog(QDialog):
|
|
|
9603
10105
|
|
|
9604
10106
|
output = n3d.label_branches(my_network.edges, nodes = my_network.nodes, bonus_array = original_array, GPU = GPU, down_factor = down_factor, arrayshape = original_shape)
|
|
9605
10107
|
|
|
10108
|
+
if fix2:
|
|
10109
|
+
|
|
10110
|
+
temp_network = n3d.Network_3D(nodes = output)
|
|
10111
|
+
|
|
10112
|
+
max_val = np.max(temp_network.nodes)
|
|
10113
|
+
|
|
10114
|
+
background = temp_network.nodes == 0
|
|
10115
|
+
|
|
10116
|
+
background = background * max_val
|
|
10117
|
+
|
|
10118
|
+
temp_network.nodes = temp_network.nodes + background
|
|
10119
|
+
|
|
10120
|
+
del background
|
|
10121
|
+
|
|
10122
|
+
temp_network.morph_proximity(search = [3,3], fastdil = True) #Detect network of nearby branches
|
|
10123
|
+
|
|
10124
|
+
output = n3d.fix_branches(output, temp_network.network, max_val)
|
|
10125
|
+
|
|
10126
|
+
|
|
9606
10127
|
if fix:
|
|
9607
10128
|
|
|
9608
10129
|
temp_network = n3d.Network_3D(nodes = output)
|
|
@@ -9611,7 +10132,7 @@ class BranchDialog(QDialog):
|
|
|
9611
10132
|
|
|
9612
10133
|
temp_network.community_partition(weighted = False, style = 1, dostats = False, seed = seed) #Find communities with louvain, unweighted params
|
|
9613
10134
|
|
|
9614
|
-
targs = n3d.
|
|
10135
|
+
targs = n3d.fix_branches_network(temp_network.nodes, temp_network.network, temp_network.communities, fix_val)
|
|
9615
10136
|
|
|
9616
10137
|
temp_network.com_to_node(targs)
|
|
9617
10138
|
|
|
@@ -9798,6 +10319,11 @@ class ModifyDialog(QDialog):
|
|
|
9798
10319
|
self.revid.setCheckable(True)
|
|
9799
10320
|
self.revid.setChecked(False)
|
|
9800
10321
|
layout.addRow("Remove Unassigned IDs from Centroid List?:", self.revid)
|
|
10322
|
+
|
|
10323
|
+
self.remove = QPushButton("Remove Missing")
|
|
10324
|
+
self.remove.setCheckable(True)
|
|
10325
|
+
self.remove.setChecked(False)
|
|
10326
|
+
layout.addRow("Remove Any Nodes Not in Nodes Channel From Properties?:", self.remove)
|
|
9801
10327
|
|
|
9802
10328
|
# trunk checkbox (default false)
|
|
9803
10329
|
self.trunk = QPushButton("Remove Trunk")
|
|
@@ -9876,6 +10402,7 @@ class ModifyDialog(QDialog):
|
|
|
9876
10402
|
prune = self.prune.isChecked()
|
|
9877
10403
|
isolate = self.isolate.isChecked()
|
|
9878
10404
|
comcollapse = self.comcollapse.isChecked()
|
|
10405
|
+
remove = self.remove.isChecked()
|
|
9879
10406
|
|
|
9880
10407
|
|
|
9881
10408
|
if isolate and my_network.node_identities is not None:
|
|
@@ -9889,6 +10416,21 @@ class ModifyDialog(QDialog):
|
|
|
9889
10416
|
pass
|
|
9890
10417
|
|
|
9891
10418
|
|
|
10419
|
+
if remove:
|
|
10420
|
+
my_network.purge_properties()
|
|
10421
|
+
try:
|
|
10422
|
+
self.parent().format_for_upperright_table(my_network.node_centroids, 'NodeID', ['Z', 'Y', 'X'], 'Node Centroids')
|
|
10423
|
+
except:
|
|
10424
|
+
pass
|
|
10425
|
+
try:
|
|
10426
|
+
self.parent().format_for_upperright_table(my_network.node_identities, 'NodeID', 'Identity', 'Node Identities')
|
|
10427
|
+
except:
|
|
10428
|
+
pass
|
|
10429
|
+
try:
|
|
10430
|
+
self.parent().format_for_upperright_table(my_network.communities, 'NodeID', 'Community', 'Node Communities')
|
|
10431
|
+
except:
|
|
10432
|
+
pass
|
|
10433
|
+
|
|
9892
10434
|
|
|
9893
10435
|
if edgeweight:
|
|
9894
10436
|
my_network.remove_edge_weights()
|
|
@@ -10483,14 +11025,9 @@ class ProxDialog(QDialog):
|
|
|
10483
11025
|
my_network.id_overlay = my_network.draw_node_indices(directory=directory)
|
|
10484
11026
|
|
|
10485
11027
|
# Update channel data
|
|
10486
|
-
self.parent().
|
|
10487
|
-
self.parent().
|
|
11028
|
+
self.parent().load_channel(2, channel_data = my_network.network_overlay, data = True)
|
|
11029
|
+
self.parent().load_channel(3, channel_data = my_network.id_overlay, data = True)
|
|
10488
11030
|
|
|
10489
|
-
# Enable the overlay channel buttons
|
|
10490
|
-
self.parent().channel_buttons[2].setEnabled(True)
|
|
10491
|
-
self.parent().channel_buttons[3].setEnabled(True)
|
|
10492
|
-
|
|
10493
|
-
|
|
10494
11031
|
self.parent().update_display()
|
|
10495
11032
|
self.accept()
|
|
10496
11033
|
|