Skip to content

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

  1. Clone this Gitlab repo locally, and open VSCode.
  2. In VSCode, select File > Open Folder....
  3. Select debug-bids-curation folder.

Setup the Virtual Environment and Python Interpreter

  1. In VSCode, run shift+command+p to open the VSCode command prompt.
  2. Start typing Python: Select Interpreter and select from the pulldown list. 001-VSCode-SelectPythonInterpreter.png
  3. Click Create Virtual Environment to set up a new virtual environment for debugging. 002-VSCode-CreateVirtualEnvironment.png
  4. Select either Venv or Conda. This tutorial will use Conda, but feel free to use whichever you are more comfortable with. 003-VSCode-SelectEnvironment.png
  5. Select a Python version for the new virtual environment. This tutorial will use Python 3.11, however, you can use any version >3.8. 004-VSCode-SelectPythonVersion.png
  6. 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. 005-VSCode-EnvironmentCreated.png

Install flywheel-bids package in virtual environment

  1. 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. 006-VSCode-OpenTerminal.png
  2. In the terminal window prompt type the following to install the flywheel-bids python package:

    python3 -m pip install flywheel-bids
    

    007-VSCode-InstallFlywheelBIDS.png

Setup the Run/Debug Configuration

  1. Navigate to the debug panel in VSCode and click on the blue Run and Debug button. 008-VSCode-NavigateToDebug.png
  2. From the center VSCode command pull-down menu, select Python Debugger. 009-VSCode-SelectPythonDebugger.png
  3. Then select Python File for the Debug Configuration. 010-VSCode-DebugPythonFile.png
  4. Back in the VSCode Run and Debug side panel, click on create a launch.json file to add custom configurations to the debugging environment. 011-VSCode-SetConfigs.png
  5. A default launch.json file should open in a new tab. 012-VSCode-LaunchJSON.png
  6. 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 the runCurate.py file. Under "console: "integratedTerminal", add the following two lines:

    "justMyCode": false,
    "debugOptions": ["DebugStdLib"],
    
  7. The second set of configuration options are specific to the curate-bids command. You will need to add both the args and env sections to pass the necessary arguments to the curate-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 the env section as needed. (You can add your API key directly as an argument and omit the env 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 and p 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"
            }
    

    013-VSCode-UpdateLaunchJSON.png 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.

  1. For file "runCurate.py", set one at main() 014-VSCode-SetMainBreakpoint.png.png

  2. Right-click on the main() function. Select Go to Declaration to open the curate_bids.py file. 015-VSCode-GoToDeclaration.png

  3. Set the following breakpoints in curate_bids.py:

    • project = fw.get_project(project_id)

    016-VSCode-ProjectBreakpoint.png

    • if fw:

    017-VSCode-IfFWBreakpoint.png

  4. In curate_bids.py, navigate to the function bidsify_flywheel.process_matching_templates(), right-click on it, and select Go to Declaration to open bidsify_flywheel.py. 018-VSCode-GoToDeclaration.png

  5. In bidsify_flywheel.py, navigate to the function rule_matches(). At rule.test(context), we will set a conditional breakpoint to test the rule for curating func 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.... 019-VSCode-ConditionalBreakpoint.png

  6. 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 the reproin_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")

020-VSCode-SetExpression.png

  1. Press Enter or Return in the Expression box to set the conditional breakpoint. 021-VSCode-ConditionalBreakpointSet.png

    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.

  2. 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. 022-VSCode-RunDebugging.png