fMRI Demo (nilearn version)

About this demo

In this demo we’ll show how to use the python nilearn library to create multi-voxel patterns and then how to use these in the rsatoolbox to create RDMs. See the patterns demo for a more birds-eye view of the analysis pipeline, with a larger portion of the dataset, including inference.

The Dataset

The data used for this demo was kindly provided by Marieke Mur (Mur et al, 2025). This study is still under review, so we will update this demo to include steps to download the data when it becomes publicly available.

Participants (n=14) viewed images of 16 objects, as well as their written name. Several properties of the stimuli were carefully balanced. They also performed several tasks, but for the purposes of this demo we will ignore these.

stimuli

This library depends on nibabel for convenience functions to access MRI data, and is used separately in the demo as well, so start by installing nibabel (pip install nibabel).

Then run the following imports:

[1]:
%matplotlib inline
from os.path import expanduser, join
from rsatoolbox.io.fmriprep import find_fmriprep_runs
from rsatoolbox.data.dataset import Dataset, merge_datasets
from rsatoolbox.vis import show_rdm
from rsatoolbox.rdm.calc import calc_rdm
from rsatoolbox.data.noise import prec_from_residuals
import numpy, pandas, matplotlib.pyplot
import nibabel
from nilearn.glm.first_level import make_first_level_design_matrix
from nilearn.plotting import plot_design_matrix

Now we define the path to the BIDS-root data directory

[2]:
data_dir = expanduser('~/data/rsatoolbox/mur32')

Next we use a utility function to find the relevant preprocessed BOLD images:

[3]:
runs = find_fmriprep_runs(data_dir, tasks=['main'])
len(runs)
[3]:
84

Let’s select all the runs for participant sub-12:

[4]:
runs = [run for run in runs if run.boldFile.sub == '12']
len(runs)
[4]:
6

Each run object carries the relevant data and metadata

[5]:
run = runs[0]
run
[5]:
<FmriprepRun [sub-12/ses-01/func/sub-12_ses-01_task-main_run-01_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz]>
[6]:
dims = run.get_data().shape ## bold timeseries: x * y * z * volumes
n_vols = dims[-1]
dims
[6]:
(275275, 546)

Access the attributes stored in the *_metadata.json* for this file

[7]:
tr = run.get_meta()['RepetitionTime'] ## TR in seconds
tr
[7]:
2

We will also load the events table

[8]:
run.get_events().sample(5) ## 5 random events
[8]:
onset duration trial_type modality identity response_time task response_mapping
274 821.997 0.5 baseline NaN NaN NaN NaN NaN
118 353.985 0.5 text_candle text candle 0.839 semantic right-left
123 368.991 0.5 image_ladder image ladder 0.897 semantic right-left
265 794.987 0.5 image_helmet image helmet 1.792 fixation left-right
230 689.997 0.5 baseline NaN NaN NaN NaN NaN
[9]:
run.get_confounds().head(3)
[9]:
global_signal csf white_matter trans_x trans_y trans_z rot_x rot_y rot_z
0 490.950364 852.897339 454.706819 -0.031540 -0.278969 -0.171883 0.003922 0.001695 -0.001443
1 488.731823 841.926156 454.439092 0.004438 -0.155145 -0.161355 0.004182 0.001695 -0.000628
2 488.417947 836.871638 454.370054 0.005771 -0.200537 -0.150666 0.004127 0.001523 -0.001216

Patterns

Next we want to establish Multi-Voxel Patterns from the timeseries, such that, for each stimulus presentation, we have one observation per voxel. The most common way to do this is with a General Linear Model, where each predictor in the model reflects one type of event, convolved with the haemodynamic response function (HRF). For the purposes of this demo we will use a very basic glm implementation in Python. For a guide on MVPA, see Mur et al. 2009.

First we use a utility function which creates predictors from the events table and convolves them with the HRF. Note that we have 34 predictors, with a value for each volume in the BOLD timeseries.

[10]:


