Many of the figures are based images that were automatically created when
afni_proc.py
was run for each subject. The followings desecriptions list
which images were used or what was done to go from the generated images
to the figures that are included in the manuscript.
Generated by manually saving slices in the AFNI GUI.
./ap_results_unifize/sub-017/pb00.sub-017.r01.tcat+orig.HEAD
was used. The I,J,K coordinates for the crosshairs are (32,32,17).
The images are from volume indices: 20, 35, 42, and 54.
The motion and outlier time course was automatically generated by
afni_proc.py
and included in the html report. That figure is stored as
./ap_results_unifize/sub-017/QC_sub-017/media/qc_09_mot_enormoutlr.jpg
Note: For all jpg images in the media directory of the html report, there is also a json file that lists the source volumes used to create the image.
Generated by manually saving slices in the AFNI GUI.
./ap_results_unifize/sub-029/pb00.sub-029.r01.tcat+orig.HEAD
was used. The I,J,K coordinates for the crosshairs are (32,32,17).
The images are from volume indices: 155, 166, 167, and 173.
The motion and outlier time course was automatically generated and included
in the html report. That figure is stored as
./ap_results_unifize/sub-029/QC_sub-029/media/qc_09_mot_enormoutlr.jpg
Not automatically output by AFNI. The following steps were required to create it:
# From the directory: ./Frontiers_QC_2022/Figure8_Overlap_Maps
####
# For the sub-001 to sub-030 Task dataset
# Create a summed count of the number of subjects with a voxel within a mask
3dMean -sum -prefix sub-0xx.mask.overlap.nii.gz \
../ap_results_unifize/sub-0??/mask_epi_anat.sub-0??+tlrc.HEAD
# We use using alpha thresholding to create a contour for N=30 (voxels with all sbj in mask)
# but then voxels with lower voxels get more translucent.
# P Taylor suggested addressing this issue by making a threshold volume where
# N=30 is 1 and 29>=N>=1 is 0.97
# Then the threshold volume is used for thresholding and there's almost no decrease
# in translucency while the summation count volume is used for coloring
3dcalc -prefix sub-0xx.mask.threshold.nii.gz \
-a sub-0xx.mask.overlap.nii.gz \
-expr "step(a)*(1*equals(a,30)+0.97*not(equals(a,30)))"
3dTcat -prefix sub-0xx.maskthresh.nii.gz \
sub-0xx.mask.overlap.nii.gz sub-0xx.mask.threshold.nii.gz
# For the sub-101 to sub-120 Rest dataset
3dMean -sum -prefix sub-1xx.mask.overlap.nii.gz \
../ap_results_masked_warper_rest/sub-1??/mask_epi_anat.sub-1??+tlrc.HEAD
3dcalc -prefix sub-1xx.mask.threshold.nii.gz \
-a sub-1xx.mask.overlap.nii.gz \
-expr "step(a)*(1*equals(a,20)+0.97*not(equals(a,20)))"
3dTcat -prefix sub-1xx.maskthresh.nii.gz \
sub-1xx.mask.overlap.nii.gz sub-1xx.mask.threshold.nii.gz
# Locate the anatomical template to use as the image underlay.
templ_path=`@FindAfniDsetPath MNI152_2009_template_SSW.nii.gz`
underlay_dset=${templ_path}/MNI152_2009_template_SSW.nii.gz
####
# Create the image for the Task data
# The underlay is the MNI anatomical alignment template
# The overlay is colored from 1-30
# The overlay is thresholded so that there can be a countour
# line around all N=30 voxels
olay_dset=sub-0xx.maskthresh.nii.gz
@chauffeur_afni \
-prefix Figure3_part_TaskData_OverlapMap \
-pbar_saveim Figure3_part_TaskData_colorbar.jpg \
-func_range 30 \
-ulay ${underlay_dset} \
-olay ${olay_dset} \
-set_dicom_xyz 1 16 6 \
-delta_slices 28 36 31 \
-cbar Plasma \
-pbar_posonly \
-save_ftype SAVE_ALLJPEG \
-ulay_range 0% 98% \
-thr_olay 0.99 \
-olay_alpha Linear \
-olay_boxed Yes \
-set_subbricks 0 0 1 \
-opacity 5 \
-save_ftype JPEG \
-montx 5 -monty 1 \
-montgap 0 \
-montcolor 'black' \
-set_xhairs OFF \
-label_mode 1 -label_size 4 \
-do_clean
# -box_focus_slices AMASK_FOCUS_OLAY \
####
# Create the image for the Rest data
# The underlay is the MNI anatomical alignment template
# The overlay is colored from 1-20
# The overlay is thresholded so that there can be a countour
# line around all N=20 voxels
olay_dset=sub-1xx.maskthresh.nii.gz
@chauffeur_afni \
-prefix Figure3_part_RestData_OverlapMap \
-pbar_saveim Figure3_part_RestData_colorbar.jpg \
-func_range 20 \
-ulay ${underlay_dset} \
-olay ${olay_dset} \
-set_dicom_xyz 1 16 6 \
-delta_slices 28 36 31 \
-cbar Plasma \
-pbar_posonly \
-save_ftype SAVE_ALLJPEG \
-ulay_range 0% 98% \
-thr_olay 0.99 \
-olay_alpha Linear \
-olay_boxed Yes \
-set_subbricks 0 0 1 \
-opacity 5 \
-save_ftype JPEG \
-montx 5 -monty 1 \
-montgap 0 \
-montcolor 'black' \
-set_xhairs OFF \
-label_mode 1 -label_size 4 \
-do_clean
# -crop_axi_x 23 172 \
# -crop_axi_y 17 203 \
# -crop_sag_x 17 203 \
# -crop_sag_y 17 192 \
# -crop_cor_x 23 172 \
# -crop_cor_y 17 192 \
This generates mosaics for each orientation plane. These images were then processed in GIMP. The black background was filled with a consistent shade of black and then “zealous crop” was used to remove black space between, above, and below slices. This retained all data, including any ghosting, while letting the brain slices be relatively large within the same amount of space.
Uses images that were automatically generated by AFNI's @SSwarper command.
In ap_results_unifize/sub-001/QC_sub-001/media
and
ap_results_unifize/sub-016/QC_sub-016/media
the following files
were used:
- Full F stat map for axial slices:
qc_06_vstat_Full_Fstat.axi.jpg
- Full F stat map for sagittal slices:
qc_06_vstat_Full_Fstat.sag.jpg
- F stat map colorbar:
qc_06_vstat_Full_Fstat.pbar.jpg
- The maximum and minimum values for the colorbar are in related json files and in the html report
- Correlation to white matter ROI for axial slices:
qc_15_regr_corr_errts.axi.jpg
- Correlation to white matter ROI for sagittal slices:
qc_15_regr_corr_errts.sag.jpg
- Corrlation to WM color bar
qc_15_regr_corr_errts.pbar.jpg
All mosiac images were cropped in Adobe Illustrator to show a subset of slices.
Code to generate visualizations for figure 5A.
cd ./ap_results_unifize/sub-018
# Calc Euclidian Norm of motion time series rather than deriv of motion timeseries
1d_tool.py -infile motion_demean.1D -collapse_cols euclidean_norm -write motion_demean_enorm.1D
# Generate the instacorr map for predefined seed coordinate
# The 'keypress w' option will save the time series for the seed voxel
portnum=`afni -available_npb_quiet`
sbjid=sub-018
dset_ulay=pb03.${sbjid}.r01.volreg+tlrc.HEAD
# coord="-7.5 76.5 -7.5"
coord1="-19.5 70.5 16.5"
thresh="0.001p"
afni -q -no_detach \
-npb ${portnum} \
-com "SWITCH_UNDERLAY ${dset_ulay}" \
-com "INSTACORR INIT \
DSET=${dset_ulay} \
BLUR=0 \
AUTOMASK=yes \
DESPIKE=no \
BANDPASS=0.01,1 \
POLORT=3 \
SEEDRAD=0 \
METHOD=P" \
-com "INSTACORR SET ${coord1} J" \
-com "SET_THRESHNEW ${thresh}" \
-com "SET_PBAR_ALL -99 0.6 Reds_and_Blues_Inv" \
-com "SET_FUNC_RANGE 0.6" \
-com "SET_XHAIRS Single" \
-com "SET_XHAIR_GAP -1" \
-com "OPEN_WINDOW sagittalimage opacity=8" \
-com "OPEN_WINDOW coronalimage opacity=8" \
-com "OPEN_WINDOW axialimage opacity=8" \
-com "OPEN_WINDOW axialgraph matrix=1 geom=1000x250 keypress=w" \
-com "SAVE_PNG axialimage instacorr_${sbjid}_coord1_p001.ax.png blowup=3" \
-com "SAVE_PNG sagittalimage instacorr_${sbjid}_coord1_p001.sag.png blowup=3" \
-com "SAVE_PNG coronalimage instacorr_${sbjid}_coord1_p001.cor.png blowup=3" \
-yesplugouts \
$dset_ulay &
# Plot the seed time series along with the motion time series on a single axis
1dplot -naked -aspect 4 -one -demean -norm1 -jpgs 2048 instacorr_${sbjid}_coord1_p001.axgraph.jpg 038_020_031.1D motion_demean_enorm.1D
Code to generate visualizations for figure 5B. Saves the EPI, Anatomical, and EPI with instacorr overlay for a single coordinate with axial, sagittal, and coronal slices.
cd ./ap_results_unifize/sub-002
portnum=`afni -available_npb_quiet`
sbjid=sub-002
dset_ulay=pb00.${sbjid}.r01.tcat+orig.HEAD
coord1="-3.145 -36.019 -9.8"
thresh="0.001p"
afni -q -no_detach \
-npb ${portnum} \
-com "SWITCH_UNDERLAY anatSS.${sbjid}_al_junk+orig.HEAD" \
-com "OPEN_WINDOW sagittalimage opacity=8" \
-com "OPEN_WINDOW coronalimage opacity=8" \
-com "OPEN_WINDOW axialimage opacity=8" \
-com "SET_XHAIRS Single" \
-com "SET_XHAIR_GAP -1" \
-com "SET_DICOM_XYZ $coord1" \
-com "SAVE_PNG axialimage anat_${sbjid}_coord1.ax.png blowup=3" \
-com "SAVE_PNG sagittalimage anat_${sbjid}_coord1.sag.png blowup=3" \
-com "SAVE_PNG coronalimage anat_${sbjid}_coord1.cor.png blowup=3" \
-com "SWITCH_UNDERLAY ${dset_ulay}" \
-com "SET_DICOM_XYZ $coord1" \
-com "SAVE_PNG axialimage epi_${sbjid}_coord1.ax.png blowup=5" \
-com "SAVE_PNG sagittalimage epi_${sbjid}_coord1.sag.png blowup=5" \
-com "SAVE_PNG coronalimage epi_${sbjid}_coord1.cor.png blowup=5" \
-com "INSTACORR INIT \
DSET=${dset_ulay} \
BLUR=0 \
AUTOMASK=yes \
DESPIKE=no \
BANDPASS=0.01,1 \
POLORT=3 \
SEEDRAD=0 \
METHOD=P" \
-com "INSTACORR SET ${coord1} J" \
-com "SET_THRESHNEW ${thresh}" \
-com "SET_PBAR_ALL -99 0.6 Reds_and_Blues_Inv" \
-com "SET_FUNC_RANGE 0.6" \
-com "SAVE_PNG axialimage instacorr_${sbjid}_coord1_p001.ax.png blowup=5" \
-com "SAVE_PNG sagittalimage instacorr_${sbjid}_coord1_p001.sag.png blowup=5" \
-com "SAVE_PNG coronalimage instacorr_${sbjid}_coord1_p001.cor.png blowup=5" \
$dset_ulay anatSS.${sbjid}_al_junk+orig.HEAD &
Uses images that were automatically generated by AFNI's @SSwarper command.
In ap_results_unifize/sub-109/QC_sub-109/media
,
ap_results_unifize/sub-102/QC_sub-102/media
, and
ap_results_unifize/sub-114/QC_sub-114/media
the following files were used:
- Correlations to the PCC:
qc_06_vstat_seed_lh-PCC.axi.jpg
with colorbar:qc_06_vstat_seed_lh-PCC.pbar.jpg
- Correlation to white matter
qc_13_regr_corr_errts.axi.jpg
with colorbar:qc_13_regr_corr_errts.pbar.jpg
- Local correlations
qc_16_radcor_rc_volreg_r01.axi.jpg
with colorbar:qc_16_radcor_rc_volreg_r01.pbar.jpg
- EPI variance line warnings
qc_21_warns_vlines_0.sag.jpg
Mosaic images were cropped in Adobe Illustrator to present a subset of slices. The maximum and minimum values for the colorbars are in related json files and in the html report
Uses images that were automatically generated as part of AFNI’s html report
with images for the presented subjects in:
./ap_results_masked_warper_rest/sub-115/QC_sub-115/media
and
./ap_results_masked_warper_rest/sub-116/QC_sub-116/media
The unflipped axial and sagittal images are:
/qc_20_warns_flip_0.axi.jpg
and /qc_20_warns_flip_0.sag.jpg
The flipped axial and sagittal images are:
/qc_20_warns_flip_1.axi.jpg
and /qc_20_warns_flip_1.sag.jpg
All mosiac images were cropped in Adobe Illustrator to show a subset of slices.
Generating the cost function plot first used a script to pull the cost functions from each run
# Within each subject, the minimum cost value is stored in a file in the row beginning with 'flip_cost_orig'
# Get cost vals from task data
grep flip_cost_orig ap_results_unifize/sub-???/aea_checkflip_results.txt | awk '{print $3}' > ./cost_func_vals/task_data_correct_anats.txt
# Get cost vals from task data from the original submission when the wrong anatomicals were used
grep flip_cost_orig ap_results_unifize_WRONGANATOMICALS/sub-???/aea_checkflip_results.txt | awk '{print $3}' > ./cost_func_vals/task_data_wrong_anats.txt
# Get cost vals from rest data
grep flip_cost_orig ap_results_masked_warper_rest/sub-???/aea_checkflip_results.txt | awk '{print $3}' > ./cost_func_vals/rest_data.txt
Then use the outputted files to generate a plot in python
from matplotlib import pyplot as plt
from matplotlib.lines import Line2D
import os
import numpy as np
os.chdir('/Volumes/NIMH_SFIM/handwerkerd/Frontiers_QC_2022/')
fnames = ['rest_data', 'task_data_correct_anats', 'task_data_wrong_anats']
flabels = ['Rest', 'Task Correct Anatomicals', 'Task Wrong Anatomicals']
wrong_task_anat_markers=['.','.','.','.','.','.','.','.','.','X',
'X','X','X','X','X','X','X','X','X','X',
'X','X','X','X','X','X','X','X','X','X']
LR_warning_rest_markers=['X','.','.','.','.','.','.','.','.','.',
'.','.','.','.','X','X','.','.','.','.']
costvals = [[],[],[]]
for idx, fname in enumerate(fnames):
tmp_file = open(f'cost_func_vals/{fname}.txt', 'r')
tmp_content = tmp_file.readlines()
costvals[idx] = [float(f) for f in tmp_content]
print(costvals[idx])
plt.clf()
fig = plt.figure(figsize=(15,4))
for midx in range(len(LR_warning_rest_markers)):
plt.plot(costvals[0][midx], 2, marker=LR_warning_rest_markers[midx], markerfacecolor='blue', markeredgecolor='None', markersize=15, linestyle='None')
# plt.plot(costvals[0], 2*np.ones((len(costvals[0]),1)), marker='.', markerfacecolor='blue', markeredgecolor='None', markersize=15, linestyle='None')
plt.plot(costvals[1], 1.5*np.ones((len(costvals[1]),1)), marker='.', markerfacecolor='green', markeredgecolor='None', markersize=15, linestyle='None')
for midx in range(len(wrong_task_anat_markers)):
plt.plot(costvals[2][midx], 1, marker=wrong_task_anat_markers[midx], markerfacecolor='red', markeredgecolor='None', markersize=15, linestyle='None')
legend_elements = [Line2D([0], [0], marker='.', markerfacecolor='blue', markeredgecolor='None', markersize=15, linestyle = 'None',label='Rest Data'),
Line2D([0], [0], marker='.', markerfacecolor='green', markeredgecolor='None', markersize=15, linestyle = 'None',label='Task Data, Correct Anatomicals'),
Line2D([0], [0], marker='.', markerfacecolor='red', markeredgecolor='None', markersize=15, linestyle = 'None',label='Task Data, Wrong Anatomicals'),
Line2D([0], [0], marker='.', markerfacecolor='gray', markeredgecolor='None', markersize=15, linestyle = 'None',label='Correct anatomicals'),
Line2D([0], [0], marker='X', markerfacecolor='gray', markeredgecolor='None', markersize=15, linestyle = 'None',label='Wrong anats or flip LR'),
]
plt.legend(handles=legend_elements, loc='lower left')
ax = plt.gca()
ax.get_yaxis().set_visible(False)
ax.set_xlabel('Alignment Cost Function Value')
plt.savefig('./cost_func_vals/Fig7_part_cost_functions.svg', dpi=600, pad_inches=0.5)
plt.savefig('./cost_func_vals/Fig7_part_cost_functions.eps', dpi=600, pad_inches=0.5)
plt.savefig('./cost_func_vals/Fig7_part_cost_functions.png', dpi=600, pad_inches=0.5)
This was a figure that was generated to try to visualize the differences between using the correct and incorrect anatomicals for alignment. The differences were subtle and this visualization did not add much to the manuscript beyond what was in the text, but the code to regenerate this comparision might be useful.
# This is a directory where we copied the aligned anatomical
# and function from the correct processing stream and when
# the wrong anatomical was used. In this case, it was the
# EPI data from sub-021 and the anatomical from sub-017
# "wrong_" is prepended to the file names from the wrong
# alignment
cd ./Frontiers_QC_2022/Wrong_Right_AnatCompare/sub-021
@chauffeur_afni \
-prefix FigureX_part_anat_correct \
-ulay anat_final.sub-021+tlrc.HEAD \
-set_dicom_xyz 22 28 44 \
-save_ftype JPEG \
-ulay_range 0% 98% \
-set_subbricks 0 0 0 \
-montcolor 'black' \
-montx 1 -monty 1 \
-set_xhairs OFF \
-label_mode 0 \
-do_clean
# -label_size 4 \
@chauffeur_afni \
-prefix FigureX_part_anat_wrong \
-ulay wrong_anat_final.sub-021+tlrc.HEAD \
-set_dicom_xyz 22 28 44 \
-save_ftype JPEG \
-ulay_range 0% 98% \
-set_subbricks 0 0 0 \
-montcolor 'black' \
-montx 1 -monty 1 \
-set_xhairs OFF \
-label_mode 0 \
-do_clean
@djunct_edgy_align_check \
-olay anat_final.sub-021+tlrc.HEAD \
-ulay final_epi_vr_base+tlrc.HEAD \
-use_olay_grid wsinc5 \
-ulay_range_am "1%" "95%" \
-ulay_min_fac 0.2 \
-set_dicom_xyz 22 28 44 \
-save_ftype JPEG \
-montx 1 -monty 1 \
-no_cor \
-prefix FigureX_part_EPI_correct
@djunct_edgy_align_check \
-olay wrong_anat_final.sub-021+tlrc.HEAD \
-ulay wrong_final_epi_vr_base+tlrc.HEAD \
-use_olay_grid wsinc5 \
-ulay_range_am "1%" "95%" \
-ulay_min_fac 0.2 \
-set_dicom_xyz 22 28 44 \
-save_ftype JPEG \
-montx 1 -monty 1 \
-no_cor \
-prefix FigureX_part_EPI_wrong