spm_dcm_review.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. function spm_dcm_review(DCM,action)
  2. % Review an estimated DCM
  3. % FORMAT spm_dcm_review(DCM,action)
  4. %
  5. % DCM - DCM structure or its filename
  6. % action - one of:
  7. % 'fixed connections'
  8. % [' effects of ' DCM.U.name{i}];
  9. % 'contrast of connections'
  10. % 'location of regions'
  11. % 'inputs'
  12. % 'outputs'
  13. % 'kernels'
  14. % 'estimates of states'
  15. % 'estimates of parameters'
  16. % 'estimates of precisions'
  17. % [' hidden states: ' DCM.Y.name{i}]
  18. %__________________________________________________________________________
  19. % Copyright (C) 2008-2018 Wellcome Trust Centre for Neuroimaging
  20. % Karl Friston
  21. % $Id: spm_dcm_review.m 7296 2018-04-18 10:36:49Z guillaume $
  22. %-Get DCM structure
  23. %==========================================================================
  24. if ~nargin
  25. [DCM, sts] = spm_select(1,'^DCM.*\.mat$','select DCM_???.mat');
  26. if ~sts, return; end
  27. end
  28. if ~isstruct(DCM)
  29. load(DCM);
  30. end
  31. %-Call spm_dcm_fmri_csd_results for DCM of CSD
  32. %--------------------------------------------------------------------------
  33. try
  34. analysis = DCM.options.analysis;
  35. catch
  36. analysis = '';
  37. end
  38. if strcmp(analysis,'CSD')
  39. spm_dcm_fmri_csd_results(DCM);
  40. return
  41. end
  42. %-Get model specification structure (see spm_nlsi)
  43. %--------------------------------------------------------------------------
  44. try
  45. m = DCM.M.m; % number of inputs
  46. l = DCM.M.l; % number of regions (responses)
  47. U = 0.9; % p-value threshold for display
  48. catch
  49. m = size(DCM.U.u,2);
  50. l = DCM.n;
  51. end
  52. % Fontsize
  53. %--------------------------------------------------------------------------
  54. if l > 0, fs = 12; end
  55. if l > 8, fs = 10; end
  56. if l > 16, fs = 8; end
  57. % experimental input specific reports
  58. %--------------------------------------------------------------------------
  59. for i = 1:m
  60. inputstr{i} = [' effects of ' DCM.U.name{i}];
  61. end
  62. % connectivity and kernels
  63. %--------------------------------------------------------------------------
  64. str = [inputstr,{'fixed connections'}];
  65. if isfield(DCM,'averaged')
  66. str = {str{:},'contrast of connections'};
  67. else
  68. str = {str{:} ,...
  69. 'contrast of connections',...
  70. 'location of regions',...
  71. 'inputs',...
  72. 'outputs',...
  73. 'kernels'};
  74. if isfield(DCM,'qP')
  75. str = {str{:} ,...
  76. 'estimates of states',...
  77. 'estimates of parameters',...
  78. 'estimates of precisions'};
  79. % region specific reports
  80. %------------------------------------------------------------------
  81. for i = 1:l
  82. hiddenstr{i} = [' hidden states: ' DCM.Y.name{i}];
  83. end
  84. str = [str,hiddenstr];
  85. else
  86. hiddenstr = {};
  87. end
  88. end
  89. if ~isfield(DCM,'M')
  90. str = {'location of regions','inputs','outputs'};
  91. end
  92. str = [str,{'quit'}];
  93. %-Get action
  94. %==========================================================================
  95. try
  96. action;
  97. catch
  98. %-Get action
  99. %----------------------------------------------------------------------
  100. action = str{spm_input('review',1,'m',str)};
  101. end
  102. %-Exponentiate coupling parameters if a two-state model
  103. %--------------------------------------------------------------------------
  104. try
  105. if DCM.options.two_state
  106. Ep.A = exp(DCM.Ep.A);
  107. Ep.B = full(exp(DCM.Ep.B));
  108. Ep.D = full(exp(DCM.Ep.D));
  109. Ep.C = DCM.Ep.C;
  110. disp('NB: The (A,B,D) parameters are scale parameters')
  111. else
  112. Ep.A = DCM.Ep.A;
  113. Ep.B = full(DCM.Ep.B);
  114. Ep.D = full(DCM.Ep.D);
  115. Ep.C = DCM.Ep.C;
  116. end
  117. end
  118. %-Set up Graphics window
  119. %--------------------------------------------------------------------------
  120. Fgraph = spm_figure('GetWin','Graphics');
  121. spm_figure('Clear',Fgraph);
  122. switch action
  123. %======================================================================
  124. % Inputs
  125. %======================================================================
  126. case inputstr
  127. %-input effects
  128. %------------------------------------------------------------------
  129. subplot(2,1,1)
  130. i = find(strcmp(action,str));
  131. b(:,:,1) = DCM.Pp.B(:,:,i);
  132. b(:,:,2) = Ep.B(:,:,i);
  133. c(:,1) = DCM.Pp.C(:,i);
  134. c(:,2) = Ep.C(:,i);
  135. spm_dcm_display(DCM.xY,b,c)
  136. title(sprintf('%s P(coupling > %0.2f)',action,DCM.T),'FontSize',16)
  137. %-direct effects - connections
  138. %------------------------------------------------------------------
  139. subplot(4,2,5)
  140. bar(c(:,2))
  141. title('C - direct effects (Hz)','FontSize',14)
  142. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  143. axis square
  144. %-direct effects - probabilities
  145. %------------------------------------------------------------------
  146. subplot(4,2,6)
  147. P = c(:,1);
  148. bar(P), hold on, plot([0 (length(P) + 1)],[U U],'-.r'), hold off
  149. title('C - probability','FontSize',14)
  150. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  151. ylabel(sprintf('P(C > %0.2f)',DCM.T))
  152. axis square
  153. %-modulatory effects - connections
  154. %------------------------------------------------------------------
  155. subplot(4,2,7)
  156. bar(b(:,:,2))
  157. title('B - modulatory effects {Hz}','FontSize',14)
  158. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  159. xlabel('target region')
  160. ylabel('strength (Hz)')
  161. %-modulatory effects - probabilities
  162. %------------------------------------------------------------------
  163. subplot(4,2,8)
  164. P = b(:,:,1);
  165. bar(P), hold on, plot([0 (length(P) + 1)],[U U],'-.r'), hold off
  166. title('B - probability','FontSize',14)
  167. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  168. xlabel('target region')
  169. ylabel(sprintf('P(B > %0.2f)',DCM.T))
  170. legend(DCM.Y.name)
  171. %======================================================================
  172. % Fixed connections
  173. %======================================================================
  174. case {'fixed connections'}
  175. % Intrinsic effects
  176. %------------------------------------------------------------------
  177. subplot(2,1,1)
  178. a(:,:,1) = DCM.Pp.A;
  179. a(:,:,2) = Ep.A;
  180. spm_dcm_display(DCM.xY,a)
  181. title(sprintf('%s P(coupling > %0.2f)','fixed',DCM.T),'FontSize',16)
  182. % intrinsic interactions
  183. %------------------------------------------------------------------
  184. subplot(2,2,3)
  185. bar(a(:,:,2))
  186. title('A - fixed effects','FontSize',16)
  187. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  188. xlabel('target region')
  189. ylabel('strength (Hz)')
  190. legend(DCM.Y.name)
  191. % intrinsic interactions - probabilities
  192. %------------------------------------------------------------------
  193. subplot(2,2,4)
  194. P = a(:,:,1);
  195. bar(P), hold on, plot([0 (length(P) + 1)],[U U],'-.r'), hold off
  196. title('A - probability','FontSize',16)
  197. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  198. xlabel('target region')
  199. ylabel(sprintf('P(A > %0.2f)',DCM.T))
  200. %======================================================================
  201. % Contrast
  202. %======================================================================
  203. case {'contrast of connections'}
  204. %-get contrast
  205. %------------------------------------------------------------------
  206. T = spm_input('Threshold (Hz)',1,'r',0);
  207. D = spm_input('contrast for',2,'b',{'A','B','C'});
  208. C = spm_dcm_contrasts(DCM,D);
  209. %-posterior density and inference
  210. %------------------------------------------------------------------
  211. c = C'*spm_vec(DCM.Ep);
  212. v = C'*DCM.Cp*C;
  213. x = c + [-512:512]*sqrt(v)*6/512;
  214. p = full(1/sqrt(2*pi*v)*exp(-[x - c].^2/(2*v)));
  215. sw = warning('off','SPM:negativeVariance');
  216. PP = 1 - spm_Ncdf(T,c,v);
  217. warning(sw);
  218. figure(Fgraph)
  219. subplot(2,1,1)
  220. plot(x,p,[1 1]*T,[0 max(p)],'-.');
  221. str = sprintf('%s P(contrast > %0.2f) = %.1f%s','Posterior density',T,PP*100,'%');
  222. title(str,'FontSize',16)
  223. xlabel('contrast of parameter estimates')
  224. ylabel('probability density')
  225. i = find(x >= T);
  226. hold on
  227. fill([x(i) fliplr(x(i))],[i*0 fliplr(p(i))],[1 1 1]*.8)
  228. axis square, grid on
  229. hold off
  230. %-contrast
  231. %------------------------------------------------------------------
  232. C = spm_unvec(C,DCM.Ep);
  233. subplot(4,2,5)
  234. imagesc(C.A)
  235. title('contrast {A}','FontSize',12)
  236. set(gca,'YTick',[1:l],'YTickLabel',DCM.Y.name)
  237. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  238. axis image
  239. subplot(4,2,6)
  240. imagesc(C.C)
  241. title('contrast {C}','FontSize',12)
  242. set(gca,'XTick',[1:m],'XTickLabel',DCM.U.name)
  243. set(gca,'YTick',[1:l],'YTickLabel',DCM.Y.name)
  244. axis image
  245. for i = 1:m
  246. subplot(4,m,i + 3*m)
  247. imagesc(C.B(:,:,i))
  248. title(['contrast {B}-' DCM.U.name{i}],'FontSize',12)
  249. set(gca,'XTick',[1:l],'XTickLabel',DCM.Y.name)
  250. set(gca,'YTick',[1:l],'YTickLabel',DCM.Y.name)
  251. axis image
  252. end
  253. %======================================================================
  254. % Location of regions
  255. %======================================================================
  256. case {'location of regions'}
  257. % transverse
  258. %------------------------------------------------------------------
  259. subplot(2,1,1)
  260. spm_dcm_graph(DCM.xY);
  261. title('Regional locations','FontSize',16)
  262. % table
  263. %------------------------------------------------------------------
  264. subplot(2,1,2)
  265. y = 0;
  266. line([0 4],[y y])
  267. y = y - 1;
  268. text(0.0,y,'Name', 'FontSize',14)
  269. text(1.2,y,'Voxels', 'FontSize',14)
  270. text(2.0,y,'Location (mm)','FontSize',14)
  271. y = y - 1;
  272. line([0 4],[y y],'LineWidth',4)
  273. y = y - 1;
  274. for i = 1:length(DCM.xY)
  275. name = DCM.xY(i).name;
  276. N = size(DCM.xY(i).XYZmm, 2);
  277. L = DCM.xY(i).xyz;
  278. r = DCM.xY(i).spec;
  279. text(0.0,y,name, 'FontWeight','bold', 'FontSize',fs)
  280. text(1.5,y,sprintf('%0.0f',N), 'FontSize',fs)
  281. text(2.0,y,sprintf('%-4.0f %-4.0f %-4.0f',L),'FontSize',fs)
  282. y = y - 1;
  283. end
  284. line([0 4],[y y])
  285. axis off square
  286. %======================================================================
  287. % Inputs
  288. %======================================================================
  289. case {'inputs'}
  290. % priors
  291. %------------------------------------------------------------------
  292. x = (1:length(DCM.U.u))*DCM.U.dt;
  293. t = (1:length(DCM.Y.y))*DCM.Y.dt;
  294. for i = 1:m
  295. subplot(m,1,i)
  296. plot(x,full(DCM.U.u(:,i)))
  297. % posteriors (if stochastic DCM)
  298. %--------------------------------------------------------------
  299. try
  300. hold on
  301. plot(t,DCM.qU.v{2}(i,:),':')
  302. end
  303. hold off
  304. title(['Input - ' DCM.U.name{i}],'FontSize',16)
  305. ylabel('event density {Hz}')
  306. axis tight
  307. lm = get(gca,'ylim'); set(gca,'ylim',lm + [-1 1]*diff(lm)/16);
  308. end
  309. xlabel('time {seconds}')
  310. if DCM.options.stochastic && isfield(DCM,'M')
  311. legend({'prior','posterior'})
  312. end
  313. %======================================================================
  314. % Outputs
  315. %======================================================================
  316. case {'outputs'}
  317. % graph
  318. %------------------------------------------------------------------
  319. x = [1:DCM.v]*DCM.Y.dt;
  320. k = min(l,8);
  321. for i = 1:k
  322. subplot(k,1,i);
  323. if isfield(DCM,'y')
  324. plot(x,DCM.y(:,i),x,DCM.y(:,i) + DCM.R(:,i),':');
  325. title([DCM.Y.name{i} ': responses and predictions' ],'FontSize',16);
  326. xlabel('time {seconds}');
  327. legend('predicted', 'observed');
  328. else
  329. plot(x,DCM.Y.y(:,i));
  330. title([DCM.Y.name{i} ': responses' ],'FontSize',16);
  331. xlabel('time {seconds}');
  332. legend('observed');
  333. end
  334. end
  335. %======================================================================
  336. % Kernels
  337. %======================================================================
  338. case {'kernels'}
  339. % input effects
  340. %------------------------------------------------------------------
  341. try
  342. tn = (1:DCM.M.N)*DCM.M.dt;
  343. th = (1:DCM.M.N)*DCM.M.dt;
  344. catch
  345. tn = (1:64)*8/1000;
  346. th = (1:64)*1/2;
  347. end
  348. for i = 1:m
  349. % input effects - neuronal
  350. %--------------------------------------------------------------
  351. y = DCM.K1(:,:,i);
  352. subplot(m,2,2*(i - 1) + 1)
  353. plot(tn,y)
  354. set(gca,'XLim',[0 min(max(tn),8)])
  355. axis square
  356. title(['neuronal responses to ' DCM.U.name{i}],'FontSize',12)
  357. xlabel('time {seconds}')
  358. for j = 1:l
  359. text(tn(j),y(j,j),DCM.Y.name{j},...
  360. 'FontWeight','bold','FontSize',fs,...
  361. 'HorizontalAlignment','Center')
  362. end
  363. % input effects - haemodynamic
  364. %--------------------------------------------------------------
  365. k = DCM.H1(:,:,i);
  366. subplot(m,2,2*(i - 1) + 2)
  367. plot(th,k)
  368. set(gca,'XLim',[0 min(max(th),24)])
  369. axis square
  370. title('hemodynamic responses','FontSize',12)
  371. xlabel('time {seconds}')
  372. for j = 1:l
  373. text(th(j),k(j,j),DCM.Y.name{j},...
  374. 'FontWeight','bold','FontSize',fs,...
  375. 'HorizontalAlignment','Center')
  376. end
  377. end
  378. %======================================================================
  379. % DEM estimates (using standard format)
  380. %======================================================================
  381. case {'estimates of states'}
  382. spm_DEM_qU(DCM.qU)
  383. % get (excitatory) neuronal states
  384. %------------------------------------------------------------------
  385. x = DCM.M(1).x;
  386. x(:,1) = 1;
  387. i = find(x(:));
  388. subplot(2,2,4)
  389. plot(1:DCM.v,full(DCM.qU.x{1}(i,:)));
  390. title('(excitatory) neuronal states','FontSize',16)
  391. ylabel('time','FontSize',12)
  392. spm_axis tight square
  393. case {'estimates of parameters'}
  394. spm_DEM_qP(DCM.qP)
  395. case {'estimates of precisions'}
  396. spm_DEM_qH(DCM.qH)
  397. case hiddenstr
  398. % get region
  399. %------------------------------------------------------------------
  400. i = find(strcmp(action,str)) - find(strcmp('estimates of precisions',str));
  401. t = [1:length(DCM.Y.y)]*DCM.Y.dt;
  402. % hidden states - causes
  403. %------------------------------------------------------------------
  404. subplot(4,1,1)
  405. j = find(DCM.c(i,:));
  406. if isempty(j)
  407. x = t*0;
  408. else
  409. x = DCM.qU.v{2}(j,:);
  410. end
  411. plot(t,x)
  412. title(['inputs or causes - ' DCM.Y.name{i}],'FontSize',16)
  413. % hidden states - neuronal
  414. %------------------------------------------------------------------
  415. subplot(4,1,2)
  416. j = DCM.M.x;
  417. if DCM.options.two_state
  418. j(i,[1 2 6]) = 1;
  419. else
  420. j(i,[1 2]) = 1;
  421. end
  422. j = find(j(:));
  423. x = full(DCM.qU.x{1}(j,:));
  424. plot(t,x,':'), hold on
  425. plot(t,x(1,:)), hold off
  426. title('hidden states - neuronal', 'FontSize',16)
  427. if DCM.options.two_state
  428. legend({'excitatory','signal','inhibitory'})
  429. else
  430. legend({'excitatory','signal'})
  431. end
  432. % hidden states - hemodynamic
  433. %------------------------------------------------------------------
  434. subplot(4,1,3)
  435. j = DCM.M.x;
  436. j(i,[3 4 5]) = 1;
  437. j = find(j(:));
  438. x = full(DCM.qU.x{1}(j,:));
  439. plot(t,exp(x))
  440. title('hidden states - hemodynamic', 'FontSize',16)
  441. legend({'flow','volume','dHb'})
  442. % response
  443. %------------------------------------------------------------------
  444. subplot(4,1,4)
  445. y = full(DCM.qU.v{1}(i,:));
  446. x = full(DCM.qU.v{1}(i,:) + DCM.qU.z{1}(i,:));
  447. plot(t,x,t,y)
  448. title('predicted BOLD signal', 'FontSize',16)
  449. xlabel('time (seconds)')
  450. legend({'observed','predicted'})
  451. %======================================================================
  452. % Quit
  453. %======================================================================
  454. case {'quit'}
  455. return;
  456. %======================================================================
  457. % Unknown action
  458. %======================================================================
  459. otherwise
  460. disp('unknown option')
  461. end
  462. % return to menu
  463. %--------------------------------------------------------------------------
  464. if nargin < 2
  465. spm_dcm_review(DCM);
  466. end