BIDS stats model#

This file allows you to specify the GLM to run and which contrasts to compute.

It follows BIDS statistical model.

This type of JSON file is a bit more complicated than the usual JSON files, you might be acquainted with in BIDS. So make sure you have a read through the JSON 101 page.

Then have a look at the walkthrough that explains how to build a simple model.

Validate your model#

In Visual Studio Code#

You can add those lines to the .vscode/settings.json of your project to help you validate BIDS stats models as you write them.

{
  "json.schemas": [
    {
      "fileMatch": [
        "model-*_smdl.json"
      ],
      "url": "https://bids-standard.github.io/stats-models/BIDSStatsModel.json"
    }
  ],
  "esbonio.sphinx.confDir": ""
}

In the browser#

Otherwise you can use the online validator and copy paste your model in it.

Using the BIDS stats model python package#

Requires python and pip.

From within the bidspm folder open a terminal and install the bidspm package.

pip install .

Then you can validate your model with the following command.

validate_model path_to_your_model_json

Loading and interacting with a BIDS stats model#

You can use the BidsModel class to create a bids model instance and interact with. This class inherits from bids-matlab bids.Model class.

class BidsModel#
Property Summary
SPM#

content of SPM.mat

Method Summary
addConfoundsToDesignMatrix(varargin)#

Add some typical confounds to the design matrix of bids stat model.

This will update the design matrix of the root node of the model.

Similar to the nilearn.interfaces.fmriprep.load_confounds()

USAGE:

bm = bm.addConfoundsToDesignMatrix('strategy', strategy);
Parameters:
  • bm (BidsModel instance or path to a _smdl.json file) – bids stats model.

  • strategy (struct) –

    structure describing the confoudd strategy.

    The structure must have the following field:

    • strategy: cell array of char with the strategies to apply.

    The structure may have the following field:

    • motion: motion regressors strategy

    • scrub: scrubbing strategy

    • wm_csf: white matter and cerebrospinal fluid regressors strategy

    • non_steady_state: non steady state regressors strategy

    See the nilearn documentation (mentioned above) for more information on the possible values those strategies can take.

  • updateName (logical) –

    Append the name of the root node with a string describing the counfounds added.

    rp-{motion}_scrub-{scrub}_tissue-{wm_csf}_nsso-{non_steady_state}

    default = false

Return type:

BidsModel instance

Returns:

bids stats model with the confounds added.

EXAMPLE:

strategy.strategies = {'motion', 'wm_csf', 'scrub', 'non_steady_state'};
strategy.motion = 'full';
strategy.scrub = true;
strategy.non_steady_state = true;

bm = bm.addConfoundsToDesignMatrix('strategy', strategy);
getHRFderivatives(varargin)#

returns the HRF derivatives of a node of a BIDS statistical model

getInclusiveMaskThreshold(varargin)#

returns the threshold for inclusive masking of subject level GLM node of a BIDS statistical model

getModelMask(varargin)#

returns the mask of a node of a BIDS statistical model

getSerialCorrelationCorrection(varargin)#

returns the Serial Correlation Correction of a node of a BIDS statistical model

groupLevelGlmType(nodeName, participants)#

Return type of GLM for a dataset level node.

USAGE:

[type, groupBy] = bm.groupLevelGlmType(obj, nodeName, participants)
Parameters:
  • nodeName (char)

  • participants (struct) – content of participants.tsv

validateConstrasts()#

validate all contrasts spec in the model

validateGroupBy(nodeName, participants)#

USAGE:

bm = bm.validateGroupBy(nodeName, participants);

Only certain type of GroupBy supported for now for each level

This helps doing some defensive programming.

There are also extra functions to interact with those models.

bidspm implementation of the BIDS stats model#

bidspm only implements a subset of what is currently theoretically possible with the BIDS stats model.

For example, at the subject level the bidspm can only access variables, that are in the events.tsv in that raw dataset or in the regressors.tsv or timeseries.tsv generated by the preprocessing pipeline.

At the group level, it is only possible to access some variables from the participants.tsv file.

Transformation#

The Transformations object allows you to define what you want to do to some variables, before you put them in the design matrix.

