Skip to content

Commit

Permalink
[custom] fix lesson contents
Browse files Browse the repository at this point in the history
  • Loading branch information
zkamvar authored and Carpentries Apprentice committed Nov 15, 2022
1 parent 7377cfa commit 0fb08e8
Showing 1 changed file with 118 additions and 108 deletions.
226 changes: 118 additions & 108 deletions episodes/02-exploring-fmriprep.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
---
title: "Exploring Preprocessed fMRI Data from fMRIPREP"
title: Exploring Preprocessed fMRI Data from fMRIPREP
teaching: 20
exercises: 5
questions:
- "How does fMRIPrep store preprocessed neuroimaging data"
- "How do I access preprocessed neuroimaging data"
objectives:
- "Learn about fMRIPrep derivatives"
- "Understand how preprocessed data is stored and how you can access key files for analysis"
keypoints:
- "fMRIPrep stores preprocessed data in a 'BIDS-like' fashion"
- "You can pull files using pyBIDS much like how you can navigate raw BIDS data"
---

## Exploring Preprocessed fMRI Data from fMRIPREP

BIDS applications such as fMRIPREP output data into a full data structure with strong similarity to BIDS organization principals. In fact, there is a specification for derivatives (outputs derived from) BIDS datasets; although this is a current work in progress, details can be found in: [BIDS Derivatives](https://bids-specification.readthedocs.io/en/latest/06-extensions.html).
::::::::::::::::::::::::::::::::::::::: objectives

- Learn about fMRIPrep derivatives
- Understand how preprocessed data is stored and how you can access key files for analysis

::::::::::::::::::::::::::::::::::::::::::::::::::

:::::::::::::::::::::::::::::::::::::::: questions

- How does fMRIPrep store preprocessed neuroimaging data
- How do I access preprocessed neuroimaging data

::::::::::::::::::::::::::::::::::::::::::::::::::

BIDS applications such as fMRIPREP output data into a full data structure with strong similarity to BIDS organization principals. In fact, there is a specification for derivatives (outputs derived from) BIDS datasets; although this is a current work in progress, details can be found in: [BIDS Derivatives](https://bids-specification.readthedocs.io/en/latest/06-extensions.html).

In this tutorial, we'll explore the outputs generated by fMRIPREP and get a handle of how the data is organized from this preprocessing pipeline

Expand All @@ -25,12 +30,11 @@ Luckily the semi-standardized output for fMRIPrep is organized in such a way tha

First let's take a quick look at the fMRIPrep data structure:

~~~
```bash
tree -L 1 '../data/ds000030/derivatives/fmriprep'
~~~
{: .language-bash}
```

~~~
```output
../data/ds000030/derivatives/fmriprep/
├── sub-10171
Expand All @@ -53,17 +57,15 @@ tree -L 1 '../data/ds000030/derivatives/fmriprep'
├── sub-50077
├── sub-50081
└── sub-50083
~~~
{: .output}
```

First note that inside the fMRIPrep folder, we have a folder per-subject. Let's take a quick look at a single subject folder:

~~~
```bash
tree '../data/ds000030/derivatives/fmriprep/sub-10788'
~~~
{: .language-bash}
```

~~~
```output
../data/ds000030/derivatives/fmriprep/sub-10788/
├── anat
│ ├── sub-10788_desc-aparcaseg_dseg.nii.gz
Expand Down Expand Up @@ -106,54 +108,53 @@ tree '../data/ds000030/derivatives/fmriprep/sub-10788'
│ ├── sub-10788_task-rest_space-T1w_desc-preproc_bold.json
│ └── sub-10788_task-rest_space-T1w_desc-preproc_bold.nii.gz
...
~~~
{: .output}
```

As you can see above, each subject folder is organized into an <code>anat</code> and <code>func</code> sub-folder.
As you can see above, each subject folder is organized into an <code>anat</code> and <code>func</code> sub-folder.

Specifically:

- the <code>anat</code> folder contains the preprocessed anatomical data. If multiple T1 files are available (all T1s even across sessions), then these data are merged - you will always have one <code>anat</code> folder under the subject folder
- the <code>func</code> folder contains the preprocessed functional data. All tasks are dumped into the same folder and like the BIDS convention are indicated by the use of their filenames (<code>task-[task_here]</code>)
- the <code>func</code> folder contains the preprocessed functional data. All tasks are dumped into the same folder and like the BIDS convention are indicated by the use of their filenames (<code>task-[task\_here]</code>)

::::::::::::::::::::::::::::::::::::::::: callout

This data is single-session, so a session folder is missing here - but with multiple sessions you will see <code>anat</code> and <code>ses-[insert\_session\_here]</code> folders where each session folder contain a <code>func</code> folder.

> This data is single-session, so a session folder is missing here - but with multiple sessions you will see <code>anat</code> and <code>ses-[insert_session_here]</code> folders where each session folder contain a <code>func</code> folder.
{: .callout}

::::::::::::::::::::::::::::::::::::::::::::::::::

Hopefully you're now convinced that the outputs of fMRIPREP roughly follows BIDS organization principles. The filenames themselves give you a full description of what each file is (check the [slides](https://docs.google.com/presentation/d/1er6dQcERL-Yeb5-7A29tJnmqgHNaLpTLXM3e-SmpjDg/edit?usp=sharing) to get an idea of what each file means!

Now let's see how we can pull data in using pyBIDS!

Let's import pyBIDS through the <code>bids</code> module first:

~~~
```python
import bids
~~~
{: .language-python}
```

We can make a <code>bids.BIDSLayout</code> object as usual by just feeding in the fmriprep directory! However, there is one caveat... note that fMRIPrep doesn't exactly adhere to the *standard BIDS convention*. It uses fields such as <code>desc-</code> which are not part of the original BIDS specification. I.e:

~~~
```bash
sub-10788_desc-preproc_T1w.nii.gz
~~~
{: .language-bash}
```

In fact, BIDS allows for *extensions* which enable you to add additional fields to the standard BIDS convention (such as <code>desc-</code>!). fMRIprep uses the <code>derivatives</code> extension of the BIDS standard. pyBIDS can handle standard extensions to the BIDS specification quite easily:

~~~
```python
layout = bids.BIDSLayout('../data/ds000030/derivatives/fmriprep/', config=['bids','derivatives'])
~~~
{: .language-python}
```

Now that we have a layout object, we can pretend like we're working with a BIDS dataset! Let's try some common commands that you would've used with a BIDS dataset:

First, we'll demonstrate that we can grab a list of pre-processed subjects much like in the way we would grab subjects from a raw BIDS dataset:

~~~
```python
layout.get_subjects()
~~~
{: .language-python}
```

~~~
```output
['10171',
'10292',
'10365',
Expand All @@ -174,31 +175,27 @@ layout.get_subjects()
'50077',
'50081',
'50083']
~~~
{: .output}
```

We can also do the same for tasks
We can also do the same for tasks

~~~
layout.get_tasks()
~~~
{: .language-python}
```python
layout.get_tasks()
```

~~~
['rest']
~~~
{: .output}
```output
['rest']
```

Now let's try fetching specific files. Similar to how you would fetch BIDS data using pyBIDS, the exact same syntax will work for fMRIPREP derivatives. Let's try pulling just the preprocessed anatomical data.
Now let's try fetching specific files. Similar to how you would fetch BIDS data using pyBIDS, the exact same syntax will work for fMRIPREP derivatives. Let's try pulling just the preprocessed anatomical data.

Recall that the anatomical folder is organized as follows:

~~~
```bash
tree '../data/ds000030/derivatives/fmriprep/sub-10788/anat'^
~~~
{: .language-bash}
```

~~~
```output
../data/ds000030/derivatives/fmriprep/sub-10788/anat
├── sub-10788_desc-aparcaseg_dseg.nii.gz
├── sub-10788_desc-aseg_dseg.nii.gz
Expand All @@ -222,84 +219,97 @@ tree '../data/ds000030/derivatives/fmriprep/sub-10788/anat'^
└── sub-10788_space-MNI152NLin2009cAsym_label-WM_probseg.nii.gz
0 directories, 20 files
~~~
{: .output}
```

The file that we're interested in is of form <code>sub-[subject]_desc-preproc_T1w.nii.gz</code>. Now we can construct a pyBIDS call to pull these types of files specifically:
The file that we're interested in is of form <code>sub-[subject]\_desc-preproc\_T1w.nii.gz</code>. Now we can construct a pyBIDS call to pull these types of files specifically:

~~~
```python
preproc_T1 = layout.get(datatype='anat', desc='preproc', extension=".nii.gz")
preproc_T1
~~~
{: .language-python}
```

~~~
```output
[<BIDSImageFile filename='/home/jerry/projects/workshops/SDC-BIDS-fMRI/data/ds000030/derivatives/fmriprep/sub-10438/anat/sub-10438_desc-preproc_T1w.nii.gz'>,
<BIDSImageFile filename='/home/jerry/projects/workshops/SDC-BIDS-fMRI/data/ds000030/derivatives/fmriprep/sub-10438/anat/sub-10438_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz'>,
<BIDSImageFile filename='/home/jerry/projects/workshops/SDC-BIDS-fMRI/data/ds000030/derivatives/fmriprep/sub-10788/anat/sub-10788_desc-preproc_T1w.nii.gz'>,
<BIDSImageFile filename='/home/jerry/projects/workshops/SDC-BIDS-fMRI/data/ds000030/derivatives/fmriprep/sub-10788/anat/sub-10788_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz'>,
~~~
{: .output}
```

::::::::::::::::::::::::::::::::::::::::: callout

If we didn't configure pyBIDS with <code>config=['bids','derivatives']</code> then the <code>desc</code> keyword would not work!


>> If we didn't configure pyBIDS with <code>config=['bids','derivatives']</code> then the <code>desc</code> keyword would not work!
{: .callout}
::::::::::::::::::::::::::::::::::::::::::::::::::

Note that we also pulled in MNI152NLin2009cAsym_preproc.nii.gz data as well. This is data that has been transformed into MNI152NLin2009cAsym template space. We can pull this data out by further specifying our <code>layout.get</code> using the <code>space</code> argument:
Note that we also pulled in MNI152NLin2009cAsym\_preproc.nii.gz data as well. This is data that has been transformed into MNI152NLin2009cAsym template space. We can pull this data out by further specifying our <code>layout.get</code> using the <code>space</code> argument:

~~~
```python
mni_preproc_T1 = layout.get(datatype='anat',desc='preproc',extension='.nii.gz',space='MNI152NLin2009cAsym')
mni_preproc_T1
~~~
{: .language-python}
```

~~~
```output
[<BIDSImageFile filename='/home/jerry/projects/workshops/SDC-BIDS-fMRI/data/ds000030/derivatives/fmriprep/sub-10438/anat/sub-10438_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz'>,
<BIDSImageFile filename='/home/jerry/projects/workshops/SDC-BIDS-fMRI/data/ds000030/derivatives/fmriprep/sub-10788/anat/sub-10788_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz'>,
...
~~~
{: .output}
```

What if we wanted to pull out the data in T1 "native space" (it really is a template space, since it is merged T1s)? Unfortunately for this isn't directly possible using <code>layout.get</code>. Instead we'll use a bit of python magic to pull the data that we want:

~~~
```python
native_preproc_T1 = [f for f in preproc_T1 if f not in mni_preproc_T1]
native_preproc_T1
~~~
{: .language-python}

```

Similarily fMRI data can be pulled by specifying <code>datatype='func'</code> and using the <code>desc</code> argument as appropriate:

> ## Exercise 1
> 1. Get the list of **all** preprocessed functional data
> 2. Get the list of functional data in MNI152NLin2009cAsym space
> 3. Get the list of functional data in T1w space (native)
> Note that T1 space fMRI data can be pulled using <code>space="T1w"</code> (this is unlike the T1w data which required you to do some filtering)
>
> > ## Solution
> > *All the functional data*
> > ~~~
> > func_data = layout.get(datatype='func', desc='preproc')
> > ~~~
> > {: .language-python}
> >
> > *MNI152NLin2009cAsym Functional Data*
> > ~~~
> > mni_func_data = layout.get(datatype='func', desc='preproc', space='MNI152NLin2009cAsym')
> > mni_func_data
> > ~~~
> > {: .language-python}
> >
> > *Native/T1w space functional data*
> > ~~~
> > t1w_func_data = layout.get(datatype='func', desc='preproc', space='T1w')
> > t1w_func_data
> > ~~~
> > {: .language-python}
> >
> {: .solution}
{: .challenge}
::::::::::::::::::::::::::::::::::::::: challenge

## Exercise 1

1. Get the list of **all** preprocessed functional data
2. Get the list of functional data in MNI152NLin2009cAsym space
3. Get the list of functional data in T1w space (native)
Note that T1 space fMRI data can be pulled using <code>space="T1w"</code> (this is unlike the T1w data which required you to do some filtering)

::::::::::::::: solution

## Solution

*All the functional data*

```python
func_data = layout.get(datatype='func', desc='preproc')
```

*MNI152NLin2009cAsym Functional Data*

```python
mni_func_data = layout.get(datatype='func', desc='preproc', space='MNI152NLin2009cAsym')
mni_func_data
```

*Native/T1w space functional data*

```python
t1w_func_data = layout.get(datatype='func', desc='preproc', space='T1w')
t1w_func_data
```

:::::::::::::::::::::::::

::::::::::::::::::::::::::::::::::::::::::::::::::

Now that we have a handle on how fMRIPREP preprocessed data is organized and how we can pull this data. Let's start working with the actual data itself!

{% include links.md %}


:::::::::::::::::::::::::::::::::::::::: keypoints

- fMRIPrep stores preprocessed data in a 'BIDS-like' fashion
- You can pull files using pyBIDS much like how you can navigate raw BIDS data

::::::::::::::::::::::::::::::::::::::::::::::::::


0 comments on commit 0fb08e8

Please sign in to comment.