Summary: Reads in data generated from running simulations on a compute cluster (20 simulations/subjects). For each simulated subject, we run a resting-state simulation, a task-state simulation (for topdown hub stimulation), a second task-state simulation (for simultaneous topdown and bottomup network stimulation), and perform the information transfer mapping procedure for each task. Each task consists for 4 different task conditions.
Simulations are run using a network with five communities, comprising of a single hub community and four local communities. We employ a firing rate code model, and simulate functional MRI data by convolving the simulated signal with a hemodynamic response function (defined in model.py module).
See Supplemental materials/methods for a full description.
where $x_i$ is the activity of region $i$, $\tau_{i}$ is the time constant for region $i$, $s$ is the recurrent (local) coupling, $g$ is the global coupling parameter, $\phi$ is the bounded transfer function (in this scenario is the hyperbolic tangent), $W_{xy}$ is the synaptic connectivity matrix, and $I$ is the task-stimulation (if any).
N.B. All simulations were performed separately using the provided modules; data provided are a direct product for running the provided model. This notebook is configured to run analyses in parallel using the multiprocessing module in python.
1.0 Load and visualize synaptic connectivity, resting-state FC
2.0 Compute out-of-network degree centrality
3.0 Load in network-to-network activity flow mapping predictions; perform predicted-to-actual similarity analysis (RSA)
4.0 Seconday analysis: Load in network-to-network activity flow mapping predictions; perform predicted-to-actual similarity analysis (using SVMs)
In [378]:
import numpy as np
import sys
sys.path.append('utils/')
import os
os.environ['OMP_NUM_THREADS'] = str(1)
import matplotlib.pyplot as plt
% matplotlib inline
import scipy.stats as stats
import statsmodels.api as sm
import multiprocessing as mp
import sklearn.preprocessing as preprocessing
import sklearn.svm as svm
import statsmodels.sandbox.stats.multicomp as mc
# Import custom modules
import multregressionconnectivity as mreg
import model
import analysis
from matplotlib.colors import Normalize
# Code to generate a normalized midpoint for plt.imshow visualization function
class MidpointNormalize(Normalize):
def __init__(self, vmin=None, vmax=None, midpoint=None, clip=False):
self.midpoint = midpoint
Normalize.__init__(self, vmin, vmax, clip)
def __call__(self, value, clip=None):
# I'm ignoring masked values and all kinds of edge cases to make a
# simple example...
x, y = [self.vmin, self.midpoint, self.vmax], [0, 0.5, 1]
return np.ma.masked_array(np.interp(value, x, y))
In [379]:
# Specify the directory to read in provided data
# If data file was unzippd in current working directory this shouldn't need to be changed
datadir = 'ItoEtAl2017_Simulations/'
# Specify number of CPUs to process on (using multiprocessing module in python)
nproc = 10
# Output file to save generated figures (from this notebook)
outputdir = './figures/' # default with output in current working directory
if not os.path.exists(outputdir): os.makedirs(outputdir)
Basic simulation parameters
In [380]:
nsubjs = range(0,20) # number of simulations (i.e., subject numbers)
nblocks = 20 # number of blocks per task condition
#### Define the condition numbers associated with each task
# Conditions 1-4 are for top-down stimulation only (i.e., task 1)
topdown_only = range(1,5)
# Conditions 5-9 are simultaneous top-down (hub-network) and bottom-up (local-network) stimulation (i.e., task 2)
topdown_and_bottomup = range(5,9)
In [381]:
#### Set up subject networks ####
# Parameters for subject's networks
ncommunities = 5
innetwork_dsity = .35
outnetwork_dsity = .05
hubnetwork_dsity = .20
nodespercommunity = 50
totalnodes = nodespercommunity*ncommunities
##########
# Construct structural matrix
W = model.generateStructuralNetwork(ncommunities=ncommunities, innetwork_dsity=innetwork_dsity,
outnetwork_dsity=outnetwork_dsity, hubnetwork_dsity=hubnetwork_dsity,
nodespercommunity=nodespercommunity, showplot=False)
# Construct synaptic matrix
G = model.generateSynapticNetwork(W, showplot=False)
# Define community affiliation vector
Ci = np.repeat(np.arange(ncommunities),nodespercommunity)
# Plot figure
plt.figure()
# norm = MidpointNormalize(midpoint=0)
plt.imshow(G,origin='lower',interpolation='none')
plt.xlabel('Regions')
plt.ylabel('Regions')
plt.title('Synaptic Weight Matrix', y=1.04, fontsize=18)
plt.colorbar()
Out[381]:
In [382]:
fcmat_pearson = np.zeros((totalnodes,totalnodes,len(nsubjs)))
fcmat_multreg = np.zeros((totalnodes,totalnodes,len(nsubjs)))
##########
# Load in subject FC data
scount = 0
for subj in nsubjs:
indir = datadir + '/restfc/'
# Load in pearson FC matrix
filename1 = 'subj' + str(subj) + '_restfc_pearson.txt'
fcmat_pearson[:,:,scount] = np.loadtxt(indir + filename1, delimiter=',')
# Loda in multreg FC matrix
filename2 = 'subj' + str(subj) + '_restfc_multreg.txt'
fcmat_multreg[:,:,scount] = np.loadtxt(indir + filename2, delimiter=',')
scount += 1
##########
# Plot group FC averages
plt.figure()
avg = np.mean(fcmat_pearson,axis=2)
np.fill_diagonal(avg,0)
plt.imshow(avg ,origin='lower',interpolation='none')#,vmin=0)
plt.xlabel('Regions')
plt.ylabel('Regions')
plt.title('Group Rest FC Matrix\nPearson FC', y=1.04, fontsize=18)
plt.colorbar()
plt.tight_layout()
plt.figure()
avg = np.mean(fcmat_multreg,axis=2)
np.fill_diagonal(avg,0)
plt.imshow(avg ,origin='lower',interpolation='none')#,vmin=-.08,vmax=.08)
plt.xlabel('Regions')
plt.ylabel('Regions')
plt.title('Group Rest FC Matrix\nMultiple Regression FC', y=1.04, fontsize=18)
plt.colorbar()
plt.tight_layout()
In [383]:
outofnet_intrinsicFC = np.zeros((ncommunities,len(nsubjs)))
indices = np.arange(nodespercommunity*ncommunities)
##########
# Calculate average out-of-network degree across subjects
scount = 0
for subj in nsubjs:
for net in range(0,ncommunities):
# if net == hubnet: continue
net_ind = np.where(Ci==net)[0]
net_ind.shape = (len(net_ind),1)
outofnet_ind = np.setxor1d(net_ind,indices)
outofnet_ind.shape = (len(outofnet_ind),1)
outofnet_intrinsicFC[net,scount] = np.mean(fcmat_multreg[net_ind, outofnet_ind.T, scount])
scount += 1
# Compute average stats
fcmean = np.mean(outofnet_intrinsicFC,axis=1)
fcerr = np.std(outofnet_intrinsicFC,axis=1)/np.sqrt(len(nsubjs))
##########
# Plot figure
fig = plt.bar(range(len(fcmean)), fcmean, yerr=fcerr)
# fig = plt.ylim([.09,0.10])
fig = plt.xticks(np.arange(.4,5.4,1.0),['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'],fontsize=14)
fig = plt.ylabel('Multiple Regression FC', fontsize=16)
fig = plt.xlabel('Networks', fontsize=16)
fig = plt.title("Average Out-Of-Network IntrinsicFC\nSimulated Resting-State Data", fontsize=18, y=1.02)
fig = plt.tight_layout()
Region-to-region activity flow mapping is performed already (with provided simulation data); we only perform the predicted-to-actual similarity analysis.
In [384]:
# Empty variables for topdown task analysis
ite_topdown = np.zeros((ncommunities,ncommunities,len(nsubjs)))
# Empty variables for topdown and bottomup task analysis
ite_topdownbottomup = np.zeros((ncommunities,ncommunities,len(nsubjs)))
##########
# Run predicted-to-actual similarity for every network-to-network configuration (using RSA approach)
for i in range(ncommunities):
for j in range(ncommunities):
if i==j: continue
fromnet = i
net = j
nblocks = nblocks
## First run on topdown only task conditions
inputs = []
for subj in nsubjs: inputs.append((subj,net,fromnet,topdown_only,nblocks,Ci,nodespercommunity,datadir))
# Run multiprocessing across subjects
pool = mp.Pool(processes=nproc)
results_topdown = pool.map_async(analysis.predictedToActualRSA, inputs).get()
pool.close()
pool.join()
## Second run on topdown and bottomup task conditions
inputs = []
for subj in nsubjs: inputs.append((subj,net,fromnet,topdown_and_bottomup,nblocks,Ci,nodespercommunity,datadir))
# Run multiprocessing
pool = mp.Pool(processes=nproc)
results_topdownbottomup = pool.map_async(analysis.predictedToActualRSA, inputs).get()
pool.close()
pool.join()
## Get results and store in network X network X subjects matrix
scount = 0
for subj in nsubjs:
# Obtain topdown task results
ite = results_topdown[scount]
ite_topdown[i,j,scount] = ite
# Obtain topdown and bottom up task results
ite = results_topdownbottomup[scount]
ite_topdownbottomup[i,j,scount] = ite
scount += 1
In [392]:
# Instantiate empty result matrices
tmat_topdown = np.zeros((ncommunities,ncommunities))
pmat_topdown = np.ones((ncommunities,ncommunities))
tmat_topdownbottomup = np.zeros((ncommunities,ncommunities))
pmat_topdownbottomup = np.ones((ncommunities,ncommunities))
# Run t-tests for every network-to-network configuration
for i in range(ncommunities):
for j in range(ncommunities):
if i==j: continue
##########
## Run statistical test for first task (topdown only stim)
t, p = stats.ttest_1samp(ite_topdown[i,j,:],0)
tmat_topdown[i,j] = t
# Make p-value one-sided (for one-sided t-test)
if t > 0:
p = p/2.0
else:
p = 1-p/2.0
pmat_topdown[i,j] = p
##########
## Run statistical test for second task (topdown and bottomup stim)
t, p = stats.ttest_1samp(ite_topdownbottomup[i,j,:],0)
# Make p-value one-sided (for one-sided t-test)
tmat_topdownbottomup[i,j] = t
if t > 0:
p = p/2.0
else:
p = 1-p/2.0
pmat_topdownbottomup[i,j] = p
##########
# Run FDR correction on p-values (exclude diagonal values)
## TopDown Task
qmat_topdown = np.ones((ncommunities,ncommunities))
triu_ind = np.triu_indices(ncommunities,k=1)
tril_ind = np.tril_indices(ncommunities,k=-1)
all_ps = np.hstack((pmat_topdown[triu_ind],pmat_topdown[tril_ind]))
h, all_qs = mc.fdrcorrection0(all_ps)
# the first half of all qs belong to triu, second half belongs to tril
qmat_topdown[triu_ind] = all_qs[:len(triu_ind[0])]
qmat_topdown[tril_ind] = all_qs[len(tril_ind[0]):]
binary_mat_topdown = qmat_topdown < .05
## TopDown and BottomUp Task
qmat_topdownbottomup = np.ones((ncommunities,ncommunities))
triu_ind = np.triu_indices(ncommunities,k=1)
tril_ind = np.tril_indices(ncommunities,k=-1)
all_ps = np.hstack((pmat_topdownbottomup[triu_ind],pmat_topdownbottomup[tril_ind]))
h, all_qs = mc.fdrcorrection0(all_ps)
# the first half of all qs belong to triu, second half belongs to tril
qmat_topdownbottomup[triu_ind] = all_qs[:len(triu_ind[0])]
qmat_topdownbottomup[tril_ind] = all_qs[len(tril_ind[0]):]
binary_mat_topdownbottomup = qmat_topdownbottomup < .05
##########
# Plot figures for topdown task
# (Unthresholded plot)
plt.figure(figsize=(12,10))
plt.subplot(121)
norm = MidpointNormalize(midpoint=0)
plt.imshow(np.mean(ite_topdown,axis=2),norm=norm,origin='lower',interpolation='None',cmap='bwr')
plt.title('Network-to-Network ITE (using RSA) (Unthresholded)\nTopDown Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
# (Thresholded plot)
plt.subplot(122)
threshold_acc = np.multiply(binary_mat_topdown,np.mean(ite_topdown,axis=2))
norm = MidpointNormalize(midpoint=0)
plt.imshow(threshold_acc,norm=norm,origin='lower',interpolation='None',cmap='bwr')
plt.title('Network-to-Network ITE (using RSA) (Thresholded)\nTopDown Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
plt.tight_layout()
plt.savefig(outputdir + 'SFig_CompModel_RSA_topdownOnly.pdf')
##########
# Plot figures for topdown and bottomup task
# (Unthresholded plot)
plt.figure(figsize=(12,10))
((12,10))
plt.subplot(121)
norm = MidpointNormalize(midpoint=0)
plt.imshow(np.mean(ite_topdownbottomup,axis=2),origin='lower',interpolation='None',norm=norm,cmap='bwr')
plt.title('Network-to-Network ITE (using RSA) (Unthresholded)\nTopDownBottomUp Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
# (Thresholded plot)
plt.subplot(122)
threshold_acc = np.multiply(binary_mat_topdownbottomup,np.mean(ite_topdownbottomup,axis=2))
norm = MidpointNormalize(midpoint=0)
plt.imshow(threshold_acc,origin='lower',interpolation='None',norm=norm,cmap='bwr')
plt.title('Network-to-Network ITE (using RSA)(Thresholded)\nTopDownBottomUp Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
plt.tight_layout()
plt.savefig(outputdir + 'SFig_CompModel_RSA_topdownbottomup.pdf')
In [386]:
# Empty variables for topdown task analysis
svm_topdown = np.zeros((ncommunities,ncommunities,len(nsubjs)))
# Empty variables for topdown and bottomup task analysis
svm_topdownbottomup = np.zeros((ncommunities,ncommunities,len(nsubjs)))
##########
# Run predicted-to-actual similarity for every network-to-network configuration (using RSA approach)
for i in range(ncommunities):
for j in range(ncommunities):
if i==j: continue
fromnet = i
net = j
nblocks = nblocks
## First run on topdown only task conditions
inputs = []
for subj in nsubjs: inputs.append((subj,net,fromnet,topdown_only,nblocks,Ci,nodespercommunity,datadir))
# Run multiprocessing across subjects
pool = mp.Pool(processes=nproc)
results_topdown = pool.map_async(analysis.predictedToActualSVM, inputs).get()
pool.close()
pool.join()
## Second run on topdown and bottomup task conditions
inputs = []
for subj in nsubjs: inputs.append((subj,net,fromnet,topdown_and_bottomup,nblocks,Ci,nodespercommunity,datadir))
# Run multiprocessing
pool = mp.Pool(processes=nproc)
results_topdownbottomup = pool.map_async(analysis.predictedToActualSVM, inputs).get()
pool.close()
pool.join()
## Get results and store in network X network X subjects matrix
scount = 0
for subj in nsubjs:
# Obtain topdown task results
svm = results_topdown[scount]
svm_topdown[i,j,scount] = svm
# Obtain topdown and bottom up task results
svm = results_topdownbottomup[scount]
svm_topdownbottomup[i,j,scount] = svm
scount += 1
In [394]:
# Instantiate empty result matrices
tmat_topdown_svm = np.zeros((ncommunities,ncommunities))
pmat_topdown_svm = np.ones((ncommunities,ncommunities))
tmat_topdownbottomup_svm = np.zeros((ncommunities,ncommunities))
pmat_topdownbottomup_svm = np.ones((ncommunities,ncommunities))
# Perform accuracy decoding t-test against chance, which is 25% for a 4-way classification
chance = .25
for i in range(ncommunities):
for j in range(ncommunities):
if i==j: continue
# Run statistical test for first task (topdown only stim)
t, p = stats.ttest_1samp(svm_topdown[i,j,:],chance)
tmat_topdown_svm[i,j] = t
# Make p-value one-sided (for one-sided t-test)
if t > 0:
p = p/2.0
else:
p = 1-p/2.0
pmat_topdown_svm[i,j] = p
# Run statistical test for second task (topdown and bottomup stim)
t, p = stats.ttest_1samp(svm_topdownbottomup[i,j,:],chance)
tmat_topdownbottomup_svm[i,j] = t
# Make p-value one-sided (for one-sided t-test)
if t > 0:
p = p/2.0
else:
p = 1-p/2.0
pmat_topdownbottomup_svm[i,j] = p
## TopDown Tasks
# Run FDR correction on p-values (Don't get diagonal values)
qmat_topdown_svm = np.ones((ncommunities,ncommunities))
triu_ind = np.triu_indices(ncommunities,k=1)
tril_ind = np.tril_indices(ncommunities,k=-1)
all_ps = np.hstack((pmat_topdown_svm[triu_ind],pmat_topdown_svm[tril_ind]))
h, all_qs = mc.fdrcorrection0(all_ps)
# the first half of all qs belong to triu, second half belongs to tril
qmat_topdown_svm[triu_ind] = all_qs[:len(triu_ind[0])]
qmat_topdown_svm[tril_ind] = all_qs[len(tril_ind[0]):]
binary_mat_topdown_svm = qmat_topdown_svm < .05
## TopDown and BottomUp Tasks
# Run FDR correction on p-values (Don't get diagonal values)
qmat_topdownbottomup_svm = np.ones((ncommunities,ncommunities))
triu_ind = np.triu_indices(ncommunities,k=1)
tril_ind = np.tril_indices(ncommunities,k=-1)
all_ps = np.hstack((pmat_topdownbottomup_svm[triu_ind],pmat_topdownbottomup_svm[tril_ind]))
h, all_qs = mc.fdrcorrection0(all_ps)
# the first half of all qs belong to triu, second half belongs to tril
qmat_topdownbottomup_svm[triu_ind] = all_qs[:len(triu_ind[0])]
qmat_topdownbottomup_svm[tril_ind] = all_qs[len(tril_ind[0]):]
binary_mat_topdownbottomup_svm = qmat_topdownbottomup_svm < .05
####
## Plot figures for Top Down Task
# Unthresholded map
plt.figure(figsize=(12,10))
plt.subplot(121)
mat = np.mean(svm_topdown,axis=2)
norm = MidpointNormalize(midpoint=0)
plt.imshow(mat,norm=norm,origin='lower',interpolation='None',cmap='bwr')
plt.title('Network-to-Network ITE (using SVMs) (Unthresholded)\nTopDown Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=0.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
plt.tight_layout()
plt.savefig(outputdir + 'SFig_CompModel_SVM_topdownOnly_Unthresholded.pdf')
# Thresholded map
plt.subplot(122)
mat = np.mean(svm_topdown,axis=2)
mat = np.multiply(binary_mat_topdown_svm,mat)
norm = MidpointNormalize(midpoint=0)
plt.imshow(mat,norm=norm,origin='lower',interpolation='None',cmap='bwr')
plt.title('Network-to-Network ITE (using SVMs) (Thresholded)\nTopDown Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=0.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
plt.tight_layout()
plt.savefig(outputdir + 'SFig_CompModel_SVM_topdownOnly.pdf')
####
## Plot figures for Top Down AND Bottom Up Task
# Unthresholded map
plt.figure(figsize=(12,10))
plt.subplot(121)
mat = np.mean(svm_topdownbottomup,axis=2)
norm = MidpointNormalize(midpoint=0)
plt.imshow(mat,origin='lower',interpolation='None',norm=norm,cmap='bwr')
plt.title('Network-to-Network ITE (using SVMs) (Unthresholded)\nTopDownBottomUp Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=0.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
# Thresholded map
plt.subplot(122)
mat = np.mean(svm_topdownbottomup,axis=2)
mat = np.multiply(binary_mat_topdownbottomup_svm,mat)
norm = MidpointNormalize(midpoint=0)
plt.imshow(mat,origin='lower',interpolation='None',norm=norm,cmap='bwr')
plt.title('Network-to-Network ITE (using SVMs) (Thresholded)\nTopDownBottomUp Tasks',fontsize=16, y=1.02)
plt.colorbar(fraction=0.046)
plt.yticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.xticks(range(ncommunities), ['FlexHub', 'Net1', 'Net2', 'Net3', 'Net4'])
plt.ylabel('Network ActFlow FROM',fontsize=15)
plt.xlabel('Network ActFlow TO',fontsize=15)
plt.tight_layout()
plt.savefig(outputdir + 'SFig_CompModel_SVM_topdownbottomup.pdf')