qol improvements + optode location fix
This commit is contained in:
@@ -2403,6 +2403,71 @@ def plot_3d_evoked_array(
|
||||
return brain
|
||||
|
||||
|
||||
def aggregate_fnirs_group_geometry(raw_list):
|
||||
"""
|
||||
Averages fNIRS geometry across participants in two tiers:
|
||||
1. Average by Channel Pairing (S_D).
|
||||
2. Average by Individual Optode (S, D) across all averaged pairings.
|
||||
Returns a unified MNE Raw object with exactly one dot per optode.
|
||||
"""
|
||||
import mne
|
||||
import numpy as np
|
||||
|
||||
channel_locs = {}
|
||||
all_ch_names = []
|
||||
|
||||
for raw in raw_list:
|
||||
if raw is None: continue
|
||||
raw_hbo = raw.copy().pick(picks="hbo")
|
||||
|
||||
for i, ch_name in enumerate(raw_hbo.ch_names):
|
||||
if ch_name not in channel_locs:
|
||||
channel_locs[ch_name] = []
|
||||
all_ch_names.append(ch_name)
|
||||
|
||||
channel_locs[ch_name].append(raw_hbo.info['chs'][i]['loc'])
|
||||
|
||||
avg_pairings = {name: np.nanmean(locs, axis=0) for name, locs in channel_locs.items()}
|
||||
|
||||
optode_collections = {'sources': {}, 'detectors': {}}
|
||||
|
||||
for ch_name, loc in avg_pairings.items():
|
||||
parts = ch_name.split()[0].split('_')
|
||||
s_name, d_name = parts[0], parts[1]
|
||||
|
||||
optode_collections['sources'].setdefault(s_name, []).append(loc[3:6])
|
||||
optode_collections['detectors'].setdefault(d_name, []).append(loc[6:9])
|
||||
|
||||
final_sources = {s: np.nanmean(coords, axis=0) for s, coords in optode_collections['sources'].items()}
|
||||
final_detectors = {d: np.nanmean(coords, axis=0) for d, coords in optode_collections['detectors'].items()}
|
||||
|
||||
ref_raw = raw_list[0].copy().pick(picks="hbo")
|
||||
template_lookup = {ch['ch_name']: ch for ch in ref_raw.info['chs']}
|
||||
final_chs = []
|
||||
|
||||
for ch_name in all_ch_names:
|
||||
unified_loc = avg_pairings[ch_name].copy()
|
||||
parts = ch_name.split()[0].split('_')
|
||||
s_name, d_name = parts[0], parts[1]
|
||||
|
||||
unified_loc[3:6] = final_sources[s_name]
|
||||
unified_loc[6:9] = final_detectors[d_name]
|
||||
unified_loc[0:3] = (final_sources[s_name] + final_detectors[d_name]) / 2.0
|
||||
|
||||
# Create the new channel object
|
||||
new_ch = template_lookup.get(ch_name, ref_raw.info['chs'][0]).copy()
|
||||
new_ch['ch_name'] = ch_name
|
||||
new_ch['loc'] = unified_loc
|
||||
final_chs.append(new_ch)
|
||||
|
||||
# Create the final MNE Info
|
||||
fake_info = mne.create_info(ch_names=all_ch_names, sfreq=ref_raw.info['sfreq'], ch_types='hbo')
|
||||
with fake_info._unlock():
|
||||
fake_info['chs'] = final_chs
|
||||
|
||||
return mne.io.RawArray(np.zeros((len(all_ch_names), 1)), fake_info)
|
||||
|
||||
|
||||
|
||||
def brain_3d_visualization(raw_haemo, df_cha, selected_event, t_or_theta: Literal['t', 'theta'] = 'theta', show_optodes: Literal['sensors', 'labels', 'none', 'all'] = 'all', show_text: bool = True, brain_bounds: float = 1.0) -> None:
|
||||
|
||||
@@ -2446,7 +2511,7 @@ def brain_3d_visualization(raw_haemo, df_cha, selected_event, t_or_theta: Litera
|
||||
brain = plot_3d_evoked_array(raw_for_plot.pick(picks="hbo"), model_df, view="dorsal", distance=0.02, colorbar=True, clim=clim, mode="weighted", size=(800, 700)) # type: ignore
|
||||
|
||||
if show_optodes == 'all' or show_optodes == 'sensors':
|
||||
brain.add_sensors(getattr(raw_for_plot, "info"), trans=Transform('head', 'mri', np.eye(4)), fnirs=["channels", "pairs", "sources", "detectors"], verbose=False) # type: ignore
|
||||
brain.add_sensors(raw_for_plot.pick(picks="hbo").info, trans=Transform('head', 'mri', np.eye(4)), fnirs=["channels", "pairs", "sources", "detectors"], verbose=False) # type: ignore
|
||||
|
||||
if True:
|
||||
display_text = ('Folder: ' + '\nGroup: ' + '\nCondition: '+ cond + '\nShort Channel Regression: '
|
||||
@@ -4025,7 +4090,7 @@ def process_participant(file_path, progress_callback=None):
|
||||
if num_bad > MAX_BAD_CHANNELS:
|
||||
raise Exception(
|
||||
f"Data Quality Error: {num_bad} channels flagged for removal, "
|
||||
f"which exceeds the limit of {MAX_BAD_CHANNELS}. To avoid this,"
|
||||
f"which exceeds the limit of {MAX_BAD_CHANNELS}. To avoid this, "
|
||||
f"either lower your filtering parameters or increase MAX_BAD_CHANNELS."
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user