DSE.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. """
  4. DSE decomposition and DVARS inference.
  5. REFERENCE:
  6. Afyouni, Soroosh, and Thomas E. Nichols. "Insight and Inference for DVARS."
  7. NeuroImage 172 (2018): 291-312.
  8. REQUIREMENT:
  9. os, numpy, nibabel, scipy
  10. FUNCTIONS:
  11. CleanNIFTI, DSE_Calc, DVARS_Calc
  12. Created on Mon Mar 12 11:56:21 2018
  13. @author: sorooshafyouni
  14. University of Oxford, 2018
  15. srafyouni@gmail.com
  16. """
  17. def CleanNIFTI(V,\
  18. scl = 0,\
  19. norm = 0,\
  20. demean = True,\
  21. copy = True):
  22. """
  23. CleanNIFTI(V,scl = 1,demean = True)
  24. Cleans and reshape the input images.
  25. INPUT:
  26. V: Can be (1) a string indicating the path to the
  27. nifti file (2) a numerical matrix of size IxT.
  28. Where I is number of voxels (I=Nx x Ny x Nz) and T is
  29. number of data-points.
  30. scl [optional]: Scaling factor in intensity normalisation. To down
  31. scale us fractions. [default: 0, meaning there will be
  32. no scaling]
  33. demean [optional]: if True it will demean the time series. [default: True]
  34. SA, Ox, 2019
  35. srafyouni@gmail.com
  36. """
  37. import numpy as np
  38. import nibabel as nib #pip install nibabel
  39. import os
  40. if copy:
  41. #Also V is going to be copied only if it is not str
  42. #see the else argument in the next if statement
  43. scl = np.copy(scl)
  44. norm = np.copy(norm)
  45. if isinstance(V, str):
  46. print('CleanNIFTI::: Input is a path to a nifti file')
  47. [pth, fn] = os.path.split(V)
  48. filename = os.path.expandvars(V)
  49. imobj = nib.load(filename, mmap=False)
  50. imdat = imobj.get_data().astype(float)
  51. T = imdat.shape[3]
  52. I = np.prod(imdat.shape[0:3])
  53. Y = np.reshape(imdat,(I,T))
  54. else:
  55. Y = V.copy()
  56. del V #to save some memory, ffs
  57. shapes = np.shape(Y)
  58. if len(shapes)==2:
  59. print('CleanNIFTI::: Input is a 2D matrix.')
  60. T = np.shape(Y)[1]
  61. I = np.shape(Y)[0]
  62. imobj = ''
  63. elif len(shapes)==4:
  64. print('CleanNIFTI::: Input is a 4D matrix.')
  65. I = np.prod(np.shape(Y)[:3])
  66. T = np.shape(Y)[-1]
  67. Y = np.reshape(Y,(I,T))
  68. else: raise ValueError('CleanNIFTI::: the shape of the input should be either 2D or 4D')
  69. print("CleanNIFTI::: The image has total of: " + str(I) + " voxels & " + str(T) + " time-points.")
  70. #find zeros or nans
  71. zrIdx = np.where(~Y.any(axis=1))[0];
  72. nanIdx = np.where(np.isnan(Y))[0];
  73. rmvIdx = np.concatenate((zrIdx,nanIdx));
  74. Y = np.delete(Y,rmvIdx,axis=0)
  75. I1 = Y.shape[0]
  76. print("CleanNIFTI::: After cleaning; " + str(I1) + " voxels & " + str(T) + " time-points.")
  77. #Intensity Normalisation##############################
  78. MeanImage = np.mean(Y,axis = 1)
  79. if scl!=0 and norm==0:
  80. print("CleanNIFTI::: Scaled by " + str(scl))
  81. #md = np.median(MeanImage) #median of mean image
  82. md = 1
  83. Y = Y/md * scl;
  84. elif norm!=0 and scl==0:
  85. print("CleanNIFTI::: Intensity Normalisation done by: " + str(scl))
  86. md = np.median(MeanImage) #median of mean image
  87. Y = Y/md * norm;
  88. elif norm==0 and scl==0:
  89. print('CleanNIFTI::: No normalisation/scaling has been set!')
  90. else:
  91. raise ValueError('CleanNIFTI::: norm (' + str(norm) + ') and scl (' + str(scl) + ') parameters are wrong!')
  92. #Global Signal#########################################
  93. GS = np.mean(Y,axis = 0)
  94. #Demean each time series##############################
  95. if demean:
  96. print("CleanNIFTI::: Demean along T")
  97. Y = Y-np.transpose(np.tile(MeanImage,(T,1)));
  98. # return {'Y':Y,\
  99. # 'T':T,\
  100. # 'I':I,\
  101. # 'I1':I1,\
  102. # 'removables':rmvIdx,\
  103. # 'ImageObj':imobj}
  104. return (Y,T,I,I1,rmvIdx,imobj,GS,MeanImage)
  105. ######################################################
  106. ######################################################
  107. def SaveMe2txt(Dict2Save,Where2Save):
  108. """ Save the input dictionary to a text file. SA, OX, 2019"""
  109. import numpy as np
  110. import os
  111. if not os.path.exists(Where2Save):
  112. os.makedirs(Where2Save)
  113. for varname in Dict2Save.keys():
  114. np.savetxt(Where2Save + '/DSE_' + str(varname) + '.txt',Dict2Save[varname],fmt='%10.5f')
  115. ######################################################
  116. ######################################################
  117. def SaveMe2Nifti(Dict2Save,Where2Save,imobj,rmvIdx):
  118. """ Save the input dictionary (VarImages) to a NIFTI files.
  119. SA, OX, 2019"""
  120. import numpy as np
  121. import nibabel as nib #pip install nibabel
  122. import os
  123. if not os.path.exists(Where2Save):
  124. os.makedirs(Where2Save)
  125. imghdr = imobj.header.copy()
  126. [X,Y,Z,T] = imobj.shape[0:4]
  127. I = np.prod((X,Y,Z))
  128. idx_tmp = range(I+1)[1:I+1]
  129. idx_tmp0 = np.delete(idx_tmp,rmvIdx,axis=0)
  130. for varname in Dict2Save.keys():
  131. print('SaveMe2Nifti::: writing *' + varname + '* images...')
  132. if len(np.shape(Dict2Save[varname]))==1:
  133. G = Dict2Save[varname];
  134. Y2I = np.zeros(shape=I)
  135. Y2I[idx_tmp0] = G;
  136. I3Y = np.reshape(Y2I,(X,Y,Z))
  137. elif len(np.shape(Dict2Save[varname]))==2:
  138. G = Dict2Save[varname];
  139. Y2I = np.zeros(shape=(I,np.shape(G)[1]))
  140. Y2I[idx_tmp0,0:T] = G;
  141. I3Y = np.reshape(Y2I,(X,Y,Z,np.shape(G)[1]))
  142. else: raise(ValueError ,"SaveMe2Nifti::: Something is wrong with image dimensions.")
  143. imgobj_vars = nib.nifti1.Nifti1Image(I3Y, None, header=imghdr)
  144. nib.save(imgobj_vars, Where2Save+'/DSE_'+ str(varname) +'.nii.gz')
  145. del(Y2I,I3Y,G)
  146. ##########################################################
  147. ##########################################################
  148. def DSE_Calc(Y,\
  149. NewDir2DSE = '',\
  150. scl = 0,\
  151. norm = 0,\
  152. demean = True,\
  153. DSEImage = False,\
  154. imobj = '',\
  155. verbose = False):
  156. """
  157. DSE_Calc(Y, NewDir2DSE='', scl = 0, demean = True, \
  158. DSEImage = False, verbose = False)
  159. Calculate the DSE descomposition components; fast slow and edge variabilities,
  160. in form of scalar, time series, 3D and 4D images.
  161. INPUTS:
  162. V0: Can be (1) a string indicating the path to the
  163. nifti/cifti file (2) a numerical matrix of size IxT.
  164. Where I is number of voxels (I=Nx x Ny x Nz) and T is
  165. number of data-points.
  166. 'scl': Output directory. Should only be used when the
  167. input is a nifti image and user needs to save the
  168. S, D and E (3D and 4D) images. [this is a param related to
  169. function CleanNIFTI]
  170. demean [optional]: if True it will demean the time series. [default: True]
  171. 'NewDir2DSE' Path to directory which contain the results; including tables
  172. and variance images
  173. e.g.: DSEOut=dse.DSE_Calc(V0,'NewDir2DSE'='~/Where/to/save/')
  174. 'DSEImage' If set True then the function will reconstruct 3D and 4D
  175. images and save them. NB! It requires lots of storage
  176. [defualt: Flase]
  177. 'verbose' : Set to 1 if you need the function to save ANOVA tables, plots
  178. and summary files.[default:False]
  179. Soroosh Afyouni, Ox, 2019
  180. srafyouni@gmail.com
  181. """
  182. import numpy as np
  183. import os
  184. if NewDir2DSE=='':
  185. NewDir2DSE = (os.getcwd() + '/DSE/')
  186. #READ AND CLEAN###########################################
  187. NFT = CleanNIFTI(Y,scl=scl,demean=demean,norm=norm)
  188. Y = NFT[0];
  189. T = NFT[1];
  190. #I = NFT[2];
  191. I1 = NFT[3];
  192. rmvIdx = NFT[4];
  193. imobj = NFT[5];
  194. ##########################################################
  195. bar_Y = np.sum(Y,axis=0)/I1; #global signal is here!
  196. #Dvar
  197. Dvar = Y[:,0:T-1]-Y[:,1:T] #OMG, python!
  198. bar_Dvar = np.sum(Dvar,axis=0)/I1;
  199. #print(Dvar[:5,:5])
  200. #print(I1)
  201. #Svar
  202. Svar = Y[:,0:T-1]+Y[:,1:T]
  203. bar_Svar = np.sum(Svar,axis=0)/I1;
  204. #print(Svar[:5,:5])
  205. #print(I1)
  206. #Evar
  207. Ytail = Y[:,-1];
  208. Yhead = Y[:,0];
  209. bar_Ytbar = np.sum(Ytail)/I1;
  210. bar_Y1bar = np.sum(Yhead)/I1;
  211. #SED Var Images######################################################
  212. print("DSE_Calc::: Variance 4D Images")
  213. VImg_Avar_ts = Y**2;
  214. VImg_Dvar_ts = Dvar**2/4;
  215. VImg_Svar_ts = Svar**2/4;
  216. VImg_Evar_ts = np.transpose(np.array((Yhead,Ytail))**2/2);
  217. #Averaged across time#######################################
  218. print("DSE_Calc::: Variance 3D Images")
  219. VImg_Avar = np.mean(Y**2,axis=1);
  220. VImg_Dvar = np.mean(Dvar**2,axis=1)/2;
  221. VImg_Svar = np.mean(Svar**2,axis=1)/2;
  222. VImg_Evar = np.mean(np.array((Yhead**2,Ytail**2)),axis=0); # <<<< should be checked
  223. if imobj != '' and DSEImage:
  224. print('DSE_Calc::: Writing the DSE images...')
  225. vimg = {'Avar_Img3': VImg_Avar,\
  226. 'Dvar_Img3': VImg_Dvar/VImg_Avar*100,\
  227. 'Svar_Img3': VImg_Svar/VImg_Avar*100,\
  228. 'Evar_Img3': VImg_Evar/VImg_Avar*100,\
  229. 'Avar_Img4': VImg_Avar_ts,\
  230. 'Dvar_Img4': VImg_Dvar_ts/np.transpose(np.tile(VImg_Avar,(T-1,1))*100),\
  231. 'Svar_Img4': VImg_Svar_ts/np.transpose(np.tile(VImg_Avar,(T-1,1))*100),\
  232. 'Evar_Img4': VImg_Evar_ts/np.transpose(np.tile(VImg_Avar,(2,1))*100)};
  233. SaveMe2Nifti(vimg,NewDir2DSE+"/VarImg",imobj,rmvIdx)
  234. else:
  235. vimg=''
  236. print('DSE_Calc::: The DSE image option was left False or there is no image object, if you need them trigger option DSEImage=.')
  237. #DSE Time series -- averaged across I#######################
  238. print("DSE_Calc::: DSE time series")
  239. V_Avar_ts = np.mean(VImg_Avar_ts,axis=0);
  240. V_Dvar_ts = np.mean(VImg_Dvar_ts,axis=0);
  241. V_Svar_ts = np.mean(VImg_Svar_ts,axis=0);
  242. V_Evar_ts = np.mean(VImg_Evar_ts,axis=0);
  243. ####### Whole Variances
  244. V_w_Avar = np.sum(V_Avar_ts);
  245. V_w_Dvar = np.sum(V_Dvar_ts);
  246. V_w_Svar = np.sum(V_Svar_ts);
  247. V_w_Evar = np.sum(V_Evar_ts);
  248. ###########Global
  249. V_g_Avar_ts = bar_Y**2;
  250. V_g_Dvar_ts = bar_Dvar**2/4;
  251. V_g_Svar_ts = bar_Svar**2/4;
  252. V_g_Evar_ts = bar_Y[np.array((0,T-1))]**2/2;
  253. ###########Global ts (Just for vis)
  254. #V_g_Dts=bar_Dvar/2;
  255. #V_g_Ats=bar_Y;
  256. #V_g_Sts=bar_Svar/2;
  257. V_g_Avar = np.sum(V_g_Avar_ts);
  258. V_g_Dvar = np.sum(V_g_Dvar_ts);
  259. V_g_Svar = np.sum(V_g_Svar_ts);
  260. V_g_Evar = np.sum(V_g_Evar_ts);
  261. #V.g_Avar = np.sum(B.Ybar**2);
  262. #V.g_Dvar = np.sum(B.Dbar**2)/4;
  263. #V.g_Svar = np.sum(B.Sbar**2)/4;
  264. #V.g_Evar = np.sum(B.Ybar([1,T0])**2)/2;
  265. #sys.exit("Stop HERE")
  266. #exit()
  267. #Here Here #Here Here #Here Here
  268. ###########Non-Global
  269. V_ng_Avar_ts = np.mean((Y-np.tile(bar_Y,[I1,1]))**2,axis=0);
  270. V_ng_Dvar_ts = np.mean((Dvar-np.tile(bar_Dvar,[I1,1]))**2,axis=0)/4;
  271. V_ng_Svar_ts = np.mean((Svar-np.tile(bar_Svar,[I1,1]))**2,axis=0)/4;
  272. V_ng_Evar_ts = np.mean([(Yhead-bar_Y1bar)**2,(Ytail-bar_Ytbar)**2],axis=0)/2;
  273. V_ng_Avar = np.sum(V_ng_Avar_ts);
  274. V_ng_Dvar = np.sum(V_ng_Dvar_ts);
  275. V_ng_Svar = np.sum(V_ng_Svar_ts);
  276. V_ng_Evar = np.sum(V_ng_Evar_ts);
  277. vts = {'Avar_ts':V_Avar_ts,\
  278. 'Dvar_ts':V_Dvar_ts,\
  279. 'Svar_ts':V_Svar_ts,\
  280. 'Evar_ts':V_Evar_ts};
  281. normvts = {'pDvar_ts':V_Dvar_ts/np.mean(V_Avar_ts),\
  282. 'pSvar_ts':V_Svar_ts/np.mean(V_Avar_ts),\
  283. 'pEvar_ts':V_Evar_ts/np.mean(V_Avar_ts)};
  284. vv = {'Avar' : V_w_Avar,\
  285. 'Dvar' : V_w_Dvar,\
  286. 'Svar' : V_w_Svar,\
  287. 'Evar' : V_w_Evar,\
  288. 'gAvar' : V_g_Avar ,\
  289. 'gDvar' : V_g_Dvar,\
  290. 'gSvar' : V_g_Svar,\
  291. 'gEvar' : V_g_Evar,\
  292. 'ngAvar': V_ng_Avar,\
  293. 'ngDvar': V_ng_Dvar,\
  294. 'ngSvar': V_ng_Svar,\
  295. 'ngEvar': V_ng_Evar};
  296. print("DSE_Calc::: DSE Variances:")
  297. for keys, values in vv.items():
  298. print (keys + " : " + str(values))
  299. print ("_________________________________")
  300. #V.GrandMean_Untouched = np.mean(mvY_Untouched);
  301. #V.GrandMean_NormInt = np.mean(mvY_NormInt);
  302. #V.GrandMean_Demeaned = np.mean(mvY_Demeaned);
  303. #V.GranMean_WholeBrain = np.mean(mvY_WholeImage);
  304. #V.ng_Avar = sum(mean((Y-repmat(B.Ybar,[I1,1])).^2));
  305. #V.ng_Dvar = sum(mean((D-repmat(B.Dbar,[I1,1])).^2))./4;
  306. #V.ng_Svar = sum(mean((S-repmat(B.Sbar,[I1,1])).^2))./4;
  307. #V.ng_Evar = sum(mean([(Yhead-B.Y1bar).^2,(Ytail-B.Ytbar).^2]))./2;
  308. # Sanity Chek - The moment of truth!
  309. # gvars = V.g_Dvar+V.g_Svar+V.g_Evar;
  310. # rgvars = V.rg_Dvar+V.rg_Svar+V.rg_Evar;
  311. # WholeWholeVar_Test=gvars+rgvars;
  312. # %assert(WholeWholeVar==WholeWholeVar_Test,'VarDecomp failed')
  313. # disp(['WholeVar= ' num2str(V.w_Avar) ' , sum of decomp var= ' num2str(WholeWholeVar_Test)])
  314. ########### SED ANOVA table
  315. SS = I1 * np.array((V_w_Avar,V_w_Dvar,V_w_Svar,V_w_Evar,\
  316. V_g_Avar,V_g_Dvar,V_g_Svar,V_g_Evar))
  317. MS = SS/I1/T
  318. RMS = np.sqrt(MS)
  319. Prntg = RMS**2/RMS[0]**2*100
  320. Expd = np.concatenate(\
  321. (np.array((1,(T-1)/T/2,(T-1)/T/2,1/T),dtype='float64'),\
  322. np.array((1,(T-1)/T/2,(T-1)/T/2,1/T),dtype='float64')/I1))
  323. RelVar = Prntg/100/Expd
  324. if verbose:
  325. import matplotlib.pyplot as plt
  326. VarStatDir = NewDir2DSE+'/VarTS'
  327. if not os.path.exists(VarStatDir):
  328. os.makedirs(VarStatDir)
  329. DSEVarfig = plt.figure()
  330. plt.plot(vts['Svar_ts'])
  331. plt.plot(vts['Dvar_ts'])
  332. plt.legend(['Svar_ts', 'Dvar_ts'], loc='upper left')
  333. plt.savefig(VarStatDir+"/DSvars.png")
  334. plt.close(DSEVarfig)
  335. #plt.show()
  336. SaveMe2txt({'Percents':Prntg,\
  337. 'Relatives':RelVar,\
  338. 'SumOfSquares':SS,\
  339. 'RootMeanOfSquares':MS},\
  340. VarStatDir)
  341. ##SAVE Variance Time Series
  342. SaveMe2txt(vts,VarStatDir)
  343. ##
  344. #Var_Tab = [V_w_Avar,V_w_Dvar,V_w_Svar,V_w_Evar;...
  345. # V_g_Avar,V_g_Dvar,V_g_Svar,V_g_Evar;...
  346. # V_ng_Avar,V_ng_Dvar,V_ng_Svar,V_ng_Evar];
  347. ######################################################
  348. DSEOut = {'VarScalar':vv\
  349. ,'VarTimeSeries':vts\
  350. ,'NormVarTimeSeries':normvts\
  351. ,'percent':Prntg\
  352. ,'MeanSquared':MS\
  353. ,'RMS':RMS\
  354. ,'Relative':RelVar\
  355. ,'Expected':Expd\
  356. ,'VarImages':vimg}
  357. return DSEOut
  358. ####################################################################################################################
  359. ####################################################################################################################
  360. def DVARS_Calc(Y,\
  361. dd=1, \
  362. WhichExpVal = 'median',
  363. WhichVar = 'hIQRd',\
  364. scl = 0,\
  365. norm = 0,\
  366. demean = True,\
  367. DeltapDvarThr = 5,\
  368. copy = True):
  369. """
  370. DVARS_Calc(Y, dd=1, WhichExpVal = 'median', WhichVar = 'hIQRd',\
  371. scl = 0,demean = True,DeltapDvarThr = 5)
  372. Find p-values, and performs statistical and practical significance testing
  373. to identify corrupted volumes in a scan. Also calculates standardised DVARS
  374. INPUTS:
  375. V0: Can be (1) a string indicating the path to the
  376. nifti/cifti file (2) a numerical matrix of size IxT.
  377. Where I is number of voxels (I=Nx x Ny x Nz) and T is
  378. number of data-points.
  379. 'dd': Power of transformation [default:1]
  380. 'WhichExpVal': Method for robust estimate of expected value. The value
  381. should be a digit corresponding to the order of
  382. following methods [default:'median']:
  383. 'sig2bar','sig2median','median','sigbar2','xbar'.
  384. For example: WhichExpVal='median' means the method
  385. to estimate robust expected value is empirical median.
  386. e.g. DVARS=dse.DVARS_Calc(V0,WhichExpVal='median')
  387. 'WhichVar': Method for robust estimate of variance. It can be either
  388. 'IQR' for full IQR or 'hIQR' for half-IQR.
  389. [default:'hIQR']
  390. e.g. DVARS=dse.DVARS_Calc(V0,WhichVar='hIQR')
  391. 'DeltapDvarThr': Threshold (in percentage) for DeltapDvar variable which
  392. result in practical significance. [default: 5]
  393. 'scl': Output directory. Should only be used when the
  394. input is a nifti image and user needs to save the
  395. S, D and E (3D and 4D) images. [this is a param related to
  396. function CleanNIFTI]
  397. 'demean': if True it will demean the time series. [default: True]
  398. 'verbose' : Set to 1 if you need the function to save ANOVA tables, plots
  399. and summary files.[default:False]
  400. Soroosh Afyouni, Ox, 2019
  401. srafyouni@gmail.com
  402. """
  403. import scipy.stats as st
  404. import numpy as np
  405. #defaults:
  406. #WhichExpVal = 'median';
  407. #WhichVar = 'hIQRd';
  408. #dd = 1;
  409. ##FUNCS####################################################
  410. def IQRsd(x): return ((np.percentile(x,75,axis=0) - np.percentile(x,25,axis=0))/1.349);
  411. def H_IQRsd(x): return ((np.percentile(x,50,axis=0) - np.percentile(x,25,axis=0))/1.349*2);
  412. #--
  413. #if tsflag
  414. # def Zstat(x,m,s): abs((x-m)/s);
  415. #else
  416. def ZStat(x,m,s): return((x-m)/s)
  417. def Zp(x,m,s): return(1-st.norm.cdf(ZStat(x,m,s)))
  418. #--
  419. def X2Stat(x,m,s): return(2*m/s**2*x)
  420. def X2df(m,s): return(2*m**2/s**2)
  421. def X2p0(x,m,s): return((X2Stat(x,m,s)-X2df(m,s))/np.sqrt(2*X2df(m,s)));
  422. def X2p(x,m,s): return(1-st.chi2.cdf(X2Stat(x,m,s),X2df(m,s)));
  423. #READ AND CLEAN###########################################
  424. NFT = CleanNIFTI(Y,scl=scl,norm=norm,demean=demean)
  425. Y = NFT[0];
  426. T = NFT[1];
  427. #I = NFT[2];
  428. I1 = NFT[3];
  429. ##########################################################
  430. #Dvar
  431. Dvar = Y[:,0:T-1]-Y[:,1:T] #OMG, python!
  432. DVARS = np.sqrt(np.sum(Dvar**2,axis=0)/I1)
  433. DVARS2 = np.mean(Dvar**2,axis=0);
  434. Rob_S_D = IQRsd(Dvar);
  435. Z = DVARS2**dd;
  436. M_Z = np.median(Z,axis=0);
  437. print('DVARS_Calc::: Estimating the moments...')
  438. DVMean = {'sig2bar':np.mean(Rob_S_D**2,axis=0),\
  439. 'sig2median':np.median(Rob_S_D**2,axis=0),\
  440. 'median':np.median(DVARS2,axis=0),\
  441. 'sigbar2':np.mean(Rob_S_D,axis=0)**2,\
  442. 'xbar':np.mean(DVARS2,axis=0)};
  443. DVVar = {'S2':np.var(DVARS2,axis=0),\
  444. 'IQRd':(1/dd*M_Z**(1/dd-1)*IQRsd(Z))**2,\
  445. 'hIQRd':(1/dd*M_Z**(1/dd-1)*H_IQRsd(Z))**2};
  446. print('DVARS_Calc::: Estimating Delta % Vars')
  447. DeltapDvar = (DVARS2-np.median(DVARS2,axis=0))/(4*np.mean(Y**2))*100; #This is one other Standardised DVARS!
  448. print('DVARS_Calc::: Doing the inference...')
  449. M_DV2 = DVMean[WhichExpVal];
  450. S_DV2 = np.sqrt(DVVar[WhichVar]);
  451. Pval = X2p(DVARS2,M_DV2,S_DV2);
  452. Zval = ZStat(DVARS2,M_DV2,S_DV2);
  453. c = X2Stat(DVARS2,M_DV2,S_DV2);
  454. nu = X2df(M_DV2,S_DV2); #Spatial EDF
  455. NDVARS_X2 = -st.norm.ppf(Pval) # This should be checked!!
  456. NDVARS_X20 = X2p0(DVARS2,M_DV2,S_DV2);
  457. #only substitute the infs, the rest is better done in matlab.
  458. WhereIsInf = np.where(np.isinf(NDVARS_X2))
  459. NDVARS_X2[WhereIsInf] = NDVARS_X20[WhereIsInf] #This is one version of the standardised DVARS!
  460. Alp_level = (0.05/(T-1));
  461. Hval_stat = np.where(Pval<Alp_level)
  462. print('DVARS_Calc::: ' + str(np.size(Hval_stat)) + ' of volumes are statistically significant.')
  463. Hval_practical = np.where(DeltapDvar>DeltapDvarThr)
  464. print('DVARS_Calc::: ' + str(np.size(Hval_practical)) + ' of volumes are practically significant.')
  465. Hval = np.intersect1d(Hval_stat,Hval_practical);
  466. print('DVARS_Calc::: ' + str(np.size(Hval)) + ' of volumes are significant.')
  467. #DVARSfig = plt.figure()
  468. #plt.plot(DeltapDvar)
  469. #plt.close(DVARSfig)
  470. #plt.show()
  471. DVARSOut = {'DVARS': {'DVARS': DVARS, 'DeltapDvar': DeltapDvar,'NDVARS_X2': NDVARS_X2},\
  472. 'Inference': {'Pval': Pval,'H': Hval, 'HStat': Hval_stat, 'HPrac': Hval_practical},\
  473. 'Stats': {'Mean': M_DV2,'SD':S_DV2,'DF':nu}}
  474. return DVARSOut
  475. ##########################################################
  476. ##########################################################
  477. #def main():
  478. # ################################Read and Clean
  479. # V = '/Users/sorooshafyouni/Desktop/HCP\
  480. # /135932/135932_RS/MNINonLinear/Results/rfMRI_REST1_LR/\
  481. # rfMRI_REST1_LR_hp2000_clean.nii.gz'
  482. #
  483. # ###################################################################
  484. # NewDir2DSE = pth + '/DSE/'
  485. #
  486. # #Do the DSE Analysis and Save the file and everything
  487. # DSE(Y,I,T,I1,imobj,pth,fn,rmvIdx,Dvar,NewDir2DSE)
  488. #
  489. #
  490. #if __name__ == "__main__":
  491. # main()