Currently bidspm can only transform variables contained in events.tsv files.

It uses bids-matlab transformers to run those transformations. Please see this bids-matlab documentation to know how to use them and call them in your JSON.

You can find a list of the available variables transformations in the bids matlab doc and on the variable-transforms repository

The advantage of these bids-matlab transformers is that they allow you to directly test them on tsv files to quickly see what outcome a series of transformers will produce.

Below is an example on how to subtract 3 seconds from the event onsets of the conditions motion listed in the trial_type columns of the events.tsv file, and put the output in a variable called motion.

"Transformations": {
    "Transformer": "bidspm",
    "Instructions": [
        {
            "Name": "Subtract",
            "Input": [
              "onset"
            ],
            "Query": "trial_type==motion",
            "Value": 3,
            "Output": [
                "motion"
            ]
        }
    ]
}

At the subject level, bidspm can only access apply transformation on the content events.tsv.

You can find demo of how to design the transformers for your analysis in the demos/transformers folder and also in demos/ds003717/code/04_transformation.m.

HRF#

For a given Node, Model.X defines the variables that have to be put in the design matrix.

Here trans_? means any of the translation parameters (in this case trans_x, trans_y, trans_z) from the realignment that are stored in _confounds.tsv files.

Similarly *outlier* means that ANY “scrubbing” regressors containing the word outlier created by fMRIprep or bidspm to detect motion outlier or potential dummy scans will be included.

"Model": {
    "Type": "glm",
    "X": [
        "motion",
        "static",
        "trans_?",
        "rot_?",
        "*outlier*"
    ],
    "HRF": {
        "Variables": [
            "motion",
            "static"
        ],
        "Model": "spm"
    }
}

HRF specifies:

  • which variables of X have to be convolved

  • what HRF model to use to do so.

You can choose from:

  • "spm"

  • "spm + derivative"

  • "spm + derivative + dispersion"

Not yet implemented:

  • "fir"

Corresponding options in SPM batch

Software#

By default, bidspm will use SPM’s FAST model for the SerialCorrelation model.

It will also use a value of 0.8 for the InclusiveMaskingThreshold to define the implicit inclusive mask that is used by SPM to determine in which voxels the GLM will be estimated (the value is taken fromdefaults.mask.thresh from SPM’s defaults).

This corresponds to explicitly setting the following fields in the Model.Software.SPM object of a node in the BIDS stats model.

{
  "Nodes": [
    {
      "Level": "Run",
      "Name": "run_level",
      "Model": {
        "X": ["trial_type.listening"],
        "HRF": {
          "Variables": ["trial_type.listening"],
          "Model": "spm"
        },
        "Type": "glm",
        "Software": {
          "SPM": {
            "SerialCorrelation": "FAST",
            "InclusiveMaskingThreshold": 0.8
          }
        }
      }
    }
  ]
}

These values will explicitly be added to your your default BIDS stats model if you use bidspm 'default_model' action.

bidspm(bids_dir, output_dir, 'dataset', ...
        'action', 'default_model')

Note that if you wanted to use the AR(1) model for the serial correlation and to include all voxels in the implicit mask, you would have to set the following:

{
  "Nodes": [
    {
      "Level": "Run",
      "Name": "run_level",
      "Model": {
        "X": ["trial_type.listening"],
        "HRF": {
          "Variables": ["trial_type.listening"],
          "Model": "spm"
        },
        "Type": "glm",
        "Software": {
          "SPM": {
            "SerialCorrelation": "AR(1)",
            "InclusiveMaskingThreshold": "-Inf"
          }
        }
      }
    }
  ]
}
../_images/gui_batch_model_serialCorrelation_maskThresh.png

Corresponding options in SPM batch#

Results#

It is possible to specify the results you want to view directly in the Model.Software object of any Nodes in the BIDS stats model.

See the help section of the bidsResults() function for more detail, but here is an example how you could specify it in a JSON.

