BIDS Curation Tutorial Part 6: Project Curation Template
Introduction
For studies using existing custom BIDS curation templates or looking to create their own custom curation templates, it is important to understand how to make edits or extend a template to accommodate a new BIDS curation use-case. It is also useful to understand the basic steps for debugging errors with BIDS curation templates locally. This tutorial will walk users through a couple of examples to extend the Flywheel BIDS curation reproin.json
template file, as well as how to set up debugging in VSCode.
Extend the Curation Template by Creating a New Rule
Existing Flywheel BIDS Curation template files
The existing Flywheel BIDS Curation template files can be found here. If you are interested in extending an existing Flywheel-provided template, we recommend extending the reproin.json
template file.
Example 1: Extending a template to fix a curation error
The following example demonstrates how to extend a template file rule to fix a common curation failure. In this scenario, we have multiple runs of the same functional acquisition (e.g., multiple runs of the same task). However, the acquisition label does not include the key word run
. So, we end up with multiple, duplicate BIDS filepaths.
To extend the existing reproin.json
template file, we first copy the existing reproin_func_file
rule from the reproin.json
template file to a new JSON
file and then edit the Run
initialization.
Note
In the below code block, parts of the reproin_func_file
rule are replaced with ...
to save space.
The reproin
template already has a Run
attribute, so we just need to replace the existing code with code that will automatically add a run-<index>
descriptor to the BIDS filename and iterate the <index>
. An example of JSON
code that will do this is shown below in the "Run": { }
block. This block of text includes both "acquisition.label"
and "$run_counter"
.
{
"extends": "reproin",
"description": "Handle functional files without ‘run‘ in them",
"rules": [
{
"id": "reproin_func_file",
"template": "func_file",
"where": {
"container_type": "file",
"parent_container_type": "acquisition",
...
},
"initialize": {
"Task": {...},
"Acq": {...},
"Ce": {...},
"Rec": {...},
"Dir": {...},
"Run": {
"acquisition.label": {
"$take": true,
"$format": [
{
"$replace": {
"$pattern": ".+",
"$replacement": "+"
}
}
]
},
"$run_counter": {
"key": "func.{file.info.BIDS.Task}.{file.info.BIDS.Suffix}.{file.type}"
}
},
"Echo": {...},
"Part": {...},
"Suffix": {...}
}
}
]
}
Once we have made the above edits to our copy of the reproin_func_file
rule, we can save this out in a new JSON
file (e.g., reproin_run_counter.json
) and upload it as an attachment to our project in the Flywheel interface. Then, when running the BIDS Curation Gear
, we can supply our template extension file as the optional input template file.
Example 2: Extending a template to add a new acquisition type
In this second example, we will cover the case where you need to extend a definition to cover a new acquisition type. In this case, we will demonstrate how to extend the existing reproin.json
template file to curate QSM acquisitions. Consulting the BIDS Specification, QSM acquisitions are handled the same way as all other anat
files, so we do not need to update or add any new rules. We do need to extend the reproin
template definition section for anat
files to include the required Chimap
suffix.
Note
In the below code block, parts of the anat_file
definition are replaced with ...
to save space.
The reproin.json
template file already has a definition for anat_file
, but it is missing Chimap
in the list of known suffixes. As with Example 1, we can copy the definition for anat_file
from the reproin.json
template file to a new JSON
file. Then, we just need to add Chimap
to the list under "Suffix": {"enum: []}
. Once we have made our update, we can save out our extension as a new JSON
file (e.g., reproin_template_chimap.json
) and upload it as an attachment to our project in the Flywheel interface. Again as with Example 1, we can then specify our template extension JSON
file as the optional input template file to the BIDS Curation Gear.
{
"extends": "reproin",
"description": "Curate QSM scans using Chimap suffix",
"definitions": {
"anat_file": {
"description": "BIDS anat file template",
"properties": {
"Filename": {...},
"Folder": {...},
"Path": {...},
"Acq": {...},
"Ce": {...},
"Rec": {...},
"Run": {...},
"Inv": {...},
"Mod": {...},
"Echo": {...},
"Part": {...},
"Suffix": {
"type": "string",
"title": "Suffix: after all entities and before the file extension",
"default": "",
"enum": [
"FLAIR",
"PDT2",
"Pdw",
"T1w",
...,
"mp2rage",
"Chimap"
]
},
"Custom": {...}
},
"required": [
"Filename",
"Suffix"
]
}
}
}
Use a Debugging Environment to Test the New Rule
To test whether a new rule fixes a curation failure or correctly curates a new acquisition type, we recommend the use a development environment that has a debugging tool. Below is an example of how to setup VSCode and its debugger.
Download the Flywheel BIDS curation debug code
- Clone this Gitlab repo locally, and open VSCode.
- In VSCode, select File > Open Folder....
- Select debug-bids-curation folder.
Setup the Virtual Environment and Python Interpreter
- In VSCode, run shift+command+p to open the VSCode command prompt.
- Start typing Python: Select Interpreter and select from the pulldown list.
- Click Create Virtual Environment to set up a new virtual environment for debugging.
- Select either Venv or Conda. This tutorial will use Conda, but feel free to use whichever you are more comfortable with.
- Select a Python version for the new virtual environment. This tutorial will use Python 3.11, however, you can use any version >3.8.
- It may take a minute or so for VSCode to build the new virtual environment and install Python. Check the debug-bids-curation folder for a new .conda (or .venv) folder.
Install flywheel-bids package in virtual environment
- In the upper-right hand corner of the VSCode window, click on the Toggle Panel icon (command+j) to open a terminal window. On the far left-hand side of the terminal prompt, you should see
(.conda)
indicating that terminal window is running inside the virtual environment we just created in the previous step. -
In the terminal window prompt type the following to install the
flywheel-bids
python package:
Setup the Run/Debug Configuration
- Navigate to the debug panel in VSCode and click on the blue Run and Debug button.
- From the center VSCode command pull-down menu, select Python Debugger.
- Then select Python File for the Debug Configuration.
- Back in the VSCode Run and Debug side panel, click on create a launch.json file to add custom configurations to the debugging environment.
- A default
launch.json
file should open in a new tab. -
The first configuration options you need to add to the default
launch.json
file tells VSCode to step into functions that are not part of the local directory/repository. Adding these config options will allow us to debug more than just therunCurate.py
file. Under"console: "integratedTerminal"
, add the following two lines: -
The second set of configuration options are specific to the
curate-bids
command. You will need to add both theargs
andenv
sections to pass the necessary arguments to thecurate-bids
command. In the below code block and screengrab, the--api-key
argument assumes that you have your Flywheel API key saved as an environmental variable called,FW_API_KEY
. Update this environmental variable name here and below in theenv
section as needed. (You can add your API key directly as an argument and omit theenv
section, but this is not recommended, as it risks exposing your API key to others.) You will also need to update the-p
argument with your project name and the-g
name with the group name of your project. If only one session needs to be curated, then a session id can be passed instead of the-g
andp
parameters. You can leave--reset
and--pickle_tree
as is."args": [ "--api-key", "${env:FW_API_KEY}", "-p", "project_name", "-g", "group_name", "--reset", "--pickle_tree" ], "env": { "FW_API_KEY": "arg1" }
8. Save your changes to the
launch.json
file.
Setting Breakpoints
The breakpoints below are recommended to aid with debugging.
Breakpoints in runCurate.py
and curate_bids.py
The breakpoints in runCurate.py
and curate_bids.py
are mostly for stepping through the code the first time, so that one can understand how it works.
-
For file "runCurate.py", set one at
main()
-
Right-click on the
main()
function. Select Go to Declaration to open thecurate_bids.py
file. -
Set the following breakpoints in
curate_bids.py
:project = fw.get_project(project_id)
if fw:
-
In
curate_bids.py
, navigate to the functionbidsify_flywheel.process_matching_templates()
, right-click on it, and select Go to Declaration to openbidsify_flywheel.py
. -
In
bidsify_flywheel.py
, navigate to the functionrule_matches()
. Atrule.test(context)
, we will set a conditional breakpoint to test the rule for curatingfunc
files. In VSCode, to set a conditional breakpoint, right-click at the line where you want to set a breakpoint and select Add Conditional Breakpoint.... -
In the code box that pops up, make sure Expression is selected, and enter the desired condition to activate the breakpoint. For this example, we will use an expression that stops when a
func
file is being curated using thereproin_func_file
rule. You can edit the below framework to match your needs for debugging, replacing"func"
with any string from an acquisition label, and"reproin_func_file"
with the name of the rule you want to debug.
("file" in context) and ("func" in context["file"].data["name"]) and (rule.id == "reproin_func_file")
-
Press Enter or Return in the Expression box to set the conditional breakpoint.
Conditional breakpoint in
bidsify_flywheel.rule_matches()
The conditional breakpoint we just set is the most important one for debugging a newly added rule. Setting this conditional breakpoint with the desired stopping criterion should make debugging new or updated rules more efficient.
-
Now that the breakpoints are set, you can start debugging. Navigate back to the file tab with
runCurate.py
and launch the Python Debugger by clicking on the green arrow ("play") button at the top of the VSCode debugging panel. Use the up and down arrows to step through the code. The red square ("stop") button will exit the current debugging session. You should start to see logging information in the TERMINAL window. The DEBUG CONSOLE can be used to print out variables and interactively test potential fixes.