fix to stats when no json file is defined
This commit is contained in:
@@ -152,8 +152,8 @@ class CrossGroupStatsWidget(CrossGroupUIMixin, FlaresBaseWidget):
|
||||
df_ind_dict: dict[str, DataFrame],
|
||||
design_matrix_dict: dict[str, DataFrame],
|
||||
contrast_results_dict: dict[str, dict[str, Any]],
|
||||
roi_channel_map_dict: dict[str, dict[str, str]],
|
||||
group_dict: dict[str, str],
|
||||
json_location: str | Path
|
||||
) -> None:
|
||||
|
||||
super().__init__("CrossGroupStats")
|
||||
@@ -163,14 +163,14 @@ class CrossGroupStatsWidget(CrossGroupUIMixin, FlaresBaseWidget):
|
||||
self.df_ind_dict = df_ind_dict
|
||||
self.design_matrix_dict = design_matrix_dict
|
||||
self.contrast_results_dict = contrast_results_dict
|
||||
# self.group_dict = group_dict
|
||||
self.json_location = json_location
|
||||
self.roi_channel_map_dict = roi_channel_map_dict
|
||||
self.group_dict = group_dict
|
||||
|
||||
self.setup_cross_group_ui(["0 (Raw ROI Comparison)", "1 (Laterality Comparison)", "2 (Contrast Comparison)",], placeholder_text=DESCRIPTION)
|
||||
|
||||
|
||||
def process_request(self):
|
||||
request = self.get_common_request_data(PARAMETERIZED_INDEXES, self.json_location, self.contrast_results_dict)
|
||||
request = self.get_common_request_data(PARAMETERIZED_INDEXES, self.df_ind_dict, self.contrast_results_dict)
|
||||
if request is None:
|
||||
return
|
||||
|
||||
@@ -200,6 +200,12 @@ class CrossGroupStatsWidget(CrossGroupUIMixin, FlaresBaseWidget):
|
||||
target_chroma = params.get("target_chroma", "hbo")
|
||||
threshold_topo = params.get("threshold_topo", False)
|
||||
|
||||
selected_roi_maps = {
|
||||
fp: self.roi_channel_map_dict[fp]
|
||||
for fp in (file_paths_a + file_paths_b)
|
||||
if fp in self.roi_channel_map_dict
|
||||
}
|
||||
|
||||
run_cross_group_second_level_analysis(
|
||||
df_roi_all=df_ind_combined, # Individual stats dataframe
|
||||
file_paths_a=file_paths_a,
|
||||
@@ -213,7 +219,7 @@ class CrossGroupStatsWidget(CrossGroupUIMixin, FlaresBaseWidget):
|
||||
correction_method=correction_method,
|
||||
target_chroma=target_chroma,
|
||||
selected_event=selected_event,
|
||||
roi_config=self.json_location,
|
||||
roi_channel_maps=selected_roi_maps,
|
||||
threshold_topo=threshold_topo # Shows the raw difference map (Unthresholded)
|
||||
)
|
||||
elif idx == 1:
|
||||
@@ -317,12 +323,27 @@ class CrossGroupStatsWidget(CrossGroupUIMixin, FlaresBaseWidget):
|
||||
if df_contrasts_a.empty or df_contrasts_b.empty:
|
||||
print("No contrast data found for one or both groups.")
|
||||
continue
|
||||
|
||||
|
||||
roi_maps_a = {
|
||||
fp: self.roi_channel_map_dict[fp]
|
||||
for fp in file_paths_a
|
||||
if fp in self.roi_channel_map_dict
|
||||
}
|
||||
roi_maps_b = {
|
||||
fp: self.roi_channel_map_dict[fp]
|
||||
for fp in file_paths_b
|
||||
if fp in self.roi_channel_map_dict
|
||||
}
|
||||
if not roi_maps_a or not roi_maps_b:
|
||||
print("No channel-to-ROI mapping available for one or both groups.")
|
||||
continue
|
||||
|
||||
run_cross_group_contrast_analysis(
|
||||
df_contrasts_a=df_contrasts_a,
|
||||
df_contrasts_b=df_contrasts_b,
|
||||
contrast_name=contrast_name,
|
||||
roi_json_path=self.json_location,
|
||||
roi_channel_maps_a=roi_maps_a,
|
||||
roi_channel_maps_b=roi_maps_b,
|
||||
group_a_name=self.group_a_dropdown.currentText(),
|
||||
group_b_name=self.group_b_dropdown.currentText(),
|
||||
target_chroma=target_chroma,
|
||||
|
||||
@@ -165,8 +165,8 @@ class InterGroupStatsWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
df_ind_dict: dict[str, DataFrame],
|
||||
design_matrix_dict: dict[str, DataFrame],
|
||||
contrast_results_dict: dict[str, dict[str, Any]],
|
||||
roi_channel_map_dict: dict[str, dict[str, str]],
|
||||
group_dict: dict[str, str],
|
||||
json_location: str | Path
|
||||
) -> None:
|
||||
|
||||
super().__init__("InterGroupStats")
|
||||
@@ -176,14 +176,14 @@ class InterGroupStatsWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
self.df_ind_dict = df_ind_dict
|
||||
self.design_matrix_dict = design_matrix_dict
|
||||
self.contrast_results_dict = contrast_results_dict
|
||||
self.roi_channel_map_dict = roi_channel_map_dict
|
||||
self.group_dict = group_dict
|
||||
self.json_location = json_location
|
||||
|
||||
self.setup_inter_group_ui(["0 (ROI vs. Zero)", "1 (Paired ROI Contrast)", "2 (Joint Contrast, ROI-Aggregated)"], placeholder_text=DESCRIPTION)
|
||||
|
||||
|
||||
def process_request(self):
|
||||
request = self.get_common_request_data(PARAMETERIZED_INDEXES, self.json_location, self.contrast_results_dict)
|
||||
request = self.get_common_request_data(PARAMETERIZED_INDEXES, self.df_ind_dict, self.contrast_results_dict)
|
||||
if request is None:
|
||||
return
|
||||
|
||||
@@ -276,7 +276,6 @@ class InterGroupStatsWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
correction_method=correction_method,
|
||||
target_chroma=target_chroma,
|
||||
graph_bounds=graph_bounds if graph_bounds > 0.0 else None,
|
||||
roi_config=self.json_location
|
||||
)
|
||||
|
||||
elif idx == 1:
|
||||
@@ -358,11 +357,20 @@ class InterGroupStatsWidget(InterGroupUIMixin, FlaresBaseWidget):
|
||||
continue
|
||||
|
||||
df_contrasts = pd.concat(all_contrasts, ignore_index=True)
|
||||
|
||||
|
||||
selected_roi_maps = {
|
||||
fp: self.roi_channel_map_dict[fp]
|
||||
for fp in selected_file_paths
|
||||
if fp in self.roi_channel_map_dict
|
||||
}
|
||||
if not selected_roi_maps:
|
||||
print("No channel-to-ROI mapping available for selected participants.")
|
||||
continue
|
||||
|
||||
try:
|
||||
roi_theta = aggregate_channel_contrasts_to_roi(
|
||||
df_contrasts,
|
||||
roi_json_path=self.json_location,
|
||||
roi_channel_maps=selected_roi_maps,
|
||||
weighted=weighted,
|
||||
)
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import json
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Sequence, Any
|
||||
import pandas as pd
|
||||
from pandas import DataFrame
|
||||
from PySide6.QtWidgets import QApplication, QComboBox, QDialog, QGridLayout, QHBoxLayout, QLabel, QLineEdit, QListView, QMessageBox, QPushButton, QScrollArea, QVBoxLayout, QWidget, QFrame, QSpinBox
|
||||
from PySide6.QtGui import QStandardItemModel, QStandardItem, QPixmap, QIntValidator, QDoubleValidator
|
||||
from PySide6.QtCore import QEvent, QSize, Qt
|
||||
@@ -1380,7 +1382,7 @@ class CrossGroupUIMixin:
|
||||
def get_common_request_data(
|
||||
self,
|
||||
parameterized_indexes: dict[int, list[dict[str, Any]]],
|
||||
json_location: str | Path | None = None,
|
||||
df_ind_dict: dict[str, DataFrame] | None = None,
|
||||
contrast_dfs: dict[str, dict[str, Any]] | None = None,
|
||||
) -> tuple[str | None, list[str], list[str], list[str], list[int], dict[str, Any]] | None:
|
||||
|
||||
@@ -1423,19 +1425,15 @@ class CrossGroupUIMixin:
|
||||
|
||||
dynamic_rois = []
|
||||
|
||||
# 1. Check for the JSON file and parse ROI names
|
||||
if os.path.exists(json_location):
|
||||
try:
|
||||
with open(json_location, 'r', encoding='utf-8') as f:
|
||||
regions_data = json.load(f)
|
||||
|
||||
# Extract "name" from each region under "regions_of_interest"
|
||||
regions_list = regions_data.get("regions_of_interest", [])
|
||||
dynamic_rois = [region["name"] for region in regions_list if "name" in region]
|
||||
|
||||
except Exception as e:
|
||||
# Safe log if JSON is corrupted or unreadable
|
||||
print(f"Error reading ROI configurations from {json_location}: {e}")
|
||||
if df_ind_dict:
|
||||
roi_set = set()
|
||||
for fp in all_selected_paths:
|
||||
df_roi = df_ind_dict.get(fp)
|
||||
if isinstance(df_roi, pd.DataFrame) and "ROI" in df_roi.columns:
|
||||
roi_set.update(df_roi["ROI"].dropna().unique())
|
||||
|
||||
if roi_set:
|
||||
dynamic_rois = sorted(list(roi_set))
|
||||
|
||||
# Fallback to prevent UI crashes if JSON file doesn't exist or is empty
|
||||
if not dynamic_rois:
|
||||
@@ -1580,7 +1578,7 @@ class InterGroupUIMixin:
|
||||
self.layout.addLayout(self.top_bar)
|
||||
|
||||
self.group_to_paths = {}
|
||||
for file_path, group_name in self.group.items():
|
||||
for file_path, group_name in self.group_dict.items():
|
||||
self.group_to_paths.setdefault(group_name, []).append(file_path)
|
||||
|
||||
self.group_names = sorted(self.group_to_paths.keys())
|
||||
@@ -1632,7 +1630,7 @@ class InterGroupUIMixin:
|
||||
def get_common_request_data(
|
||||
self,
|
||||
parameterized_indexes: dict[int, list[dict[str, Any]]],
|
||||
json_location: str | Path | None = None,
|
||||
df_ind_dict: dict[str, DataFrame] | None = None,
|
||||
contrast_dfs: dict[str, dict[str, Any]] | None = None,
|
||||
) -> tuple[str | None, list[str], list[int], dict[str, Any]] | None:
|
||||
|
||||
@@ -1679,20 +1677,16 @@ class InterGroupUIMixin:
|
||||
|
||||
dynamic_rois = []
|
||||
|
||||
# 1. Check for the JSON file and parse ROI names
|
||||
if json_location is not None and os.path.exists(json_location):
|
||||
try:
|
||||
with open(json_location, 'r', encoding='utf-8') as f:
|
||||
regions_data = json.load(f)
|
||||
|
||||
# Extract "name" from each region under "regions_of_interest"
|
||||
regions_list = regions_data.get("regions_of_interest", [])
|
||||
dynamic_rois = [region["name"] for region in regions_list if "name" in region]
|
||||
|
||||
except Exception as e:
|
||||
# Safe log if JSON is corrupted or unreadable
|
||||
print(f"Error reading ROI configurations from {json_location}: {e}")
|
||||
|
||||
if df_ind_dict:
|
||||
roi_set = set()
|
||||
for fp in selected_file_paths:
|
||||
df_roi = df_ind_dict.get(fp)
|
||||
if isinstance(df_roi, pd.DataFrame) and "ROI" in df_roi.columns:
|
||||
roi_set.update(df_roi["ROI"].dropna().unique())
|
||||
|
||||
if roi_set:
|
||||
dynamic_rois = sorted(list(roi_set))
|
||||
|
||||
# Fallback to prevent UI crashes if JSON file doesn't exist or is empty
|
||||
if not dynamic_rois:
|
||||
dynamic_rois = ["Option 1", "Option 2"]
|
||||
|
||||
@@ -24,7 +24,7 @@ from src.shared.shareddata import APP_NAME
|
||||
|
||||
|
||||
class ViewerLauncherWidget(QWidget):
|
||||
def __init__(self, haemo_dict, epochs_dict, cha_dict, df_ind_dict, design_matrix_dict, config_dict, fig_bytes_dict, contrast_results_dict, folding_bypass, json_location):
|
||||
def __init__(self, haemo_dict, epochs_dict, cha_dict, df_ind_dict, design_matrix_dict, config_dict, fig_bytes_dict, contrast_results_dict, roi_channel_map_dict, folding_bypass):
|
||||
super().__init__()
|
||||
self.setWindowTitle(f"Viewer Launcher - {APP_NAME.upper()}")
|
||||
|
||||
@@ -36,8 +36,8 @@ class ViewerLauncherWidget(QWidget):
|
||||
("Participant Fold Channels Viewer", ParticipantFoldChannelsWidget, [haemo_dict, cha_dict], False),
|
||||
("Participant Functional Connectivity Viewer [BETA]", ParticipantFunctionalConnectivityWidget, [haemo_dict, epochs_dict], True),
|
||||
("Inter-Group Functional Connectivity Viewer [BETA]", InterGroupFunctionalConnectivityWidget, [haemo_dict, group_dict, config_dict], True),
|
||||
("Inter-Group Stats Viewer", InterGroupStatsWidget, [haemo_dict, cha_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, group_dict, json_location], True),
|
||||
("Cross-Group Stats Viewer", CrossGroupStatsWidget, [haemo_dict, cha_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, group_dict, json_location], True),
|
||||
("Inter-Group Stats Viewer", InterGroupStatsWidget, [haemo_dict, cha_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, roi_channel_map_dict, group_dict], True),
|
||||
("Cross-Group Stats Viewer", CrossGroupStatsWidget, [haemo_dict, cha_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, roi_channel_map_dict, group_dict], True),
|
||||
("Inter-Group Brain and Image Viewer", InterGroupBrainImageWidget, [haemo_dict, cha_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, group_dict], True),
|
||||
("Cross-Group Brain and Image Viewer", CrossGroupBrainImageWidget, [haemo_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, group_dict], True),
|
||||
("Export To CSV Viewer", ExportToCSVWidget, [haemo_dict, cha_dict, df_ind_dict, design_matrix_dict, contrast_results_dict, group_dict, config_dict], True)
|
||||
|
||||
Reference in New Issue
Block a user