"Model": {
    "Software": {
        "bidspm": {
          "Results": [
              {
                "name": [
                    "contrast_name", "other_contrast_name"
                ],
                "p": 0.05,
                "MC": "FWE",
                "png": true,
                "binary": true,
                "nidm": true,
                "montage": {
                    "do": true,
                    "slices": [
                    -4,
                    0,
                    4,
                    8,
                    16
                    ],
                    "background": {
                    "suffix": "T1w",
                    "desc": "preproc",
                    "modality": "anat"
                    }
                }
              },
              {
                "Description": "Note that you can specify multiple results objects, each with different parameters.",
                "name": [
                    "yes_another_contrast_name"
                ],
                "p": 0.01,
                "k": 10,
                "MC": "none",
                "csv": true,
                "atlas": "AAL"
              }
          ]
        }
    }
}

Contrasts#

Run level#

To stay close to the way most SPM users are familiar with, all runs are analyzed in one single GLM.

Contrasts are the run level that are either specified using DummyContrasts or Contrasts will be computed.

Implicit contrast numbering#

If a run label or session label cannot be inferred from the BIDS filenames for example with a subject like this one (with trial type listening):

sub-01
└── func
    ├── sub-01_task-auditory_bold.nii
    └── sub-01_task-auditory_events.tsv

a number will be appended to their name (for example listening_1) as shown in the SPM gui in Contrast naming when no explicit run or session can be inferred.

{
  "Level": "Run",
  "Name": "run_level",
  "GroupBy": [
    "run",
    "subject"
  ],
  "Model": {
    "X": [
      "trial_type.listening",
      "trans_?",
      "rot_?"
    ],
    "HRF": {
      "Variables": [
        "trial_type.listening"
      ],
      "Model": "spm"
    },
    "Type": "glm"
  },
  "DummyContrasts": {
    "Test": "t",
    "Contrasts": [
      "trial_type.listening"
    ]
  },
  "Contrasts": [
    {
      "Name": "listening_inf_baseline",
      "ConditionList": [
        "trial_type.listening"
      ],
      "Weights": [
        -1
      ],
      "Test": "t"
    }
  ]
}
../_images/gui_contrast_no_run.png

Contrast naming when no explicit run or session can be inferred#

Explicit contrast numbering#
Run label#

When possible the contrast name will be containing the BIDS session and / or run label from where it came from. For example cash_demean_run-1, cash_demean_run-2 if only run labels are available, with a subject like this one (with trial type cash_demean):

sub-01
└── func
    ├── sub-01_task-balloonanalogrisktask_run-01_bold.nii.gz
    ├── sub-01_task-balloonanalogrisktask_run-01_events.tsv
    ├── sub-01_task-balloonanalogrisktask_run-02_bold.nii.gz
    ├── sub-01_task-balloonanalogrisktask_run-02_events.tsv
    ├── sub-01_task-balloonanalogrisktask_run-03_bold.nii.gz
    └── sub-01_task-balloonanalogrisktask_run-03_events.tsv

as shown in Contrast for run-1 and Contrast for run-2.

{
  "Level": "Run",
  "Name": "run_level",
  "GroupBy": [
    "run",
    "subject"
  ],
  "Model": {
    "X": [
      "trial_type.cash_demean",
      "trial_type.control_pumps_demean",
      "trial_type.explode_demean",
      "trial_type.pumps_demean",
      "trans_*",
      "rot_*",
      "*outlier*"
    ],
    "HRF": {
      "Variables": [
        "trial_type.cash_demean",
        "trial_type.control_pumps_demean",
        "trial_type.explode_demean",
        "trial_type.pumps_demean"
      ],
      "Model": "spm + derivative"
    },
    "Type": "glm"
  },
  "DummyContrasts": {
    "Test": "t",
    "Contrasts": [
      "trial_type.cash_demean",
      "trial_type.control_pumps_demean",
      "trial_type.explode_demean",
      "trial_type.pumps_demean"
    ]
  }
}
../_images/gui_contrast_run_1.png

Contrast for run-1#

../_images/gui_contrast_run_2.png

Contrast for run-2#

Session label#

For a subject likes this one (with trial type Correct_Task)

sub-01
├── ses-retest
│   └── func
│       ├── sub-01_ses-retest_task-linebisection_bold.nii.gz
│       └── sub-01_ses-retest_task-linebisection_events.tsv
└── ses-test
    └── func
        ├── sub-01_ses-test_task-linebisection_bold.nii.gz
        └── sub-01_ses-test_task-linebisection_events.tsv

