OSCR

Distilling noise characteristics and prior expectations in multisensory causal inference.

Code ↔ Paper

18 matches between paragraphs of the paper and lines of its authors' code, computed by the harvester (lexical-v1). Click a colored paragraph or line to see its counterpart.

The 18 matches
  1. [1] § Methods › Model fitting ↔ utils/cmaes.m, lines 1–60 · score 0.74 · CMA ES, Covariance Matrix, Evolution Strategy, Adaptation, minimization
  2. [2] § Methods › Model fitting ↔ utils/cmaes_modded.m, lines 1–60 · score 0.74 · CMA ES, Covariance Matrix, Evolution Strategy, Adaptation, minimization
  3. [3] § Methods › Models and free parameters › Parametric models. ↔ manuscript_allplots.m, lines 238–249 · score 0.70 · TwoGaussians, Const GaussianLaplace, SingleGaussian, Exp GaussianLaplace, parametric models, causal
  4. [4] § Methods › Models and free parameters › Parametric models. ↔ manuscript_allplots_old.m, lines 236–252 · score 0.70 · TwoGaussians, Const GaussianLaplace, SingleGaussian, Exp GaussianLaplace, parametric models, causal
  5. [5] § Methods › Model recovery analysis ↔ manuscript_allplots.m, lines 373–496 · score 0.68 · ground truth generative, model recovery, fitted model, Rows, matrix, NLL
  6. [6] § Results › Distilled parametric shapes for priors and noise › All-tasks fits. ↔ manuscript_allplots.m, lines 238–249 · score 0.65 · TwoGaussians, Const GaussianLaplace, SingleGaussian, Exp GaussianLaplace, Model comparison, parametric model
  7. [7] § Results › Distilled parametric shapes for priors and noise › All-tasks fits. ↔ manuscript_allplots_old.m, lines 236–252 · score 0.64 · TwoGaussians, Const GaussianLaplace, SingleGaussian, Exp GaussianLaplace, Model comparison, parametric model
  8. [8] § Methods › Models and free parameters › Parametric model names. ↔ manuscript_allplots_old.m, lines 941–1038 · score 0.64 · Gaussian Laplace prior, Exponential sensory noise, auditory stimulus
  9. [9] § Results › Distilled parametric shapes for priors and noise › Unisensory data fits. ↔ manuscript_allplots.m, lines 1206–1303 · score 0.63 · exponential sensory noise, TwoGaussians, SingleGaussian, GaussianLaplace
  10. [10] § Results › Distilled parametric shapes for priors and noise › Unisensory data fits. ↔ manuscript_allplots_old.m, lines 941–1038 · score 0.63 · exponential sensory noise, TwoGaussians, SingleGaussian, GaussianLaplace
  11. [11] § Methods › Model recovery analysis ↔ manuscript_allplots.m, lines 373–496 · score 0.62 · ground truth generative, Model recovery, AIC, BIC
  12. [12] § Results › Models ↔ analysis/nllfun_bc_parametric.m, lines 167–211 · score 0.61 · causal inference strategy, BC task, Model Selection, motor noise, posterior, Matching
  13. [13] § Methods › Models and free parameters › Parametric model names. ↔ manuscript_allplots.m, lines 1206–1303 · score 0.55 · Gaussian Laplace prior, Exponential sensory noise, stimulus
  14. [14] § Results › Distilled parametric shapes for priors and noise › All-tasks fits. ↔ manuscript_allplots_old.m, lines 607–696 · score 0.55 · lifted semiparametric fits, parametric model fit, BC, Exp, GaussianLaplace
  15. [15] § Results › Lifting the semiparametric fits to all tasks ↔ manuscript_allplots_old.m, lines 607–696 · score 0.55 · best lifted semiparametric, model fits, AIC, BIC, causal
  16. [16] § Results › Distilled parametric shapes for priors and noise › All-tasks fits. ↔ manuscript_allplots.m, lines 866–961 · score 0.54 · lifted SemiParametric fits, lifted SemiParametric model, model parameters, AIC, BIC, Exp
  17. [17] § Methods › Models and free parameters › Parametric model fits on only unisensory data. ↔ create_composite_allfits_figures.ipynb, lines 133–193 · score 0.51 · unisensory parametric, Exp GaussianLaplace, sensory noise, Const, fitted, models
  18. [18] § Results › Lifting the semiparametric fits to all tasks ↔ analysis/manuscript_bimodalavfits_visualization_resc.m, lines 176–313 · score 0.50 · stimulus location disparity, visual reliabilities, bias, ribbons, weight, stratified

Paper

Loaded from Europe PMC by your browser, not stored by OSCR: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

