Finding clusters for a group

Hi there. I am new to AFNI (and fMRI), and I'd appreciate any advice:

I have performed an individual analysis on a few hundred subjects (229) and would like to identify clusters of activation within my population so that I can create masks for further DWI analysis. This is a longitudinal study with three sessions 2 years apart. The task is a grammar task with 4 trial types.

I was hoping I could do this:

For each task and trial type, extract the sub brick of interest, one for the beta values, another for tstat:

3dbucket -aglueto sub-XX_ses-XX-beta+tlrc.HEAD stats.XX+tlrc'[1]'
`3dbucket -aglueto sub-XX_ses-XX-tstat+tlrc.HEAD stats.XX+tlrc'[2]'``

This will produce 229 x 2 files; a volume with beta weights and one with tstatistic for each subject for the specific trial_type I am interested in.

3dMEMA -prefix mema_output -jobs 6 -set group ...
...followed by pars of beta and tstat files

This produces a brik and head file that I was hoping could be used to find clusters, using the t-statistic as a threshold. Because I have averaged across subjects I have introduced variability and lost statistical power. Many of the clusters are outside the brain (I expect this is due do differences with individual registrations), so I can manually work through that. I have some small clusters where I would expect to see them after increasing p-value to 0.05. Should I increase it further to get bigger/more clusters?

My hope is to save these to masks so I can perform tractography analysis of tracts between these masked regions.

Is this a reasonable approach to create the masks? Is there a better one?

My dataset is here: OpenNeuro
AFNI_23.1.07

Thanks, AFNI is #1.
-dave.

Dave,

Clusters based on statistical evidence are inherently arbitrary and artificial, as there is always a degree of uncertainty involved. No one can claim activation with absolute certainty. In your case, one option is to consider adopting a highlight-but-not-hide approach as proposed here. You may use p=0.05 and a number of voxels (e.g., 10) as soft thresholds. If you observe any overlap between the statistical evidence and an anatomical region or parcel, it would be appropriate to use that specific region or parcel for your follow-up analysis. An anatomical region or functional parcel holds more neurological relevance compared to an arbitrarily dichotomized cluster.

Gang

Hi, Dave-

A couple of points on individual aspects here, just for future reference or ease of some processing. This is separate from Gang's sage advice about specific ways forward.

To extract out 2 volumes, consider this (concatenating datasets, even if there is just one; the main point is using sub-volume selectors):

3dTcat -prefix DSET_PART DSET_WHOLE"[1..2]"

This should preserve more header information, like stats-to-p conversion. And you don't have to glue things together separately.

To make a 3dMEMA command, you can make your own, sure, or you can also use gen_group_command.py which will have a more compact representation for generating a group level command. An example with 3dMEMA specifically from a paper is here:
https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/codex/fmri/2018a_ChenEtal.html
(search for gen_group_command.py).

--pt

Thanks Gang, this is a great article and your advice is well taken. This is my first fMRI study, and I appreciate your support getting me pointed in the right direction.

Thanks PT, this is also great advice and I will take a close look at it. I appreciate this.
-dave.

Hi there, I went through the article you referenced Gang. Thanks.
Can you (or anyone) please guide me on the best practice for achieving the following:

I have a cluster in MNI space and want to see the overlap from ROIs in the Freesurfer output atlas aparc.a2009s+aseg.

I would like to achieve something like this (table 2 from the article you offered):

Similar output from the command:

whereami -omask my_cluster -atlas named_atlas

table2

My cluster is from a group analysis derived from data that underwent the following transformations:

Orig =>recon-all => fmriPrep (MNI space) => afni_proc.py => gen_group_command.py

Since aparc.a2009s+aseg is created per subject in original space, and my cluster is derived from a group of subjects in MNI space, it seems inappropriate to convert a representative subject’s aparc.a2009s+aseg atlas into MNI space and use that for the group? I have tried it, but the alignment was off considerably more than I would want.

Is there a better way? I looked for a Desikan-Killiany Atlas in MNI space in ~/.abin but I didn’t see one (AFNI_23.1.07). I think the same ROIs are in TT_desai_dd_mpm atlas but I had trouble converting my cluster with @auto_tlrc

I have tried this:
@auto_tlrc -base TT_N27+tlrc -input Clust_mask_0002+tlrc -no_ss

Message: Input dataset is in +tlrc already, @auto_tlrc might fail.
….
No new files are produced
3dinfo of Clust_mask_0002+tlrc indicates MNI space.

Also, can someone also please clarify the meaning of “Overlap” produced by whereami -omask my-cluster? Is this the percentage of the ROI volume covered by the mask?

Thanks,
-dave.

Hi, Dave-

There are 2 parts of this. Firstly, having your FS atlas/parcellation of interest on the same grid as the cluster dataset. I will start by assuming you have that, which can be verified with either:

# detailed output, should be five '1' values output 
# if all tested grid props match
3dinfo -same_all_grid -prefix DSET_ATLAS DSET_CLUST

# single number output, should be one '1' value output 
# if all tested grid props match (simpler for programming evaluation)
3dinfo -same_grid -prefix DSET_ATLAS DSET_CLUST

We can discuss getting to the same grid later. The simplest way to do this while processing is to use the 'follower ROI dataset' functionality in afni_proc.py, like in this Example 11:

afni_proc.py                                                         \
    -subj_id                  FT.11.rest                             \
    -blocks                   despike tshift align tlrc volreg blur  \
                              mask scale regress                     \
    ...
    -anat_follower_ROI        aaseg anat                             \
                              aparc.a2009s+aseg_REN_all.nii.gz       \
    -anat_follower_ROI        aeseg epi                              \
                              aparc.a2009s+aseg_REN_all.nii.gz       \

That way everything gets to the same space directly and happily with minimal interpolation.

The script I used for making the table from the "Highlight, Don't Hide" paper is called do_06_clust_olap.tcsh, and I guess I should add it to the github repo for the paper. In this case, one has to turn the FS parcellation dataset into atlasized form, which I just did on my computer separately for a follower dset:

# turn a FS follower parcellation into an atlasized reference for whereami
3dcopy follow_ROI_aaseg+tlrc.HEAD follow_ROI_aaseg_ATLIZE.nii.gz
@MakeLabelTable -atlasize_labeled_dset follow_ROI_aaseg_ATLIZE.nii.gz

Now, the above dataset can be referenced in a whereami call, as follow_ROI_aaseg_ATLIZE (note there is no file extension present). If you have an example cluster map output called Clust_mask+tlrc.HEAD, such a call to get the overlap list of ROI #1 could look like:

whereami -omask Clust_mask+tlrc.HEAD'<1>' -atlas follow_ROI_aaseg_ATLIZE

To make the table in the above Highlight paper, I scripted around this functionality, keeping a list of the maximal overlapping ROI and any others that have at least 10% of the ROI volume. The script to do this with the above dset is:

#!/bin/tcsh

# NB: this makes a table of whereami results when a Clust_table.1D is
# input.  It rearranges information with some awk-ward fun.

# This script is run from a directory with the Clust_table.1D file (at
# present).

# ---------------------------------------------------------------------------

setenv AFNI_WHEREAMI_NO_WARN YES

#set ref_atl = MNI_Glasser_HCP_v1.0
#  3dcopy follow_ROI_aaseg+tlrc.HEAD follow_ROI_aaseg_ATLIZE.nii.gz
#  @MakeLabelTable -atlasize_labeled_dset follow_ROI_aaseg_ATLIZE.nii.gz
#
#
set ref_atl = follow_ROI_aaseg_ATLIZE   # note: no file extension

set all_type = ( olap )

set min_olap = 10    # minimum percentile for overlap to be included in table

foreach ii ( `seq 1 1 ${#all_type}` )
    set type   = "${all_type[$ii]}"

    echo "++ Make table for: ${type}"

    # start the output file and formatting
    set ofile  = info_table_clust_wami_${type}.txt
    printf "" > ${ofile}
    printf "%5s  %5s   %7s  %s  \n"                       \
            "Clust" "Nvox" "Overlap" "ROI location"     \
        |& tee -a ${ofile}

    set idset  = Clust_mask+tlrc.HEAD            # dumped by GUI-Clusterize
    set nclust = `3dinfo -max "${idset}"`

    set tfile  = __tmp_file_olap.txt

    # go through the dset, int by int, to parse a bit
    foreach nn ( `seq 1 1 ${nclust}` )
        # create zero-based index
        @ mm = $nn - 1

        set nvox = `3dROIstats -nomeanout -quiet -nzvoxels \
                        -mask "${idset}<${nn}>"            \
                        "${idset}"` 

        whereami                                          \
            -omask "${idset}<${nn}>"                      \
            -atlas "${ref_atl}"                           \
            | grep --color=never '% overlap with'         \
            > ${tfile}

        set nrow = `cat ${tfile} | wc -l`

        set NEED_ONE = 1
        foreach rr ( `seq 1 1 ${nrow}` )
            set line = `cat ${tfile} | sed -n ${rr}p`
            set perc = `echo "${line}" | awk '{print $1}'`

            set roi = `echo "${line}"                           \
                        | awk -F'% overlap with' '{print $2}'   \
                        | awk -F, '{print $1}'`


            if ( ${NEED_ONE} ) then
                printf "%5d  %5d  %7.1f%%  %s  \n"             \
                    "${nn}" "${nvox}" "${perc}" "${roi}"       \
                    |& tee -a ${ofile}
                set NEED_ONE = 0
            else if (`echo "${perc} > ${min_olap}" | bc` ) then
                printf "%5s  %5s  %7.1f%%  %s  \n"             \
                    "" "" "${perc}" "${roi}"       \
                    |& tee -a ${ofile}
            endif
        end
    end
end

\rm ${tfile} 

cat <<EOF
------------------------------
DONE.

Check out:
${ofile}

EOF

It assumes 2 files in the same directory here: follow_ROI_aaseg_ATLIZE.nii.gz (atlasized FS-parcellation dset) and Clust_mask+tlrc.HEAD (3dClusterize cluster map of ROIs).

When I ran the above on my test case (essentially a seedbased correlation map after that afni_proc.py example 11 on the Bootcamp data), I got a table that looked like this in a file called info_table_clust_wami_olap.txt:

Clust   Nvox   Overlap  ROI location  
    1   7218      9.6%  Right-Cerebral-White-Matter  
    2    837     16.4%  ctx_rh_G_front_middle  
                 15.7%  ctx_rh_S_front_sup  
    3    295     18.6%  ctx_lh_G_precentral  
                 17.6%  ctx_lh_S_central  
                 11.7%  ctx_lh_G_postcentral  
    4    285     15.3%  Right-Cerebral-White-Matter  
                 13.1%  ctx_rh_G_front_middle  
                 11.8%  ctx_rh_G_front_sup  
    5    263     20.0%  ctx_lh_S_front_sup  
                 19.8%  ctx_lh_G_front_sup  
                 13.0%  ctx_lh_G_front_middle  
    6    233     21.2%  ctx_rh_G_and_S_cingul-Ant  
                 16.1%  ctx_lh_G_front_sup  
                 10.4%  ctx_rh_G_front_sup  
    7    164     26.3%  ctx_rh_S_temporal_sup  
                 22.5%  ctx_rh_G_temp_sup-Lateral  
                 22.2%  ctx_rh_G_temporal_middle  
                 11.3%  Right-Cerebral-White-Matter  
    8    111     18.6%  ctx_lh_G_front_middle  
                 10.8%  ctx_lh_G_front_sup  
    9     92     47.8%  ctx_rh_S_central  
                 16.4%  ctx_rh_G_precentral  
                 15.4%  Right-Cerebral-White-Matter  
   10     91     31.1%  ctx_lh_S_front_inf  
                 14.6%  ctx_lh_G_front_middle  
                 12.4%  Left-Cerebral-White-Matter  
   11     89     36.5%  ctx_lh_G_front_middle  
                 16.5%  Left-Cerebral-White-Matter  
                 10.8%  ctx_lh_S_front_middle  
   12     63     48.3%  ctx_lh_G_and_S_cingul-Mid-Post  
                 14.1%  ctx_lh_G_front_sup  
   13     60     43.0%  ctx_rh_S_front_inf  
                 39.0%  Right-Cerebral-White-Matter  
   14     46     35.6%  ctx_lh_G_and_S_occipital_inf  
   15     43     39.5%  ctx_lh_G_front_sup  
   16     42     32.2%  ctx_rh_G_temporal_inf  
                 24.9%  Right-Cerebral-White-Matter  
                 22.8%  ctx_rh_S_temporal_inf  
   17     42     53.5%  ctx_rh_G_temporal_middle  
                 13.1%  Right-Cerebral-White-Matter  

--pt

Amazing! You are #1, thanks pt. This gets me where I need to go, and thanks so much for the robust response.

Cool, glad that is useful.

I have now updated the referenced github repo for the Highlight paper scripts to include the original script I used, and I put a comment at the top of it about the points mentioned here for FreeSurfer atlases specifically.

--pt