contrasts would be named Correct_Task_ses-test, Correct_Task_ses-retest since only session labels are available

Subject level#

At the moment the only type of model supported at the subject level are:

  • averaging of run level contrasts (fixed effect analysis)

  • cross-session comparisons

fixed effect analysis#

In this case the only the basename of the contrast being averaged is kept, and any session or run label is removed.

{
  "Level": "Subject",
  "Name": "subject_level",
  "GroupBy": [
    "contrast",
    "subject"
  ],
  "Model": {
    "X": [
      1
    ],
    "Type": "glm"
  },
  "DummyContrasts": {
    "Test": "t"
  }
}
../_images/gui_contrast_subject_level.png

Subject level contrast averaging beta across runs#

cross-session comparisons#
{
  "Nodes": [
    {
      "Level": "Run",
      "Name": "run",
      "GroupBy": [
        "run",
        "session",
        "subject"
      ],
      "Model": {
        "X": [
          "trial_type.Correct_Task",
          "trial_type.Incorrect_Task",
          "trial_type.No_Response_Control",
          "trial_type.No_Response_Task",
          "trial_type.Response_Control",
          "trans_?",
          "rot_?",
          "1"
        ],
        "Type": "glm",
        "HRF": {
          "Variables": [
            "trial_type.Correct_Task",
            "trial_type.Incorrect_Task",
            "trial_type.No_Response_Control",
            "trial_type.No_Response_Task",
            "trial_type.Response_Control"
          ],
          "Model": "spm"
        }
      },
      "DummyContrasts": {
        "Test": "t",
        "Contrasts": [
          "trial_type.Correct_Task",
          "trial_type.Incorrect_Task",
          "trial_type.No_Response_Control",
          "trial_type.No_Response_Task",
          "trial_type.Response_Control"
        ]
      },
      "Contrasts": [
        {
          "Name": "TaskResponded_gt_CtrlResponded",
          "ConditionList": [
            "trial_type.Correct_Task",
            "trial_type.Incorrect_Task",
            "trial_type.Response_Control"
          ],
          "Weights": [
            0.5,
            0.5,
            -1
          ],
          "Test": "t"
        }
      ]
    },
    {
      "Level": "Session",
      "Name": "session",
      "GroupBy": [
        "session",
        "subject",
        "contrast"
      ],
      "Model": {
        "X": [
          1
        ],
        "Type": "glm"
      },
      "DummyContrasts": {
        "Test": "t"
      }
    },
    {
      "Level": "Subject",
      "Name": "compare_sessions",
      "GroupBy": [
        "subject",
        "contrast"
      ],
      "Model": {
        "X": [
          "session",
          1
        ],
        "Type": "glm",
        "Software": {
          "bidspm": {
            "Results": [
              {
                "name": [
                  "test_gt_retest-TaskResponded_gt_CtrlResponded"
                ]
              }
            ]
          }
        }
      },
      "Contrasts": [
        {
          "Name": "test_gt_retest",
          "ConditionList": [
            "test",
            "retest"
          ],
          "Weights": [
            1,
            -1
          ],
          "Test": "t"
        }
      ]
    }
  ],
  "Edges": [
    {
      "Source": "run",
      "Destination": "session",
      "Filter": {
        "contrast": [
          "TaskResponded_gt_CtrlResponded"
        ]
      }
    },
    {
      "Source": "session",
      "Destination": "compare_sessions"
    }
  ]
}
../_images/gui_contrast_cross_session.png

Subject level contrast averaging beta across runs#

Dataset level#

At the moment only, the only type of models that are supported are:

one sample t-test: averaging across all subjects#

{
  "Level": "Dataset",
  "Name": "dataset_level",
  "GroupBy": [
    "contrast"
  ],
  "Model": {
    "X": [
      1
    ],
    "Type": "glm"
  },
  "DummyContrasts": {
    "Test": "t"
  }
}

one sample t-test: averaging across all subjects of a specific group#

