How to automate getting Peak t Cluster Values

Hi everyone,
Recently, I’ve been tasked with documenting all the peak cluster Thr values for each of the contrasts we ran in our lab. The way I was told to do this (manually) is as follows:

  1. In the report Gui, click Jump for the first voxel cluster
  2. Record the Thr = value from the “Values at current crosshair voxel” section of the afni GUI
  3. Repeat for each voxel in the list

However, as it can be tedious repeating this for 100+ voxels, I was wondering if there was a way to automate getting all of these Thr = values for the peak voxel clusters into a table. For example, we currently use the 3dClust trick with “>” to get output tables like these (screenshot is attached to this post), which we then use to automate the creation of Excel Tables. However, as far as I can tell, the Thr values are not included in these tables. Is there a way to add the Peak Cluster Thr values to this output table or is there an alternative way to automate putting these Peak Cluster Thr values into a different table?

Thanks again,
Rookie

Howdy, Rookie-

This may be a bit of what you are doing already, but just to note:

When you run Clusterize in the GUI and open the Rpt (report), you can click “3dclust” in the new panel and get an equivalent 3dClusterize command to run on the command line (it used to be a 3dclust command, but that syntax is paaaainful and we updated it a while ago in the new program, but didn’t change the button name because it was nice and short).

You can run that command and indeed, output the table to a text file:


3dClusterize ... > o.cluster_report.txt

… and then view the contents with, say:


cat o.cluster_report.txt

or, to ignore the commented part,


1dcat o.cluster_report.txt

The column of interest with the cluster peak (from 3dClusterize’s help) should be this one:


Max Int      : Maximum Intensity value for the volume cluster

The table generally stores the peak Olay value, not Thr. We generally recommend visualizating the beta (= effect estimate or coefficient) from stat modeling, while using the stat as Thr. If you wanted the peak Thr for this, you could use the stat value as Olay, as well as for THr, and then the reported Max Int value would be the same value as your Thr.

The Max Int appears to be the 13th column (with one-based counting) in the table. You can print out the 13th column values with, say:


1dcat o.cluster_report.txt  | awk '{print $13}'

# or, redirecting to a file:
1dcat o.cluster_report.txt  | awk '{print $13}' > o.peak_thr_list.txt

Note in all of this, we often recommend looking at a lot more than just the statistic from FMRI datasets:
Is the statistic value all we should care about in neuroimaging?
https://pubmed.ncbi.nlm.nih.gov/27729277/
… and also there is more to clusters than just peaks:
Sources of Information Waste in Neuroimaging: Mishandling Structures, Thinking Dichotomously, and Over-Reducing Data
https://www.humanbrainmapping.org/files/Aperture/Accepted%20Works%20PDF/Chen_Sources_of_information_waste_in_neuroimaging.pdf
For example, looking at the what regions the clusters overlap might be useful.

Happy to discuss more about this.

–pt

Hi ptaylor,
First off, wow, thank you so much for the quick reply. We have been using that 3dclust button and the 3dClusterize … > o.cluster_report.txt trick religiously. It’s been a huge help in automating the quantitative findings of our contrasts. As you suggested, in the past I did stumble upon setting the stat value as Olay as a way to automatically get the Thr= values, however, because the coordinates of the cluster peaks change when changing the Olay to the stat value, the outputted Peak Cluster Thr= value is a little different. To show, I’ve attached two screenshots, both with the crosshairs set to the first peak cluster coordinates. As you can see the Thr= values of each are different.

Is there a way to get the peak cluster thr= value for the coordinates of the clusters without Olay also set to the stat value? And, if not, what is the functional difference in changing the Olay set to the stat value? Are the peak Thr= values comparable, should a separate table be created for these different coordinates. Is it advisable to always just set the Olay to the stat value?

Thanks for all the help and I’ll be sure to check out those links regarding looking at more than just the statistics. We have been using the wamI feature to start getting a sense of which regions the clusters overlap. If there are any other approaches to getting the “bigger picture” from afni results (as in, looking at more than the statistics), please let me know. As a college freshman, I still have a lot to learn lol so any information you could provide or resources to point me in the right direction would be a huge help.

