diff --git a/src/analysis/crossgroupbrainimage.py b/src/analysis/crossgroupbrainimage.py index 17d0eca..b8fb60b 100644 --- a/src/analysis/crossgroupbrainimage.py +++ b/src/analysis/crossgroupbrainimage.py @@ -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: diff --git a/src/analysis/intergroupfunctionalconnectivity.py b/src/analysis/intergroupfunctionalconnectivity.py index 2f5ac55..3ba87d1 100644 --- a/src/analysis/intergroupfunctionalconnectivity.py +++ b/src/analysis/intergroupfunctionalconnectivity.py @@ -1,171 +1,58 @@ """ -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): +PARAMETERIZED_INDEXES = { + 0: [ + { + "key": "n_lines", + "label": "", + "default": "20", + "type": int, + }, + { + "key": "vmin", + "label": "", + "default": "0.9", + "type": float, + }, + ], +} + + + +class InterGroupFunctionalConnectivityWidget(InterGroupUIMixin, FlaresBaseWidget): def __init__(self, haemo_dict, group, config_dict): - super().__init__("GroupFunctionalConnectivityWidget") - self.setWindowTitle(f"Group Functional Connectivity Viewer [BETA] - {APP_NAME.upper()}") + 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 - 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("") - 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("") - - 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() + self.setup_inter_group_ui(["0 (Betas)",]) - def show_brain_images(self): - import flares as flares - - selected_event = self.event_dropdown.currentText() - if selected_event == "": - 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.") + def process_request(self): + request = self.get_common_request_data(PARAMETERIZED_INDEXES) + if request is None: return - # Only keep indexes 0 and 1 that need parameters - parameterized_indexes = { - 0: [ - { - "key": "n_lines", - "label": "", - "default": "20", - "type": int, - }, - { - "key": "vmin", - "label": "", - "default": "0.9", - "type": float, - }, - ], - } - - # 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: - return + (selected_event, selected_file_paths, selected_indexes, param_values,) = request for idx in selected_indexes: if idx == 0: @@ -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}") + print(f"No method defined for index {idx}") \ No newline at end of file diff --git a/src/analysis/participantbrain.py b/src/analysis/participantbrain.py index 4124b52..8682cbb 100644 --- a/src/analysis/participantbrain.py +++ b/src/analysis/participantbrain.py @@ -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 diff --git a/src/analysis/participantfoldchannels.py b/src/analysis/participantfoldchannels.py index 26ba682..4f96d27 100644 --- a/src/analysis/participantfoldchannels.py +++ b/src/analysis/participantfoldchannels.py @@ -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 diff --git a/src/analysis/participantfunctionalconnectivity.py b/src/analysis/participantfunctionalconnectivity.py index a898989..02e50b3 100644 --- a/src/analysis/participantfunctionalconnectivity.py +++ b/src/analysis/participantfunctionalconnectivity.py @@ -1,183 +1,103 @@ """ 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): +PARAMETERIZED_INDEXES = { + 0: [ + { + "key": "n_lines", + "label": "", + "default": "20", + "type": int, + }, + { + "key": "vmin", + "label": "", + "default": "0.9", + "type": float, + }, + ], + 1: [ + { + "key": "n_lines", + "label": "", + "default": "20", + "type": int, + }, + { + "key": "vmin", + "label": "", + "default": "0.9", + "type": float, + }, + + ], + 2: [ + { + "key": "n_lines", + "label": "", + "default": "20", + "type": int, + }, + { + "key": "vmin", + "label": "", + "default": "0.9", + "type": float, + }, + + ], + 3: [ + { + "key": "n_lines", + "label": "", + "default": "20", + "type": int, + }, + { + "key": "vmin", + "label": "", + "default": "0.9", + "type": float, + }, + + ], +} + + + +class ParticipantFunctionalConnectivityWidget(ParticipantUIMixin, FlaresBaseWidget): def __init__(self, haemo_dict, epochs_dict): - super().__init__("FunctionalConnectivityWidget") - self.setWindowTitle(f"Functional Connectivity Viewer [BETA] - {APP_NAME.upper()}") + 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.") - # 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("") - - - 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() + self.setup_participant_ui(["0 (Spectral Connectivity Epochs)", "1 (Envelope Correlation)", "2 (Betas)", "3 (Spectral Connectivity Epochs)",]) - def show_brain_images(self): - import flares as flares - selected_event = self.event_dropdown.currentText() - if selected_event == "": - selected_event = None + def process_request(self): + request = self.get_common_request_data(PARAMETERIZED_INDEXES) + if request is None: + return - 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 = { - 0: [ - { - "key": "n_lines", - "label": "", - "default": "20", - "type": int, - }, - { - "key": "vmin", - "label": "", - "default": "0.9", - "type": float, - }, - ], - 1: [ - { - "key": "n_lines", - "label": "", - "default": "20", - "type": int, - }, - { - "key": "vmin", - "label": "", - "default": "0.9", - "type": float, - }, - - ], - 2: [ - { - "key": "n_lines", - "label": "", - "default": "20", - "type": int, - }, - { - "key": "vmin", - "label": "", - "default": "0.9", - "type": float, - }, - - ], - 3: [ - { - "key": "n_lines", - "label": "", - "default": "20", - "type": int, - }, - { - "key": "vmin", - "label": "", - "default": "0.9", - "type": float, - }, - - ], - } - - # 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: - 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: @@ -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}") \ No newline at end of file diff --git a/src/analysis/participantimage.py b/src/analysis/participantimage.py index 292bf6a..adc6aeb 100644 --- a/src/analysis/participantimage.py +++ b/src/analysis/participantimage.py @@ -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) diff --git a/src/shared/flaresbasewidget.py b/src/shared/flaresbasewidget.py index 00c292a..a752a7a 100644 --- a/src/shared/flaresbasewidget.py +++ b/src/shared/flaresbasewidget.py @@ -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:"))