{
  "Level": "Dataset",
  "Name": "within_group",
  "Description": "one sample t-test for each group",
  "GroupBy": [
    "contrast",
    "Group"
  ],
  "Model": {
    "Type": "glm",
    "X": [
      1
    ]
  },
  "DummyContrasts": {
    "Test": "t"
  }
}

2 samples t-test: comparing 2 groups#

Participants are allocated to a group based on a the corresponding column in the participants.tsv of in the raw dataset (Group in this case).

{
  "Level": "Dataset",
  "Name": "between_groups",
  "Description": "2 sample t-test between groups",
  "GroupBy": [
    "contrast"
  ],
  "Model": {
    "Type": "glm",
    "X": [
      1,
      "group"
    ]
  },
  "Contrasts": [
    {
      "Name": "blind_gt_control",
      "ConditionList": [
        "Group.blind",
        "Group.control"
      ],
      "Weights": [
        1,
        -1
      ],
      "Test": "t"
    }
  ]
}

one way ANOVA: comparing several groups#

Participants are allocated to a group based on a the corresponding column in the participants.tsv of in the raw dataset (Group in this case).

{
  "Name": "1_way_ANOVA",
  "BIDSModelVersion": "1.0.0",
  "Input": {
    "task": [
      "checkerboard"
    ],
    "space": [
      "MNI152NLin2009cAsym"
    ]
  },
  "Nodes": [
    {
      "Level": "Run",
      "Name": "run_level",
      "GroupBy": [
        "run",
        "subject"
      ],
      "Model": {
        "Type": "glm",
        "X": [
          "trial_type.flashing checkerboard",
          "trans_?",
          "rot_?"
        ],
        "HRF": {
          "Variables": [
            "trial_type.flashing checkerboard"
          ],
          "Model": "spm"
        }
      },
      "Contrasts": [
        {
          "Name": "flashing checkerboard",
          "ConditionList": [
            "trial_type.flashing checkerboard"
          ],
          "Weights": [
            1
          ],
          "Test": "t"
        }
      ]
    },
    {
      "Level": "Subject",
      "Name": "subject_level",
      "GroupBy": [
        "contrast",
        "subject"
      ],
      "Model": {
        "Type": "glm",
        "X": [
          1
        ]
      },
      "DummyContrasts": {
        "Test": "t"
      }
    },
    {
      "Level": "Dataset",
      "Name": "between_groups",
      "Description": "one way anova",
      "GroupBy": [
        "contrast"
      ],
      "Model": {
        "Type": "glm",
        "X": [
          1,
          "group"
        ]
      },
      "Contrasts": [
        {
          "Name": "B > I",
          "ConditionList": [
            "group.B",
            "group.I",
            "group.BI"
          ],
          "Weights": [
            1,
            -1,
            0
          ],
          "Test": "t"
        },
        {
          "Name": "average across groups",
          "ConditionList": [
            "group.B",
            "group.I",
            "group.BI"
          ],
          "Weights": [
            1,
            1,
            1
          ],
          "Test": "t"
        }
      ]
    }
  ],
  "Edges": [
    {
      "Source": "run_level",
      "Destination": "subject_level"
    },
    {
      "Source": "subject_level",
      "Destination": "between_groups",
      "Filter": {
        "contrast": [
          "flashing checkerboard"
        ]
      }
    }
  ]
}

Note

Contrast must be explicitly passed the Edges.Filter.contrast.

Method section#

It is possible to write a draft of method section based on a BIDS statistical model.

opt.model.file = fullfile(pwd, ...
                          'models', ...
                          'model-faceRepetition_smdl.json');
opt.fwhm.contrast = 0;
opt = checkOptions(opt);

opt.designType = 'block';

outputFile = boilerplate(opt, ...
                        'outputPath', pwd, ...
                        'pipelineType', 'stats');
## fMRI statistical analysis

