Brief Introduction to bidser

bidser is an R package for working with the BIDS neuroimaging projects. The goal of the package is to allow one to query files that are stored in a hierarchical BIDS structure. Below we load in a BIDS example project, which is stored and accessed through a bids_project object.

There is a Python package called pybids that can be used to work with BIDS in Python and is more developed.

#> Loading bidser


library(bidser)
library(tibble)
library(gluedown)

proj_path <- system.file("inst/extdata/ds001", package="bidser")
proj <- bids_project(proj_path)

print(proj)
#> project:  ds001 
#> participants (n): 16 
#> tasks:  balloonanalogrisktask 
#> image types:  func 
#> modalities:   
#> keys:  folder, kind, subid, suffix, type, run, task

We can see that this is a project with 16 participants with anatomical and functional scans and a task called balloonanalogrisktask.

We can also make some basic queries of the project to gather information. For example, does the project have any “sessions”?


sessions(proj)
#> NULL

No sessions. And what are the participant ids?

sids <- participants(proj)
  • 01
  • 02
  • 03
  • 04
  • 05
  • 06
  • 07
  • 08
  • 09
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

Does it have task event files?



fnames <- head(basename(event_files(proj)), n=3)
## print the first three event files
  1. sub-01_task-balloonanalogrisktask_run-01_events.tsv
  2. sub-01_task-balloonanalogrisktask_run-02_events.tsv
  3. sub-01_task-balloonanalogrisktask_run-03_events.tsv

Searching the BIDS structure

Lets now search for some arbitrary files. For example, we wish to retrieve all the “T1w” anatomical images.

  • sub-01/anat/sub-01_T1w.nii.gz
  • sub-02/anat/sub-02_T1w.nii.gz
  • sub-03/anat/sub-03_T1w.nii.gz
  • sub-04/anat/sub-04_T1w.nii.gz
  • sub-05/anat/sub-05_T1w.nii.gz
  • sub-06/anat/sub-06_T1w.nii.gz
  • sub-07/anat/sub-07_T1w.nii.gz
  • sub-08/anat/sub-08_T1w.nii.gz
  • sub-09/anat/sub-09_T1w.nii.gz
  • sub-10/anat/sub-10_T1w.nii.gz
  • sub-11/anat/sub-11_T1w.nii.gz
  • sub-12/anat/sub-12_T1w.nii.gz
  • sub-13/anat/sub-13_T1w.nii.gz
  • sub-14/anat/sub-14_T1w.nii.gz
  • sub-15/anat/sub-15_T1w.nii.gz
  • sub-16/anat/sub-16_T1w.nii.gz

Now we search for any scans containing the string “bold”.


bold <- search_files(proj, "bold")

## take the first 5 files, since there are alot.
bold <- head(bold, 5)
  • sub-01/func/sub-01_task-balloonanalogrisktask_run-01_bold.nii.gz
  • sub-01/func/sub-01_task-balloonanalogrisktask_run-02_bold.nii.gz
  • sub-01/func/sub-01_task-balloonanalogrisktask_run-03_bold.nii.gz
  • sub-02/func/sub-02_task-balloonanalogrisktask_run-01_bold.nii.gz
  • sub-02/func/sub-02_task-balloonanalogrisktask_run-02_bold.nii.gz

Specialized querying functions

If we are only interested in functional bolds scans (rather than any file with “bold” in it), there is a special function called func_scans to return such files


fscans <- func_scans(proj)

## take the first 5 files, since there are alot.
fscans <- head(bold, 5)
  • sub-01/func/sub-01_task-balloonanalogrisktask_run-01_bold.nii.gz
  • sub-01/func/sub-01_task-balloonanalogrisktask_run-02_bold.nii.gz
  • sub-01/func/sub-01_task-balloonanalogrisktask_run-03_bold.nii.gz
  • sub-02/func/sub-02_task-balloonanalogrisktask_run-01_bold.nii.gz
  • sub-02/func/sub-02_task-balloonanalogrisktask_run-02_bold.nii.gz

Suppose though that we only want the scans from subject “16”?