MATLAB · 1,561 lines · 69 KB · no license · 7 matches

  1. clear all; close all;
  2. cd('C:\Users\liu_s\Audiovisual-causal-inference')
  3. fig_maxwidth_inches = 7.5;
  4. fig_maxheight_inches = 8.75;
  5. set(0,'units','inches');
  6. Inch_SS = get(0,'screensize');
  7. set(0,'units','pixels');
  8. figsize = get(0, 'ScreenSize');
  9. Res = figsize(3)./Inch_SS(3);
  10. set(groot,'DefaultAxesFontName','Arial')
  11. %figsize_RespDistr = [0,0,figsize(4)*4/3, figsize(4)];
  12. figsize_RespDistr = [0,0,fig_maxwidth_inches, fig_maxheight_inches] .* Res;
  13. figformat = "svg";
  14. figpath = "plots\"; %"newplots\"
  15. fontsize=9; %9
  16. png_dpi = 500;
  17. plot_lapse = true;
  18. lapse_type = "Uniform";
  19. model_path = "modelfits\";
  20. data_path = "data\";
  21. analysis_path = "analysis\";
  22. addpath(analysis_path,data_path,model_path,"utils\");
  23. %% s_V, s_A generative distributions
  24. linewidth = 1;
  25. figure('Position', [0,0,figsize_RespDistr(3)./5,figsize_RespDistr(3)./8]);
  26. tiledlayout(1,1,'TileSpacing','none', 'Padding','none'); set(gca,'TickDir','out'); hold on;
  27. sV_vals = [-25:1:-20,-20:1:20,20:1:25]; p_sV_vals = [zeros(size(-25:1:-20)),repmat(1/40,1,length(-20:1:20)),zeros(size(20:1:25))];
  28. plot(sV_vals, p_sV_vals, "k-", 'LineWidth',linewidth); area(sV_vals, p_sV_vals,'FaceColor','k', 'FaceAlpha',0.2);
  29. xlim([-25,25]); ylim([0,0.03]); xticks(-20:20:20); yticks([0,1/40]); yticklabels(["0","1/40"])
  30. xlabel("{\its}_V",'FontSize',fontsize+1); ylabel("p({\its}_V)",'FontSize',fontsize+1);
  31. set(gca,'FontSize',fontsize)
  32. exportgraphics(gcf,figpath+'sV_gen'+'.pdf',"ContentType","vector");
  33. figure('Position', [0,0,figsize_RespDistr(3)./5,figsize_RespDistr(3)./8]);
  34. tiledlayout(1,1,'TileSpacing','none', 'Padding','tight'); set(gca,'TickDir','out'); hold on;
  35. sA_vals = [-15:5:15]; p_sA_vals = repmat(1/length(sA_vals), 1,length(sA_vals));
  36. h=stem(sA_vals, p_sA_vals,"k-", 'LineWidth',linewidth); set(h, 'Marker', 'none')
  37. xlim([-20,20]); ylim([0,0.16]); xticks(-15:15:15); xtickangle(0); yticks([0,1/length(sA_vals)]); yticklabels(["0","1/7"])
  38. xlabel("{\its}_A",'FontSize',fontsize); ylabel("p({\its}_A)",'FontSize',fontsize);
  39. set(gca,'FontSize',fontsize)
  40. exportgraphics(gcf,figpath+'sA_gen'+'.pdf',"ContentType","vector");
  41. %% UAV data visualized, without model prediction ribbons.
  42. prior = "NaN";
  43. noise = "NaN";
  44. aud_rescale = "NaN";
  45. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  46. exportgraphics(gcf,figpath+'UAV_dataonly'+'.png','Resolution',png_dpi);
  47. exportgraphics(gcf,figpath+'UAV_dataonly'+'.pdf',"ContentType","vector");
  48. %% UJoint parametric model response distribution visualization
  49. prior = "SingleGaussian";
  50. noise = "constant";
  51. aud_rescale = "1";
  52. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type, false, true);
  53. exportgraphics(gcf,figpath+'Const-SingleGaussian_rescaleaud1'+'.png','Resolution',png_dpi);
  54. exportgraphics(gcf,figpath+'Const-SingleGaussian_rescaleaud1'+'.pdf',"ContentType","vector");
  55. %%
  56. prior = "SingleGaussian";
  57. noise = "constant";
  58. aud_rescale = "free";
  59. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  60. exportgraphics(gcf,figpath+'Const-SingleGaussian'+'.png','Resolution',png_dpi);
  61. exportgraphics(gcf,figpath+'Const-SingleGaussian'+'.pdf',"ContentType","vector");
  62. %%
  63. prior = "GaussianLaplaceBothFixedZero";
  64. noise = "exp";
  65. aud_rescale = "free";
  66. %manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, four_by_three_figsize);
  67. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  68. exportgraphics(gcf,figpath+'Exp-GaussianLaplace'+'.png','Resolution',png_dpi);
  69. exportgraphics(gcf,figpath+'Exp-GaussianLaplace'+'.pdf',"ContentType","vector");
  70. %% Individual-level
  71. prior = "GaussianLaplaceBothFixedZero";
  72. noise = "exp";
  73. aud_rescale = "free";
  74. save_name = "Exp-GaussianLaplace";
  75. plot_individual = true;
  76. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type, plot_individual);
  77. figure(1)
  78. saveas(gca, figpath+save_name+'_Individualmean.fig')
  79. exportgraphics(gcf,figpath+save_name+'_Individualmean'+'.png','Resolution',png_dpi);
  80. exportgraphics(gcf,figpath+save_name + '_Individualmean'+'.pdf',"ContentType","vector");
  81. figure(2)
  82. saveas(gca, figpath+save_name+'_IndividualSD.fig')
  83. exportgraphics(gcf,figpath+save_name+'_IndividualSD'+'.png','Resolution',png_dpi);
  84. exportgraphics(gcf,figpath+save_name + '_IndividualSD'+'.pdf',"ContentType","vector");
  85. %% Exemplary subject
  86. subjidx=7;
  87. fitted_on_all_data = false;
  88. allindvsubjplots_to_onesubjplot(save_name, subjidx, fitted_on_all_data, 10, [0 0 figsize_RespDistr(3) figsize_RespDistr(3)*0.5], figpath)
  89. exportgraphics(gcf,figpath+'Exp-GaussianLaplace_Individual_example'+'.png','Resolution',png_dpi);
  90. exportgraphics(gcf,figpath+'Exp-GaussianLaplace_Individual_example'+'.pdf',"ContentType","vector");
  91. %% No Lapse
  92. prior = "GaussianLaplaceBothFixedZero";
  93. noise = "exp";
  94. aud_rescale = "free";
  95. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, false, lapse_type);
  96. exportgraphics(gcf,figpath+'Exp-GaussianLaplace_nolapse'+'.png','Resolution',png_dpi);
  97. exportgraphics(gcf,figpath+'Exp-GaussianLaplace_nolapse'+'.pdf',"ContentType","vector");
  98. %% Gaussian
  99. prior = "GaussianLaplaceBothFixedZero";
  100. noise = "exp";
  101. aud_rescale = "free";
  102. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, true, "Gaussian");
  103. exportgraphics(gcf,figpath+'Exp-GaussianLaplace_Gaussianlapse'+'.png','Resolution',png_dpi);
  104. exportgraphics(gcf,figpath+'Exp-GaussianLaplace_Gaussianlapse'+'.pdf',"ContentType","vector");
  105. % Compute model comparison between uniform lapse model.
  106. UnimodalData_ModelComparison_FinalTables_uniformgaussianlapse = unimodaldata_modelcomparison_visualize_uniformgaussianlapse(model_path, data_path);
  107. %%
  108. prior = "SingleGaussian";
  109. noise = "exp";
  110. aud_rescale = "free";
  111. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  112. exportgraphics(gcf,figpath+'Exp-SingleGaussian'+'.png','Resolution',png_dpi);
  113. exportgraphics(gcf,figpath+'Exp-SingleGaussian'+'.pdf',"ContentType","vector");
  114. prior = "GaussianLaplaceBothFixedZero";
  115. noise = "constant";
  116. aud_rescale = "free";
  117. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  118. exportgraphics(gcf,figpath+'Const-GaussianLaplace'+'.png','Resolution',png_dpi);
  119. exportgraphics(gcf,figpath+'Const-GaussianLaplace'+'.pdf',"ContentType","vector");
  120. prior = "TwoGaussiansBothFixedZero";
  121. noise = "exp";
  122. aud_rescale = "free";
  123. manuscript_ujoint_respdistrvisualization(prior, noise, aud_rescale, fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  124. exportgraphics(gcf,figpath+'Exp-TwoGaussians'+'.png','Resolution',png_dpi);
  125. exportgraphics(gcf,figpath+'Exp-TwoGaussians'+'.pdf',"ContentType","vector");
  126. %% Unimodal semiparam model
  127. % Response distribution visualization
  128. % manuscript_ujoint_respdistrvisualization_semiparam(fontsize, four_by_three_figsize);
  129. manuscript_ujoint_respdistrvisualization_semiparam(fontsize, figsize_RespDistr, model_path, plot_lapse, lapse_type);
  130. exportgraphics(gcf,figpath+'Semiparam_FittedRespDistr'+'.png','Resolution',png_dpi);
  131. exportgraphics(gcf,figpath+'Semiparam_FittedRespDistr'+'.pdf',"ContentType","vector");
  132. %%
  133. % sigma(s), p(s) visualization
  134. semiparam_sigmafun_prior_visualization(fontsize+1, figsize_RespDistr, model_path);
  135. exportgraphics(gcf,figpath+'Semiparam_FittedParams'+'.png','Resolution',png_dpi);
  136. exportgraphics(gcf,figpath+'Semiparam_FittedParams'+'.pdf',"ContentType","vector");
  137. %% Unimodal data ModelComparison
  138. priors = ["","GaussianLaplaceBothFixedZero","GaussianLaplaceBothFixedZero","GaussianLaplaceBothFixedZero", "SingleGaussian", "GaussianLaplaceBothFixedZero", "TwoGaussiansBothFixedZero","SingleGaussian","SingleGaussian","SingleGaussian"];
  139. noises = ["","exp", "exp", "exp", "exp", "constant", "exp", "constant","constant","constant"];
  140. rescales = ["","free", "4over3", "1", "free","free","free","free","4over3","1"];
  141. model_types = ["semiparametric","exp-GaussianLaplace", "exp-GaussianLaplace\_4/3","exp-GaussianLaplace\_1", "exp-SingleGaussian", "const-GaussianLaplace","exp-TwoGaussians","const-SingleGaussian","const-SingleGaussian\_4/3","const-SingleGaussian\_1"];
  142. num_params = [40,14,13,13,12,10,14,8,7,7];
  143. %% Vanila 3 models on unimodal data only
  144. figure('Position', [0 0 5.2*Res figsize_RespDistr(4)*0.4]);
  145. set(gcf, 'Color', 'w')
  146. UnimodalData_ModelComparison_FinalTables_Vanilla = unimodaldata_modelcomparison_visualize(priors((end-2):end), noises((end-2):end), rescales((end-2):end), model_types((end-2):end), num_params((end-2):end), true, fontsize+1, model_path, data_path, false);
  147. exportgraphics(gcf,figpath+'UJoint_ModelSelection_vanilla'+'.png','Resolution',png_dpi);
  148. exportgraphics(gcf,figpath+'UJoint_ModelSelection_vanilla'+'.pdf',"ContentType","vector");
  149. save(analysis_path+'unimodaldata_modelcomparison_finaltables_vanilla','UnimodalData_ModelComparison_FinalTables_Vanilla');
  150. % All models on unimodal data
  151. keep_modelidx = [2,5,6,7,8,1];
  152. figure('Position', [0 0 5.2*Res figsize_RespDistr(3)*0.6*0.5]);
  153. set(gcf, 'Color', 'w')
  154. UnimodalData_ModelComparison_FinalTables = unimodaldata_modelcomparison_visualize(priors(keep_modelidx), noises(keep_modelidx), rescales(keep_modelidx), model_types(keep_modelidx), num_params(keep_modelidx), true, fontsize+1, model_path, data_path, true);
  155. exportgraphics(gcf,figpath+'UJoint_ModelSelection_BIC'+'.png','Resolution',png_dpi);
  156. exportgraphics(gcf,figpath+'UJoint_ModelSelection_BIC'+'.pdf',"ContentType","vector");
  157. keep_modelidx = [2,3,4,5,6,7,8,9,10,1];
  158. figure('Position', [0 0 5.2*Res figsize_RespDistr(3)*0.6*0.7]);
  159. set(gcf, 'Color', 'w')
  160. UnimodalData_ModelComparison_FinalTables = unimodaldata_modelcomparison_visualize(priors(keep_modelidx), noises(keep_modelidx), rescales(keep_modelidx), model_types(keep_modelidx), num_params(keep_modelidx), true, fontsize+1, model_path, data_path, true);
  161. exportgraphics(gcf,figpath+'UJoint_ModelSelection_BIC_full'+'.png','Resolution',png_dpi);
  162. exportgraphics(gcf,figpath+'UJoint_ModelSelection_BIC_full'+'.pdf',"ContentType","vector");
  163. figure('Position', [0 0 figsize_RespDistr(3) figsize_RespDistr(3)]);
  164. set(gcf, 'Color', 'w')
  165. UnimodalData_ModelComparison_FinalTables = unimodaldata_modelcomparison_visualize(priors, noises, rescales, model_types, num_params, true, fontsize+1, model_path, data_path, false);
  166. exportgraphics(gcf,figpath+'UJoint_ModelSelection'+'.png','Resolution',png_dpi);
  167. exportgraphics(gcf,figpath+'UJoint_ModelSelection'+'.pdf',"ContentType","vector");
  168. save(analysis_path+'unimodaldata_modelcomparison_finaltables','UnimodalData_ModelComparison_FinalTables');
  169. %% AllData LiftedSemiparam Response distribution visualization
  170. causal_inf_strategy = "ProbMatching";
  171. save_name = "PM";
  172. manuscript_allfits_respdistrvisual_semiparaminsp_maintext(causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type);
  173. manuscript_allfits_respdistrvisualization_semiparaminsp_resc(causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type);
  174. %%
  175. causal_inf_strategy = "ModelSelection";
  176. save_name = "MS";
  177. manuscript_allfits_respdistrvisualization_semiparaminsp_resc(causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type);
  178. causal_inf_strategy = "ModelAveraging";
  179. save_name = "MA";
  180. manuscript_allfits_respdistrvisualization_semiparaminsp_resc(causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type);
  181. %% AllData parametric model response distributions
  182. prior_type = "GaussianLaplaceBothFixedZero";
  183. hetero_type = "exp";
  184. causal_inf_strategy = "ProbMatching";
  185. save_name = "exp-GaussianLaplace-PM";
  186. manuscript_allfits_respdistrvisualization_resc_maintext(prior_type, hetero_type, causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type)
  187. manuscript_allfits_respdistrvisualization_resc(prior_type, hetero_type, causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type)
  188. %% Individual-level plots for the above model
  189. prior_type = "GaussianLaplaceBothFixedZero";
  190. hetero_type = "exp";
  191. causal_inf_strategy = "ProbMatching";
  192. save_name = "exp-GaussianLaplace-PM";
  193. manuscript_allfits_respdistrvisualization_resc(prior_type, hetero_type, causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type, true)
  194. %% Exemplary subject
  195. subjidx=7;
  196. fitted_on_all_data = true;
  197. allindvsubjplots_to_onesubjplot(save_name,subjidx, fitted_on_all_data, fontsize, figsize_RespDistr, figpath)
  198. exportgraphics(gcf,figpath+'Exp-GaussianLaplace-PM_Individual_example'+'.pdf',"ContentType","vector");
  199. exportgraphics(gcf,figpath+'Exp-GaussianLaplace-PM_Individual_example'+'.png','Resolution',png_dpi);
  200. %%
  201. prior_type = "GaussianLaplaceBothFixedZero";
  202. hetero_type = "exp";
  203. causal_inf_strategy = "ModelAveraging";
  204. save_name = "exp-GaussianLaplace-MA";
  205. manuscript_allfits_respdistrvisualization_resc(prior_type, hetero_type, causal_inf_strategy, fontsize, figsize_RespDistr, figpath, save_name, png_dpi, model_path, plot_lapse, lapse_type)
  206. %% AllData ModelComparison
  207. causal_inf_strategies = ["ModelSelection","ModelAveraging","ProbMatching"];
  208. param_model_names = ["exp-GaussianLaplace","exp-SingleGaussian","const-GaussianLaplace","exp-TwoGaussians","const-SingleGaussian","paramBest", "LiftedSemiparam"];
  209. % Only BIC for PM models
  210. figure('Position', [0 0 5.2*Res figsize_RespDistr(3)*0.3]);
  211. hold on;
  212. set(gcf, 'Color', 'w')
  213. alldata_modelcomparison_visualize([causal_inf_strategies(3)], param_model_names, true, fontsize, model_path, data_path, true, true, true);
  214. alldata_modelcomparison_visualize([causal_inf_strategies(3)], param_model_names, true, fontsize, model_path, data_path, true, false, false);
  215. exportgraphics(gcf,figpath+'SemiparamIndv_ModelSelection_BIC'+'.png','Resolution',png_dpi);
  216. exportgraphics(gcf,figpath+'SemiparamIndv_ModelSelection_BIC'+'.pdf',"ContentType","vector");
  217. %% Only BIC for all models
  218. figure('Position', [0 0 5.2*Res figsize_RespDistr(3)*0.6]);
  219. set(gcf, 'Color', 'w')
  220. alldata_modelcomparison_visualize(causal_inf_strategies, param_model_names, true, fontsize, model_path, data_path, true, true, true);
  221. alldata_modelcomparison_visualize(causal_inf_strategies, param_model_names, true, fontsize, model_path, data_path, true, false, false);
  222. exportgraphics(gcf,figpath+'SemiparamIndv_ModelSelection_BIC_full'+'.png','Resolution',png_dpi);
  223. exportgraphics(gcf,figpath+'SemiparamIndv_ModelSelection_BIC_full'+'.pdf',"ContentType","vector");
  224. % NLL, AIC, BIC for all models
  225. figure('Position', [0 0 figsize_RespDistr(3) figsize_RespDistr(3)]);
  226. set(gcf, 'Color', 'w')
  227. AllData_ModelComparison_FinalTables_liftedsemiparam_count = alldata_modelcomparison_visualize(causal_inf_strategies, param_model_names, true, fontsize, model_path, data_path, false, true, true);
  228. AllData_ModelComparison_FinalTables = alldata_modelcomparison_visualize(causal_inf_strategies, param_model_names, true, fontsize, model_path, data_path, false, false, false);
  229. writematrix(round(AllData_ModelComparison_FinalTables{1},2), figpath+"NLL.csv")
  230. writematrix(round(AllData_ModelComparison_FinalTables{2},2), figpath+"AIC.csv")
  231. writematrix(round(AllData_ModelComparison_FinalTables{3},2), figpath+"BIC.csv")
  232. exportgraphics(gcf,figpath+'SemiparamIndv_ModelSelection'+'.png','Resolution',png_dpi);
  233. exportgraphics(gcf,figpath+'SemiparamIndv_ModelSelection'+'.pdf',"ContentType","vector");
  234. save(analysis_path+'alldata_modelcomparison_finaltables','AllData_ModelComparison_FinalTables');
  235. %% sigma(s) and p(s) examples
  236. figure('Position', [0 0 figsize_RespDistr(3) figsize_RespDistr(3)]);
  237. set(gcf, 'Color', 'w')
  238. sigmafun_prior_examples(fontsize);
  239. exportgraphics(gcf,figpath+'SensoryNoisePriorParamFamilies'+'.png','Resolution',png_dpi);
  240. exportgraphics(gcf,figpath+'SensoryNoisePriorParamFamilies'+'.pdf',"ContentType","vector");
  241. %% Parameter recovery
  242. load(model_path+"fittedparams_UJoint_exp-GaussianLaplaceBothFixedZero_rescalefree_lapseUniform.mat")
  243. theta_fitted_orig = theta_fitted;
  244. F_vals_orig = F_vals;
  245. load(model_path+"fittedparams_UJoint_exp-GaussianLaplaceBothFixedZero_rescalefree_lapseUniform__exp-GaussianLaplaceBothFixedZero_rescalefree_lapseUniform")
  246. num_params_model = length(theta_fitted(1,:));
  247. param_names = ["\sigma_{0,V}","k_{1,V}","k_{2,V}","\alpha_{med}","\alpha_{low}","\sigma_s","\lambda","b","w","\sigma_{motor}","\sigma_{0,A}","k_{1,A}","k_{2,A}", "\rho_A"];
  248. figure('Position',[50,100,700,500]);
  249. t=tiledlayout(3,ceil(num_params_model/3),'Padding', 'tight', 'TileSpacing', 'tight');
  250. for param =1:num_params_model
  251. nexttile(t); hold on;
  252. theta_aug = [theta_fitted_orig(:,param); theta_fitted(:,param)];
  253. scatter(theta_fitted_orig(:,param), theta_fitted(:,param), "k.")
  254. plot([min(0,min(theta_aug)), max(theta_aug)], [min(0,min(theta_aug)), max(theta_aug)], "g-")
  255. title("$"+param_names(param)+"$",'interpreter','latex','fontsize',12)
  256. end
  257. xlabel(t,'Ground-truth parameter value','FontSize',12)
  258. ylabel(t,'Recovered parameter value','FontSize',12)
  259. exportgraphics(gcf,figpath+"UAV_Exp-GaussianLaplace_ParamRecovery"+".pdf","ContentType","vector");
  260. %% Check model recovery
  261. prior_types = ["SingleGaussian","GaussianLaplaceBothFixedZero","SingleGaussian","SingleGaussian","GaussianLaplaceBothFixedZero","GaussianLaplaceBothFixedZero"]; % "SingleGaussian", "GaussianLaplaceBothFixedZero", or "TwoGaussiansBothFixedZero"
  262. hetero_types = ["constant","exp","constant","exp","constant","exp"]; % "constant" or "exp";
  263. lapse_types = repmat("Uniform",1,length(prior_types)); % "Uniform" or "Gaussian";
  264. rescale_auds = ["free","free","1","free","free","1"]; % "1", "4/3", or "free";
  265. prior_type_modelrecovdatas = prior_types;
  266. hetero_type_modelrecovdatas = hetero_types; % "constant" or "exp";
  267. lapse_type_modelrecovdatas = lapse_types; % "Uniform" or "Gaussian";
  268. rescale_aud_modelrecovdatas = rescale_auds; % "1", "4/3", or "free";
  269. % Model parameters
  270. num_params = [8,14,7,12,10,13];
  271. num_datasets = length(prior_type_modelrecovdatas);
  272. num_models = length(prior_types);
  273. num_subjects = 15;
  274. load(data_path+"data_stratified_UV.mat");
  275. load(data_path+"data_stratified_UA.mat");
  276. data_UV = data_stratified_to_data(data_stratified_UV, false, true); % last argument is is_visual.
  277. data_UA = data_stratified_to_data(data_stratified_UA, false, false);
  278. n_data = zeros(1,15);
  279. for subjidx=1:num_subjects
  280. n_data(subjidx) = length(data_UA{subjidx}) +length(data_UV{subjidx});
  281. end
  282. % AIC, BIC
  283. NLLs = zeros(num_datasets, num_models, num_subjects);
  284. AICs = zeros(num_datasets, num_models, num_subjects);
  285. BICs = zeros(num_datasets, num_models, num_subjects);
  286. % load nonparam indv UJoint fits
  287. for model_idx =1:6
  288. prior_type = prior_types(model_idx);
  289. hetero_type = hetero_types(model_idx);
  290. lapse_type = lapse_types(model_idx);
  291. rescale_aud = rescale_auds(model_idx);
  292. for dataset_idx =1:6
  293. prior_type_modelrecovdata = prior_type_modelrecovdatas(dataset_idx); % "SingleGaussian", "GaussianLaplaceBothFixedZero", or "TwoGaussiansBothFixedZero"
  294. hetero_type_modelrecovdata = hetero_type_modelrecovdatas(dataset_idx); % "constant" or "exp";
  295. lapse_type_modelrecovdata = lapse_type_modelrecovdatas(dataset_idx); % "Uniform" or "Gaussian";
  296. rescale_aud_modelrecovdata = rescale_aud_modelrecovdatas(dataset_idx); % "1", "4/3", or "free";
  297. filename = 'fittedparams_UJoint_'+hetero_type+"-"+prior_type+"_rescale"+rescale_aud+"_lapse"+lapse_type;
  298. datafilename = hetero_type_modelrecovdata+"-"+prior_type_modelrecovdata+"_rescale"+rescale_aud_modelrecovdata+"_lapse"+lapse_type_modelrecovdata;
  299. filename_final = filename + "__" + datafilename;
  300. for model=1:(num_models)
  301. load(model_path + filename_final+".mat")
  302. [min_val, min_idx] = min(F_vals,[],2);
  303. NLLs(dataset_idx, model_idx,:) = min_val';
  304. AICs(dataset_idx, model_idx,:) = 2.*min_val' + 2.* num_params(model_idx);
  305. BICs(dataset_idx, model_idx,:) = 2.*min_val' + num_params(model_idx).*log(n_data);
  306. end
  307. end
  308. end
  309. NLL_sum = sum(NLLs,3);
  310. AIC_sum = sum(AICs,3);
  311. BIC_sum = sum(BICs,3);
  312. % figure; hold on;
  313. NLL_sumvalues_diff = NLL_sum - diag(NLL_sum);
  314. [~,min_NLL_model] = min(NLL_sum,[],2);
  315. AIC_sumvalues_diff = AIC_sum - diag(AIC_sum);
  316. [~,min_AIC_model] = min(AIC_sum,[],2);
  317. BIC_sumvalues_diff = BIC_sum - diag(BIC_sum);
  318. [~,min_BIC_model] = min(BIC_sum,[],2);
  319. %% Manuscript polished figure
  320. num_colors = 64;
  321. half_colors = num_colors/2;
  322. green_to_white = [linspace(0,1,half_colors)', linspace(0.5,1,half_colors)', linspace(0,1,half_colors)']; % dark blue→white
  323. white_to_red = [linspace(1,1,half_colors)', linspace(1,0,half_colors)', linspace(1,0.5,half_colors)']; % white→dark red
  324. diverging_cmap = flip([green_to_white; white_to_red]);
  325. % Data stack (3 x 6 x 6)
  326. matrices = zeros(3,6,6);
  327. matrices(1,:,:) = NLL_sumvalues_diff;
  328. matrices(2,:,:) = AIC_sumvalues_diff;
  329. matrices(3,:,:) = BIC_sumvalues_diff;
  330. % Panel letters
  331. panel_letters = {'(a)','(b)','(c)'};
  332. % Original names (as currently aligned with matrices rows/cols = 1..6)
  333. model_names = {'Const-SingleGaussian', ...
  334. 'Exp-GaussianLaplace', ...
  335. 'Const-SingleGaussian-1', ...
  336. 'Exp-SingleGaussian', ...
  337. 'Const-GaussianLaplace', ...
  338. 'Exp-GaussianLaplace-1'};
  339. nModels = numel(model_names);
  340. % --- NEW desired order for both axes ---
  341. new_order_names = { ...
  342. 'Exp-GaussianLaplace', ...
  343. 'Exp-GaussianLaplace-1', ...
  344. 'Exp-SingleGaussian', ...
  345. 'Const-GaussianLaplace', ...
  346. 'Const-SingleGaussian', ...
  347. 'Const-SingleGaussian-1'};
  348. % Map names -> indices in the current matrices
  349. new_idx = cellfun(@(nm) find(strcmp(model_names, nm), 1, 'first'), new_order_names);
  350. % Precompute signed-log to unify color limits across all tiles (order doesn't affect max)
  351. A_signedlog_all = zeros(size(matrices));
  352. for i = 1:3
  353. A0 = squeeze(matrices(i,:,:));
  354. A_signedlog_all(i,:,:) = sign(A0) .* log10(1 + abs(A0));
  355. end
  356. clim_abs = max(abs(A_signedlog_all(:)));
  357. % Figure & layout
  358. figure('Position',[50,100,1200,400]);
  359. t = tiledlayout(1,3,'TileSpacing','compact','Padding','tight'); % annotations use figure coords
  360. ax = gobjects(1,3);
  361. for subplot_idx = 1:3
  362. ax(subplot_idx) = nexttile; hold on;
  363. % --- Apply the row/col permutation by name ---
  364. A0 = squeeze(matrices(subplot_idx,:,:));
  365. A = A0(new_idx, new_idx); % reorder rows and columns
  366. A_signedlog = sign(A) .* log10(1 + abs(A));
  367. % Heatmap
  368. imagesc(A_signedlog);
  369. set(gca,'YDir','reverse');
  370. axis image tight
  371. % Unified color scale (no per-axes colorbar)
  372. caxis([-clim_abs, clim_abs]);
  373. % Tick setup:
  374. set(gca, 'XTick', 1:nModels, 'XTickLabel', '', 'TickLabelInterpreter','none');
  375. xtickangle(45);
  376. % Y: show labels only on the first subplot to reduce clutter; others keep ticks but hide labels
  377. set(gca, 'YTick', 1:nModels, 'YTickLabel', new_order_names, 'TickLabelInterpreter','none');
  378. if subplot_idx > 1
  379. set(gca, 'YTickLabel', []);
  380. end
  381. % Axis labels per subplot (no shared x-axis)
  382. xlabel('Fitted model');
  383. if subplot_idx == 1
  384. ylabel('Ground-truth generative model');
  385. end
  386. % Overlay original (untransformed) values (matching the permuted grid)
  387. [cols, rows] = deal(size(A,2), size(A,1));
  388. [X, Y] = meshgrid(1:cols, 1:rows);
  389. textStrings = compose('%.2f', A(:));
  390. high_contrast = abs(A_signedlog(:)) > 0.6*clim_abs;
  391. textColors = repmat([0 0 0], numel(textStrings), 1);
  392. textColors(high_contrast,:) = repmat([1 1 1], sum(high_contrast), 1);
  393. for k = 1:numel(textStrings)
  394. text(X(k), Y(k), textStrings{k}, ...
  395. 'HorizontalAlignment','center', ...
  396. 'VerticalAlignment','middle', ...
  397. 'Color', textColors(k,:), ...
  398. 'FontSize', 9, 'FontWeight','bold');
  399. end
  400. set(gca,'TickDir','out','Box','on');
  401. box off;
  402. end
  403. % One unified colorbar on the very right (compatible with older MATLAB)
  404. colormap(gcf, diverging_cmap);
  405. cb = colorbar(ax(end));
  406. cb.Layout.Tile = 'east';
  407. cb.Label.String = 'signed log_{10}(1 + |\Delta|) · sign(\Delta)';
  408. % --- Panel letters ---
  409. for i = 1:3
  410. pos = ax(i).Position;
  411. x = pos(1); y = pos(2) + pos(4);
  412. dx = -0.03; dy = 0.05;
  413. if i == 1
  414. x = x - 0.01;
  415. end
  416. annotation('textbox', [x+dx, y+dy, 0.01, 0.01], ...
  417. 'String', panel_letters{i}, ...
  418. 'FontSize', 11, 'FontWeight','bold', ...
  419. 'LineStyle', 'none', 'HorizontalAlignment','left', 'VerticalAlignment','top');
  420. end
  421. exportgraphics(gcf,figpath+"UAV_ModelRecovery"+".pdf","ContentType","vector");
  422. %% BELOW: Helper Functions
  423. function [UnimodalData_ModelComparison_FinalTables] = unimodaldata_modelcomparison_visualize(priors, noises, rescales, model_types, num_params, is_plot, fontsize, model_path, data_path, plot_BIC_only)
  424. num_models = length(priors);
  425. num_subjects = 15;
  426. load(data_path+"data_stratified_UV.mat");
  427. load(data_path+"data_stratified_UA.mat");
  428. data_UV = data_stratified_to_data(data_stratified_UV, false, true); % last argument is is_visual.
  429. data_UA = data_stratified_to_data(data_stratified_UA, false, false);
  430. n_data = zeros(1,15);
  431. for subjidx=1:num_subjects
  432. n_data(subjidx) = length(data_UA{subjidx}) +length(data_UV{subjidx});
  433. end
  434. % AIC, BIC
  435. NLLs = zeros(num_models, num_subjects);
  436. AICs = zeros(num_models, num_subjects);
  437. BICs = zeros(num_models, num_subjects);
  438. % load nonparam indv UJoint fits
  439. for model=1:(num_models)
  440. if(model_types(model)=="semiparametric")
  441. load(model_path + "fittedparams_UJoint_Semiparam_rescalefree_lapseUniform.mat")
  442. [min_val, min_idx] = min(F_vals,[],1);
  443. [num_inits,num_params_nonparam]=size(theta_fitted);
  444. NLLs(model,:) = min_val;
  445. AICs(model,:) = 2.*min_val + 2.* num_params(model);
  446. BICs(model,:) = 2.*min_val + num_params(model).*log(n_data);
  447. else
  448. load(model_path + "fittedparams_UJoint_"+noises(model)+"-"+priors(model)+"_rescale"+rescales(model)+"_lapseUniform.mat")
  449. [min_val, min_idx] = min(F_vals,[],2);
  450. NLLs(model,:) = min_val';
  451. AICs(model,:) = 2.*min_val' + 2.* num_params(model);
  452. BICs(model,:) = 2.*min_val' + num_params(model).*log(n_data);
  453. end
  454. end
  455. NLL_sum = sum(NLLs,2);
  456. AIC_sum = sum(AICs,2);
  457. BIC_sum = sum(BICs,2);
  458. NLL_sumvalues_diff = NLL_sum - min(NLL_sum);
  459. [~,min_NLL_model] = min(NLL_sum);
  460. AIC_sumvalues_diff = AIC_sum - min(AIC_sum);
  461. [~,min_AIC_model] = min(AIC_sum);
  462. BIC_sumvalues_diff = BIC_sum - min(BIC_sum);
  463. [~,min_BIC_model] = min(BIC_sum);
  464. % AIC/BIC bootstrapping
  465. num_bootstrap_samps = 100000;
  466. NLL_sum_bootstraps = zeros(num_models,num_bootstrap_samps);
  467. AIC_sum_bootstraps = zeros(num_models,num_bootstrap_samps);
  468. BIC_sum_bootstraps = zeros(num_models,num_bootstrap_samps);
  469. rng("default")
  470. rng(0)
  471. for samp = 1:num_bootstrap_samps
  472. sampled_subj = datasample(1:num_subjects,num_subjects);
  473. for model=1:(num_models)
  474. NLL_sum_bootstraps(model, samp) = sum(NLLs(model, sampled_subj));
  475. AIC_sum_bootstraps(model, samp) = sum(AICs(model, sampled_subj));
  476. BIC_sum_bootstraps(model, samp) = sum(BICs(model, sampled_subj));
  477. end
  478. end
  479. NLL_bootstraps_diff = NLL_sum_bootstraps - NLL_sum_bootstraps(min_NLL_model,:);
  480. AIC_bootstraps_diff = AIC_sum_bootstraps - AIC_sum_bootstraps(min_AIC_model,:);
  481. BIC_bootstraps_diff = BIC_sum_bootstraps - BIC_sum_bootstraps(min_BIC_model,:);
  482. NLL_bootstraps_errorbars = prctile(NLL_bootstraps_diff,[2.5, 97.5], 2);
  483. AIC_bootstraps_errorbars = prctile(AIC_bootstraps_diff,[2.5, 97.5], 2);
  484. BIC_bootstraps_errorbars = prctile(BIC_bootstraps_diff,[2.5, 97,5], 2);
  485. % Plot
  486. bootstraps_errorbars_allstats = {NLL_bootstraps_errorbars, AIC_bootstraps_errorbars, BIC_bootstraps_errorbars};
  487. allstats = {NLL_sumvalues_diff, AIC_sumvalues_diff, BIC_sumvalues_diff};
  488. stat_names = ["\DeltaNLL", "\DeltaAIC", "\DeltaBIC"];
  489. if(is_plot)
  490. if(plot_BIC_only)
  491. statistics = 3;
  492. else
  493. statistics = 1:length(stat_names)
  494. end
  495. tiledlayout(length(statistics),1, 'TileSpacing', 'tight','Padding', 'none')
  496. for statistic=statistics
  497. nexttile
  498. set(gca,'TickDir','out');
  499. bootstraps_errorbars = bootstraps_errorbars_allstats{statistic};
  500. mean_stat = allstats{statistic};
  501. hold on
  502. %for model=[1,2,3]
  503. cats = model_types;
  504. cats = insertBefore(cats,"_no","\");
  505. C = categorical(cats);
  506. C = reordercats(C,cellstr(C)');
  507. barh(0:(length(C)-1),mean_stat,'FaceColor','k', 'FaceAlpha',0.2)
  508. errorbar(mean_stat,0:(length(C)-1),mean_stat-squeeze(bootstraps_errorbars(:, 1)),squeeze(bootstraps_errorbars(:, 2))-mean_stat,'horizontal', 'k.')
  509. yticks(0:(length(C)-1))
  510. C_capitalized = C;
  511. for c=1:length(C)
  512. cat_char = char(string(C(c)));
  513. C_capitalized(c) = convertCharsToStrings([upper(cat_char(1)), cat_char(2:end)]);
  514. end
  515. yticklabels(C_capitalized)
  516. ylim([0-0.5, length(C)-0.5])
  517. set(gca,'YDir','reverse')
  518. %end
  519. if(statistic~=length(stat_names))
  520. xticklabels([]);
  521. set(gca,'xtick',[])
  522. end
  523. set(gca,'FontSize',9)
  524. xlabel(stat_names(statistic))
  525. %set(gca,'xticklabel',["diff","max","ent"].')
  526. end
  527. end
  528. % Create a .mat file with the delta NLL, AIC, and BIC tables
  529. UnimodalData_ModelComparison_FinalTables = cell(1,3);
  530. for stat=1:3
  531. final_table = zeros(length(allstats{1}),3);
  532. final_table(:,1) = bootstraps_errorbars_allstats{stat}(:,1); % 2.5% percentile
  533. final_table(:,2) = allstats{stat}; % Sum
  534. final_table(:,3) = bootstraps_errorbars_allstats{stat}(:,2); % 97.5% percentile
  535. UnimodalData_ModelComparison_FinalTables{stat} = final_table;
  536. end
  537. end
  538. %%
  539. function [UnimodalData_ModelComparison_FinalTables] = unimodaldata_modelcomparison_visualize_uniformgaussianlapse(model_path, data_path)
  540. num_models = 2;
  541. num_subjects=15;
  542. NLLs = [];
  543. load(model_path + "fittedparams_UJoint_exp-GaussianLaplaceBothFixedZero_rescalefree_lapseUniform.mat")
  544. NLLs = [NLLs; min(F_vals,[],2)'];
  545. load(model_path + "fittedparams_UJoint_exp-GaussianLaplaceBothFixedZero_rescalefree_lapseGaussian.mat")
  546. NLLs = [NLLs; min(F_vals,[],2)'];
  547. delta_NLLs = NLLs - NLLs(1,:);
  548. NLL_allmodels_sumdiff = sum(delta_NLLs,2);
  549. num_model_params = [14;15];
  550. AICs = 2.*(NLLs + num_model_params);
  551. delta_AICs = AICs - AICs(1,:);
  552. AIC_allmodels_sumdiff = sum(delta_AICs,2);
  553. load(data_path+"data_stratified_UV.mat");
  554. load(data_path+"data_stratified_UA.mat");
  555. data_UV = data_stratified_to_data(data_stratified_UV, false, true); % last argument is is_visual.
  556. data_UA = data_stratified_to_data(data_stratified_UA, false, false);
  557. n_data = zeros(1,15);
  558. for subjidx=1:15
  559. n_data(subjidx) = length(data_UA{subjidx}) +length(data_UV{subjidx});
  560. end
  561. BICs = 2.*NLLs + num_model_params.*log(n_data);
  562. delta_BICs = BICs - BICs(1,:);
  563. BIC_allmodels_sumdiff = sum(delta_BICs,2);
  564. % AIC/BIC bootstrapping
  565. num_bootstrap_samps = 100000;
  566. NLL_sum_bootstraps = zeros(num_models,num_bootstrap_samps);
  567. AIC_sum_bootstraps = zeros(num_models,num_bootstrap_samps);
  568. BIC_sum_bootstraps = zeros(num_models,num_bootstrap_samps);
  569. rng('default')
  570. rng(0)
  571. for samp = 1:num_bootstrap_samps
  572. sampled_subj = datasample(1:num_subjects,num_subjects);
  573. for model=1:num_models
  574. NLL_sum_bootstraps(model, samp) = sum(NLLs(model, sampled_subj));
  575. AIC_sum_bootstraps(model, samp) = sum(AICs(model, sampled_subj));
  576. BIC_sum_bootstraps(model, samp) = sum(BICs(model, sampled_subj));
  577. end
  578. end
  579. NLL_bootstraps_diff = NLL_sum_bootstraps - NLL_sum_bootstraps(1,:);
  580. AIC_bootstraps_diff = AIC_sum_bootstraps - AIC_sum_bootstraps(1,:);
  581. BIC_bootstraps_diff = BIC_sum_bootstraps - BIC_sum_bootstraps(1,:);
  582. NLL_bootstraps_errorbars = prctile(NLL_bootstraps_diff,[2.5, 97.5], 2);
  583. AIC_bootstraps_errorbars = prctile(AIC_bootstraps_diff,[2.5, 97.5], 2);
  584. BIC_bootstraps_errorbars = prctile(BIC_bootstraps_diff,[2.5, 97,5], 2);
  585. % Plot
  586. bootstraps_errorbars_allstats = {NLL_bootstraps_errorbars, AIC_bootstraps_errorbars, BIC_bootstraps_errorbars};
  587. allstats = {NLL_allmodels_sumdiff, AIC_allmodels_sumdiff, BIC_allmodels_sumdiff};
  588. stat_names = ["\DeltaNLL", "\DeltaAIC", "\DeltaBIC"];
  589. if(false)
  590. tiledlayout(length(stat_names),1, 'TileSpacing', 'tight','Padding', 'none')
  591. for statistic=1:length(stat_names)
  592. nexttile
  593. set(gca,'TickDir','out');
  594. bootstraps_errorbars = bootstraps_errorbars_allstats{statistic};
  595. mean_stat = allstats{statistic};
  596. hold on
  597. bar(1:(num_models),mean_stat,'FaceColor','k', 'FaceAlpha',0.2)
  598. errorbar(1:(num_models)',mean_stat,mean_stat-squeeze(bootstraps_errorbars(:, 1)),squeeze(bootstraps_errorbars(:, 2))-mean_stat, 'k.')
  599. if(statistic~=length(stat_names))
  600. xticklabels([])
  601. set(gca,'xtick',[])
  602. else
  603. xticks(1:(3*num_models));
  604. xticklabels(allmodel_xticklabels)
  605. xtickangle(20)
  606. end
  607. set(gca,'FontSize',9)
  608. ylabel(stat_names(statistic), 'FontSize',9)
  609. xlim([0, num_models+0.7])
  610. end
  611. end
  612. % Create a .mat file with the delta NLL, AIC, and BIC tables
  613. UnimodalData_ModelComparison_FinalTables = cell(1,3);
  614. for stat=1:3
  615. final_table = zeros(num_models,3);
  616. final_table(:,1) = bootstraps_errorbars_allstats{stat}(:,1); % 2.5% percentile
  617. final_table(:,2) = allstats{stat}; % Sum
  618. final_table(:,3) = bootstraps_errorbars_allstats{stat}(:,2); % 97.5% percentile
  619. UnimodalData_ModelComparison_FinalTables{stat} = final_table;
  620. end
  621. end
  622. %%
  623. function [AllData_ModelComparison_FinalTables] = alldata_modelcomparison_visualize(causal_inf_strategies, param_model_names, is_plot, fontsize, model_path, data_path, plot_BIC_only, LiftedSemiparamParamAll, new_figure)
  624. num_strategies = length(causal_inf_strategies);
  625. num_models = length(param_model_names);
  626. num_subjects = 15;
  627. if(LiftedSemiparamParamAll)
  628. barcolor = [1,1,1];
  629. else
  630. barcolor = [204,204,204]./255;
  631. end
  632. out_structs = cell(1,num_strategies);
  633. NLL_allmodels = zeros(num_models*num_strategies, 15);
  634. AIC_allmodels = zeros(num_models*num_strategies, 15);
  635. BIC_allmodels = zeros(num_models*num_strategies, 15);
  636. for causal_inf_strategy_idx=1:num_strategies
  637. causal_inf_strategy_idx
  638. out_struct = alldata_modelcomparison_visualize_helper(causal_inf_strategies(causal_inf_strategy_idx), param_model_names, model_path, data_path, LiftedSemiparamParamAll);
  639. out_structs{causal_inf_strategy_idx} = out_struct;
  640. NLL_allmodels(causal_inf_strategy_idx:num_strategies:end,:) = out_struct.NLLs;
  641. AIC_allmodels(causal_inf_strategy_idx:num_strategies:end,:) = out_struct.AICs;
  642. BIC_allmodels(causal_inf_strategy_idx:num_strategies:end,:) = out_struct.BICs;
  643. end
  644. % deltaNLL and deltaAIC across all 18 models
  645. baseline_modelidx = find(causal_inf_strategies=="ProbMatching"); % Use the first model's PM version as baseline.
  646. NLL_allmodels_sum = sum(NLL_allmodels,2);
  647. NLL_allmodels_sumdiff = NLL_allmodels_sum - NLL_allmodels_sum(baseline_modelidx);
  648. NLL_min_model = baseline_modelidx;
  649. AIC_allmodels_sum = sum(AIC_allmodels,2);
  650. AIC_allmodels_sumdiff = AIC_allmodels_sum - AIC_allmodels_sum(baseline_modelidx);
  651. AIC_min_model = baseline_modelidx;
  652. BIC_allmodels_sum = sum(BIC_allmodels,2);
  653. BIC_allmodels_sumdiff = BIC_allmodels_sum - BIC_allmodels_sum(baseline_modelidx);
  654. BIC_min_model = baseline_modelidx;
  655. %causal_inf_strategies_abbrev = strrep(causal_inf_strategies,["ModelSelection", "ModelAveraging","ProbMatching"], "-"+["MS","MA","PM"]);
  656. causal_inf_strategies_abbrev = [];
  657. for strategy=1:num_strategies
  658. if(causal_inf_strategies(strategy)=="ModelSelection")
  659. causal_inf_strategies_abbrev = [causal_inf_strategies_abbrev,"-MS"];
  660. elseif(causal_inf_strategies(strategy)=="ModelAveraging")
  661. causal_inf_strategies_abbrev = [causal_inf_strategies_abbrev,"-MA"];
  662. else(causal_inf_strategies(strategy)=="ProbMatching")
  663. causal_inf_strategies_abbrev = [causal_inf_strategies_abbrev,"-PM"];
  664. end
  665. end
  666. allmodel_xticklabels = param_model_names' + causal_inf_strategies_abbrev;
  667. allmodel_xticklabels = allmodel_xticklabels';
  668. allmodel_xticklabels = allmodel_xticklabels(:);
  669. for lab_idx = 1:length(allmodel_xticklabels)
  670. lab = char(allmodel_xticklabels(lab_idx));
  671. allmodel_xticklabels(lab_idx) = convertCharsToStrings([upper(lab(1)) lab(2:end)]);
  672. end
  673. % AIC/BIC bootstrapping
  674. num_bootstrap_samps = 100000;
  675. NLL_sum_bootstraps = zeros(num_strategies*num_models,num_bootstrap_samps);
  676. AIC_sum_bootstraps = zeros(num_strategies*num_models,num_bootstrap_samps);
  677. BIC_sum_bootstraps = zeros(num_strategies*num_models,num_bootstrap_samps);
  678. rng('default')
  679. rng(0)
  680. for samp = 1:num_bootstrap_samps
  681. sampled_subj = datasample(1:num_subjects,num_subjects);
  682. for model=1:(num_strategies*num_models)
  683. NLL_sum_bootstraps(model, samp) = sum(NLL_allmodels(model, sampled_subj));
  684. AIC_sum_bootstraps(model, samp) = sum(AIC_allmodels(model, sampled_subj));
  685. BIC_sum_bootstraps(model, samp) = sum(BIC_allmodels(model, sampled_subj));
  686. end
  687. end
  688. NLL_bootstraps_diff = NLL_sum_bootstraps - NLL_sum_bootstraps(NLL_min_model,:);
  689. AIC_bootstraps_diff = AIC_sum_bootstraps - AIC_sum_bootstraps(AIC_min_model,:);
  690. BIC_bootstraps_diff = BIC_sum_bootstraps - BIC_sum_bootstraps(BIC_min_model,:);
  691. NLL_bootstraps_errorbars = prctile(NLL_bootstraps_diff,[2.5, 97.5], 2);
  692. AIC_bootstraps_errorbars = prctile(AIC_bootstraps_diff,[2.5, 97.5], 2);
  693. BIC_bootstraps_errorbars = prctile(BIC_bootstraps_diff,[2.5, 97,5], 2);
  694. % Plot
  695. bootstraps_errorbars_allstats = {NLL_bootstraps_errorbars, AIC_bootstraps_errorbars, BIC_bootstraps_errorbars};
  696. allstats = {NLL_allmodels_sumdiff, AIC_allmodels_sumdiff, BIC_allmodels_sumdiff};
  697. stat_names = ["\DeltaNLL", "\DeltaAIC", "\DeltaBIC"];
  698. if(is_plot)
  699. if(plot_BIC_only)
  700. statistics = 3;
  701. else
  702. statistics = 1:length(stat_names);
  703. end
  704. if(new_figure)
  705. tiledlayout(length(statistics),1, 'TileSpacing', 'tight','Padding', 'none')
  706. end
  707. stat_idx = 1;
  708. for statistic=statistics
  709. if(new_figure || length(statistics)>1)
  710. nexttile(stat_idx)
  711. end
  712. set(gca,'TickDir','out');
  713. bootstraps_errorbars = bootstraps_errorbars_allstats{statistic};
  714. mean_stat = allstats{statistic};
  715. hold on
  716. barh(1:(num_strategies*num_models),mean_stat,'FaceColor',barcolor, 'FaceAlpha',1)
  717. errorbar(mean_stat,(1:(num_strategies*num_models))', mean_stat-squeeze(bootstraps_errorbars(:, 1)),squeeze(bootstraps_errorbars(:, 2))-mean_stat,'horizontal', 'k.')
  718. yticks(1:(num_strategies*num_models));
  719. yticklabels(allmodel_xticklabels)
  720. ylim([0.2, num_strategies*num_models+0.7])
  721. set(gca, 'YDir','reverse')
  722. set(gca,'FontSize',9)
  723. xlabel(stat_names(statistic), 'FontSize', 9)
  724. stat_idx=stat_idx+1;
  725. end
  726. end
  727. % Create a .mat file with the delta NLL, AIC, and BIC tables
  728. AllData_ModelComparison_FinalTables = cell(1,3);
  729. for stat=1:3
  730. final_table = zeros(num_models*num_strategies,3);
  731. final_table(:,1) = bootstraps_errorbars_allstats{stat}(:,1); % 2.5% percentile
  732. final_table(:,2) = allstats{stat}; % Sum
  733. final_table(:,3) = bootstraps_errorbars_allstats{stat}(:,2); % 97.5% percentile
  734. AllData_ModelComparison_FinalTables{stat} = final_table;
  735. end
  736. end
  737. %%
  738. function [out_struct_allmodels] = alldata_modelcomparison_visualize_helper(causal_inf_strategy, param_model_names, model_path, data_path, LiftedSemiparamParamAll)
  739. if(nargin==0)
  740. causal_inf_strategy = "ModelSelection";
  741. is_plot=false;
  742. elseif(nargin==1)
  743. is_plot=false;
  744. end
  745. num_subjects = 15;
  746. % Get number of observations for BIC
  747. load(data_path+"BAV_data.mat");
  748. load(data_path+"BC_data.mat");
  749. load(data_path+"data_stratified_UV.mat");
  750. load(data_path+"data_stratified_UA.mat");
  751. data_UV = data_stratified_to_data(data_stratified_UV, false, true); % last argument is is_visual.
  752. data_UA = data_stratified_to_data(data_stratified_UA, false, false);
  753. UAV_data = cell(1,num_subjects);
  754. for i=1:num_subjects
  755. data_UA{i}(:,3) = 4;
  756. UAV_data{i} = [data_UV{i}; data_UA{i}];
  757. end
  758. n_data = zeros(1,15);
  759. n_data_bytasktype = zeros(4,15);
  760. for subjidx=1:num_subjects
  761. n_data(subjidx) = length(BAV_data{subjidx}) + length(BC_data{subjidx}) + length(UAV_data{subjidx});
  762. n_data_bytasktype(1,subjidx) = length(data_UV{subjidx});
  763. n_data_bytasktype(2,subjidx) = length(data_UA{subjidx});
  764. n_data_bytasktype(3,subjidx) = length(BC_data{subjidx});
  765. n_data_bytasktype(4,subjidx) = length(BAV_data{subjidx});
  766. end
  767. % save("NumTrials_allsubjects",'n_data_bytasktype','n_data')
  768. colors = brewermap(10,"Accent");
  769. colors = colors([1,2,3,5:10],:);
  770. noises = ["exp","exp","constant","exp","constant"];
  771. priors = ["GaussianLaplaceBothFixedZero", "SingleGaussian", "GaussianLaplaceBothFixedZero", "TwoGaussiansBothFixedZero","SingleGaussian"];
  772. helper_model_order = strrep(noises+"-"+priors,"constant","const");
  773. helper_model_order = strrep(helper_model_order,"BothFixedZero","");
  774. helper_model_order = ["paramBest","LiftedSemiparam",helper_model_order]; % Order used by this helper function to read files.
  775. num_models = length(priors);
  776. NLLs_param = zeros(num_models,15);
  777. num_parametric_model_params = zeros(num_models,1);
  778. idx=0;
  779. for i=1:num_models
  780. idx = idx+1;
  781. filename = "fittedparams_All_UBresc_"+noises(i)+"-"+priors(i)+"-"+causal_inf_strategy+"_rescalefree_lapseUniform.mat";
  782. load(model_path + filename)
  783. NLLs_param(idx,:) = min(F_vals,[],2);
  784. num_parametric_model_params(idx) = length(theta_fitted(1,:));
  785. if(noises(i)=="constant") % Remove place filler zeros in theta_fitted for k_vis, k_aud.
  786. num_parametric_model_params(idx) = num_parametric_model_params(idx)-2;
  787. end
  788. end
  789. [NLL_param_min, NLL_param_min_idx] = min(NLLs_param, [],1);
  790. % LiftedSemiparam model for this causal_inf_strategy
  791. filename_basis = "fittedparams_All_UBresc_SemiparamInspired_"+causal_inf_strategy+"_rescalefree_lapseUniform.mat";
  792. load(model_path + filename_basis)
  793. num_LiftedSemiparam_params = 9; %12+12+11
  794. if(LiftedSemiparamParamAll) % Count in the sigma_v(s), sigma_a(s), p(s) pivot points from the semiparametric fits
  795. num_LiftedSemiparam_params = num_LiftedSemiparam_params + 12+12+11;
  796. end
  797. [F_min_val, F_min_idx] = min(F_vals,[],1);
  798. % Order: paramBest,LiftedSemiParam, ParamModels.
  799. NLLs = [NLL_param_min;F_min_val;NLLs_param];
  800. % AIC
  801. AIC_LiftedSemiparam_best = 2.*(num_LiftedSemiparam_params+F_min_val);
  802. AIC_param_best = 2.*(num_parametric_model_params(NLL_param_min_idx)'+NLL_param_min);
  803. AICs = [AIC_param_best; AIC_LiftedSemiparam_best];
  804. for model=1:num_models
  805. AICs = [AICs; 2.*(num_parametric_model_params(repmat(model,1,num_subjects))'+NLLs_param(model,:))];
  806. end
  807. % BIC
  808. %load("NumTrials_allsubjects")
  809. BIC_LiftedSemiparam_best = 2.*F_min_val + num_LiftedSemiparam_params.*log(n_data);
  810. BIC_param_best = 2.*NLL_param_min + num_parametric_model_params(NLL_param_min_idx)'.*log(n_data);
  811. BICs = [BIC_param_best; BIC_LiftedSemiparam_best];
  812. for model=1:num_models
  813. BICs = [BICs; 2.*NLLs_param(model,:) + num_parametric_model_params(repmat(model,1,num_subjects))'.*log(n_data)];
  814. end
  815. [~,prompted_model_order] = ismember(param_model_names,helper_model_order);
  816. out_struct_allmodels.NLLs = NLLs(prompted_model_order,:);
  817. out_struct_allmodels.AICs = AICs(prompted_model_order,:);
  818. out_struct_allmodels.BICs = BICs(prompted_model_order,:);
  819. out_struct_allmodels.n_data = n_data;
  820. end
  821. %% Plot nonparam fitted sigma(s) and p(s) shapes
  822. function [] = semiparam_sigmafun_prior_visualization(fontsize, figspec, model_path)
  823. num_subjects = 15;
  824. num_params = 40;
  825. num_iters = 81*15;
  826. num_inits = 81;
  827. colors = brewermap(12,"Set3");
  828. colors2 = brewermap(8,"Set2");
  829. colors(2,:) = colors2(2,:);
  830. colors = [colors; colors2([4,7,8],:)];
  831. %colors = colors .* 0.9;
  832. filename_basis = "fittedparams_UJoint_Semiparam_rescalefree_lapseUniform.mat";
  833. load(model_path + filename_basis);
  834. theta_fitted_cmaes = theta_fitted;
  835. F_vals_cmaes = F_vals;
  836. ModelComponents.SPivot = [0,0.1,0.3,1,2,4,6,8,10,15,20,45];
  837. % Plot function shapes
  838. s_pivot = ModelComponents.SPivot;
  839. s_pivot_full = [-fliplr(s_pivot(2:end)), s_pivot];
  840. s_fine = linspace(0,15,2^7);
  841. s_fine_full = linspace(0,45,2^9);
  842. num_pivots = length(s_pivot);
  843. figure('Position', figspec);
  844. set(gcf, 'Color', 'w')
  845. T = tiledlayout(2,10,'TileSpacing','compact', "Padding","none");
  846. linewidth = 1;
  847. for fun_idx=1:3
  848. t = nexttile(T,[1,5]);
  849. set(t,'TickDir','out');
  850. hold(t,'on')
  851. pl = get(t, 'Position');
  852. switch fun_idx
  853. case 1
  854. h = axes('Parent', gcf, 'Position', [pl(1)+pl(3)*.61 pl(2)+pl(4)*0.72 pl(3)*0.35 pl(3)*0.35.*3/4]);
  855. case 2
  856. h = axes('Parent', gcf, 'Position', [pl(1)+pl(3)*.65 pl(2)+.07 pl(3)*0.33 pl(3)*0.35.*3/4]);
  857. case 3
  858. h = axes('Parent', gcf, 'Position', [pl(1)+pl(3)*.61 pl(2)+pl(4)*0.75 pl(3)*0.35 pl(3)*0.35.*3/4]);
  859. end
  860. %box(h,'on');
  861. hold(h,'on')
  862. set(h,'TickDir','out');
  863. for subj=1:num_subjects
  864. %[fun_idx, subj]
  865. theta=squeeze(theta_fitted_cmaes(subj,:));
  866. color = colors(subj,:);
  867. switch fun_idx
  868. case 1
  869. sigma_fun_vis_rel_high_pivots = cumsum(theta(1:num_pivots));
  870. sigma_fun_vis_rel_high_pivots = [fliplr(sigma_fun_vis_rel_high_pivots(2:end)), sigma_fun_vis_rel_high_pivots];
  871. sigma_fun_vis = @(s) min([repmat(45,length(s),1)' ; interp1(s_pivot_full, exp(sigma_fun_vis_rel_high_pivots), s, 'pchip')], [], 1);
  872. p=plot(t,s_fine, sigma_fun_vis(s_fine),'-','Color', color, 'LineWidth',linewidth);
  873. p.Color(4)=0.9;
  874. scatter1 = scatter(t,s_pivot_full, exp(sigma_fun_vis_rel_high_pivots),'o','MarkerFaceColor',color,'MarkerEdgeColor',color);
  875. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  876. scatter1.SizeData = linewidth.*5;
  877. ylabel(t,"$\sigma_{\mathrm{V}}(s)$", 'interpreter','latex', 'FontSize', fontsize)
  878. xlabel(t,"Visual stimulus location (\circ)", 'FontSize', fontsize)
  879. xlim(t,[0,15])
  880. ylim(t,[0,6.1])
  881. xl = xlim(t); yl = ylim(t);
  882. yticks(t,0:6)
  883. t.XAxis.FontSize = 9;
  884. t.YAxis.FontSize = 9;
  885. p=plot(h, s_fine_full, sigma_fun_vis(s_fine_full),'-', 'Color',color);
  886. p.Color(4)=0.9;
  887. scatter1 = scatter(h, s_pivot_full, min(45,exp(sigma_fun_vis_rel_high_pivots)),'o','MarkerFaceColor',color,'MarkerEdgeColor',color);
  888. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  889. scatter1.SizeData = 1;
  890. rectangle('Position',[xl(1) yl(1) xl(2)-xl(1) yl(2)-yl(1)])
  891. %ylabel(h,"$\sigma_{\mathrm{V}}(s)$", 'interpreter','latex', 'FontSize', fontsize)
  892. xlim(h,[0,45])
  893. ylim(h,[0,45])
  894. xticks(h,0:15:45)
  895. yticks(h,0:15:45)
  896. h.XAxis.FontSize = 9;
  897. h.YAxis.FontSize = 9;
  898. case 2
  899. sigma_fun_aud_pivots = cumsum(theta((num_pivots+1):(2*num_pivots)));
  900. sigma_fun_aud_pivots = [fliplr(sigma_fun_aud_pivots(2:end)), sigma_fun_aud_pivots];
  901. sigma_fun_aud = @(s) min([repmat(45,length(s),1)' ; interp1(s_pivot_full, exp(sigma_fun_aud_pivots), s, 'pchip')], [], 1);
  902. p=plot(t,s_fine, sigma_fun_aud(s_fine),'-', 'Color',color, 'LineWidth', linewidth);
  903. p.Color(4)=0.9;
  904. scatter1 = scatter(t,s_pivot_full, exp(sigma_fun_aud_pivots),'o','MarkerFaceColor',color,'MarkerEdgeColor',color);
  905. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  906. scatter1.SizeData = linewidth.*5;
  907. ylabel(t,"$\sigma_{\mathrm{A}}(s)$", 'interpreter','latex', 'FontSize', fontsize)
  908. xlabel(t,"Auditory stimulus location (\circ)", 'FontSize', fontsize)
  909. xlim(t,[0,15])
  910. ylim(t,[0,6.1])
  911. xl = xlim(t); yl = ylim(t);
  912. yticks(t,0:6)
  913. t.XAxis.FontSize = 9;
  914. t.YAxis.FontSize = 9;
  915. p=plot(h, s_fine_full, sigma_fun_aud(s_fine_full),'-', 'Color',color);
  916. p.Color(4)=0.9;
  917. scatter1 = scatter(h, s_pivot_full, min(45,exp(sigma_fun_aud_pivots)),'o','MarkerFaceColor',color,'MarkerEdgeColor',color);
  918. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  919. scatter1.SizeData = 1;
  920. rectangle('Position',[xl(1) yl(1) xl(2)-xl(1) yl(2)-yl(1)])
  921. %ylabel(h,"$\sigma_{\mathrm{A}}(s)$", 'interpreter','latex', 'FontSize', fontsize)
  922. xlim(h,[0,45])
  923. ylim(h,[0,45])
  924. xticks(h,0:15:45)
  925. yticks(h,0:15:45)
  926. h.XAxis.FontSize = 9;
  927. h.YAxis.FontSize = 9;
  928. case 3
  929. prior_pivots = cumsum([1,theta((2*num_pivots+1):(3*num_pivots-1))]);
  930. prior_pivots = [fliplr(prior_pivots(2:end)), prior_pivots];
  931. prior = @(s) exp(interp1(s_pivot_full, prior_pivots, s, 'pchip'));
  932. s_fine_full_width = s_fine_full(2) - s_fine_full(1);
  933. normalization_constant = 1./(qtrapz(prior(s_fine_full).*s_fine_full_width));
  934. p=plot(t,s_fine_full, (prior(s_fine_full).*normalization_constant),'-', 'Color',color, 'LineWidth', linewidth);
  935. p.Color(4)=0.9;
  936. %scatter(s_pivot_full, prior_pivots,"o", "MarkerFaceAlpha",0.1)
  937. scatter1 = scatter(t,s_pivot_full, exp(prior_pivots).*normalization_constant,'o','MarkerFaceColor',color,'MarkerEdgeColor',color);
  938. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  939. scatter1.SizeData = linewidth.*5;
  940. ylabel(t,"$p(s)$", 'interpreter','latex', 'FontSize', fontsize)
  941. xlabel(t,"Visual/Auditory stimulus location (\circ)", 'FontSize', fontsize)
  942. xlim(t,[0,3])
  943. ylim(t,[0,5])
  944. xl = xlim(t); yl = ylim(t);
  945. xticks(t,0:1:3);
  946. yticks(t, 0:1:5);
  947. t.XAxis.FontSize = 9;
  948. t.YAxis.FontSize = 9;
  949. p=plot(h, s_fine_full, log(prior(s_fine_full).*normalization_constant),'-', 'Color',color);
  950. p.Color(4)=0.9;
  951. scatter1 = scatter(h, s_pivot_full, log(exp(prior_pivots).*normalization_constant),'o','MarkerFaceColor',color,'MarkerEdgeColor',color);
  952. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  953. scatter1.SizeData = 1;
  954. %rectangle('Position',[xl(1) yl(1) xl(2)-xl(1) yl(2)-yl(1)])
  955. xlim(h,[0,45])
  956. ylim(h,[-20,3])
  957. xticks(h,0:15:45)
  958. yticks(h, -20:10:0);
  959. h.XAxis.FontSize = 9;
  960. h.YAxis.FontSize = 9;
  961. ylabel(h,"$\log p(s)$", 'interpreter','latex', 'FontSize', fontsize)
  962. end
  963. end
  964. ax.XAxis.FontSize = fontsize;
  965. ax.YAxis.FontSize = fontsize;
  966. end
  967. x_labels_pos = (3*num_pivots):num_params;
  968. x_labels = "$"+{"\alpha_\mathrm{med}", "\alpha_\mathrm{low}", "\lambda","\sigma_\mathrm{motor}","\rho_\mathrm{A}"}+"$";
  969. t=nexttile(T,[1,3]);
  970. boxplot(theta_fitted_cmaes(:,x_labels_pos([1,2,5])), 'Color','k')
  971. hold on
  972. idx=0
  973. for param=[1,2,5]
  974. idx=idx+1
  975. for subj=1:num_subjects
  976. scatter1 = scatter(repmat(idx,1), theta_fitted_cmaes(subj,x_labels_pos(param)),'o','MarkerFaceColor','k','MarkerEdgeColor','none');
  977. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  978. scatter1.SizeData = 5;
  979. end
  980. end
  981. xticks(1:3);
  982. xaxisproperties=get(gca, 'XAxis');
  983. xaxisproperties.TickLabelInterpreter = 'latex';
  984. xticklabels(x_labels([1,2,5]));
  985. %xtickangle(45);
  986. ax=gca;
  987. ax.XAxis.FontSize = fontsize;
  988. xlim([1-0.5,idx+0.5])
  989. ylim([0, Inf])
  990. yticks(0:1:5)
  991. t.XAxis.FontSize = 9;
  992. t.YAxis.FontSize = 9;
  993. box off
  994. set(gca,'TickDir','out');
  995. t=nexttile(T);
  996. boxplot(theta_fitted_cmaes(:,x_labels_pos(3)), 'Color','k')
  997. hold on
  998. for subj=1:num_subjects
  999. scatter1 = scatter(1, theta_fitted_cmaes(subj,x_labels_pos(3)),'o','MarkerFaceColor','k','MarkerEdgeColor','none');
  1000. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  1001. scatter1.SizeData = 5;
  1002. end
  1003. % scatter1 = scatter(repmat(1,num_subjects,1), theta_fitted_cmaes(:,x_labels_pos(3)),'o','MarkerFaceColor','k','MarkerEdgeColor','k');
  1004. % scatter1.SizeData = 5;
  1005. xticks([1])
  1006. xtickangle(0);
  1007. yticks(0:0.005:0.015)
  1008. xaxisproperties=get(gca, 'XAxis');
  1009. xaxisproperties.TickLabelInterpreter = 'latex';
  1010. xticklabels(x_labels(3));
  1011. ax=gca;
  1012. ax.XAxis.FontSize = fontsize;
  1013. xlim([0.5,1.5])
  1014. ylim([0, 0.015])
  1015. t.XAxis.FontSize = 9;
  1016. t.YAxis.FontSize = 9;
  1017. set(gca,'TickDir','out');
  1018. box off
  1019. t=nexttile(T);
  1020. boxplot(theta_fitted_cmaes(:,x_labels_pos(4)), 'Color','k')
  1021. hold on
  1022. for subj=1:num_subjects
  1023. scatter1 = scatter(1, theta_fitted_cmaes(subj,x_labels_pos(4)),'o','MarkerFaceColor','k','MarkerEdgeColor','none');
  1024. %scatter1.MarkerFaceAlpha = .2; scatter1.MarkerEdgeAlpha = .2;
  1025. scatter1.SizeData = 5;
  1026. end
  1027. % scatter1 = scatter(repmat(1,num_subjects,1), theta_fitted_cmaes(:,x_labels_pos(4)),'o','MarkerFaceColor','k','MarkerEdgeColor','k');
  1028. % scatter1.SizeData = 5;
  1029. xticks([1])
  1030. yticks(0:0.1:0.5);
  1031. xtickangle(0);
  1032. xaxisproperties=get(gca, 'XAxis');
  1033. xaxisproperties.TickLabelInterpreter = 'latex';
  1034. xticklabels(x_labels(4));
  1035. ax=gca;
  1036. ax.XAxis.FontSize = fontsize;
  1037. xlim([0.5,1.5])
  1038. ylim([0, 0.5])
  1039. t.XAxis.FontSize = 9;
  1040. t.YAxis.FontSize = 9;
  1041. set(gca,'TickDir','out');
  1042. box off
  1043. %set(gca,'fontsize', fontsize)
  1044. end
  1045. %%
  1046. function [] = sigmafun_prior_examples(fontsize)
  1047. s_grid = -45:0.1:45;
  1048. sigma0_vals = [0.5,1,2,3];
  1049. colors = brewermap(12,"Set1");
  1050. hetero_type = "exp";
  1051. sigma_fun_constant = heterotype_to_sigmafun("constant");
  1052. sigma_fun_exp = heterotype_to_sigmafun("exp");
  1053. subplot(2,3,1)
  1054. set(gca,'TickDir','out');
  1055. hold on
  1056. for i=1:length(sigma0_vals)
  1057. plot(s_grid, repmat(sigma0_vals(i), length(s_grid),1), "-", 'Color', colors(i,:));
  1058. end
  1059. lg = legend("$\sigma_0="+sigma0_vals+"$", 'Interpreter', 'latex', 'FontSize', fontsize);
  1060. set(lg,'Box','off')
  1061. ylim([0,6])
  1062. yticks(0:1:6)
  1063. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1064. ylabel("$\sigma(s)$", 'Interpreter', 'latex', 'FontSize', fontsize)
  1065. title("Constant sensory noise", 'FontSize', fontsize+1)
  1066. sigma0_vals = [0.5,1,1,1,3];
  1067. k1_vals = [1,1,2,1,1];
  1068. k2_vals = [0.1,0.1,0.1,0.5 0.5];
  1069. subplot(2,3,2)
  1070. set(gca,'TickDir','out');
  1071. hold on
  1072. for i=1:length(sigma0_vals)
  1073. plot(s_grid, sigma_fun_exp(s_grid,sigma0_vals(i), [k1_vals(i),k2_vals(i)]), "-", 'Color', colors(i,:));
  1074. end
  1075. lg = legend("$\sigma_0="+sigma0_vals+", k_1="+k1_vals+", k_2="+k2_vals+"$", 'Interpreter', 'latex', 'FontSize', fontsize);
  1076. set(lg,'Box','off')
  1077. lg.Position(1:2) = [0.63,0.8];
  1078. ylim([0,6])
  1079. yticks(0:1:6)
  1080. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1081. title("Exponential sensory noise", 'FontSize', fontsize+1)
  1082. % Priors
  1083. sigma_s_vals = [3, 5, 8, 10];
  1084. subplot(2,3,4)
  1085. set(gca,'TickDir','out');
  1086. hold on
  1087. for i=1:length(sigma_s_vals)
  1088. plot(s_grid, normpdf(s_grid, 0, sigma_s_vals(i)), "-", 'Color', colors(i,:))
  1089. end
  1090. lg = legend("$\sigma_s="+sigma_s_vals+"$", 'Interpreter', 'latex', 'FontSize', fontsize);
  1091. set(lg,'Box','off')
  1092. lg.Position(1) = 0.25;
  1093. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1094. ylabel("$p(s)$", 'Interpreter', 'latex', 'FontSize', fontsize)
  1095. title("SingleGaussian prior", 'FontSize', fontsize+1)
  1096. ylim([0,0.15])
  1097. yticks(0:0.05:0.15)
  1098. sigma_s_vals = [8, 8, 8, 15].*2;
  1099. b_vals = [1,2,1,2].*2;
  1100. w_vals = [0.3, 0.3, 0.5, 0.5];
  1101. subplot(2,3,6)
  1102. set(gca,'TickDir','out');
  1103. hold on
  1104. for i=1:length(sigma_s_vals)
  1105. plot(s_grid, (1-w_vals(i)).*normpdf(s_grid, 0, sigma_s_vals(i)) + w_vals(i).*1./(2.*b_vals(i)).*exp(-abs(s_grid)./b_vals(i)), "-", 'Color', colors(i,:))
  1106. end
  1107. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1108. lg = legend("$\sigma_s="+sigma_s_vals+", b="+b_vals+", w="+w_vals+"$", 'Interpreter', 'latex', 'FontSize', fontsize);
  1109. set(lg,'Box','off')
  1110. lg.Position(1:2) = [0.69,0.48];
  1111. title("GaussianLaplace prior", 'FontSize', fontsize+1)
  1112. ylim([0,0.15])
  1113. yticks(0:0.05:0.15)
  1114. sigma_s_vals = [3,5,8,10];
  1115. sigma_s2_vals = [8, 8, 8, 15].*2 - sigma_s_vals;
  1116. w_vals = [0.3, 0.3, 0.7, 0.7];
  1117. subplot(2,3,5)
  1118. set(gca,'TickDir','out');
  1119. hold on
  1120. for i=1:length(sigma_s_vals)
  1121. plot(s_grid, (1-w_vals(i)).*normpdf(s_grid, 0, sigma_s_vals(i)) + w_vals(i).*normpdf(s_grid, 0, sigma_s_vals(i)+sigma_s2_vals(i)), "-", 'Color', colors(i,:))
  1122. end
  1123. ylim([0,0.15])
  1124. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1125. lg = legend("$\sigma_s="+sigma_s_vals+", \sigma_{\Delta}="+sigma_s2_vals+", w="+w_vals+"$", 'Interpreter', 'latex', 'FontSize', fontsize);
  1126. set(lg,'Box','off')
  1127. lg.Position(1:2) = [0.42, 0.348];
  1128. title("TwoGaussians prior", 'FontSize', fontsize+1)
  1129. ylim([0,0.15])
  1130. yticks(0:0.05:0.15)
  1131. %set(gca,'fontsize', fontsize)
  1132. end
  1133. %%
  1134. function [] = allindvsubjplots_to_onesubjplot(save_name, subjidx, fitted_on_all_data, fontsize, figspecs, figpath)
  1135. % This function assumes that the individual-level plots have been saved
  1136. % as .fig files.
  1137. close all;
  1138. if(~fitted_on_all_data)
  1139. F1 = openfig(figpath + save_name + "_Individualmean.fig");
  1140. t1 = nexttile(subjidx);
  1141. ax1=gca;
  1142. F2 = openfig(figpath + save_name + "_IndividualSD.fig");
  1143. t2 = nexttile(subjidx);
  1144. ax2=gca;
  1145. figure('Position', figspecs);
  1146. set(gcf, 'Color', 'w')
  1147. T=tiledlayout(1,2,'Padding', 'tight', 'TileSpacing', 'tight');
  1148. t1 = nexttile(1);
  1149. set(gca,'TickDir','out');
  1150. hold on
  1151. plot([-20,20],[0,0],"k--",'HandleVisibility','off');
  1152. fig1 = get(ax1,'children');
  1153. copyobj(fig1, t1);
  1154. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1155. ylabel("Bias (\circ)", 'FontSize', fontsize)
  1156. ylim([-20,20])
  1157. xticks(-20:10:20)
  1158. set(gca,"FontSize",9)
  1159. t2 = nexttile(2);
  1160. fig2 = get(ax2,'children');
  1161. set(gca,'TickDir','out');
  1162. copyobj(fig2, t2);
  1163. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1164. ylabel("SD of location response (\circ)", 'FontSize', fontsize)
  1165. h = findall(gca, 'LineStyle', '-');
  1166. for i=1:4
  1167. h(i).HandleVisibility="off";
  1168. end
  1169. lg = legend("Visual (high reliability)","Visual (med. reliability)", "Visual (low reliability)", "Auditory");
  1170. set(lg,'Box','off')
  1171. lg.FontSize = max(9,fontsize-1);
  1172. lg.Location="northeast";
  1173. lg.ItemTokenSize(1) = 10;
  1174. xticks(-20:10:20)
  1175. set(gca,"FontSize",9)
  1176. else
  1177. F1 = openfig(figpath + save_name + "-UAV_Individualmean.fig");
  1178. t1 = nexttile(subjidx);
  1179. ax1=gca;
  1180. F2 = openfig(figpath + save_name + "-UAV_IndividualSD.fig");
  1181. t2 = nexttile(subjidx);
  1182. ax2=gca;
  1183. F3 = openfig(figpath + save_name + "-BC_Individual.fig");
  1184. ax3_center = F3.Children.Children((end-subjidx+1)).Children(2);
  1185. ax3_periphery = F3.Children.Children((end-subjidx+1)).Children(1);
  1186. F4 = openfig(figpath + save_name + "-BV_Individual.fig");
  1187. ax4_right = F4.Children.Children((end-subjidx+1)).Children(1);
  1188. ax4_center = F4.Children.Children((end-subjidx+1)).Children(2);
  1189. ax4_left = F4.Children.Children((end-subjidx+1)).Children(3);
  1190. F5 = openfig(figpath + save_name + "-BA_Individual.fig");
  1191. ax5_right = F5.Children.Children((end-subjidx+1)).Children(1);
  1192. ax5_center = F5.Children.Children((end-subjidx+1)).Children(2);
  1193. ax5_left = F5.Children.Children((end-subjidx+1)).Children(3);
  1194. %% Move to new plot
  1195. figure('Position', figspecs);
  1196. set(gcf, 'Color', 'w')
  1197. T=tiledlayout(2,12,'Padding', 'tight', 'TileSpacing', 'tight');
  1198. t12=tiledlayout(T,1,2, 'Padding','none','TileSpacing','tight');
  1199. t12.Layout.Tile = 1;
  1200. t12.Layout.TileSpan = [1 6];
  1201. t1 = nexttile(t12);
  1202. hold on
  1203. set(gca,'TickDir','out');
  1204. plot([-20,20],[0,0],"k--",'HandleVisibility','off');
  1205. fig1 = get(ax1,'children');
  1206. copyobj(fig1, t1);
  1207. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1208. ylabel("Bias of location response (\circ)", 'FontSize', fontsize)
  1209. ylim([-20,20])
  1210. ttl = title('(a)', "Fontsize", 10);
  1211. ttl.Units = 'Normalize';
  1212. ttl.Position(1) = -0.3; % use negative values (ie, -0.1) to move further left
  1213. ttl.HorizontalAlignment = 'left';
  1214. xticks(-20:10:20)
  1215. set(gca,"FontSize",9)
  1216. t2 = nexttile(t12);
  1217. set(gca,'TickDir','out');
  1218. fig2 = get(ax2,'children');
  1219. copyobj(fig2, t2);
  1220. xlabel("Stimulus location (\circ)", 'FontSize', fontsize)
  1221. ylabel("SD of location response (\circ)", 'FontSize', fontsize)
  1222. ylim([0,9])
  1223. h = findall(gca, 'LineStyle', '-');
  1224. for i=1:4
  1225. h(i).HandleVisibility="off";
  1226. end
  1227. lg = legend("Visual (high rel.)","Visual (med. rel.)", "Visual (low rel.)", "Auditory");
  1228. set(lg,'Box','off')
  1229. lg.FontSize = 9;
  1230. lg.ItemTokenSize(1) = 10;
  1231. xticks(-20:10:20)
  1232. set(gca,"FontSize",9)
  1233. % BC
  1234. %t3 = nexttile([1,2]);
  1235. t3=tiledlayout(T,1,2, 'Padding','none','TileSpacing','compact');
  1236. t3.Layout.Tile = 7;
  1237. t3.Layout.TileSpan = [1 6];
  1238. xlabel(t3,"Stimulus location disparity, {\its}_A– {\its}_V (\circ)", 'FontSize',fontsize)
  1239. ylabel(t3,{"{\rm \fontsize{9} {Proportion responding "+ '"'+'same'+ '"'+"}}"}, 'FontSize',fontsize);
  1240. BC_strat_names = ["Center", "Periphery"];
  1241. for strats=1:2
  1242. tt = nexttile(t3);
  1243. set(gca,'TickDir','out');
  1244. hold on;
  1245. if(strats==1)
  1246. fig31 = get(ax3_center,'children');
  1247. copyobj(fig31, tt);
  1248. ttl = title('(b)', "Fontsize", 10);
  1249. ttl.Units = 'Normalize';
  1250. ttl.Position(1) = -0.3; % use negative values (ie, -0.1) to move further left
  1251. ttl.HorizontalAlignment = 'left';
  1252. subtitle(tt,"Center",'Fontsize', fontsize, 'FontWeight','bold')
  1253. yticks(0:0.2:1)
  1254. else
  1255. fig32 = get(ax3_periphery,'children');
  1256. copyobj(fig32, tt);
  1257. subtitle(tt,"Periphery",'Fontsize', fontsize, 'FontWeight','bold')
  1258. yticks([])
  1259. end
  1260. h = findall(gca, 'LineStyle', '-');
  1261. for i=1:3
  1262. h(i).HandleVisibility="off";
  1263. end
  1264. xlim([-30,30])
  1265. ylim([0,1])
  1266. xticks(-30:15:30)
  1267. xtickangle(0)
  1268. set(gca,"FontSize",9)
  1269. lg = legend({"High vis. rel.","Med. vis. rel.","Low vis. rel."});
  1270. set(lg,'Box','off')
  1271. lg.FontSize = 9;
  1272. lg.Location="south";
  1273. lg.ItemTokenSize(1) = 10;
  1274. end
  1275. BAV_strat_names = ["Left","Center","Right"];
  1276. t4=tiledlayout(T,1,3, 'Padding','none','TileSpacing','compact');
  1277. t4.Layout.Tile = 13;
  1278. t4.Layout.TileSpan = [1 6];
  1279. xlabel(t4, "Stimulus location disparity, {\its}_A– {\its}_V (\circ)", 'FontSize',fontsize)
  1280. ylabel(t4,"{\rm \fontsize{10} {Visual bias (\circ)}}");
  1281. for strats=1:3
  1282. tt = nexttile(t4);
  1283. set(gca,'TickDir','out');
  1284. hold on;
  1285. if(strats==1)
  1286. fig4 = get(ax4_left,'children');
  1287. copyobj(fig4, tt);
  1288. ttl = title('(c)', "Fontsize", 10);
  1289. ttl.Units = 'Normalize';
  1290. ttl.Position(1) = -0.4; % use negative values (ie, -0.1) to move further left
  1291. ttl.HorizontalAlignment = 'left';
  1292. subtitle(tt,"Left",'Fontsize', fontsize, 'FontWeight','bold')
  1293. elseif(strats==2)
  1294. yticks([])
  1295. fig4 = get(ax4_center,'children');
  1296. copyobj(fig4, tt);
  1297. subtitle(tt,"Center",'Fontsize', fontsize, 'FontWeight','bold')
  1298. else
  1299. yticks([])
  1300. fig4 = get(ax4_right,'children');
  1301. copyobj(fig4, tt);
  1302. subtitle(tt,"Right",'Fontsize', fontsize, 'FontWeight','bold')
  1303. end
  1304. h = findall(gca, 'LineStyle', '-');
  1305. for i=1:3
  1306. h(i).HandleVisibility="off";
  1307. end
  1308. xlim([-35,35])
  1309. ylim([-15,15])
  1310. xticks(-30:15:30)
  1311. xtickangle(0)
  1312. set(gca,"FontSize",9)
  1313. lg = legend({"High vis. rel.","Med. vis. rel.","Low vis. rel."});
  1314. set(lg,'Box','off')
  1315. lg.FontSize = 9;
  1316. lg.Location="north";
  1317. lg.ItemTokenSize(1) = 10;
  1318. end
  1319. t5=tiledlayout(T,1,3, 'Padding','none','TileSpacing','compact');
  1320. t5.Layout.Tile = 19;
  1321. t5.Layout.TileSpan = [1 6];
  1322. xlabel(t5, "Stimulus location disparity, {\its}_A– {\its}_V (\circ)", 'FontSize',fontsize)
  1323. ylabel(t5,"{\rm \fontsize{10} {Auditory bias (\circ)}}");
  1324. for strats=1:3
  1325. tt = nexttile(t5);
  1326. set(gca,'TickDir','out');
  1327. hold on;
  1328. if(strats==1)
  1329. fig5 = get(ax5_left,'children');
  1330. copyobj(fig5, tt);
  1331. ttl = title('(d)', "Fontsize", 10);
  1332. ttl.Units = 'Normalize';
  1333. ttl.Position(1) = -0.4; % use negative values (ie, -0.1) to move further left
  1334. ttl.HorizontalAlignment = 'left';
  1335. subtitle(tt,"Left",'Fontsize', fontsize, 'FontWeight','bold')
  1336. elseif(strats==2)
  1337. yticks([])
  1338. fig5 = get(ax5_center,'children');
  1339. copyobj(fig5, tt);
  1340. subtitle(tt,"Center",'Fontsize', fontsize, 'FontWeight','bold')
  1341. else
  1342. yticks([])
  1343. fig5 = get(ax5_right,'children');
  1344. copyobj(fig5, tt);
  1345. subtitle(tt,"Right",'Fontsize', fontsize, 'FontWeight','bold')
  1346. end
  1347. h = findall(gca, 'LineStyle', '-');
  1348. for i=1:3
  1349. h(i).HandleVisibility="off";
  1350. end
  1351. set(gca,"FontSize",9)
  1352. xlim([-35,35])
  1353. ylim([-15,15])
  1354. xticks(-30:15:30)
  1355. xtickangle(0)
  1356. lg = legend({"High vis. rel.","Med. vis. rel.","Low vis. rel."});
  1357. set(lg,'Box','off')
  1358. lg.FontSize = 9;
  1359. lg.Location="north";
  1360. lg.ItemTokenSize(1) = 10;
  1361. switch strats
  1362. case 2
  1363. lg.Position(1) = 0.46;
  1364. lg.Position(2) = 0.7725;
  1365. case 3
  1366. lg.Position(1) = 0.74;
  1367. lg.Position(2) = 0.7725;
  1368. end
  1369. end
  1370. end
  1371. end

manuscript_allplots.m at commit b065a19, no license · at the source

Overview

Authors: Shuze Liu1, Trevor Holland2, Wei Ji Ma2,3, Luigi Acerbi4
  1. PhD Program in Neuroscience, Harvard University, Cambridge, Massachusetts, United States of America‌‌
  2. Previously at Department of Neuroscience, Baylor College of Medicine, Houston, Texas, United States of America
  3. Center for Neural Science and Department of Psychology, New York University, New York City, New York, United States of America
  4. Department of Computer Science, University of Helsinki, Helsinki, Uusimaa, Finland
Institutions: Harvard University (United States); Baylor College of Medicine (United States); New York University (United States); University of Helsinki (Finland)
Journal: PLoS computational biology, volume 22, issue 5, article e1014251
Dates: received 13 June 2025; accepted 20 April 2026; published online 8 May 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1371/journal.pcbi.1014251 · PMID 42102227 · PMCID PMC13155690 · OpenAlex W4411170078
Open access: gold, a free copy (OpenAlex)
Status: code verified
Categories: human (organism), cognitive (subfield)
Methods: Smoothing, state filtering, decompositions
MeSH: Brain*, Models, Neurological*, Perception*, Bayes Theorem, Causality, Humans, Neural Pathways, Sensation (* major topic)
Journal subjects: Biology and Life Sciences, Neuroscience, Cognitive Science, Cognitive Psychology, Perception, Sensory Perception, Psychology, Social Sciences, Vision, Physical Sciences, Mathematics, Statistics, Statistical Noise, Gaussian Noise, Computer and Information Sciences, Data Management, Data Visualization, Organisms, Eukaryota, Plants, Flowering Plants, Vanilla, Research and Analysis Methods, Separation Processes, Distillation, Sensory Cues, Animals, Vertebrates, Amniotes, Birds, Zoology
Topic: Multisensory perception and integration (Experimental and Cognitive Psychology, Psychology), according to OpenAlex
Funding: Research Council of Finland (356498, 358980)
Citations: not cited yet (Europe PMC); 111 references in the paper

Abstract

The perception of the external world relies on integrating information from multiple sensory modalities. To do this effectively, the brain must determine whether sensory signals come from a common source and, if so, combine them to reduce perceptual uncertainty. While Bayesian observer models have been successful in accounting for multisensory causal inference decisions by humans, they typically rely on simplifying assumptions that may not reflect the true complexity of human perception. In this study, we challenge two assumptions common in Bayesian multisensory perception models: homoskedastic (constant across space) sensory noise and Gaussian priors. We collected an auditory-visual perceptual dataset featuring both unisensory and bisensory tasks, where participants must either provide stimulus location estimates or same-different source judgments. Subsequently, we developed a flexible semiparametric approach that allowed us to infer the sensory noise and prior shapes from participants’ data, and subsequently ‘distill’ them into new model classes through visual inspection of the semiparametrically fitted function shapes. We find that human multisensory perception is best described by an eccentricity-dependent sensory noise that plateaus in the periphery and a prior distribution with a narrow central peak and smoother tails. We also found evidence for auditory range recalibration and increased sensory noise in multisensory conditions, suggesting complex interactions between sensory modalities. These findings deviate substantially from traditional modeling assumptions and highlight the value of data-driven rather than theory-driven modeling assumptions. Overall, our study demonstrates the value of systematically exploring model assumptions in multisensory research and provides a new set of modeling tools for perceptual causal inference.

Reproduced under the paper's license (CC BY), from the paper cited above.

Repository

Its files are read in the Code ↔ Paper reader above, with 18 matches between paragraphs and lines of code.

LSZ2001/Audiovisual-causal-inference

License: none: the authors keep all their rights
State: the link answers, verified on 28 September 2026
Evidence: files inventoried
Commit: b065a1984a7a2bbc9b6df5e06c9caddc927961ea, 20 January 2026
Languages: MATLAB (42), Jupyter (2)
Size: 288 files, 44 scripts
Software Heritage: not archived
Found in: “Data Availability”
Holds: README, 1 notebook
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Availability: 1 check, the latest on 28 September 2026: the link answers
  • 28 September 2026: the link answers
45 files

The paper's code and data availability statement is in the Data section.

Tracing map

Proposed by the machine: these links were found in the paper and verified at the source, without human review. The map will receive a Zenodo DOI once one of the paper's authors has validated it with their ORCID.

What the map holds:

  • 1 repository of the authors' code, each at its verified commit, with its license and how the link was found in the paper;
  • 44 scripts, each with its path and the digest of its content;
  • 18 matches between paragraphs of the paper and lines of the code (method lexical-v1);
  • neither the text of the paper nor the code itself.

Its JSON (tracing-map.json) is deposited on Zenodo with its DOI once the map is validated.

Data

No dataset and no data link were found in the paper.

Data Availability

All data and analysis code are available at https://github.com/LSZ2001/Audiovisual-causal-inference.

Reproduced under the paper's license (CC BY), from the paper cited above.

Versions

The history of this record: each version stored by the harvester or made by a correction of its authors or of the maintainers of its code, and what changed in its facts. The texts of the paper (its abstract, its availability statements) are not part of it; versions that changed only those are not listed.

Version 1, 28 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 8 MeSH terms, 1 funder, 96 references.

Cite

This paper

Liu, S., Holland, T., Ma, W. J., & Acerbi, L. (2026). Distilling noise characteristics and prior expectations in multisensory causal inference. PLoS computational biology, 22(5), e1014251. https://doi.org/10.1371/journal.pcbi.1014251

BibTeX

@article{liu2026distilling,
author = {Liu, Shuze and Holland, Trevor and Ma, Wei Ji and Acerbi, Luigi},
title = {{Distilling noise characteristics and prior expectations in multisensory causal inference}},
journal = {PLoS computational biology},
year = {2026},
month = may,
volume = {22},
number = {5},
pages = {e1014251},
publisher = {PLOS},
issn = {1553-734X},
doi = {10.1371/journal.pcbi.1014251},
url = {https://doi.org/10.1371/journal.pcbi.1014251},
pmid = {42102227},
pmcid = {PMC13155690}
}

RIS

TY - JOUR
AU - Liu, Shuze
AU - Holland, Trevor
AU - Ma, Wei Ji
AU - Acerbi, Luigi
TI - Distilling noise characteristics and prior expectations in multisensory causal inference
T2 - PLoS computational biology
J2 - PLoS Comput Biol
PY - 2026
DA - 2026/05/08
VL - 22
IS - 5
SP - e1014251
SN - 1553-734X
PB - PLOS
DO - 10.1371/journal.pcbi.1014251
UR - https://doi.org/10.1371/journal.pcbi.1014251
LA - en
ER -

CSL-JSON

{
"id": "10.1371/journal.pcbi.1014251",
"type": "article-journal",
"title": "Distilling noise characteristics and prior expectations in multisensory causal inference",
"container-title": "PLoS computational biology",
"author": [
{
"family": "Liu",
"given": "Shuze"
},
{
"family": "Holland",
"given": "Trevor"
},
{
"family": "Ma",
"given": "Wei Ji"
},
{
"family": "Acerbi",
"given": "Luigi"
}
],
"container-title-short": "PLoS Comput Biol",
"volume": "22",
"issue": "5",
"page": "e1014251",
"DOI": "10.1371/journal.pcbi.1014251",
"PMID": "42102227",
"PMCID": "PMC13155690",
"ISSN": "1553-734X",
"publisher": "PLOS",
"URL": "https://doi.org/10.1371/journal.pcbi.1014251",
"language": "en",
"issued": {
"date-parts": [
[
2026,
5,
8
]
]
}
}

The tracing map gets a citation of its own once an author has validated it and it has a DOI.

Similar papers

The papers with a page that share the most with this one: the tools found in their code, their categories, datasets, cited references and authors, the rarest counting most.

[1] doi:10.1038/s41467-026-73947-8 [code]
Frontal cortex organization supporting audiovisual processing during naturalistic viewing.
Journal: Nature communications
In common: cognitive, 7 references
[2] doi:10.7554/elife.101277 [code]
Endogenous precision of the number sense.
Journal: eLife
In common: cognitive, 5 references
[3] doi:10.1016/j.isci.2026.115708 [code]
Integrating multiple sensory modalities during dyadic interactions drives self-other distinction at the behavioral and electrocortical level.
Journal: iScience
In common: 5 references
[4] doi:10.1038/s41593-026-02255-7 [code]
Neural circuits encode prior knowledge of temporal statistics.
Journal: Nature neuroscience
In common: Statistics and Machine Learning Toolbox, 4 references
[5] doi:10.1038/s41467-026-69633-4 [code]
Visuomotor decision-making through multifeature convergence in the larval zebrafish hindbrain.
Journal: Nature communications
In common: cognitive, 3 references
[6] doi:10.1038/s41467-026-73032-0 [code]
Fast efficient coding and sensory adaptation in gain-adaptive recurrent networks.
Journal: Nature communications
In common: 3 references
[7] doi:10.1038/s41598-026-53525-0 [code]
Timing-induced illusory percepts of pitch.
Journal: Scientific reports
In common: cognitive, 2 references
[8] doi:10.1038/s41562-026-02445-0 [code]
Human gloss perception reproduced by tiny neural networks.
Journal: Nature human behaviour
In common: Statistics and Machine Learning Toolbox, cognitive, 1 reference
[9] doi:10.7554/elife.104684 [code]
Regime shift detection and neurocomputational substrates for under and overreactions to change.
Journal: eLife
In common: Statistics and Machine Learning Toolbox, cognitive, 1 reference
[10] doi:10.1371/journal.pbio.3003767 [code]
Ultrasound neuromodulation reveals distinct roles of the dorsal anterior cingulate cortex and anterior insula in learning.
Journal: PLoS biology
In common: Statistics and Machine Learning Toolbox, cognitive, 1 reference

Contribute

The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.

Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.

Request its removal

To ask OSCR to remove this record, the copies of its authors' scripts or its tracing map, use the removal request page: signed in, you say who you are, what to remove and why, then review and confirm the request. Published rules decide every request (how).

Discussion, reproductions, activity

Discussion: questions and error reports about this paper and its code, from signed-in readers and its authors. It opens with sign-in.

Reproductions: reports from readers who ran the authors' code: what they reproduced, with which environment, commit and data. It opens with sign-in.

Activity: what happens around this paper: new versions of its record, its map's validation, discussions and reproductions. It opens with sign-in.