The fMRI data were analysed with bidspm (v2.2.0; https://github.com/cpp-lln-lab/bidspm; DOI: https://doi.org/10.5281/zenodo.3554331)
using statistical parametric mapping
(SPM12 - 7771; Wellcome Center for Neuroimaging, London, UK;
https://www.fil.ion.ucl.ac.uk/spm; RRID:SCR_007037)
using MATLAB 9.4.0.813654 (R2018a)
on a unix computer (Linux version 5.15.0-53-generic (build@lcy02-amd64-047) (gcc (Ubuntu 11.2.0-19ubuntu1) 11.2.0, GNU ld (GNU Binutils for Ubuntu) 2.38) #59-Ubuntu SMP Mon Oct 17 18:53:30 UTC 2022
).

The input data were the preprocessed BOLD images in IXI549Space space for the task " facerepetition ".

### Run / subject level analysis

At the subject level, we performed a mass univariate analysis with a linear
regression at each voxel of the brain, using generalized least squares with a
global  AR(1)  model to account for temporal auto-correlation
 and a drift fit with discrete cosine transform basis ( 128 seconds cut-off).

Image intensity scaling was done run-wide before statistical modeling such that
the mean image would have a mean intracerebral intensity of 100.

We modeled the fMRI experiment in a  event  design with regressors
entered into the run-specific design matrix. The onsets
were convolved with SPM canonical hemodynamic response function (HRF)
 and its temporal and dispersion derivatives for the conditions:
  - `famous_1`,
 - `famous_2`,
 - `unfamiliar_1`,
 - `unfamiliar_2`,
 .

 Nuisance covariates included:

 - `trans_?`,
 - `rot_?`,

to account for residual motion artefacts,
 .



 ## References

This method section was automatically generated using bidspm
(v2.2.0; https://github.com/cpp-lln-lab/bidspm; DOI: https://doi.org/10.5281/zenodo.3554331)
and octache (https://github.com/Remi-Gau/Octache).

Parametric modulation#

Those are not yet fully implemented but there is an example of how to get started in the face repetition demo folder.

{
  "Name": "parametric modulation",
  "BIDSModelVersion": "1.0.0",
  "Description": "model for face repetition",
  "Input": {
    "task": [
      "facerepetition"
    ],
    "space": [
      "IXI549Space"
    ]
  },
  "Nodes": [
    {
      "Level": "Run",
      "Name": "parametric",
      "GroupBy": [
        "run",
        "subject"
      ],
      "Transformations": {
        "Description": "merge the familiarity and repetition column to create the trial type column",
        "Transformer": "bidspm",
        "Instructions": [
          {
            "Name": "Concatenate",
            "Input": [
              "face_type",
              "repetition_type"
            ],
            "Output": "trial_type"
          }
        ]
      },
      "Model": {
        "X": [
          "trial_type.famous_first_show",
          "trial_type.famous_delayed_repeat",
          "trial_type.unfamiliar_first_show",
          "trial_type.unfamiliar_delayed_repeat",
          "trans_?",
          "rot_?"
        ],
        "HRF": {
          "Variables": [
            "trial_type.famous_first_show",
            "trial_type.famous_delayed_repeat",
            "trial_type.unfamiliar_first_show",
            "trial_type.unfamiliar_delayed_repeat"
          ],
          "Model": "spm"
        },
        "Type": "glm",
        "Options": {
          "HighPassFilterCutoffHz": 0.0078,
          "Mask": {
            "suffix": [
              "mask"
            ],
            "desc": [
              "brain"
            ]
          }
        },
        "Software": {
          "SPM": {
            "SerialCorrelation": "AR(1)",
            "ParametricModulations": [
              {
                "Name": "lag mod",
                "Conditions": [
                  "trial_type.famous_delayed_repeat",
                  "trial_type.unfamiliar_delayed_repeat"
                ],
                "Values": [
                  "lag"
                ],
                "PolynomialExpansion": 2
              }
            ]
          }
        }
      },
      "DummyContrasts": {
        "Test": "t",
        "Contrasts": [
          "trial_type.famous_first_show",
          "trial_type.famous_delayed_repeat",
          "trial_type.unfamiliar_first_show",
          "trial_type.unfamiliar_delayed_repeat"
        ]
      },
      "Contrasts": [
        {
          "Name": "faces_gt_baseline",
          "ConditionList": [
            "trial_type.famous_first_show",
            "trial_type.famous_delayed_repeat",
            "trial_type.unfamiliar_first_show",
            "trial_type.unfamiliar_delayed_repeat"
          ],
          "Weights": [
            1,
            1,
            1,
            1
          ],
          "Test": "t"
        },
        {
          "Name": "faces_lt_baseline",
          "ConditionList": [
            "trial_type.famous_first_show",
            "trial_type.famous_delayed_repeat",
            "trial_type.unfamiliar_first_show",
            "trial_type.unfamiliar_delayed_repeat"
          ],
          "Weights": [
            -1,
            -1,
            -1,
            -1
          ],
          "Test": "t"
        }
      ]
    }
  ]
}

See the help section of convertOnsetTsvToMat for more information.

Examples#

There are several examples of models in the model zoo along with links to their datasets.

Several of the demos have their own model and you can find several “dummy” models (without corresponding data) used for testing in this folder.

An example of JSON file could look something like that:

{
  "Name": "vislocalizer",
  "BIDSModelVersion": "1.0.0",
  "Description": "contrasts for the visual localizer",
  "Input": {
    "task": [
      "vislocalizer"
    ],
    "space": [
      "IXI549Space"
    ]
  },
  "Nodes": [
    {
      "Level": "Run",
      "Name": "run_level",
      "GroupBy": [
        "run",
        "subject"
      ],
      "Model": {
        "Type": "glm",
        "X": [
          "trial_type.VisMot",
          "trial_type.VisStat",
          "trial_type.missing_condition",
          "trans_?",
          "rot_?"
        ],
        "HRF": {
          "Variables": [
            "trial_type.VisMot",
            "trial_type.VisStat"
          ],
          "Model": "spm+derivative"
        },
        "Options": {
          "HighPassFilterCutoffHz": 0.008,
          "Mask": {
            "desc": [
              "brain"
            ],
            "suffix": [
              "mask"
            ]
          }
        },
        "Software": {
          "SPM": {
            "InclusiveMaskingThreshold": 0.8,
            "SerialCorrelation": "FAST"
          },
          "bidspm": {
            "Results": [
              {
                "name": [
                  "VisMot_&_VisStat"
                ],
                "p": 0.001,
                "MC": "none"
              },
              {
                "name": [
                  "VisStat",
                  "VisMot"
                ],
                "k": 10
              }
            ]
          }
        }
      },
      "DummyContrasts": {
        "Test": "t",
        "Contrasts": [
          "trial_type.VisMot",
          "trial_type.VisStat"
        ]
      },
      "Contrasts": [
        {
          "Name": "VisMot_&_VisStat",
          "ConditionList": [
            "trial_type.VisMot",
            "trial_type.VisStat"
          ],
          "Weights": [
            1,
            1
          ],
          "Test": "t"
        },
        {
          "Name": "VisMot_&_VisStat_lt_baseline",
          "ConditionList": [
            "trial_type.VisMot",
            "trial_type.VisStat"
          ],
          "Weights": [
            -1,
            -1
          ],
          "Test": "t"
        }
      ]
    },
    {
      "Level": "Subject",
      "Name": "subject_level",
      "GroupBy": [
        "contrast",
        "subject"
      ],
      "Model": {
        "Type": "glm",
        "X": [
          1
        ],
        "Options": {
          "Mask": {
            "desc": [
              "brain"
            ],
            "suffix": [
              "mask"
            ]
          }
        },
        "Software": {
          "bidspm": {
            "Results": [
              {
                "name": [
                  "VisMot_&_VisStat"
                ],
                "p": 0.001,
                "MC": "FDR"
              }
            ]
          }
        }
      },
      "DummyContrasts": {
        "Test": "t"
      }
    },
    {
      "Level": "Dataset",
      "Name": "dataset_level",
      "GroupBy": [
        "contrast"
      ],
      "Model": {
        "Type": "glm",
        "X": [
          1
        ],
        "Options": {
          "Mask": {
            "desc": [
              "brain"
            ],
            "suffix": [
              "mask"
            ]
          }
        },
        "Software": {
          "bidspm": {
            "Results": [
              {
                "name": [
                  "VisMot_&_VisStat_lt_baseline"
                ],
                "p": 0.001,
                "binary": true
              }
            ]
          }
        }
      },
      "DummyContrasts": {
        "Test": "t"
      }
    }
  ]
}