frame_times = numpy.linspace(0, tr*(n_vols-1), n_vols) ## [0, 2, 4] onsets of scans in seconds design_matrix = make_first_level_design_matrix( frame_times, run.get_events(), drift_model='polynomial', drift_order=3) plot_design_matrix(design_matrix)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
[10]:
<Axes: label='conditions', ylabel='scan number'>
_images/demo_fmri_nilearn_22_2.png

This plot shows the design matrix. Every blip reflects the haemodynamic response to a single trial.

GLM

Here we fit nilearn’s implementation of the GLM

[11]:
from nilearn.glm.first_level import FirstLevelModel
glm = FirstLevelModel(
    t_r=tr,
    mask_img=False,
    minimize_memory=False,
    signal_scaling=0,
    n_jobs=-2
)
glm.fit([run.boldFile.fpath], design_matrices=design_matrix)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(
[11]:
FirstLevelModel(mask_img=<nibabel.nifti1.Nifti1Image object at 0x317ead2d0>,
                minimize_memory=False, n_jobs=-2, t_r=2)
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
[12]:
conditions = [c for c in design_matrix.columns if ('image_' in c) or ('text_' in c)]
conditions
[12]:
['image_bagel',
 'image_brick',
 'image_candle',
 'image_clock',
 'image_glass',
 'image_glove',
 'image_helmet',
 'image_kettle',
 'image_knife',
 'image_ladder',
 'image_pedal',
 'image_saddle',
 'image_spade',
 'image_sponge',
 'image_table',
 'image_wheel',
 'text_bagel',
 'text_brick',
 'text_candle',
 'text_clock',
 'text_glass',
 'text_glove',
 'text_helmet',
 'text_kettle',
 'text_knife',
 'text_ladder',
 'text_pedal',
 'text_saddle',
 'text_spade',
 'text_sponge',
 'text_table',
 'text_wheel']
[13]:
beta_img = glm.compute_contrast('image_glove', output_type='effect_size')

The output of this is a statistical map; a whole-brain volume with a beta-weight for every voxel.

Defining a Region-of-Interest

We want to sample a pattern for a specific brain region. Luckily this fmriprep run comes with the aparcaseg parcellation map projected into the subject’s space. Let’s use this atlas to create a mask for the Fusiform Gyrus.

[14]:
# Navigate to the aparcaseg file for this run:
aparc = run.boldFile.get_mri_sibling(desc='aparcaseg', suffix='dseg')
aparc_data = aparc.get_data()
print(aparc_data.shape)
print(numpy.unique(aparc_data[:10]))
(65, 77, 55)
[   0. 1001. 1015. 1022. 1030. 1031.]

As we see, this is a volume with an whole number at every voxel. We can use the corresponding lookup-table (LUT) to understand these numbers:

[15]:
lut_fpath = join(data_dir, 'derivatives', 'fmriprep',
                 'desc-aparcaseg_dseg.tsv')
lut_df = pandas.read_csv(lut_fpath, sep='\t')
lut_df
[15]:
index name color
0 0 Unknown #000000
1 1 Left-Cerebral-Exterior #4682b4
2 2 Left-Cerebral-White-Matter #f5f5f5
3 3 Left-Cerebral-Cortex #cd3e4e
4 4 Left-Lateral-Ventricle #781286
... ... ... ...
1369 14171 wm_rh_S_suborbital #15143c
1370 14172 wm_rh_S_subparietal #653c3c
1371 14173 wm_rh_S_temporal_inf #15b4b4
1372 14174 wm_rh_S_temporal_sup #dfdc3c
1373 14175 wm_rh_S_temporal_transverse #dd3c3c

1374 rows × 3 columns

Now let’s find the numbers that correspond to the Fusiform Gyrus in the left- and right hemisphere:

[16]:
matches = lut_df[lut_df['name'] == 'ctx-lh-fusiform']
left_index = matches['index'].values[0]
matches = lut_df[lut_df['name'] == 'ctx-rh-fusiform']
right_index = matches['index'].values[0]
left_index, right_index
[16]:
(1007, 2007)

Index the atlas with these numbers and combine into a single mask:

[17]:
fusiform_mask = numpy.zeros_like(aparc_data, dtype=bool)
fusiform_mask[aparc_data == float(left_index)] = True
fusiform_mask[aparc_data == float(right_index)] = True

Let’s see how many voxels are in the mask:

[18]:
roi_size = fusiform_mask.sum()
roi_size
[18]:
829

Let’s have a look at this Region-of-Interest (ROI)

[19]:
from nilearn.plotting import plot_roi
# borrow the affine transformation for this new image from their sibling
affine = nibabel.load(aparc.fpath).affine
plot_roi(
    nibabel.nifti1.Nifti1Image(
        fusiform_mask*1.0,  # the plotting image requires a float-based mask
        affine=affine
    )
)
[19]:
<nilearn.plotting.displays._slicers.OrthoSlicer at 0x343f972d0>
_images/demo_fmri_nilearn_40_1.png

Creating a Dataset

Now we are able to select only the betas for this ROI:

[20]:
pattern = beta_img.get_fdata()[fusiform_mask]
pattern.shape, pattern[-10:]
[20]:
((829, 1),
 array([[157.67828937],
        [  6.57029055],
        [  6.43865366],
        [  6.12197048],
        [-10.46893236],
        [ 16.69253657],
        [-72.01982946],
        [-17.89987039],
        [ -4.91374503],
        [ -1.04137262]]))

Let’s also collect the patterns for the other conditions

[21]:
patterns = numpy.full([len(conditions), roi_size], numpy.nan)
for c, condition in enumerate(conditions):
    beta_img = glm.compute_contrast(condition, output_type='effect_size')
    patterns[c, :] = beta_img.get_fdata()[fusiform_mask].squeeze()

The run object then provides us with dictionaries with attributes that identify this run and its various dimensions. These map unto the rsatoolbox descriptors.

[22]:
run.get_dataset_descriptors()
[22]:
{'sub': '12', 'ses': '01', 'run': '01', 'task': 'main'}

We can then combine the patterns and descriptors to create an rsatoolbox Dataset object

[23]:
ds = Dataset(
    measurements=patterns,
    descriptors=run.get_dataset_descriptors(),
    obs_descriptors=dict(condition=conditions),
)

Noise

If we want to apply multivariate noise normalization, we should also collect and process a measure of the noise of our observation. The nilearn glm can provide us with the residuals (e.g. error) of the GLM:

[24]:
resid_img = glm.residuals[0]
resid_img.get_fdata().shape
[24]:
(65, 77, 55, 546)

These we can also limit to the extend of our ROI:

[25]:
resids = resid_img.get_fdata()[fusiform_mask, :].T
resids.shape
[25]:
(546, 829)

Next we need to determine the degrees-of-freedom for our design. This is the number of columns in the design matrix figure above;

  • 32 stimulus conditions

  • the “baseline” and “instruction” conditions

  • 4 confound predictors

[26]:
degrees_of_freedom = 38

We can then calculate a noise precision matrix:

[27]:
prec_matrix = prec_from_residuals(
    resids,
    dof=degrees_of_freedom,
    method='shrinkage_diag'
)
prec_matrix
[27]:
array([[0.02081756, 0.        , 0.        , ..., 0.        , 0.        ,
        0.        ],
       [0.        , 0.01565435, 0.        , ..., 0.        , 0.        ,
        0.        ],
       [0.        , 0.        , 0.05739469, ..., 0.        , 0.        ,
        0.        ],
       ...,
       [0.        , 0.        , 0.        , ..., 0.00942196, 0.        ,
        0.        ],
       [0.        , 0.        , 0.        , ..., 0.        , 0.03871096,
        0.        ],
       [0.        , 0.        , 0.        , ..., 0.        , 0.        ,
        0.02422791]])

Calculating RDMs

Now that we have the Dataset and noise precision, we can calculate an RDM for this single run:

[28]:
rdms = calc_rdm(
    dataset=ds,
    noise=prec_matrix,
    method='mahalanobis',
    descriptor='condition',
)
rdms
[28]:
rsatoolbox.rdm.RDMs(
dissimilarity_measure =
squared mahalanobis
dissimilarities =
[[0.38365942 0.33658986 0.31859911 0.29808972 0.3224023  0.42602224
  0.37384069 0.31120577 0.34875965 0.31970565 0.35857025 0.36532242
  0.35291608 0.30943487 0.4088163  0.35436635 0.3157959  0.40211281
  0.39414911 0.35124768 0.29041107 0.49595231 0.32703596 0.43430263
  0.30354277 0.32431712 0.32335989 0.31068237 0.32235356 0.38775498
  0.37401073 0.34064614 0.46852911 0.29005866 0.35930841 0.34972533
  0.33482445 0.44607791 0.30067009 0.36044098 0.35054297 0.46780848
  0.40660717 0.35586898 0.298206   0.33660109 0.4475611  0.32698626
  0.37007769 0.36586169 0.40355882 0.52560357 0.30387521 0.35904086
  0.37814055 0.37914135 0.50645511 0.34805984 0.37793495 0.36994403
  0.33578252 0.32183139 0.29427345 0.32296704 0.38577602 0.29622093
  0.34148527 0.3063691  0.35274345 0.31752502 0.33553897 0.36076734
  0.29295141 0.37303643 0.3295859  0.37702671 0.30051722 0.31803179
  0.33935567 0.30397038 0.4106019  0.30567882 0.37523922 0.30812558
  0.34693256 0.38417054 0.28407867 0.42171425 0.37907335 0.35462167
  0.35871634 0.32830908 0.44066941 0.37882407 0.35056501 0.352783
  0.35876029 0.34108032 0.3693031  0.41951924 0.32281385 0.40969043
  0.2817943  0.34364457 0.3839676  0.33507307 0.39492724 0.29456228
  0.41678108 0.33392649 0.37952361 0.29772352 0.31596104 0.30334004
  0.31529434 0.35301654 0.39524425 0.44193822 0.32615342 0.39122543
  0.2961974  0.34743089 0.30330261 0.31190851 0.32571936 0.41895775
  0.33986222 0.31562947 0.34113675 0.34726745 0.36534566 0.28120935
  0.34220995 0.30775225 0.31612228 0.46255136 0.31082    0.38209386
  0.28680498 0.32134924 0.41164036 0.27537297 0.33320177 0.30753193
  0.39152007 0.36397378 0.32662793 0.38243648 0.31728578 0.35151498
  0.24932721 0.45617331 0.39326436 0.28884329 0.34039174 0.33339579
  0.3717897  0.38007074 0.37731453 0.39588326 0.35601921 0.39088614
  0.32699209 0.33026386 0.33613591 0.2947967  0.32833944 0.35856873
  0.3290698  0.3724945  0.33371614 0.37762255 0.41823704 0.37746227
  0.39287745 0.33545191 0.45862312 0.45368924 0.38536121 0.39355385
  0.40878267 0.4337443  0.45540747 0.31067034 0.49072365 0.3965818
  0.44696618 0.38922851 0.29964255 0.38010278 0.41096019 0.4649724
  0.4258352  0.37856928 0.41447601 0.44292887 0.38263938 0.27643898
  0.35873526 0.28381349 0.40886014 0.29649073 0.28729771 0.308368
  0.31876813 0.36284564 0.30090555 0.33305492 0.35274992 0.33488425
  0.41681135 0.30617063 0.32580317 0.31228993 0.34894055 0.42499663
  0.29331324 0.41720128 0.37298401 0.29181027 0.37921646 0.40893044
  0.42524246 0.36282012 0.36226838 0.31531993 0.40184359 0.39145155
  0.34207857 0.3982803  0.32348785 0.42010876 0.3315484  0.3735424
  0.39639976 0.37790319 0.31801319 0.31270397 0.35164045 0.36405153
  0.40597667 0.35728166 0.39140814 0.35211213 0.2980696  0.41632799
  0.36780166 0.29582931 0.28498624 0.30733261 0.3353395  0.34932668
  0.29807706 0.38795209 0.3609488  0.41229117 0.33246308 0.31927944
  0.32739513 0.33040202 0.37389012 0.36090297 0.36870581 0.42590143
  0.37845215 0.31739251 0.39440427 0.41350172 0.37732946 0.39905022
  0.32466516 0.36867776 0.4151196  0.39035861 0.41877979 0.35406982
  0.54079077 0.3668866  0.34606039 0.31999223 0.36579863 0.35790416
  0.32348279 0.34433854 0.4537239  0.42875251 0.457368   0.40561256
  0.31263115 0.28871059 0.28677285 0.38771861 0.4115757  0.36986707
  0.46587296 0.37491792 0.42863078 0.35434501 0.32831253 0.35021994
  0.31902437 0.31619527 0.35999297 0.34909999 0.43116244 0.32785729
  0.32985608 0.33461299 0.50209752 0.34488972 0.30025798 0.40200311
  0.37049691 0.34059968 0.31648776 0.54378493 0.40867373 0.54510549
  0.39741953 0.35848022 0.44709738 0.37222573 0.37263514 0.46732677
  0.39377312 0.29872868 0.41548701 0.34035773 0.35706753 0.3354803
  0.36533742 0.32028373 0.38848406 0.50130004 0.37206401 0.46393178
  0.38924986 0.37345367 0.49485343 0.36700646 0.39204357 0.4439464
  0.34017554 0.35041571 0.29235121 0.29271388 0.33851551 0.31216012
  0.3326029  0.33529686 0.39110598 0.28462362 0.33179157 0.3054615
  0.27397701 0.33504062 0.31918687 0.33544426 0.34311498 0.29187141
  0.3324812  0.42111988 0.35822678 0.37622419 0.46223548 0.40320291
  0.39032707 0.37070938 0.34880572 0.3959683  0.34416842 0.42934844
  0.3729773  0.38004958 0.40896177 0.32917717 0.28309584 0.34408797
  0.28961083 0.37933243 0.35598857 0.38524887 0.30824041 0.35186346
  0.29036155 0.25686452 0.35340966 0.34832248 0.29922168 0.40167345
  0.34207291 0.43519466 0.36018369 0.34207539 0.33114787 0.44156591
  0.34186326 0.44250057 0.31142469 0.29800567 0.36722042 0.35709416
  0.30565547 0.44562177 0.35638909 0.34520724 0.31360234 0.33500902
  0.48743093 0.30587233 0.42981415 0.35447747 0.36849816 0.48230638
  0.32187483 0.43022734 0.32161206 0.39175851 0.40721461 0.34632074
  0.37387487 0.35499979 0.29983164 0.28657787 0.36146499 0.42473921
  0.38103872 0.41971482 0.35763499 0.41713811 0.32697159 0.55474069
  0.31876417 0.53949583 0.34510411 0.37229907 0.52457296 0.33188449
  0.39526109 0.38775345 0.34865844 0.47828601 0.33477541 0.39858296
  0.28591541 0.31457465 0.34238576 0.24252126 0.33733686 0.34419159
  0.42300143 0.4494506  0.40790177 0.4483051  0.34847699 0.40138228
  0.4870107  0.44446131 0.45686683 0.40143464 0.37959466 0.30124384
  0.32695512 0.42228108 0.30600138 0.36100341 0.35246728 0.33561192
  0.33099148 0.37227684 0.38803882 0.4121324  0.43871247 0.37961855
  0.44618495 0.30766322 0.37480181 0.32578568 0.33469076 0.34947416
  0.42182684 0.29100202 0.31059335 0.3071345  0.34933706 0.36649643
  0.3898815  0.35702013 0.45063323 0.44594839 0.39050003 0.30787676
  0.33413993 0.45483421 0.40807713 0.42662313]]
descriptors =
{'noise': array([[0.02081756, 0.        , 0.        , ..., 0.        , 0.        ,
        0.        ],
       [0.        , 0.01565435, 0.        , ..., 0.        , 0.        ,
        0.        ],
       [0.        , 0.        , 0.05739469, ..., 0.        , 0.        ,
        0.        ],
       ...,
       [0.        , 0.        , 0.        , ..., 0.00942196, 0.        ,
        0.        ],
       [0.        , 0.        , 0.        , ..., 0.        , 0.03871096,
        0.        ],
       [0.        , 0.        , 0.        , ..., 0.        , 0.        ,
        0.02422791]])}
rdm_descriptors =
{'sub': ['12'], 'ses': ['01'], 'run': ['01'], 'task': ['main'], 'index': [0]}
pattern_descriptors =
{'condition': ['image_bagel', 'image_brick', 'image_candle', 'image_clock', 'image_glass', 'image_glove', 'image_helmet', 'image_kettle', 'image_knife', 'image_ladder', 'image_pedal', 'image_saddle', 'image_spade', 'image_sponge', 'image_table', 'image_wheel', 'text_bagel', 'text_brick', 'text_candle', 'text_clock', 'text_glass', 'text_glove', 'text_helmet', 'text_kettle', 'text_knife', 'text_ladder', 'text_pedal', 'text_saddle', 'text_spade', 'text_sponge', 'text_table', 'text_wheel'], 'index': [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]}

Now, instead of making an RDM for every run, we could use crossvalidation across the runs to get an RDM of the “crossnobis” dissimilarity. So let’s loop across the runs:

[41]:
run_datasets = []
prec_matrices = []

for r, run in enumerate(runs):
    design_matrix = make_first_level_design_matrix(
        frame_times,
        run.get_events(),
        drift_model='polynomial',
        drift_order=3
    )
    glm = FirstLevelModel(
        t_r=tr,
        mask_img=False,
        minimize_memory=False,
        signal_scaling=0,
        n_jobs=-2
    )
    glm.fit([run.boldFile.fpath], design_matrices=design_matrix)

    patterns = numpy.full([len(conditions), roi_size], numpy.nan)
    for c, condition in enumerate(conditions):
        beta_img = glm.compute_contrast(condition, output_type='effect_size')
        patterns[c, :] = beta_img.get_fdata()[fusiform_mask].squeeze()

    descs = run.get_dataset_descriptors()
    descs['run'] = str(r)
    run_datasets.append(
        Dataset(
            measurements=patterns,
            descriptors=descs,
            obs_descriptors=dict(condition=conditions),
        )
    )
    resids = glm.residuals[0].get_fdata()[fusiform_mask, :].T
    prec_matrices.append(
        prec_from_residuals(
            resids,
            dof=degrees_of_freedom,
            method='shrinkage_diag'
        )
    )
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/experimental_paradigm.py:167: UserWarning: The following unexpected columns in events data will be ignored: response_mapping, response_time, modality, identity, task
  warnings.warn(
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/nilearn/glm/first_level/first_level.py:707: UserWarning: Mean values of 0 observed. The data have probably been centered.Scaling might not work as expected
  Y, _ = mean_scaling(Y, self.signal_scaling)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/joblib/externals/loky/process_executor.py:752: UserWarning: A worker stopped while some jobs were given to the executor. This can be caused by a too short worker timeout or by a memory leak.
  warnings.warn(

Now we have to combine the run-wise datasets into one single subject Dataset

[42]:
subject_ds = merge_datasets(run_datasets)

And we can calculate the crossnobis RDM:

[44]:
rdms = calc_rdm(
    dataset=subject_ds,
    noise=prec_matrices,
    method='crossnobis',
    descriptor='condition',
    cv_descriptor='run',
)
/Users/jasper/projects/rsatoolbox/env/lib/python3.11/site-packages/rsatoolbox/data/computations.py:36: RuntimeWarning: invalid value encountered in multiply
  average = np.nan * np.empty(

Last but not least; let’s view the RDM:

[45]:
fig, _, _ = show_rdm(rdms, show_colorbar='panel')
matplotlib.pyplot.show()
_images/demo_fmri_nilearn_68_0.png