fMRI-EGG Processing Pipeline#

Process EGG data recorded concurrently with fMRI. This example demonstrates scanner trigger parsing, per-volume phase extraction, and transient volume removal using gastropy.neuro.fmri.

import matplotlib.pyplot as plt

import gastropy as gp
from gastropy.neuro.fmri import apply_volume_cuts, create_volume_windows, phase_per_volume

plt.rcParams["figure.dpi"] = 100
plt.rcParams["figure.facecolor"] = "white"

Load fMRI-EGG Data#

The fMRI-EGG sample data includes scanner trigger times and the repetition time (TR).

fmri = gp.load_fmri_egg(session="0001")

print(f"Signal shape:    {fmri['signal'].shape}")
print(f"Sampling rate:   {fmri['sfreq']} Hz")
print(f"TR:              {fmri['tr']} s")
print(f"Trigger times:   {len(fmri['trigger_times'])} volumes")
print(f"Duration:        {fmri['duration_s']:.0f} s ({fmri['duration_s'] / 60:.1f} min)")
Signal shape:    (8, 7795)
Sampling rate:   10.0 Hz
TR:              1.856 s
Trigger times:   420 volumes
Duration:        780 s (13.0 min)

Select Channel and Extract Phase#

best_idx, peak_freq, _, _ = gp.select_best_channel(fmri["signal"], fmri["sfreq"])
print(f"Best channel: {list(fmri['ch_names'])[best_idx]} ({peak_freq * 60:.1f} cpm)")

# Filter and extract phase
filtered, _ = gp.apply_bandpass(
    fmri["signal"][best_idx], fmri["sfreq"], low_hz=gp.NORMOGASTRIA.f_lo, high_hz=gp.NORMOGASTRIA.f_hi
)
phase, analytic = gp.instantaneous_phase(filtered)
Best channel: EGG8 (2.4 cpm)

Per-Volume Phase Extraction#

Map each fMRI volume to a mean gastric phase value by averaging the complex analytic signal within each volume’s time window.

n_volumes = len(fmri["trigger_times"])
windows = create_volume_windows(fmri["trigger_times"], fmri["tr"], n_volumes)
vol_phase = phase_per_volume(analytic, windows)

print(f"Volume phases: {vol_phase.shape} (one phase per volume)")
print(f"Phase range: [{vol_phase.min():.2f}, {vol_phase.max():.2f}] rad")
Volume phases: (420,) (one phase per volume)
Phase range: [-3.13, 3.13] rad

Visualize and Trim Transients#

# Plot with cut regions
fig, ax = gp.plot_volume_phase(vol_phase, tr=fmri["tr"], cut_start=21, cut_end=21)
plt.show()

# Apply cuts
trimmed = apply_volume_cuts(vol_phase, begin_cut=21, end_cut=21)
print(f"Before cut: {len(vol_phase)} volumes")
print(f"After cut:  {len(trimmed)} volumes")
../_images/c793be8fde3400f83740a6acf3ef1e8ed3cd0f4d7175aaaa7c21fd4828a3c852.png
Before cut: 420 volumes
After cut:  378 volumes

Comprehensive Figure with Volume Phase#

# Run egg_process for the overview panels
signals_df, info = gp.egg_process(fmri["signal"][best_idx], fmri["sfreq"])

fig, axes = gp.plot_egg_comprehensive(
    signals_df,
    fmri["sfreq"],
    phase_per_vol=vol_phase,
    tr=fmri["tr"],
)
plt.show()
../_images/b2da01d30fb6a20eb38a9484e20da832132fccbfc2a838ea1fa3fd615a51c01e.png

See also: Per-Volume Phase Plot, Comprehensive Figure