""" Filename: groupfunctionalconnectivity.py Description: Group functional connectivity analysis window for FLARES Author: Tyler de Zeeuw License: GPL-3.0 """ import os 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 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("") 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() 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.") 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 for idx in selected_indexes: if idx == 0: params = param_values.get(idx, {}) n_lines = params.get("n_lines", None) vmin = params.get("vmin", None) 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 else: print(f"No method defined for index {idx}")