Thanks again,
Rookie

Hi, Rookie-

Ah, I see what you mean: you want the Thr value (of a statistic, say) at the peak Olay value (of an effect estimate, say) within each cluster, and the peak effect estimate is not guaranteed to have the peak stat value. Fair enough. Indeed, I do think the “whereami” approach is generally more useful than condensing things down to a single value—I’m not sure that the peak statistic is even very meaningful after thresholding? (e.g., Clustering is a hypothesis-testing-like procedure, and so once things pass threshold, the exact statistical value shouldn’t really matter much anymore?)

Addendum to my previous comment: another way to get the column 13 (in onebase) values would be to use AFNI subbrick selectors, as follows to get the same column in a 1D file:


1dcat o.cluster_report.txt'[12]'

Note that AFNI uses zero-based counting (e.g., as in C and Python), hence the number in square brackets.

So, if you did want the above, though, I think the way I would do it would be:

  • set Olay = effect estimate volume
  • set Thr = stat volume
  • Clusterize, get data table
  • From the data table, get the *locations of each Olay peak within the cluster, which would be columns 14, 15 and 16 (in one-based counting, which awk uses):

     MI RL        : Coordinate of the Maximum Intensity value in the
                    Right-Left direction of the volume cluster
 
     MI AP        : Coordinate of the Maximum Intensity value in the
                    Anterior-Posterior direction of the volume cluster
 
     MI IS        : Coordinate of the Maximum Intensity value in the
                    Inferior-Superior direction of the volume cluster

… and you could extract those coordinates from the table with 1dcat, too, note the column numbers:


1dcat o.cluster_report.txt'[13..15]' > o.peak_coords.txt

Then, you could loop over those coordinates and extract the value from the desired dataset at that location.

For example, you extract the value for the first/zeroth coord as follows:


# get 3 coords (likely in RAI notation), and pass those into 3dUndump to make a temporary mask of hopefully 1 voxel
1dcat o.peak_coords.txt'{0}' | 3dUndump -master DSET_FOR_GRID -xyz -overwrite -prefix tmp_mask -
# use that temp mask to extract a value from a dset of interest, such as a stat volume
3dmaskave -quiet -mask tmp_mask+tlrc. DSET_OF_INTEREST

I think those papers would be useful to look at. The danger is that condensing a whole cluster down to one voxel value, esp. a stat, can lose a lot of valuable information.

–pt

Howdy ptaylor,
Thanks for the tips. I was able to create the mask with just one voxel, I believe, and a picture of this can be seen in the attachment to this file. However, when I go to use the 3dmaskave command, like so:


bash-3.2$ 3dmaskave -quiet -mask tmp_mask+tlrc /Users/reynaadmin/test.results/Ado_Updated_LargeRewardSmallReward_GroupHungerRegress+tlrc.BRIK[1]
++ 3dmaskave: AFNI version=AFNI_22.0.10 (Feb 15 2022) [64-bit]
+++ 1 voxels survive the mask
0

The command outputs a value of 0. I’ve tried several variations of the code and I just kept on getting 0, so I figured it was time to turn to the afni gods once more.

Also attached to this document is the 3dinfo -verb output for the .Brik file I am testing on. The Thr= value for the first peak cluster coordinate is around -3.579. Below is the code that I ran based on your suggestions:


1dcat o.peak_coords.txt'{0}' | 3dUndump -master /Users/reynaadmin/test.results/Ado_Updated_LargeRewardSmallReward_GroupHungerRegress+tlrc.BRIK -xyz -overwrite -prefix tmp_mask -

3dmaskave -quiet -mask tmp_mask+tlrc /Users/reynaadmin/test.results/Ado_Updated_LargeRewardSmallReward_GroupHungerRegress+tlrc.BRIK[1]

Thanks again for all the help,
-Rookie

After some careful sleuthing, I realized that the issue what that the coordinates were not being fed into the program as RAI coordinates. Adding the -orient feature I was able to fully automate the process. Thanks for all the help!!

-Rookie

That makes sense, thanks for mentioning that.

–pt