https://github.com/CNG-LAB/cngopen
Tip revision: b8031194ea8737e7aae34249d9376dbf1259f4e3 authored by Bin Wan on 09 August 2022, 14:49:26 UTC
update_issue_license_openaccess
update_issue_license_openaccess
Tip revision: b803119
Hettwer2022_Figure2_Transdiagnostic_Gradients.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Coordinated Cortical Thickness alterations Across Mental Disorders: A Transdiagnostic ENIGMA Project
% Script 1: Loads ENIGMA summary statistics (Cohen's d maps), computes
% cross-disorder similarity, derives transdiagnostic Gradients, and
% contextualizes these gradients with functional, macro- and
% microstructural and transcriptomic profiles.
%This script runs analyses presented in Figure 2 of the manuscript.
%Meike Hettwer 2022 - CNG Lab
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% add Toolboxes and data paths
%set your paths
%DataPath = '....';
%ScriptPath = '....';
%% add Toolboxes and data paths
%required toolboxes are:
%ENIGMA-1.1.3
%BrainSpace-0.1.2
%SurfStat
%cbrewer
%spiderPlot
%gifti-master
%quantileranks
%GAMBA
%load data from GitHub
%CT_psych_gradients.mat
%Valk2020_CT_structural_covariance_gradient.mat
%midbrain_vertices_fsa5.mat %useful for conversion between atlases (note: extra midbrain - parcels when mapping from fsa5 to Desikan-Killiany are: 1 5 40)
%DK_midbrain_parcels.mat
%% 1. Load Summary statistics Data
%If data uploaded on Github is used:
load(strcat(DataPath,'CT_6_Disorders.mat'));
%If data is loaded individually from the ENIGMA Toolbox
%{
%Schizophrenia
sum_stats = load_summary_stats('schizophrenia')
CT = sum_stats.CortThick_case_vs_controls;
CT_d_sz = CT.d_icv;
%Bipolar
sum_stats = load_summary_stats('bipolar');
CT = sum_stats.CortThick_case_vs_controls_adult;
CT_d_bipo = CT.d_icv;
%ASD
sum_stats = load_summary_stats('asd');
CT = sum_stats.CortThick_case_vs_controls_meta_analysis;
CT_d_asd = CT.d_icv;
%ADHD
sum_stats = load_summary_stats('adhd');
CT = sum_stats.CortThick_case_vs_controls_adult;
CT_d_adhd = CT.d_icv;
%MDD
sum_stats = load_summary_stats('depression');
CT = sum_stats.CortThick_case_vs_controls_adult;
CT_d_mdd = CT.d_icv;
%OCD
sum_stats = load_summary_stats('ocd');
CT = sum_stats.CortThick_case_vs_controls_adult;
CT_d_ocd = CT.d_icv;
%}
%% Disorders: BD, SZC, ADHD, ASD, MDD, OCD
disorders = [CT_d_bipo, CT_d_adhd, CT_d_asd, CT_d_mdd, CT_d_ocd, CT_d_sz];
disorder_names = {'Bipolar Disorder'; 'ADHD'; 'ASD'; 'Depression'; 'OCD'; 'Schizophrenia'};
%% Compute Transdiagnostic Gradients (Figure 2)
% 1) derive cross-disorder correlation matrix
corr_dis = corr(disorders');
% 2) build/load gradients
gm = GradientMaps('kernel','na','approach','dm'); %in GradientMaps Script, set "sparsity" to 80 (due to low number of DK parcels)
gm = gm.fit(corr_dis);
psych_grad = gm.gradients{1};
%Figure 2A
handles = scree_plot(gm.lambda{1});set(handles.axes,'FontName','Gill Sans MT','FontSize',12,'XTick',[1 7],'YTick',[0 0.4],'YTickLabel',{'0','0.4'});
CT_psych_gradient1 = psych_grad(:,1);
CT_psych_gradient2 = psych_grad(:,2);
%alternatively, load pre-computed gradients from GitHub
%load('CT_psych_gradients');
%plot gradients to surface (without midbrain values) (*Figure 2B*)
plot_G1_no_midbrain = parcel_to_surface(CT_psych_gradient1);
plot_G1_no_midbrain(midbrain_verticesfsa5) = (max(plot_G1_no_midbrain)+min(plot_G1_no_midbrain))/2;
plot_G2_no_midbrain = parcel_to_surface(CT_psych_gradient2);
plot_G2_no_midbrain(midbrain_verticesfsa5) = (max(plot_G2_no_midbrain)+min(plot_G2_no_midbrain))/2;
figure, plot_cortical(plot_G1_no_midbrain);
figure, plot_cortical(plot_G2_no_midbrain);
%% Compare Gradients to Valk 2020 (DOI: 10.1126/sciadv.abb3417) normative structural covariance gradient of cortical thickness
%Figure 2C
%re-parcel both normative CT covariance gradients to DK space (via fsa5 surface)
Valk_G1_fsa5 = parcel_to_surface(Valk2020_CT_structural_covariance_gradient(:,1),'schaefer_400_fsa5');
Valk_G2_fsa5 = parcel_to_surface(Valk2020_CT_structural_covariance_gradient(:,2),'schaefer_400_fsa5');
Valk_G1_DK = surface_to_parcel(Valk_G1_fsa5)';
Valk_G2_DK = surface_to_parcel(Valk_G2_fsa5)';
Valk_G1_DK(midbrain_parcels) = [];%remove midbrain parcels for spin test
Valk_G2_DK(midbrain_parcels) = [];
%test association with principal CT gradient via spin test
r_G1_CT = corr(Valk_G1_DK,CT_psych_gradient1);
r_G2_CT = corr(Valk_G1_DK,CT_psych_gradient2);
[p_spin_G1] = spin_test(Valk_G1_DK,CT_psych_gradient1, 'surface_name', 'fsa5', 'parcellation_name', 'aparc', 'n_rot', 1000, 'type', 'pearson');
[p_spin_G2] = spin_test(Valk_G1_DK,CT_psych_gradient2, 'surface_name', 'fsa5', 'parcellation_name', 'aparc', 'n_rot', 1000, 'type', 'pearson');
%test association with second CT gradient via spin test
r_G1_CT2 = corr(Valk_G2_DK,CT_psych_gradient1);
r_G2_CT2 = corr(Valk_G2_DK,CT_psych_gradient2);
[p_spin_G1_2] = spin_test(Valk_G2_DK,CT_psych_gradient1, 'surface_name', 'fsa5', 'parcellation_name', 'aparc', 'n_rot', 1000, 'type', 'pearson');
[p_spin_G2_2] = spin_test(Valk_G2_DK,CT_psych_gradient2, 'surface_name', 'fsa5', 'parcellation_name', 'aparc', 'n_rot', 1000, 'type', 'pearson');
%for visualization, color in midbrain with intermediate color (white)
Valk_plot_G1_no_midbrain = parcel_to_surface(Valk_G1_DK);
Valk_plot_G1_no_midbrain(midbrain_verticesfsa5)=(max(Valk_plot_G1_no_midbrain)+min(Valk_plot_G1_no_midbrain))/2;
figure; plot_cortical(Valk_plot_G1_no_midbrain)
%plot correlation between G1/G2 and CT gradient (*Figure 2C*)
Trans_Gradients = [CT_psych_gradient1 CT_psych_gradient2];
col = [0 0 0];
figure;
for j = 1:2
axs = subplot(1, 2, j); hold on
s = scatter(Valk_G1_DK, Trans_Gradients(:,j), 38, col, 'filled');
P1 = polyfit(Valk_G1_DK, Trans_Gradients(:,j), 1);
yfit_1 = P1(1) * Valk_G1_DK + P1(2);
hold on
col_line = [0.66 0.13 0.11];%[53.3/255 0 0]
plot(Valk_G1_DK, yfit_1, 'color',col_line, 'LineWidth', 3);
ylim([min(Trans_Gradients(:,j))-0.01 max(Trans_Gradients(:,j))+0.01]);
xlim([min(Valk_G1_DK)-0.01 max(Valk_G1_DK)+0.01]);
set(gca,'xtick',[],'ytick',[]);
axis square
end
%% Contextualize Gradients with cytoarchitectonic classes (von Economo Koskinas; see https://www.karger.com/Article/Abstract/103258 or https://enigma-toolbox.readthedocs.io/en/latest/pages/11.02.voneconomo/index.html)
%Figure 2D
%stratify gradients according to cytoarchitectonic classes
ve = dlmread('economo_koskinas_fsa5.csv'); %original order: {'Agranular', 'Frontal', 'Parietal', 'Polar', 'Granular'}
ve_class = zeros(5, 1);
surf_G1 = parcel_to_surface(CT_psych_gradient1);
surf_G2 = parcel_to_surface(CT_psych_gradient2);
class_meanG1 = nan(1,5);
class_meanG2 = nan(1,5);
for ii = 1:5
id = find(ve == ii);
class_meanG1(ii) = mode(surf_G1(id));
class_meanG2(ii) = mode(surf_G2(id));
end
classes_spider = [class_meanG1; class_meanG2];
%Reorder for better visualization
classes_spider_reordered(:,1:4) = classes_spider(:,2:5);
classes_spider_reordered(:,5) = classes_spider(:,1);
vek_reordered = {'Frontal','Parietal', 'Polar', 'Granular','Agranular'};
AxesLim = [- 0.1 -0.1; 0.15 0.15];
figure;
spider_plot(classes_spider_reordered, 'AxesLabels', vek_reordered,'AxesLabelsEdge', 'none','AxesLimits', [-0.26 -0.26 -0.26 -0.26 -0.26; 0.26 0.26 0.26 0.26 0.26],'AxesPrecision',2,...
'AxesDisplay','one','AxesInterval',5, 'Color', [124, 30, 43;107 142 35; 1 0 1 ]/255,...
'AxesFont', 'Gill Sans MT','LabelFont', 'Gill Sans MT','AxesFontSize', 12, 'LabelFontSize', 15);
legend_str = {'G1', 'G2'};legend(legend_str, 'Location', 'northeast'); legend boxoff
%% Identify genes whose expression pattern follows G1 / G2.
% Identified genes were then fed into the CSEA tool for developmental enrichment analyses (http://genetics.wustl.edu/jdlab/csea-tool-2/)
%% Load AHBA data and test association with transdiagnostic gradients using null models tsting for spatial and gene specificity. Requires GAMBA Toolbox (Wei et al.)
%AHBA
ahba = fetch_ahba();
regions = ahba.label;
gene_symbols = ahba.Properties.VariableNames(2:end)';
expression = table2array(ahba(1:68,2:end));
% 1. assess spatial specificity via alexander-bloch spin test
for i = 1:length(expression)
[p_spin_G1(i)] = spin_test_spin_map1_only(CT_psych_gradient1, expression(:,i), 'surface_name', 'fsa5', 'parcellation_name', 'aparc', 'n_rot', 1000, 'type', 'pearson');
[p_spin_G2(i)] = spin_test_spin_map1_only(CT_psych_gradient2, expression(:,i), 'surface_name', 'fsa5', 'parcellation_name', 'aparc', 'n_rot', 1000, 'type', 'pearson');
end
p_G1_sig = p_spin_G1(p_spin_G1<0.01);
p_G2_sig = p_spin_G1(p_spin_G2<0.01);
G1_gene_set_01 = gene_symbols(p_spin_G1<0.01);
G2_gene_set_01 = gene_symbols(p_spin_G2<0.01);
[r_G1, p_G1] = corr(CT_psych_gradient1,expression,'rows','complete'); %1:68 = only cortical parcellations (69:82 = subcortical); 2:end = all genes
[r_G2, p_G2] = corr(CT_psych_gradient2,expression,'rows','complete'); %1:68 only cortical parcellations (69:82 = subcortical); 2:end = all genes
r_G1_sig = r_G1(p_spin_G1<0.01);
r_G1_sig_positive = r_G1_sig>0;
G1_positive_genes = G1_gene_set_01(r_G1_sig_positive);
G1_negative_genes = G1_gene_set_01(~r_G1_sig_positive);
T_genes_G1 = table(G1_gene_set_01, r_G1_sig', p_G1_sig');
T_genes_G1.Properties.VariableNames = {'Gene','r','p_spin'};
writetable(T_genes_G1,'Genes_G1.xlsx','Sheet',1,'Range','A1')
% 2. assess gene specificity using GAMBA
%check whether previously identified gene set is significantly stronger
%associated with phenotype than random genes (that are also over-expressed
%in the brain!)
%res_G1_null_brain = permutation_null_brain(CT_psych_gradient1, G1_gene_set_05, expression, gene_symbols, 'brain')
res_G1_null_brain_p01 = permutation_null_brain(CT_psych_gradient1, G1_gene_set_01, expression, gene_symbols, 'brain');
res_G2_null_brain_p01 = permutation_null_brain(CT_psych_gradient2, G2_gene_set_01, expression, gene_symbols, 'brain');
% check whether imaging profiles associate with gene expression profiles, based
% on the null-coexpression model (where random genes with similar
% coexpression level is conserved).
res_G1_null_coexp_p01 = permutation_null_coexp(CT_psych_gradient1, G1_gene_set_01, expression, gene_symbols);
res_G2_null_coexp_p01 = permutation_null_coexp(CT_psych_gradient2, G2_gene_set_01, expression, gene_symbols);
%Gene set is then fed in to the CSEA Tool and presented in *Figure 2E*
%% Neurosynth functional decoding (Figure 2E)
%Functional Neurosynth decoding
cd /Users/m.hettwer/Documents/MATLAB/ENIGMA_Cross_Disorder_Gradients/Data/neurosynth_z_values;
BH = {'action_association-test_z_lh.shape.gii'
'action_association-test_z_rh.shape.gii'
'affective_association-test_z_lh.shape.gii'
'affective_association-test_z_rh.shape.gii'
'attention_association-test_z_lh.shape.gii'
'attention_association-test_z_rh.shape.gii'
'auditory_association-test_z_lh.shape.gii'
'auditory_association-test_z_rh.shape.gii'
'autobiographical_memory_association-test_z_lh.shape.gii'
'autobiographical_memory_association-test_z_rh.shape.gii'
'cognitive_control_association-test_z_lh.shape.gii'
'cognitive_control_association-test_z_rh.shape.gii'
'emotion_association-test_z_lh.shape.gii'
'emotion_association-test_z_rh.shape.gii'
'episodic_memory_association-test_z_lh.shape.gii'
'episodic_memory_association-test_z_rh.shape.gii'
'eye_movement_association-test_z_lh.shape.gii'
'eye_movement_association-test_z_rh.shape.gii'
'face_association-test_z_lh.shape.gii'
'face_association-test_z_rh.shape.gii'
'inhibition_association-test_z_lh.shape.gii'
'inhibition_association-test_z_rh.shape.gii'
'language_association-test_z_lh.shape.gii'
'language_association-test_z_rh.shape.gii'
'motor_association-test_z_lh.shape.gii'
'motor_association-test_z_rh.shape.gii'
'multisensory_association-test_z_lh.shape.gii'
'multisensory_association-test_z_rh.shape.gii'
'pain_association-test_z_lh.shape.gii'
'pain_association-test_z_rh.shape.gii'
'reading_association-test_z_lh.shape.gii'
'reading_association-test_z_rh.shape.gii'
'reward_association-test_z_lh.shape.gii'
'reward_association-test_z_rh.shape.gii'
'semantics_association-test_z_lh.shape.gii'
'semantics_association-test_z_rh.shape.gii'
'social_cognition_association-test_z_lh.shape.gii'
'social_cognition_association-test_z_rh.shape.gii'
'verbal_association-test_z_lh.shape.gii'
'verbal_association-test_z_rh.shape.gii'
'visual_association-test_z_lh.shape.gii'
'visual_association-test_z_rh.shape.gii'
'visual_perception_association-test_z_lh.shape.gii'
'visual_perception_association-test_z_rh.shape.gii'
'visuospatial_association-test_z_lh.shape.gii'
'visuospatial_association-test_z_rh.shape.gii'
'working_memory_association-test_z_lh.shape.gii'
'working_memory_association-test_z_rh.shape.gii'};
LH_ind = find(endsWith(BH, 'lh.shape.gii'));
LH = BH(LH_ind);
RH_ind = find(endsWith(BH, 'rh.shape.gii'));
RH = BH(RH_ind);
%%reparcel gradients and neurosynth data to same space (71 parcels), since
%%our Conte69 to DK converision csv file describes the 71 (instead of the
%%68) parcel version
Grad1_surf = parcel_to_surface(CT_psych_gradient1,'aparc_conte69');
Grad1 = surface_to_parcel(Grad1_surf, 'aparc_conte69');
Grad_surf2 = parcel_to_surface(CT_psych_gradient2,'aparc_conte69');
Grad2 = surface_to_parcel(Grad_surf2, 'aparc_conte69');
surf =load_conte69('surfaces');
%% bin neurosynth data
tmp = nan(24,20);
for j = 1:24
L = gifti(strcat('/Users/m.hettwer/Documents/MATLAB/ENIGMA_Cross_Disorder_Gradients/Data/neurosynth_z_values/', LH{j}));
R = gifti(strcat('/Users/m.hettwer/Documents/MATLAB/ENIGMA_Cross_Disorder_Gradients/Data/neurosynth_z_values/', RH{j}));
funcmap= [L.cdata;R.cdata];
%bins1 = [];
bins1 = quantileranks(Grad1,20); %Grad1 binned into 1:20 bins and allocated to 71 DK parcels
grad_fc = zeros(1,64984);
for i = 1:71
a = i-1; %because parcels are numbered from 0 to 70 and not 1 to 71 (due to previous Python indexing); bins from 1:20
grad_fc(:,aparc_conte69==a) = bins1(i);
end
for i = 1:20
tmp(j,i) = mean(funcmap(grad_fc==i)); %size: 24 x 20
end
end
%zscore binned functional map
Grad1_binned = nan(1,20);
for i = 1:20
Grad1_binned(i) = mean(Grad1(bins1==i));
end
tmpz2= zscore(tmp,[],2);
tmpz22 = tmpz2;
tmpz2(tmpz2<0.5) = nan;
weighted_mean = nanmean(tmpz2.*(Grad1_binned),2);
[~,b,c] = unique(weighted_mean);
tmp2 = nan(24,20);
grd_binned = nan(1,20);
for j = 1:24
L = gifti(strcat('/Users/m.hettwer/Documents/MATLAB/ENIGMA_Cross_Disorder_Gradients/Data/neurosynth_z_values/', LH{j}));
R = gifti(strcat('/Users/m.hettwer/Documents/MATLAB/ENIGMA_Cross_Disorder_Gradients/Data/neurosynth_z_values/', RH{j}));
funcmap= [L.cdata;R.cdata];
% bins1 = [];
bins1 = quantileranks(Grad2,20);
grad_fc = zeros(1,64984);
for i = 1:71
a = i-1;
grad_fc(:,find(aparc_conte69==a)) = bins1(i);
end
for i = 1:20
tmp2(j,i) = mean(funcmap(find(grad_fc==i)));
end
end
for i = 1:20
grd_binned(i) = mean(Grad2(bins1==i));
end
tmpz= zscore(tmp2,[],2);
tmpzz = tmpz;
tmpz(tmpz<0.5) = nan;
weighted_mean = nanmean(tmpz.*(grd_binned),2);
[~,d,e] = unique(weighted_mean);
j=0;
for i = 1:24
j=j+1;
words{j} = LH{j};
worrs3{j} = words{j}(1:end-32);
words_final{j} = strrep(worrs3{j},'_',' ');
wrd{j} = num2str(j);
end
eucd= sqrt(c.^2+d.^2);
%% color coding
% col = [0 0 0];
BBgrad1 = CT_psych_gradient1;
BBgrad2 = CT_psych_gradient2;
g = load('/Users/m.hettwer/Documents/MATLAB/Toolbox/cbrewer/cbrewer/cbrewer/colorbrewer.mat');
colorbrewer = g.colorbrewer;
G1peak = max(BBgrad1);
G2min = min(BBgrad2);
G2max = max(BBgrad2);
colourness = nan(68,3);
for ii = 1:length(BBgrad1)
if BBgrad1(ii) > 0
colourness(ii,2) = 1 - (G1peak - BBgrad1(ii));
else
colourness(ii,2) = 1 - (G1peak + abs(BBgrad1(ii)));
end
if BBgrad2(ii) > 0
colourness(ii,1) = 1 - (G2max- BBgrad2(ii));
colourness(ii,3) = 1 - (abs(G2min) + BBgrad2(ii));
else
colourness(ii,1) = 1 - (G2max + abs(BBgrad2(ii)));
colourness(ii,3) = 1 - (abs(G2min) - abs(BBgrad2(ii)));
end
end
% rescale colorbar
colourness_rescale = nan(68,3);
colourness_vertices = nan(64984,3);
for col = 1:3
colourness_rescale(:,col) = rescale(colourness(:,col), 0, 1);
colourness_vertices(:,col)=parcel_to_surface(colourness_rescale(:,col),'aparc_conte69');
end
%compute densities for density plot next to scatters
[x, y] = ksdensity(BBgrad1);
y2(1,:) = x; x2(1,:) = y;
[y2(2,:), x2(2,:)] = ksdensity(BBgrad2);
%% scatter (*Figure 2F*)
colourness_rescale_green = colourness_rescale;
colourness_rescale_green(:,2) = colourness_rescale_green(:,2)-min(colourness_rescale(:,2));
f= figure;
a(1) = axes('position', [0.1 0.1 0.4 0.4]); %plot colored parcels along gradients
scatter(BBgrad2, BBgrad1, 60, colourness_rescale_green,'filled');
axis([min(BBgrad2)-0.01 max(BBgrad2)+0.01 min(BBgrad1)-0.01 max(BBgrad1)+0.01])
set(gca,'xtick',[],'ytick',[])
a(2) = axes('position', [0.5 0.1 0.07 0.4]); %add densities
patch(y2(1,:),x2(1,:), ones(1,length(y2(1,:)))); axis off;
colormap(a(2), [190, 190, 190]/250)%[0.5, 0.5, 0.5])
ylim([min(BBgrad1) max(BBgrad1)])
a(3) = axes('position', [0.1 0.5 0.4 0.07]);
patch(x2(2,:), y2(2,:), ones(1,length(y2(2,:)))); axis off;
colormap(a(3), [190, 190, 190]/250)
xlim([min(BBgrad2) max(BBgrad2)])
hold on
a(4) = axes('position', [0.1 0.1 0.4 0.4]); col = [0,0,0]; %add cognitive function terms
x = e; y = c; scatter(x,y,60,col,'filled');%flipped, so G1 is on y axis
txty = words_final;
dx = 0.85;
dy = 0.2; % displacement so the text does not overlay the data points
text(x+dx, y+dy, txty,'FontSize',13, 'FontName', 'Gill Sans MT');
set(gca,'XTick',[],'YTick',[],'color','none');xlabel('G2');ylabel('G1')
hold off
%% END OF SCRIPT