continuation of the rewrite

This commit is contained in:
2026-07-15 21:43:22 -07:00
parent 12afc5d3bc
commit d300dfb7f7
7 changed files with 132 additions and 329 deletions
+1 -1
View File
@@ -64,7 +64,7 @@ class CrossGroupBrainImageWidget(CrossGroupUIMixin, FlaresBaseWidget):
self.setup_cross_group_ui(["0 (Contrast Image)"])
def proccess_request(self):
def process_request(self):
request = self.get_common_request_data(PARAMETERIZED_INDEXES)
if request is None:
+27 -146
View File
@@ -1,138 +1,20 @@
"""
Filename: groupfunctionalconnectivity.py
Description: Group functional connectivity analysis window for FLARES
Filename: intergroupfunctionalconnectivity.py
Description: Logic for the Inter-Group Functional Connectivity analysis window
Author: Tyler de Zeeuw
License: GPL-3.0
"""
import os
# External library imports
from PySide6.QtWidgets import QMessageBox
from PySide6.QtWidgets import QComboBox, QDialog, QGridLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget, QVBoxLayout, QLabel, QMessageBox
from PySide6.QtCore import QSize
from src.shared.flaresbasewidget import FlaresBaseWidget, ParameterInputDialog
from flares import run_group_functional_connectivity
from src.shared.flaresbasewidget import InterGroupUIMixin, FlaresBaseWidget
from src.shared.shareddata import APP_NAME
class GroupFunctionalConnectivityWidget(FlaresBaseWidget):
def __init__(self, haemo_dict, group, config_dict):
super().__init__("GroupFunctionalConnectivityWidget")
self.setWindowTitle(f"Group Functional Connectivity Viewer [BETA] - {APP_NAME.upper()}")
self.haemo_dict = haemo_dict
self.group = group
self.config_dict = config_dict
self.show_all_events = True
self._updating_checkstates = False
QMessageBox.warning(self, f"Warning - {APP_NAME.upper()}", f"Functional Connectivity is still in development and the results should currently be taken with a grain of salt. "
"By clicking OK, you accept that the images generated may not be factual.")
# Create mappings: file_path -> participant label and dropdown display text
self.participant_map = {} # file_path -> "Participant 1"
self.participant_dropdown_items = [] # "Participant 1 (filename)"
for i, file_path in enumerate(self.haemo_dict.keys(), start=1):
short_label = f"Participant {i}"
display_label = f"{short_label} ({os.path.basename(file_path)})"
self.participant_map[file_path] = short_label
self.participant_dropdown_items.append(display_label)
self.layout = QVBoxLayout(self)
self.top_bar = QHBoxLayout()
self.layout.addLayout(self.top_bar)
self.group_to_paths = {}
for file_path, group_name in self.group.items():
self.group_to_paths.setdefault(group_name, []).append(file_path)
self.group_names = sorted(self.group_to_paths.keys())
self.group_dropdown = QComboBox()
self.group_dropdown.addItem("<None Selected>")
self.group_dropdown.addItems(self.group_names)
self.group_dropdown.setCurrentIndex(0)
self.group_dropdown.currentIndexChanged.connect(self.update_participant_list_for_group)
self.participant_dropdown = self._create_multiselect_dropdown(self.participant_dropdown_items)
self.participant_dropdown.currentIndexChanged.connect(self.update_participant_dropdown_label)
self.participant_dropdown.setEnabled(False)
self.event_dropdown = QComboBox()
self.event_dropdown.addItem("<None Selected>")
self.index_texts = [
"0 (Betas)",
#"1 (Significance)",
#"2 (Brain Activity Visualization)",
# "3 (fourth image)",
]
self.image_index_dropdown = self._create_multiselect_dropdown(self.index_texts)
self.image_index_dropdown.currentIndexChanged.connect(self.update_image_index_dropdown_label)
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.show_brain_images)
self.top_bar.addWidget(QLabel("Group:"))
self.top_bar.addWidget(self.group_dropdown)
self.top_bar.addWidget(QLabel("Participants:"))
self.top_bar.addWidget(self.participant_dropdown)
self.top_bar.addWidget(QLabel("Event:"))
self.top_bar.addWidget(self.event_dropdown)
self.top_bar.addWidget(QLabel("Image Indexes:"))
self.top_bar.addWidget(self.image_index_dropdown)
self.top_bar.addWidget(self.submit_button)
self.scroll = QScrollArea()
self.scroll.setWidgetResizable(True)
self.scroll_content = QWidget()
self.grid_layout = QGridLayout(self.scroll_content)
self.scroll.setWidget(self.scroll_content)
self.layout.addWidget(self.scroll)
self.thumb_size = QSize(280, 180)
self.showMaximized()
def show_brain_images(self):
import flares as flares
selected_event = self.event_dropdown.currentText()
if selected_event == "<None Selected>":
selected_event = None
selected_display_names = self._get_checked_items(self.participant_dropdown)
selected_file_paths = []
for display_name in selected_display_names:
for fp, short_label in self.participant_map.items():
expected_display = f"{short_label} ({os.path.basename(fp)})"
if display_name == expected_display:
selected_file_paths.append(fp)
break
if selected_event:
valid_paths = []
for fp in selected_file_paths:
raw = self.haemo_dict.get(fp)
# Check if this participant actually has the event in their annotations
if raw is not None and hasattr(raw, "annotations"):
if selected_event in raw.annotations.description:
valid_paths.append(fp)
selected_file_paths = valid_paths
selected_indexes = [
int(s.split(" ")[0]) for s in self._get_checked_items(self.image_index_dropdown)
]
if not selected_file_paths:
print("No participants selected.")
return
# Only keep indexes 0 and 1 that need parameters
parameterized_indexes = {
PARAMETERIZED_INDEXES = {
0: [
{
"key": "n_lines",
@@ -149,24 +31,29 @@ class GroupFunctionalConnectivityWidget(FlaresBaseWidget):
],
}
# Inject full_text from index_texts
for idx, params_list in parameterized_indexes.items():
full_text = self.index_texts[idx] if idx < len(self.index_texts) else f"{idx} (No label found)"
for param_info in params_list:
param_info["full_text"] = full_text
indexes_needing_params = {idx: parameterized_indexes[idx] for idx in selected_indexes if idx in parameterized_indexes}
param_values = {}
if indexes_needing_params:
dialog = ParameterInputDialog(indexes_needing_params, parent=self)
if dialog.exec_() == QDialog.Accepted:
param_values = dialog.get_values()
if param_values is None:
return
else:
class InterGroupFunctionalConnectivityWidget(InterGroupUIMixin, FlaresBaseWidget):
def __init__(self, haemo_dict, group, config_dict):
super().__init__("InterGroupFunctionalConnectivity")
self.setWindowTitle(f"Inter-Group Functional Connectivity Viewer [BETA] - {APP_NAME.upper()}")
self.haemo_dict = haemo_dict
self.group = group
self.config_dict = config_dict
QMessageBox.warning(self, f"Warning - {APP_NAME.upper()}", f"Functional Connectivity is still in development and the results should currently be taken with a grain of salt. "
"By clicking OK, you accept that the images generated may not be factual.")
self.setup_inter_group_ui(["0 (Betas)",])
def process_request(self):
request = self.get_common_request_data(PARAMETERIZED_INDEXES)
if request is None:
return
(selected_event, selected_file_paths, selected_indexes, param_values,) = request
for idx in selected_indexes:
if idx == 0:
params = param_values.get(idx, {})
@@ -176,13 +63,7 @@ class GroupFunctionalConnectivityWidget(FlaresBaseWidget):
if n_lines is None or vmin is None:
print(f"Missing parameters for index {idx}, skipping.")
continue
flares.run_group_functional_connectivity(self.haemo_dict, self.config_dict, selected_file_paths, selected_event, 50, 0.5)
elif idx == 1:
pass
elif idx == 2:
pass
elif idx == 3:
pass
run_group_functional_connectivity(self.haemo_dict, self.config_dict, selected_file_paths, selected_event, 50, 0.5)
else:
print(f"No method defined for index {idx}")
+1 -1
View File
@@ -58,7 +58,7 @@ PARAMETERIZED_INDEXES = {
class ParticipantBrainViewerWidget(ParticipantUIMixin, FlaresBaseWidget):
def __init__(self, haemo_dict, cha_dict):
super().__init__("ParticipantBrainViewer")
super().__init__("ParticipantBrain")
self.setWindowTitle(f"Participant Brain Viewer - {APP_NAME.upper()}")
self.haemo_dict = haemo_dict
self.cha_dict = cha_dict
+1 -1
View File
@@ -1,6 +1,6 @@
"""
Filename: participantfoldchannels.py
Description: Participant fOLD channels analysis window for FLARES
Description: Logic for the Participant fOLD Channels analysis window
Author: Tyler de Zeeuw
License: GPL-3.0
+29 -109
View File
@@ -1,105 +1,20 @@
"""
Filename: participantfunctionalconnectivity.py
Description: Participant functional connectivity analysis window for FLARES
Description: Logic for the Participant Functional Connectivity analysis window
Author: Tyler de Zeeuw
License: GPL-3.0
"""
import os
# External library imports
from PySide6.QtWidgets import QMessageBox
from PySide6.QtWidgets import QComboBox, QDialog, QGridLayout, QHBoxLayout, QPushButton, QScrollArea, QWidget, QVBoxLayout, QLabel, QMessageBox
from PySide6.QtCore import QSize
from src.shared.flaresbasewidget import FlaresBaseWidget, ParameterInputDialog
from flares import functional_connectivity_betas, functional_connectivity_envelope, functional_connectivity_spectral_epochs, functional_connectivity_spectral_time
from src.shared.flaresbasewidget import ParticipantUIMixin, FlaresBaseWidget
from src.shared.shareddata import APP_NAME
class ParticipantFunctionalConnectivityWidget(FlaresBaseWidget):
def __init__(self, haemo_dict, epochs_dict):
super().__init__("FunctionalConnectivityWidget")
self.setWindowTitle(f"Functional Connectivity Viewer [BETA] - {APP_NAME.upper()}")
self.haemo_dict = haemo_dict
self.epochs_dict = epochs_dict
QMessageBox.warning(self, f"Warning - {APP_NAME.upper()}", f"Functional Connectivity is still in development and the results should currently be taken with a grain of salt. "
"By clicking OK, you accept that the images generated may not be factual.")
# Create mappings: file_path -> participant label and dropdown display text
self.participant_map = {} # file_path -> "Participant 1"
self.participant_dropdown_items = [] # "Participant 1 (filename)"
for i, file_path in enumerate(self.haemo_dict.keys(), start=1):
short_label = f"Participant {i}"
display_label = f"{short_label} ({os.path.basename(file_path)})"
self.participant_map[file_path] = short_label
self.participant_dropdown_items.append(display_label)
self.layout = QVBoxLayout(self)
self.top_bar = QHBoxLayout()
self.layout.addLayout(self.top_bar)
self.participant_dropdown = self._create_multiselect_dropdown(self.participant_dropdown_items)
self.participant_dropdown.currentIndexChanged.connect(self.update_participant_dropdown_label)
self.event_dropdown = QComboBox()
self.event_dropdown.addItem("<None Selected>")
self.index_texts = [
"0 (Spectral Connectivity Epochs)",
"1 (Envelope Correlation)",
"2 (Betas)",
"3 (Spectral Connectivity Epochs)",
]
self.image_index_dropdown = self._create_multiselect_dropdown(self.index_texts)
self.image_index_dropdown.currentIndexChanged.connect(self.update_image_index_dropdown_label)
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.show_brain_images)
self.top_bar.addWidget(QLabel("Participants:"))
self.top_bar.addWidget(self.participant_dropdown)
self.top_bar.addWidget(QLabel("Event:"))
self.top_bar.addWidget(self.event_dropdown)
self.top_bar.addWidget(QLabel("Image Indexes:"))
self.top_bar.addWidget(self.image_index_dropdown)
self.top_bar.addWidget(self.submit_button)
self.scroll = QScrollArea()
self.scroll.setWidgetResizable(True)
self.scroll_content = QWidget()
self.grid_layout = QGridLayout(self.scroll_content)
self.scroll.setWidget(self.scroll_content)
self.layout.addWidget(self.scroll)
self.thumb_size = QSize(280, 180)
self.showMaximized()
def show_brain_images(self):
import flares as flares
selected_event = self.event_dropdown.currentText()
if selected_event == "<None Selected>":
selected_event = None
selected_display_names = self._get_checked_items(self.participant_dropdown)
selected_file_paths = []
for display_name in selected_display_names:
for fp, short_label in self.participant_map.items():
expected_display = f"{short_label} ({os.path.basename(fp)})"
if display_name == expected_display:
selected_file_paths.append(fp)
break
selected_indexes = [
int(s.split(" ")[0]) for s in self._get_checked_items(self.image_index_dropdown)
]
parameterized_indexes = {
PARAMETERIZED_INDEXES = {
0: [
{
"key": "n_lines",
@@ -161,24 +76,29 @@ class ParticipantFunctionalConnectivityWidget(FlaresBaseWidget):
],
}
# Inject full_text from index_texts
for idx, params_list in parameterized_indexes.items():
full_text = self.index_texts[idx] if idx < len(self.index_texts) else f"{idx} (No label found)"
for param_info in params_list:
param_info["full_text"] = full_text
indexes_needing_params = {idx: parameterized_indexes[idx] for idx in selected_indexes if idx in parameterized_indexes}
param_values = {}
if indexes_needing_params:
dialog = ParameterInputDialog(indexes_needing_params, parent=self)
if dialog.exec_() == QDialog.Accepted:
param_values = dialog.get_values()
if param_values is None:
return
else:
class ParticipantFunctionalConnectivityWidget(ParticipantUIMixin, FlaresBaseWidget):
def __init__(self, haemo_dict, epochs_dict):
super().__init__("ParticipantFunctionalConnectivity")
self.setWindowTitle(f"Participant Functional Connectivity Viewer [BETA] - {APP_NAME.upper()}")
self.haemo_dict = haemo_dict
self.epochs_dict = epochs_dict
QMessageBox.warning(self, f"Warning - {APP_NAME.upper()}", f"Functional Connectivity is still in development and the results should currently be taken with a grain of salt. "
"By clicking OK, you accept that the images generated may not be factual.")
self.setup_participant_ui(["0 (Spectral Connectivity Epochs)", "1 (Envelope Correlation)", "2 (Betas)", "3 (Spectral Connectivity Epochs)",])
def process_request(self):
request = self.get_common_request_data(PARAMETERIZED_INDEXES)
if request is None:
return
(selected_event, selected_file_paths, selected_indexes, param_values,) = request
# Pass the necessary arguments to each method
for file_path in selected_file_paths:
haemo_obj = self.haemo_dict.get(file_path)
@@ -204,7 +124,7 @@ class ParticipantFunctionalConnectivityWidget(FlaresBaseWidget):
if n_lines is None or vmin is None:
print(f"Missing parameters for index {idx}, skipping.")
continue
flares.functional_connectivity_spectral_epochs(epochs_obj, n_lines, vmin)
functional_connectivity_spectral_epochs(epochs_obj, n_lines, vmin)
elif idx == 1:
params = param_values.get(idx, {})
@@ -214,7 +134,7 @@ class ParticipantFunctionalConnectivityWidget(FlaresBaseWidget):
if n_lines is None or vmin is None:
print(f"Missing parameters for index {idx}, skipping.")
continue
flares.functional_connectivity_envelope(epochs_obj, n_lines, vmin)
functional_connectivity_envelope(epochs_obj, n_lines, vmin)
elif idx == 2:
params = param_values.get(idx, {})
@@ -224,7 +144,7 @@ class ParticipantFunctionalConnectivityWidget(FlaresBaseWidget):
if n_lines is None or vmin is None:
print(f"Missing parameters for index {idx}, skipping.")
continue
flares.functional_connectivity_betas(haemo_obj, n_lines, vmin, selected_event)
functional_connectivity_betas(haemo_obj, n_lines, vmin, selected_event)
elif idx == 3:
params = param_values.get(idx, {})
@@ -234,7 +154,7 @@ class ParticipantFunctionalConnectivityWidget(FlaresBaseWidget):
if n_lines is None or vmin is None:
print(f"Missing parameters for index {idx}, skipping.")
continue
flares.functional_connectivity_spectral_time(epochs_obj, n_lines, vmin)
functional_connectivity_spectral_time(epochs_obj, n_lines, vmin)
else:
print(f"No method defined for index {idx}")
+11 -9
View File
@@ -1,15 +1,17 @@
"""
Filename: participant.py
Description: Participant analysis window for FLARES
Filename: participantimage.py
Description: Logic for the Participant Image analysis window
Author: Tyler de Zeeuw
License: GPL-3.0
"""
# Built-in Imports
import os
from pathlib import Path
from datetime import datetime
# External library imports
from PySide6.QtWidgets import QGridLayout, QHBoxLayout, QMessageBox, QPushButton, QScrollArea, QWidget, QVBoxLayout, QLabel
from PySide6.QtCore import Qt, QSize
from PySide6.QtGui import QPixmap
@@ -22,7 +24,7 @@ class ParticipantImageViewerWidget(FlaresBaseWidget):
def __init__(self, haemo_dict, fig_bytes_dict):
super().__init__("ParticipantImage")
self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
self.setWindowTitle(f"Participant Viewer - {APP_NAME.upper()}")
self.setWindowTitle(f"Participant Image Viewer - {APP_NAME.upper()}")
self.haemo_dict = haemo_dict
self.fig_bytes_dict = fig_bytes_dict
@@ -36,9 +38,9 @@ class ParticipantImageViewerWidget(FlaresBaseWidget):
self.participant_map[file_path] = short_label
self.participant_dropdown_items.append(display_label)
self.layout = QVBoxLayout(self)
self.main_layout = QVBoxLayout(self)
self.top_bar = QHBoxLayout()
self.layout.addLayout(self.top_bar)
self.main_layout.addLayout(self.top_bar)
self.participant_dropdown = self._create_multiselect_dropdown(self.participant_dropdown_items)
self.participant_dropdown.currentIndexChanged.connect(self.update_participant_dropdown_label)
@@ -58,12 +60,12 @@ class ParticipantImageViewerWidget(FlaresBaseWidget):
self.top_bar.addWidget(self.image_index_dropdown)
self.top_bar.addWidget(self.submit_button)
self.scroll = QScrollArea()
self.scroll.setWidgetResizable(True)
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.scroll_content = QWidget()
self.grid_layout = QGridLayout(self.scroll_content)
self.scroll.setWidget(self.scroll_content)
self.layout.addWidget(self.scroll)
self.scroll_area.setWidget(self.scroll_content)
self.main_layout.addWidget(self.scroll_area)
self.thumb_size = QSize(280, 180)
+1 -1
View File
@@ -1108,7 +1108,7 @@ class CrossGroupUIMixin:
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.proccess_request)
self.submit_button.clicked.connect(self.process_request)
self.top_bar.addWidget(QLabel("Group A:"))