Nilearn Smith 2009 network atlases are all the same

There seems to be an issue with the Smith network atlases imported with nilearn, each network image is the same. Is this a bug or am I missing something here?

Here’s a demonstration:

import nibabel as nb
import numpy as np
import pandas as pd
from nilearn import datasets

smith = datasets.fetch_atlas_smith_2009()
smith_70 = nb.load(smith["rsn70"])
smith70_dat = smith_70.get_fdata()

for i in range(69):

    network_a = smith70_dat[:,:,:,i].astype(bool)
    network_b = smith70_dat[:,:,:,i+1].astype(bool)
    print(pd.Series((network_a == network_b).flatten()).value_counts())

import nilearn as nil
nil.__version__
Out[15]: '0.11.1'

The output comparing maps:

True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64
True    902629
Name: count, dtype: int64

on 0.11.1 I am getting this when plotting the 2 first volumes

import nibabel as nb
from nilearn import datasets
from nilearn.plotting import plot_img, show
from nilearn.image import index_img

smith = datasets.fetch_atlas_smith_2009()
smith_70 = nb.load(smith["rsn70"])

plot_img(index_img(smith_70, 0), title="first dim")

plot_img(index_img(smith_70, 1), title="second dim")

show()

Figure_1

Figure_2

Interesting! Could it perhaps be that they are both the same image but that you are plotting slightly different coordinates?

Hi @scanner101, I think it’s because of your .astype(bool) calls - you’re effectively converting each 3D volume into a binary mask which is True for non-zero voxels, False elsewhere.

1 Like

If I don’t convert to bool EVERY comparison (that is all 69 of them) will return:
True 705538 False 197091 Name: count, dtype: int64

Surely zero values shouldn’t be the exact same across each map?

I have a version of Smith20 that I downloaded from someone else’s two year old github Matlab project, and with this map every comparison is clearly different regardless of whether it gets converted to bool or not: (taken from: https://github.com/anders-s-olsen/CopBET/blob/master/Atlasessmith20_thresholded_2mm.nii). Here is what I get with that exact same test on that the two year old version of Smith20 that I found:

smith20 = nb.load('/Users/gerald/Atlases/smith20_thresholded_2mm.nii')
smith20_dat = smith20.get_fdata()

for i in range(19):
    network_a = smith20_dat[:,:,:,i].astype(bool)
    network_b = smith20_dat[:,:,:,i+1].astype(bool)
    print(pd.Series((network_a == network_b).flatten()).value_counts())

True     879710
False     22919
Name: count, dtype: int64
True     872638
False     29991
Name: count, dtype: int64
True     874258
False     28371
Name: count, dtype: int64
True     884196
False     18433
Name: count, dtype: int64
True     881023
False     21606
Name: count, dtype: int64
True     878892
False     23737
Name: count, dtype: int64
True     870540
False     32089
Name: count, dtype: int64
True     867934
False     34695
Name: count, dtype: int64
True     879261
False     23368
Name: count, dtype: int64
True     872615
False     30014
Name: count, dtype: int64
True     876925
False     25704
Name: count, dtype: int64
True     867498
False     35131
Name: count, dtype: int64
True     879108
False     23521
Name: count, dtype: int64
True     876692
False     25937
Name: count, dtype: int64
True     872339
False     30290
Name: count, dtype: int64
True     878039
False     24590
Name: count, dtype: int64
True     884034
False     18595
Name: count, dtype: int64
True     885528
False     17101
Name: count, dtype: int64
True     883009
False     19620
Name: count, dtype: int64

Actually the program I’m running requires converting the atlas to boolean. With the Smith20 linked above the analysis runs as expected, but when I download the nilearn smith70 i get the same result for each of the 70 networks.

Surely zero values shouldn’t be the exact same across each map?

Why not? It’s very common for the same brain mask to be applied to all volumes of a 4D image. All your code is doing is comparing the number of non-zero voxels.

I have a version of Smith20 that I downloaded from someone else’s two year old github Matlab project

Who knows what has been done to that version? Why not go to the original source at BrainMap + RSNs ? This is where nilearn downloads its files from. The original rsn20 image also has the same number non-zero voxels in each volume.

1 Like

The images are clearly different.

See below where the cut coords are kept the same.

Note the range of values are quite different from one volume to the next.

Also using numpy to assert that each 2 consecutive volumes are different.

import nibabel as nb
from nilearn import datasets
from nilearn.plotting import plot_img, show
from nilearn.image import index_img
from numpy.testing import assert_array_equal

smith = datasets.fetch_atlas_smith_2009()
smith_70 = nb.load(smith["rsn70"])

plot_img(index_img(smith_70, 0), title="first dim", cut_coords=[0, 0, 0])
plot_img(index_img(smith_70, 1), title="second dim", cut_coords=[0, 0, 0])

show()

smith70_dat = smith_70.get_fdata()

for i in range(69):

    network_a = smith70_dat[:,:,:,i]
    network_b = smith70_dat[:,:,:,i+1]

    assert_array_equal(network_a.astype(bool), network_b.astype(bool))

    try:
        assert_array_equal(network_a, network_b)
    except AssertionError:
        print(f"arrays {i} and {i+1} are not equal")


1 Like

@scanner101 having looked at the other image (correct URL CopBET/Atlases/smith20_thresholded_2mm.nii at master · anders-s-olsen/CopBET · GitHub), I think you may be misunderstanding the nature of the original rsn20/rsn70 files.

The original rsn20/rsn70 files contain the results of ICA decompositions on resting state fMRI, where each 3D volume contains a representation of each component, where the value at each voxel reflects the strength of its involvement in that component.

The other file that you downloaded from github appears to be a copy of the rsn20 image, which has been thresholded at some arbitrary amount and converted into a binary mask.

1 Like

Oh i see! Thank you both for this explanation! It seems that overlooked the fact that the other map is thresholded (face palming at myself right now haha)

1 Like