I would like to run a BIDS-App for only a subset of participants that fulfill a specific set of criteria to save computational time. Right now, I am starting the BIDS-App for each subject by reading in the dataset and then iterating over all found subjects (the following is more or less pseudo-code):
layout = BIDSLayout(bids_dir)
participant_labels = layout.get_subjects()
for participant in participant_labels:
subprocess.run(f"bids_app ... --participant_label {participant}")
While browsing through the documentation of bids.layout.BIDSLayout
I saw that it also offers a .save
method and and sources
argument.
I thought I could somehow create a separate python script that outputs a reduced layout
object that I save to disk using layout_filtered.save('layout_filtered.sqlite3')
. I also thought that I could then pass this file to BIDSLayout().load()
in the code above so the dataset is read in and will directly be reduced to the subjects of interest. But I somehow cannot get this to work (or maybe I am reading the docs wrong).
P.S.: This whole question is loosely related to my comment in this thread. The goal is to only start a BIDS-App for certain participants known to match the criteria of interest.
Here’s some code to play around with:
import subprocess
import os
import shutil
from bids import BIDSLayout
###############################################################################
## Download example dataset
###############################################################################
ds_name = "ds006"
def download_bids_dataset(ds_name):
if not os.path.isdir(ds_name):
tmp_dir = "temp_repo" # temporary folder for cloning
# Clone the repository into a temporary directory
subprocess.run(["git", "clone", "--depth", "1", "--filter=blob:none","--sparse","https://github.com/bids-standard/bids-examples.git",tmp_dir], check=True)
# Enter the temporary repository folder
os.chdir(tmp_dir)
# Configure sparse checkout to include only the ds_name folder
subprocess.run(["git", "sparse-checkout", "set", ds_name], check=True)
# Return to the parent directory
os.chdir("..")
# Move the ds_name folder from the temporary directory to the working directory
shutil.move(os.path.join(tmp_dir, ds_name), ds_name)
# Remove the temporary repository folder
shutil.rmtree(tmp_dir)
print(f"Folder '{ds_name}' downloaded successfully into your working directory.")
# Example Usage:
download_bids_dataset(ds_name)
###############################################################################
## Read in dataset and reduce to whatever criteria so you only end up
## with subjects that fullfill these criteria. Then save this reduced layout
## to disk.
###############################################################################
## By the way: would be nice if you could do something like layout.filter(....),
## to reduce the layout in-place, but as pybids doesn't offer this atm.
layout = BIDSLayout(root=ds_name,validate=True)
partipants_all = layout.get_subjects()
# Reduce this layout. For example let's pretend only subjects 1-9 have
# all the criteria that we wish for. Keep in mind that in reality it would
# be hard to create a regex that would match all the criteria you wish for in
# one argument. For example, you might be interested in a subset of
# subjects with onyl certain sessions,runs,modalities, etc.
layout_filtered = BIDSLayout(root=ds_name,validate=True,ignore='sub-1\d')
partipants_filtered = layout_filtered.get_subjects()
# save filtered layout
if not os.path.exists('./layout_filtered.sqlite3'):
layout_filtered.save('./layout_filtered.sqlite3')
###############################################################################
## Read in reduced BIDSLayout and iterate over subjects of choice to start
## BIDS-App for each of these subjects
###############################################################################
# read in the dataset and directly reduce to subjects of interest using sources
layout_for_bids_app = BIDSLayout(root=ds_name,validate=True,sources='./layout_filtered.sqlite3')
# return list of participants given the used query
participants_for_bids_app = layout_for_bids_app.get_subjects()
for participant in participants_for_bids_app:
subprocess.run(f"echo {participant}",shell=True)