Stage 3: Head shape and sensor alignment plots
Author: Hadi Zaatiti <hadi.zaatiti@nyu.edu>
What & why
Stage 3 of the KIT general pipeline is the quality check of stage 2. For
every .fif that stage 2 lists as a current, verified output, it renders
the laser head shape, the digitised points and the MEG helmet and sensors in
the same 3-D scene and saves the picture. The scene is drawn with the
device-to-head transform (info['dev_head_t']) that was stored in the FIF
by the KIT-to-FIFF GUI, so what you see is exactly the alignment the operator
accepted when pressing Save FIFF…, not a new fit.
Why a separate stage: in the GUI the alignment is judged on screen and then the window is closed. Stage 3 keeps a picture of it next to the data, writes one row per FIF in a summary table, and puts every picture in the report, so a bad head-shape fit (head shape floating above the helmet, rotated, or mirrored) is caught before bad channels, ICA and filtering are spent on the recording.
The stage does not modify any FIF and makes no decision. A recording with an
odd picture is a recording to redo in stage 2 (--overwrite).
What you need to provide
The stage-2 outputs:
<bids_root>/derivatives/2-kit_con_to_fif/withkit2fiff_summary.csvand the*_desc-rawkit_raw.fiffiles. Only the FIFs listed in the summary with a success or skipped status are plotted; split parts (*_raw-1.fif) are read through their base file.A 3-D backend:
pyvista,pyvistaqtandvtkare in theneurowavesrecipe. Without a display the stage renders off-screen (the default);--showneeds a desktop session with OpenGL.
Configuration file
Stage 3 has no block of its own. It reads:
projectandsubjectsto resolve the BIDS root and the subject selection (subjects.include/subjects.exclude);bids_selectionto restrict the recordings (tasks, runs, acquisitions, processings);the stage-2 folder name through the pipeline utilities, so a dataset whose stage-2 outputs still sit in a pre-renumbering folder (
2-kit_con_to_fif_manualorkit2fiff) is found as well.
How to run
conda activate neurowaves
python -m pipeline.mne_pipelines.kit_general_pipelines.3-kit_fif_plot_headshape_sensor_alignment \
-c pipeline/mne_pipelines/kit_general_pipelines/pipeline_config_files/<project>_config.yml
Options:
--show: open the interactive 3-D window for every recording instead of only saving the PNG. Rotate the scene to look at the fit from the side and from above; closing the window continues with the next recording.
The VS Code launch entries are named <project> 3 Plot headshape / sensor
alignment; the pipeline console runs the stage from its Run a stage
panel.
What the script does
Per FIF, in this order:
Read
kit2fiff_summary.csvand keep the FIFs whose row is current (fif_outexists andstatusis not an error). FIFs that are on disk but absent from the summary are ignored, like in every later stage.Open the FIF without loading the data and read
info['dev_head_t']. An identity transform means no coregistration was applied; the stage records an error for that recording instead of drawing a meaningless picture. The norm of the translation is printed (typically 30 to 150 mm for a KIT subject) as a quick sanity check.Check that the FIF carries digitisation points (
info['dig']): the fiducials, the HPI coils and the head-shape points attached by stage 2.Call
mne.viz.plot_alignmentwithmeg=["helmet", "sensors"],dig=True,coord_frame='meg'and no surfaces. Rendering in the device frame means the sensors stay where they physically are and the head shape is moved into the helmet with the inverse ofdev_head_t: any gap between the two is the residual of the accepted fit.Render the scene from the front, the left and the top into one image, a temporary
*.pending.pngrenamed to the final name only when the file was written; a crash never leaves a half-written image behind. MNE’s plotter returns a black screenshot when it renders hidden on the lab workstation, so its actors (helmet, sensors, digitised points, axes) are moved into a plain off-screen PyVista plotter (brain_render.screenshot_mne_3d); an image that comes out blank is recorded as an error.Write a
.jsonsidecar with the MNE version, the plot version and the identity (path, size, modification time) of the FIF that was plotted, so a later stage-2 rerun that replaces the FIF (or a change of the drawing) invalidates the picture even when its name did not change.
Outputs
Under <bids_root>/derivatives/3-kit_fif_plot_headshape_sensor_alignment/:
alignment_summary.csv
configs/config_<timestamp>.yml
sub-<id>/[ses-<id>/]
sub-<id>..._desc-rawkit_raw.png # the 3-D scene
sub-<id>..._desc-rawkit_raw.png.json # which FIF was plotted, MNE version
alignment_summary.csv has one row per FIF: timestamp, input_fif,
output_png, status (success | up_to_date | error),
error, mne_version, source_size and source_mtime_ns. A picture
whose sidecar still matches the FIF (same path, size, modification time and
MNE version) is not redrawn and its row says up_to_date. Rows of recordings
that were not part of a run (another subjects.include) are kept, so the
table always describes the whole cohort.
Report
The report shows every picture in the stage-3 section, grouped by subject and
session, with the summary row under it. A recording whose status is
error appears with the error text instead of a picture.
Edge cases & safeguards
Identity transform: reported as an error; redo the conversion of that recording in stage 2 (the GUI must be saved with Save FIFF…, closing it does not write a file).
No digitisation: the head-shape files were not found by stage 2; check the
acq-headandacq-pointsfiles of the subject or session.3-D backend unavailable: every selected FIF gets the same error text and nothing is drawn; see Troubleshooting.
Stage 2 rerun: a FIF replaced with
--overwritechanges its size or modification time, so the next stage-3 run redraws its picture instead of reporting itup_to_date. There is no--overwritefor stage 3: the sidecar decides.
Troubleshooting
``3D backend unavailable``:
pyvistaqtorvtkcannot initialise. Run on a machine with a desktop session and OpenGL, with theneurowavesinterpreter selected; on a remote Linux box set up a virtual display (xvfb-run) for the off-screen render.Head shape outside the helmet: the fit was accepted with the wrong marker set or the wrong head-shape file. Check
mrk_pathsandhsp_pathof that row inkit2fiff_summary.csvand redo stage 2.Empty summary: no FIF of the selection is listed in the stage-2 summary; run stage 2 first, or widen
subjects.include/bids_selection.