fscans_16 <- func_scans(proj, subid="16")
  • sub-16_task-balloonanalogrisktask_run-01_bold.nii.gz
  • sub-16_task-balloonanalogrisktask_run-02_bold.nii.gz
  • sub-16_task-balloonanalogrisktask_run-03_bold.nii.gz

Reading in Task Event files

BIDS event files describe the event-structure of fmri experiments. They can be easy read in to R as a set of data.frames using the read_events function. As can be seen in the output below, read_events returns a data.frame with four columns: .subid, .run, .task, data. The data is nested in the table because there is no guantee that all events files have the same columns (for example, event files associated with different tasks).


evs <- read_events(proj)
head(evs)
#> # A tibble: 6 x 4
#> # Groups:   .subid, .run, .task [6]
#>   .subid .run  .task                 data              
#>   <chr>  <chr> <chr>                 <list>            
#> 1 01     01    balloonanalogrisktask <tibble [158 × 8]>
#> 2 01     02    balloonanalogrisktask <tibble [156 × 8]>
#> 3 01     03    balloonanalogrisktask <tibble [149 × 8]>
#> 4 02     01    balloonanalogrisktask <tibble [185 × 8]>
#> 5 02     02    balloonanalogrisktask <tibble [184 × 8]>
#> 6 02     03    balloonanalogrisktask <tibble [186 × 8]>

Now we can filter the table as we like, for example, to extract the data only from the first participant. We can then “unnest” the data variable to access the actual event structure.

library(tidyr)
#> 
#> Attaching package: 'tidyr'
#> The following object is masked from 'package:bidser':
#> 
#>     one_of
#> The following object is masked from 'package:testthat':
#> 
#>     matches
ev1 <- evs %>% filter(.subid == "01") %>% unnest(cols=c(data))
head(ev1)
#> # A tibble: 6 x 11
#> # Groups:   .subid, .run, .task [1]
#>   .subid .run  .task     onset duration trial_type  cash_demean control_pumps_d…
#>   <chr>  <chr> <chr>     <dbl>    <dbl> <chr>             <dbl>            <dbl>
#> 1 01     01    balloon…  0.061    0.772 pumps_deme…          NA               NA
#> 2 01     01    balloon…  4.96     0.772 pumps_deme…          NA               NA
#> 3 01     01    balloon…  7.18     0.772 pumps_deme…          NA               NA
#> 4 01     01    balloon… 10.4      0.772 pumps_deme…          NA               NA
#> 5 01     01    balloon… 13.4      0.772 pumps_deme…          NA               NA
#> 6 01     01    balloon… 16.8      0.772 explode_de…          NA               NA
#> # … with 3 more variables: explode_demean <dbl>, pumps_demean <dbl>,
#> #   response_time <dbl>

Reading files produced by FMRIPrep

If you have processed a dataset with FMRIPrep, bidser can be used to read in the many of the resultant derivative files. If a project has an FMRIPrep derivatives folder, then we can read in the BIDS hierarchy plus derivatives as follows:

proj_path <- system.file("inst/extdata/phoneme_stripped", package="bidser")
proj <- bids_project(proj_path, fmriprep=TRUE)
#> Warning in bids_project(proj_path, fmriprep = TRUE): dataset_description.json is
#> missing

print(proj)
#> project:  phoneme_stripped 
#> participants (n): 24 
#> tasks:  phoneme rest 
#> fmriprep:  derivatives/fmriprep 
#> image types:  func funcprep 
#> modalities:  bold 
#> keys:  folder, kind, subid, suffix, type, run, task, modality, space, label

By default it is assumed that the FMRIPrep files are in ‘derivatives/fmriprep’.

Now we can access various derivative files with convenience functions. For example, to read in “preproc” scans we can use the preproc_scans function.


pscans <- preproc_scans(proj, subid="1001")
print(as.character(pscans))
#>  [1] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-01_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [2] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-02_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [3] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-03_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [4] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-04_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [5] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-05_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [6] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-06_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [7] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-07_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [8] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-08_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#>  [9] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-09_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"
#> [10] "derivatives/fmriprep/sub-1001/func/sub-1001_task-phoneme_run-10_bold_space-MNI152NLin2009cAsym_preproc.nii.gz"