""" Filename: participantbrain.py Description: Participant brain 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 from PySide6.QtCore import QSize from src.shared.flaresbasewidget import FlaresBaseWidget, ParameterInputDialog from src.shared.shareddata import APP_NAME class ParticipantBrainViewerWidget(FlaresBaseWidget): def __init__(self, haemo_dict, cha_dict): super().__init__("ParticipantBrainViewer") self.setWindowTitle(f"Participant Brain Viewer - {APP_NAME.upper()}") self.haemo_dict = haemo_dict self.cha_dict = cha_dict # 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 (Brain Landmarks)", "1 (Brain Activity Visualization)", # "2 (third image)", # "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("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 selected_indexes = [ int(s.split(" ")[0]) for s in self._get_checked_items(self.image_index_dropdown) ] parameterized_indexes = { 0: [ { "key": "show_optodes", "label": "Determine what is rendered above the brain. Valid values are 'sensors', 'labels', 'none', 'all'.", "default": "all", "type": str, }, { "key": "show_brodmann", "label": "Show common brodmann areas on the brain.", "default": "True", "type": bool, } ], 1: [ { "key": "show_optodes", "label": "Determine what is rendered above the brain. Valid values are 'sensors', 'labels', 'none', 'all'.", "default": "all", "type": str, }, { "key": "t_or_theta", "label": "Specify if t values or theta values should be plotted. Valid values are 't', 'theta'", "default": "theta", "type": str, }, { "key": "show_text", "label": "Display informative text on the top left corner. THIS DOES NOT WORK AND SHOULD BE LEFT AT FALSE", "default": "False", "type": bool, }, { "key": "brain_bounds", "label": "Graph Upper/Lower Limit", "default": "1.0", "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 # Pass the necessary arguments to each method for file_path in selected_file_paths: haemo_obj = self.haemo_dict.get(file_path) if selected_event: participant_events = set(haemo_obj.annotations.description) if selected_event not in participant_events: print(f"Skipping {self.participant_map[file_path]}: Event '{selected_event}' not found.") continue if haemo_obj is None: raise Exception("How did we get here?") cha = self.cha_dict.get(file_path) for idx in selected_indexes: if idx == 0: params = param_values.get(idx, {}) show_optodes = params.get("show_optodes", None) show_brodmann = params.get("show_brodmann", None) if show_optodes is None or show_brodmann is None: print(f"Missing parameters for index {idx}, skipping.") continue flares.brain_landmarks_3d(haemo_obj, show_optodes, show_brodmann) elif idx == 1: params = param_values.get(idx, {}) show_optodes = params.get("show_optodes", None) t_or_theta = params.get("t_or_theta", None) show_text = params.get("show_text", None) brain_bounds = params.get("brain_bounds", None) if show_optodes is None or t_or_theta is None or show_text is None or brain_bounds is None: print(f"Missing parameters for index {idx}, skipping.") continue flares.brain_3d_visualization(haemo_obj, cha, selected_event, t_or_theta=t_or_theta, show_optodes=show_optodes, show_text=show_text, brain_bounds=brain_bounds) else: print(f"No method defined for index {idx}")