@yibeichan/claude-skills 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -0
- package/cli.js +272 -0
- package/install.py +240 -0
- package/package.json +44 -0
- package/skills/bidsapp-nidm-standards/SKILL.md +202 -0
- package/skills/bidsapp-nidm-standards/references/babs_config.md +20 -0
- package/skills/bidsapp-nidm-standards/references/cli_arguments.md +76 -0
- package/skills/bidsapp-nidm-standards/references/container_patterns.md +53 -0
- package/skills/bidsapp-nidm-standards/references/nidm_integration.md +403 -0
- package/skills/bidsapp-nidm-standards/references/repo_structure.md +121 -0
- package/skills/bidsapp-nidm-standards/references/testing_patterns.md +82 -0
- package/skills/dicom2fmriprep/SKILL.md +377 -0
- package/skills/dicom2fmriprep/evals/evals.json +26 -0
- package/skills/dicom2fmriprep/references/babs-details.md +407 -0
- package/skills/dicom2fmriprep/references/fmriprep-details.md +250 -0
- package/skills/dicom2fmriprep/references/heudiconv-details.md +243 -0
- package/skills/fmri-ssm/SKILL.md +317 -0
- package/skills/fmri-ssm/references/code_templates.md +1570 -0
- package/skills/fmri-ssm/references/downstream_analysis.md +680 -0
- package/skills/fmri-ssm/references/group_inference.md +608 -0
- package/skills/fmri-ssm/references/hrf_modeling.md +447 -0
- package/skills/fmri-ssm/references/model_catalog.md +436 -0
- package/skills/fmri-ssm/references/paradigm_guide.md +406 -0
- package/skills/fmri-ssm/references/preprocessing.md +614 -0
- package/skills/fmri-ssm.zip +0 -0
- package/skills/neuroimaging-qc/SKILL.md +203 -0
- package/skills/neuroimaging-qc/references/eeg_qc.md +400 -0
- package/skills/neuroimaging-qc/references/fmri_qc.md +343 -0
- package/skills/neuroimaging-qc/references/fnirs_qc.md +430 -0
- package/skills/neuroimaging-qc/references/structural_qc.md +454 -0
- package/skills/neuroimaging-qc/scripts/parse_fmriprep_confounds.py +153 -0
- package/skills/neuroimaging-qc/scripts/parse_mriqc.py +114 -0
- package/skills/neuroimaging-qc/scripts/qc_report.py +295 -0
- package/skills/scientific-writer/SKILL.md +202 -0
- package/skills/scientific-writer/references/citation_styles.md +163 -0
- package/skills/scientific-writer/references/field_conventions.md +245 -0
- package/skills/scientific-writer/references/figures_tables.md +225 -0
- package/skills/scientific-writer/references/reporting_guidelines.md +225 -0
- package/skills.json +54 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
# fMRI QC Reference
|
|
2
|
+
|
|
3
|
+
Comprehensive guide for QC of functional MRI data from fMRIPrep, MRIQC, and related pipelines.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
1. [Motion Metrics](#motion-metrics)
|
|
7
|
+
2. [Signal Quality Metrics](#signal-quality-metrics)
|
|
8
|
+
3. [MRIQC IQMs](#mriqc-iqms)
|
|
9
|
+
4. [fMRIPrep Confounds](#fmriprep-confounds)
|
|
10
|
+
5. [Threshold Recommendations](#threshold-recommendations)
|
|
11
|
+
6. [Python Examples](#python-examples)
|
|
12
|
+
|
|
13
|
+
## Motion Metrics
|
|
14
|
+
|
|
15
|
+
### Framewise Displacement (FD)
|
|
16
|
+
|
|
17
|
+
**Definition**: Sum of absolute translations and rotations between consecutive volumes, with rotations converted to mm using 50mm sphere radius (Power et al., 2012).
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
FD_t = |Δd_x| + |Δd_y| + |Δd_z| + |Δα| + |Δβ| + |Δγ|
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Key metrics from pipelines:**
|
|
24
|
+
- `fd_mean`: Mean FD across all volumes
|
|
25
|
+
- `fd_max`: Maximum single-volume FD
|
|
26
|
+
- `fd_num`: Number of volumes exceeding threshold (MRIQC uses 0.2mm)
|
|
27
|
+
- `fd_perc`: Percentage of volumes exceeding threshold
|
|
28
|
+
|
|
29
|
+
**Threshold recommendations by population and paradigm:**
|
|
30
|
+
|
|
31
|
+
| Context | Conservative | Standard | Lenient | Reference |
|
|
32
|
+
|---------|-------------|----------|---------|-----------|
|
|
33
|
+
| Adult resting-state | 0.2 mm | 0.3 mm | 0.5 mm | Power et al., 2014 |
|
|
34
|
+
| Adult task | 0.5 mm | 0.9 mm | 1.0 mm | Siegel et al., 2014 |
|
|
35
|
+
| Pediatric (6-12y) | 0.25 mm | 0.3 mm | 0.4 mm | Satterthwaite et al., 2012 |
|
|
36
|
+
| Infant (sleep) | 0.2 mm | 0.5 mm | — | Smyser et al., 2010 |
|
|
37
|
+
| Infant (awake) | 0.3 mm | 0.5 mm | — | Ellis et al., 2020 |
|
|
38
|
+
|
|
39
|
+
**Subject exclusion criteria:**
|
|
40
|
+
- Mean FD > threshold (see table above)
|
|
41
|
+
- >20-50% of volumes exceed threshold (fd_perc)
|
|
42
|
+
- <5 minutes of usable data after scrubbing (resting-state)
|
|
43
|
+
- Insufficient trials remaining (task fMRI)
|
|
44
|
+
|
|
45
|
+
### DVARS (Derivative of Variance)
|
|
46
|
+
|
|
47
|
+
**Definition**: Root mean square of temporal derivative of BOLD signal across brain voxels. Indexes frame-to-frame signal intensity changes.
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
DVARS_t = sqrt(mean((S_t - S_{t-1})^2))
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**Interpretation:**
|
|
54
|
+
- Spikes indicate rapid signal changes (often motion-related)
|
|
55
|
+
- Correlates with FD but captures signal-level artifacts
|
|
56
|
+
- Standardized DVARS (stdDVARS) normalized to baseline variance
|
|
57
|
+
|
|
58
|
+
**Thresholds:**
|
|
59
|
+
- Raw DVARS: Site/scanner dependent
|
|
60
|
+
- Standardized DVARS > 1.5: Potential artifact
|
|
61
|
+
- Used in conjunction with FD for volume censoring
|
|
62
|
+
|
|
63
|
+
## Signal Quality Metrics
|
|
64
|
+
|
|
65
|
+
### Temporal SNR (tSNR)
|
|
66
|
+
|
|
67
|
+
**Definition**: Mean BOLD signal divided by temporal standard deviation.
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
tSNR = mean(S_t) / std(S_t)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**Interpretation:**
|
|
74
|
+
- Higher is better
|
|
75
|
+
- Typical adult values: 40-100 (varies with sequence, field strength)
|
|
76
|
+
- Lower in infants/neonates
|
|
77
|
+
- Affected by motion, physiological noise, hardware
|
|
78
|
+
|
|
79
|
+
**Population norms (approximate, 3T):**
|
|
80
|
+
- Adults: 50-80 (cortex average)
|
|
81
|
+
- Children: 40-70
|
|
82
|
+
- Infants: 30-60
|
|
83
|
+
|
|
84
|
+
**No absolute cutoff** — compare within your sample, flag outliers >2 SD below mean.
|
|
85
|
+
|
|
86
|
+
### Global Signal Correlation
|
|
87
|
+
|
|
88
|
+
**Metrics:**
|
|
89
|
+
- `gsr_x`, `gsr_y`: Ghost-to-signal ratio along phase-encoding axes
|
|
90
|
+
- `gcor`: Global correlation (mean correlation of all voxels)
|
|
91
|
+
|
|
92
|
+
**Interpretation:**
|
|
93
|
+
- High gcor may indicate excessive global signal / physiological noise
|
|
94
|
+
- GSR artifacts indicate gradient/reconstruction issues
|
|
95
|
+
|
|
96
|
+
## MRIQC IQMs
|
|
97
|
+
|
|
98
|
+
### BOLD IQMs (Complete List)
|
|
99
|
+
|
|
100
|
+
| Metric | Description | Direction | Notes |
|
|
101
|
+
|--------|-------------|-----------|-------|
|
|
102
|
+
| `aor` | AFNI outlier ratio | Lower better | Fraction of outlier voxels |
|
|
103
|
+
| `aqi` | AFNI quality index | Lower better | Mean outlier ratio |
|
|
104
|
+
| `dvars_std` | Standardized DVARS mean | Lower better | ~1.0 is baseline |
|
|
105
|
+
| `dvars_vstd` | Voxelwise std DVARS | Lower better | Variability in DVARS |
|
|
106
|
+
| `dvars_nstd` | Non-standardized DVARS | Lower better | Raw DVARS mean |
|
|
107
|
+
| `efc` | Entropy focus criterion | Lower better | Image ghosting |
|
|
108
|
+
| `fber` | Foreground-background energy ratio | Higher better | Signal clarity |
|
|
109
|
+
| `fd_mean` | Mean framewise displacement | Lower better | Overall motion |
|
|
110
|
+
| `fd_num` | # volumes with FD > 0.2mm | Lower better | High-motion volumes |
|
|
111
|
+
| `fd_perc` | % volumes with FD > 0.2mm | Lower better | Motion proportion |
|
|
112
|
+
| `fwhm_avg` | Average smoothness (mm) | Context | Spatial smoothness |
|
|
113
|
+
| `gcor` | Global correlation | Lower better | Global signal |
|
|
114
|
+
| `gsr_x`, `gsr_y` | Ghost-to-signal ratio | Lower better | Nyquist ghosting |
|
|
115
|
+
| `size_t` | Number of volumes | Context | Scan length |
|
|
116
|
+
| `size_x/y/z` | Matrix dimensions | Context | Acquisition params |
|
|
117
|
+
| `snr` | Signal-to-noise ratio | Higher better | Image quality |
|
|
118
|
+
| `spacing_tr` | Repetition time | Context | Acquisition params |
|
|
119
|
+
| `summary_*_mean/std` | Tissue signal stats | Context | Per-tissue metrics |
|
|
120
|
+
| `tsnr` | Temporal SNR | Higher better | Key quality metric |
|
|
121
|
+
|
|
122
|
+
### Prioritized Metrics for Exclusion
|
|
123
|
+
|
|
124
|
+
**Primary (always check):**
|
|
125
|
+
1. `fd_mean` — motion summary
|
|
126
|
+
2. `fd_perc` — motion distribution
|
|
127
|
+
3. `tsnr` — signal quality
|
|
128
|
+
|
|
129
|
+
**Secondary (for outlier detection):**
|
|
130
|
+
4. `dvars_std` — signal stability
|
|
131
|
+
5. `aor` — outlier volumes
|
|
132
|
+
6. `efc` — ghosting artifacts
|
|
133
|
+
|
|
134
|
+
## fMRIPrep Confounds
|
|
135
|
+
|
|
136
|
+
### Key Confound Columns
|
|
137
|
+
|
|
138
|
+
From `*_desc-confounds_timeseries.tsv`:
|
|
139
|
+
|
|
140
|
+
**Motion parameters:**
|
|
141
|
+
- `trans_x`, `trans_y`, `trans_z`: Translation (mm)
|
|
142
|
+
- `rot_x`, `rot_y`, `rot_z`: Rotation (radians)
|
|
143
|
+
- `*_derivative1`: First derivatives
|
|
144
|
+
- `*_power2`: Squared terms
|
|
145
|
+
|
|
146
|
+
**Composite motion:**
|
|
147
|
+
- `framewise_displacement`: FD per volume
|
|
148
|
+
- `rmsd`: Root mean squared deviation from reference
|
|
149
|
+
|
|
150
|
+
**Signal regressors:**
|
|
151
|
+
- `dvars`: DVARS per volume
|
|
152
|
+
- `std_dvars`: Standardized DVARS
|
|
153
|
+
- `global_signal`: Whole-brain mean
|
|
154
|
+
- `csf`, `white_matter`: Tissue signals
|
|
155
|
+
|
|
156
|
+
**Outlier detection:**
|
|
157
|
+
- `motion_outlier_*`: Binary columns for censoring
|
|
158
|
+
- `non_steady_state_*`: Initial volumes to exclude
|
|
159
|
+
|
|
160
|
+
### Calculating Summary Statistics
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
import pandas as pd
|
|
164
|
+
import numpy as np
|
|
165
|
+
|
|
166
|
+
def summarize_confounds(confounds_path, fd_thresh=0.5):
|
|
167
|
+
"""Summarize fMRIPrep confounds for QC."""
|
|
168
|
+
df = pd.read_csv(confounds_path, sep='\t')
|
|
169
|
+
|
|
170
|
+
fd = df['framewise_displacement'].values
|
|
171
|
+
fd = fd[~np.isnan(fd)] # First volume is NaN
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
'fd_mean': np.mean(fd),
|
|
175
|
+
'fd_max': np.max(fd),
|
|
176
|
+
'fd_perc': 100 * np.sum(fd > fd_thresh) / len(fd),
|
|
177
|
+
'n_volumes': len(df),
|
|
178
|
+
'n_high_motion': np.sum(fd > fd_thresh),
|
|
179
|
+
'dvars_mean': df['std_dvars'].mean(),
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Threshold Recommendations
|
|
184
|
+
|
|
185
|
+
### Resting-State fMRI (Adults)
|
|
186
|
+
|
|
187
|
+
**Conservative (high-quality connectivity):**
|
|
188
|
+
- fd_mean < 0.2 mm
|
|
189
|
+
- fd_perc < 20%
|
|
190
|
+
- Minimum 5 min after scrubbing
|
|
191
|
+
- tsnr > sample mean - 2 SD
|
|
192
|
+
|
|
193
|
+
**Standard:**
|
|
194
|
+
- fd_mean < 0.3 mm
|
|
195
|
+
- fd_perc < 30%
|
|
196
|
+
- Minimum 4 min after scrubbing
|
|
197
|
+
|
|
198
|
+
**Lenient (preserve sample size):**
|
|
199
|
+
- fd_mean < 0.5 mm
|
|
200
|
+
- fd_perc < 50%
|
|
201
|
+
|
|
202
|
+
### Task fMRI (Adults)
|
|
203
|
+
|
|
204
|
+
**Standard:**
|
|
205
|
+
- fd_mean < 0.9 mm (Siegel et al., 2014)
|
|
206
|
+
- fd_max < 3-5 mm
|
|
207
|
+
- >80% of task trials usable
|
|
208
|
+
|
|
209
|
+
**Per-run exclusion:**
|
|
210
|
+
- Exclude run if >20% frames censored
|
|
211
|
+
|
|
212
|
+
### Developmental Populations
|
|
213
|
+
|
|
214
|
+
**Infants (0-12 months):**
|
|
215
|
+
- fd_mean < 0.5 mm (more lenient than adults)
|
|
216
|
+
- Accept shorter usable segments (2-3 min)
|
|
217
|
+
- Visual QC critical for registration
|
|
218
|
+
|
|
219
|
+
**Children (6-12 years):**
|
|
220
|
+
- fd_mean < 0.3-0.4 mm
|
|
221
|
+
- Consider age as covariate in group comparisons
|
|
222
|
+
- fd_perc < 30%
|
|
223
|
+
|
|
224
|
+
## Python Examples
|
|
225
|
+
|
|
226
|
+
### Parse MRIQC Group Output
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
import pandas as pd
|
|
230
|
+
import numpy as np
|
|
231
|
+
|
|
232
|
+
def load_mriqc_bold(group_tsv_path):
|
|
233
|
+
"""Load MRIQC group BOLD TSV."""
|
|
234
|
+
df = pd.read_csv(group_tsv_path, sep='\t')
|
|
235
|
+
return df
|
|
236
|
+
|
|
237
|
+
def flag_subjects(df, fd_mean_thresh=0.3, fd_perc_thresh=30, tsnr_zscore=-2):
|
|
238
|
+
"""Flag subjects for exclusion based on QC metrics."""
|
|
239
|
+
flags = pd.DataFrame(index=df.index)
|
|
240
|
+
|
|
241
|
+
# Motion flags
|
|
242
|
+
flags['high_fd_mean'] = df['fd_mean'] > fd_mean_thresh
|
|
243
|
+
flags['high_fd_perc'] = df['fd_perc'] > fd_perc_thresh
|
|
244
|
+
|
|
245
|
+
# tSNR flag (z-score based)
|
|
246
|
+
tsnr_z = (df['tsnr'] - df['tsnr'].mean()) / df['tsnr'].std()
|
|
247
|
+
flags['low_tsnr'] = tsnr_z < tsnr_zscore
|
|
248
|
+
|
|
249
|
+
# Composite flag
|
|
250
|
+
flags['exclude'] = flags.any(axis=1)
|
|
251
|
+
|
|
252
|
+
# Merge with subject IDs
|
|
253
|
+
result = df[['bids_name']].copy()
|
|
254
|
+
result = pd.concat([result, flags], axis=1)
|
|
255
|
+
|
|
256
|
+
return result
|
|
257
|
+
|
|
258
|
+
def generate_qc_report(df, flags):
|
|
259
|
+
"""Generate QC summary report."""
|
|
260
|
+
n_total = len(df)
|
|
261
|
+
n_exclude = flags['exclude'].sum()
|
|
262
|
+
|
|
263
|
+
report = f"""
|
|
264
|
+
QC Summary Report
|
|
265
|
+
=================
|
|
266
|
+
Total subjects: {n_total}
|
|
267
|
+
Excluded: {n_exclude} ({100*n_exclude/n_total:.1f}%)
|
|
268
|
+
|
|
269
|
+
Exclusion breakdown:
|
|
270
|
+
- High mean FD: {flags['high_fd_mean'].sum()}
|
|
271
|
+
- High FD percentage: {flags['high_fd_perc'].sum()}
|
|
272
|
+
- Low tSNR: {flags['low_tsnr'].sum()}
|
|
273
|
+
|
|
274
|
+
Included subjects: {n_total - n_exclude}
|
|
275
|
+
"""
|
|
276
|
+
return report
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Visualize QC Distributions
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
import matplotlib.pyplot as plt
|
|
283
|
+
|
|
284
|
+
def plot_qc_distributions(df, output_path=None):
|
|
285
|
+
"""Plot QC metric distributions with threshold lines."""
|
|
286
|
+
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
|
|
287
|
+
|
|
288
|
+
# FD mean
|
|
289
|
+
ax = axes[0, 0]
|
|
290
|
+
ax.hist(df['fd_mean'], bins=30, edgecolor='black')
|
|
291
|
+
ax.axvline(0.3, color='orange', linestyle='--', label='Standard (0.3mm)')
|
|
292
|
+
ax.axvline(0.5, color='red', linestyle='--', label='Lenient (0.5mm)')
|
|
293
|
+
ax.set_xlabel('Mean FD (mm)')
|
|
294
|
+
ax.set_ylabel('Count')
|
|
295
|
+
ax.set_title('Framewise Displacement')
|
|
296
|
+
ax.legend()
|
|
297
|
+
|
|
298
|
+
# FD percentage
|
|
299
|
+
ax = axes[0, 1]
|
|
300
|
+
ax.hist(df['fd_perc'], bins=30, edgecolor='black')
|
|
301
|
+
ax.axvline(20, color='orange', linestyle='--', label='20%')
|
|
302
|
+
ax.axvline(50, color='red', linestyle='--', label='50%')
|
|
303
|
+
ax.set_xlabel('% Volumes > 0.2mm')
|
|
304
|
+
ax.set_ylabel('Count')
|
|
305
|
+
ax.set_title('High-Motion Volume Percentage')
|
|
306
|
+
ax.legend()
|
|
307
|
+
|
|
308
|
+
# tSNR
|
|
309
|
+
ax = axes[1, 0]
|
|
310
|
+
ax.hist(df['tsnr'], bins=30, edgecolor='black')
|
|
311
|
+
mean_tsnr = df['tsnr'].mean()
|
|
312
|
+
std_tsnr = df['tsnr'].std()
|
|
313
|
+
ax.axvline(mean_tsnr - 2*std_tsnr, color='red', linestyle='--',
|
|
314
|
+
label=f'-2 SD ({mean_tsnr - 2*std_tsnr:.1f})')
|
|
315
|
+
ax.set_xlabel('tSNR')
|
|
316
|
+
ax.set_ylabel('Count')
|
|
317
|
+
ax.set_title('Temporal SNR')
|
|
318
|
+
ax.legend()
|
|
319
|
+
|
|
320
|
+
# DVARS
|
|
321
|
+
ax = axes[1, 1]
|
|
322
|
+
ax.hist(df['dvars_std'], bins=30, edgecolor='black')
|
|
323
|
+
ax.axvline(1.5, color='red', linestyle='--', label='1.5 (elevated)')
|
|
324
|
+
ax.set_xlabel('Standardized DVARS')
|
|
325
|
+
ax.set_ylabel('Count')
|
|
326
|
+
ax.set_title('DVARS')
|
|
327
|
+
ax.legend()
|
|
328
|
+
|
|
329
|
+
plt.tight_layout()
|
|
330
|
+
|
|
331
|
+
if output_path:
|
|
332
|
+
plt.savefig(output_path, dpi=150, bbox_inches='tight')
|
|
333
|
+
|
|
334
|
+
return fig
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
## Key References
|
|
338
|
+
|
|
339
|
+
- Power JD et al. (2012). Spurious but systematic correlations in functional connectivity MRI networks arise from subject motion. NeuroImage 59(3):2142-2154. doi:10.1016/j.neuroimage.2011.10.018
|
|
340
|
+
- Power JD et al. (2014). Methods to detect, characterize, and remove motion artifact in resting state fMRI. NeuroImage 84:320-341. doi:10.1016/j.neuroimage.2013.08.048
|
|
341
|
+
- Satterthwaite TD et al. (2012). Impact of in-scanner head motion on multiple measures of functional connectivity. NeuroImage 60(1):623-632.
|
|
342
|
+
- Siegel JS et al. (2014). Statistical improvements in functional magnetic resonance imaging analyses produced by censoring high-motion data points. Human Brain Mapping 35(5):1981-1996.
|
|
343
|
+
- Esteban O et al. (2017). MRIQC: Advancing the automatic prediction of image quality in MRI from unseen sites. PLOS ONE 12(9):e0184661.
|