preparation for 1.5.1

This commit is contained in:
2026-07-17 23:59:42 -07:00
parent 0680718398
commit 2b019c1bc0
11 changed files with 350 additions and 59 deletions
+24 -11
View File
@@ -967,19 +967,29 @@ def interpolate_fNIRS_bads_weighted_average(raw, max_dist=0.03, min_neighbors=2)
if hbo_names[i] != hbr_names[i]:
raise RuntimeError(f"Channel pairs do not match: {hbo_names[i]} vs {hbr_names[i]}")
all_distances = source_detector_distances(raw.info)
pair_distances = all_distances[hbo_picks]
# Identify bad pairs if either channel in pair is bad
bad_pairs = []
good_pairs = []
n_short_excluded = 0
for i, base in enumerate(hbo_names):
hbo_ch = raw.ch_names[hbo_picks[i]]
hbr_ch = raw.ch_names[hbr_picks[i]]
if (hbo_ch in raw.info['bads']) or (hbr_ch in raw.info['bads']):
is_bad = (hbo_ch in raw.info['bads']) or (hbr_ch in raw.info['bads'])
is_short = pair_distances[i] < SHORT_CHANNELS_THRESHOLD
if is_bad:
bad_pairs.append(i)
elif is_short:
n_short_excluded += 1
else:
good_pairs.append(i)
print(f"Total pairs: {len(hbo_names)}")
print(f"Good pairs: {len(good_pairs)}")
print(f"Good LONG pairs (eligible donors): {len(good_pairs)}")
print(f"Good SHORT pairs (excluded from donor pool): {n_short_excluded}")
print(f"Bad pairs to interpolate: {len(bad_pairs)}")
if len(bad_pairs) == 0:
@@ -1488,8 +1498,9 @@ def epochs_calculations(raw_haemo, events, event_dict):
def make_design_matrix(raw_haemo):
events_to_remove = REMOVE_EVENTS
# events_to_remove = REMOVE_EVENTS
events_to_remove = ""
filtered_annotations = [ann for ann in raw_haemo.annotations if ann['description'] not in events_to_remove]
new_annot = Annotations(
@@ -2742,7 +2753,7 @@ def load_snirf(file_path: str) -> tuple[BaseRaw, Figure]:
# Read the snirf file
raw = read_raw_snirf(file_path, preload=True, verbose=VERBOSITY) # type: ignore
raw.load_data(verbose=VERBOSITY) # type: ignore
#raw.load_data(verbose=VERBOSITY) # type: ignore redundant since preload is set to true
# TODO: Why was this commented again?
# Maybe this should be a bypass parameter?
@@ -3217,7 +3228,6 @@ def run_cross_group_second_level_analysis(df_roi_all, file_paths_a, file_paths_b
ax.set_xlabel('Region of Interest (ROI)', fontsize=12)
ax.set_title(f"Cross-Group Comparison: {group_a_name} vs {group_b_name}\n({target_chroma.upper()} - {selected_event})", fontsize=13, fontweight='bold', pad=15)
plt.tight_layout()
plt.show()
# 4. Channel-by-Channel Group-Contrast Topography Map (Zero Hardcoding)
if df_cha_all is not None and raw_haemo is not None:
@@ -3231,7 +3241,7 @@ def run_cross_group_second_level_analysis(df_roi_all, file_paths_a, file_paths_b
(df_cha_all['Chroma'] == target_chroma) &
(df_cha_all['Condition'] == selected_event)
].copy()
con_summary['clean_ID'] = con_summary['ID'].apply(clean_subject_id)
con_summary['clean_ID'] = con_summary['ID']
raw_picked = raw_haemo.copy().pick(picks=target_chroma)
@@ -3254,7 +3264,8 @@ def run_cross_group_second_level_analysis(df_roi_all, file_paths_a, file_paths_b
'ch_name': ch,
'Coef.': mean_diff, # Represents Mean A - Mean B
't': t_stat,
'P>|t|': p_val # For threshold masking
'P>|t|': p_val,
'Chroma': target_chroma, # For threshold masking
})
con_model_df = pd.DataFrame(contrast_data)
@@ -5401,6 +5412,8 @@ def process_participant(file_path, progress_callback=None):
if k in globals() and k != "REQUIRED_KEYS"
}
print(config_dict)
# Step 1: Preprocessing
raw = load_snirf(file_path)
fig_raw = raw.plot(duration=raw.times[-1], n_channels=raw.info['nchan'], title="Loaded Raw", show=False)
@@ -5417,7 +5430,7 @@ def process_participant(file_path, progress_callback=None):
# Step 3: Verify Optode Placement
if OPTODE_PLACEMENT:
fig_optodes = raw.plot_sensors(show_names=SHOW_OPTODE_NAMES, to_sphere=True, show=False) # type: ignore
fig_optodes = raw.plot_sensors(show_names=SHOW_OPTODE_NAMES, to_sphere=True, show=False, verbose=VERBOSITY) # type: ignore
fig_individual["Plot Sensors"] = fig_optodes
if progress_callback: progress_callback(3)
logger.info("Step 3 Completed.")
@@ -5426,7 +5439,7 @@ def process_participant(file_path, progress_callback=None):
if SHORT_CHANNELS and not FOLDING_BYP:
#NOTE: Have to split again later but since needed for heart rate, this will stay at step 4. Will split later again.
_short_chans = get_short_channels(raw, max_dist=SHORT_CHANNELS_THRESHOLD) # JUST FOR PLOTTING THEM SEPERATELY
fig_short_chans = _short_chans.plot(duration=raw.times[-1], n_channels=raw.info['nchan'], title="Short Channels Only", show=False)
fig_short_chans = _short_chans.plot(duration=raw.times[-1], n_channels=raw.info['nchan'], title="Short Channels Only", show=False, verbose=VERBOSITY)
fig_individual["Short Channels Raw Data"] = fig_short_chans
raw = get_long_channels(raw, min_dist=0, max_dist=LONG_CHANNELS_THRESHOLD)
if progress_callback: progress_callback(4)