small rewrite to impose dry principles

This commit is contained in:
2026-07-15 21:21:35 -07:00
parent ffa14693b3
commit 12afc5d3bc
14 changed files with 1825 additions and 1716 deletions
+164
View File
@@ -0,0 +1,164 @@
"""
Filename: participant.py
Description: Participant analysis window for FLARES
Author: Tyler de Zeeuw
License: GPL-3.0
"""
import os
from pathlib import Path
from datetime import datetime
from PySide6.QtWidgets import QGridLayout, QHBoxLayout, QMessageBox, QPushButton, QScrollArea, QWidget, QVBoxLayout, QLabel
from PySide6.QtCore import Qt, QSize
from PySide6.QtGui import QPixmap
from src.shared.flaresbasewidget import ClickableLabel, FlaresBaseWidget
from src.shared.shareddata import APP_NAME
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.haemo_dict = haemo_dict
self.fig_bytes_dict = fig_bytes_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)
first_fig_dict = next(iter(self.fig_bytes_dict.values()))
image_label_items = list(first_fig_dict.keys())
self.image_index_dropdown = self._create_multiselect_dropdown(image_label_items)
self.image_index_dropdown.currentIndexChanged.connect(self.update_image_index_dropdown_label)
self.submit_button = QPushButton("Submit")
self.submit_button.clicked.connect(self.show_selected_images)
self.top_bar.addWidget(QLabel("Participants:"))
self.top_bar.addWidget(self.participant_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.save_button = QPushButton("Save Displayed Images")
self.save_button.clicked.connect(self.save_displayed_images)
self.top_bar.addWidget(self.save_button)
self.showMaximized()
def show_selected_images(self):
# Clear previous images
while self.grid_layout.count():
item = self.grid_layout.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
selected_display_names = self._get_checked_items(self.participant_dropdown)
# Map from display names back to file paths
selected_file_paths = []
for display_name in selected_display_names:
# Find file_path by matching display name
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_labels = self._get_checked_items(self.image_index_dropdown)
row, col = 0, 0
for file_path in selected_file_paths:
fig_list = self.fig_bytes_dict.get(file_path, [])
participant_label = self.participant_map[file_path]
for label in selected_labels:
fig_bytes = fig_list.get(label)
if not fig_bytes:
continue
full_pixmap = QPixmap()
full_pixmap.loadFromData(fig_bytes)
thumbnail_pixmap = full_pixmap.scaled(
self.thumb_size,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation
)
container = QWidget()
hlayout = QHBoxLayout(container)
hlayout.setContentsMargins(0, 0, 0, 0)
hlayout.setSpacing(0)
hlayout.setAlignment(Qt.AlignmentFlag.AlignCenter)
image_label = ClickableLabel(full_pixmap, thumbnail_pixmap)
image_label.setToolTip(f"{participant_label}\n{label}")
hlayout.addWidget(image_label)
self.grid_layout.addWidget(container, row, col)
col += 1
if col >= 6:
col = 0
row += 1
# Update dropdown labels after display
self.update_participant_dropdown_label()
self.update_image_index_dropdown_label()
def save_displayed_images(self):
# Ensure the folder exists
save_dir = Path("individual_images")
save_dir.mkdir(exist_ok=True)
selected_display_names = self._get_checked_items(self.participant_dropdown)
selected_image_labels = self._get_checked_items(self.image_index_dropdown)
for display_name in selected_display_names:
# Match display name to file path
for file_path, short_label in self.participant_map.items():
expected_display = f"{short_label} ({os.path.basename(file_path)})"
if display_name == expected_display:
fig_dict = self.fig_bytes_dict.get(file_path, {})
for label in selected_image_labels:
if label not in fig_dict:
continue
fig_bytes = fig_dict[label]
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{os.path.basename(file_path)}_{label}_{timestamp}.png"
output_path = save_dir / filename
with open(output_path, "wb") as f:
f.write(fig_bytes)
break # file_path matched; stop loop
QMessageBox.information(self, "Save Complete", f"Images saved to {save_dir.resolve()}")