OSCR

Self-allocation bias in performance-based cooperative decisions is driven by self-interest rather than distorted performance encoding.

A correction to this paper has been published: the notice, 42627763, from Europe PMC.

Code ↔ Paper

3 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 3 matches
  1. [1] § Behavioral results › The self-allocation bias and its link to less reliance on performance. ↔ GA_analysis_plot_code.R, lines 1242 to 1283 · score 0.77 · OforO, OforS, SforO, SforS, allocation target, additive · Report a mismatch
  2. [2] § Methods › Experimental procedures › Experimental design in additional Experiment 3. ↔ GA_analysis_plot_code.R, lines 1242 to 1283 · score 0.73 · OforO, OforS, SforO, SforS, irrelevant · Report a mismatch
  3. [3] § Methods › Behavioral data analysis ↔ GA_analysis_plot_code.R, lines 92 to 136 · score 0.52 · inflated beta, emmeans, post hoc, LOO, brms, multilevel models · Report a mismatch

Paper

Loaded from Europe PMC by your browser; OSCR does not store it: doi.org · Europe PMC

The paper is loaded when this pane is shown.

The authors' code

R · 1,769 lines · 65 KB · no license · 3 matches

  1. ###### GA behavioral analysis
  2. ## ------------------------ Initialization -------------------------------------
  3. ## setting
  4. rm(list= ls())
  5. library(tidyverse)
  6. library(ggplot2)
  7. library(brms)
  8. library(emmeans)
  9. library(sjPlot)
  10. library(svglite)
  11. library(ggpubr)
  12. library(cowplot)
  13. library(bayestestR)
  14. library(papaja)
  15. setwd(".../Behavioral_data")
  16. ## color
  17. light = c("#b2df8a","#decbe4")
  18. dark = c("#4bb14b","#967cb9")
  19. color_four = c("#4bb14b","#b2df8a","#decbe4","#967cb9")
  20. contribution_color = c("#fbb4ae","#ccebc5","#b3cde3")
  21. ## -------------------Experiment 1 and 2 ---------------------------------------------
  22. ## ------------------ load and prepare data ------------------------------------
  23. ## load data Experiment 1
  24. Exp1_data <- read.csv(".../Exp1_data.csv", header = TRUE)
  25. # factorize variables
  26. Exp1_data$task <-factor(Exp1_data$task,c('Simple','Additive','Disjunctive'))
  27. Exp1_data$winorloss<-factor(Exp1_data$winorloss,levels = c('Rewards','Losses'))
  28. Exp1_data$condition <-factor(Exp1_data$condition,levels = c('Self-relevant','Self-irrelevant'))
  29. # add svo score
  30. SVOdataExp1 <-read.csv(".../Exp1_SVOscore.csv", header = TRUE)
  31. Exp1_data <- Exp1_data %>%
  32. left_join(SVOdataExp1, by = "subject") %>%
  33. mutate(experiment = 'Experiment1')
  34. # if control analysis:
  35. # filter(!subject %in% c(32, 46, 55, 56, 57))
  36. ## load data Experiment 2
  37. Exp2_data <- read.csv(".../Exp2_data.csv", header = TRUE)
  38. Exp2_data$task<-factor(Exp2_data$task,levels = c('Simple','Additive','Disjunctive'))
  39. Exp2_data$winorloss<-factor(Exp2_data$winorloss, levels = c('Rewards','Losses'))
  40. Exp2_data$condition<-factor(Exp2_data$condition, levels = c('Self-relevant','Self-irrelevant'))
  41. # add svo score
  42. SVOdataExp2 <-read.csv(".../Exp2_SVOscore.csv", header = TRUE)
  43. Exp2_data <- Exp2_data %>%
  44. left_join(SVOdataExp2, by = "subject") %>%
  45. mutate(experiment = 'Experiment2')
  46. # if control analysis:
  47. # filter(!subject %in% c(118,119,125,132,134,139,141,143))
  48. ## combine data
  49. # combine in trial level
  50. combinedData <- rbind(Exp1_data,Exp2_data)
  51. combinedData <- combinedData %>%
  52. filter(winorloss == "Rewards") %>%
  53. mutate(contribution = case_when((performance1 >= threshold & performance2 < threshold)~"Player1 only",
  54. (performance2 >= threshold & performance1 < threshold)~"Player2 only",
  55. TRUE ~"Both")) %>%
  56. dplyr::select(subject,trial,task,condition,contribution,allocation_ratio,performance_ratio,shapley_ratio,SVOscore,experiment)
  57. combinedData[,5]<-factor(combinedData[,5],levels = c('Player1 only','Both','Player2 only'))
  58. combinedData$SVOscore_z <- scale(combinedData$SVOscore)
  59. ## -------------- model 1: task * condition ------------------------------------
  60. ## model fitting
  61. # task * condition
  62. fit_zoib_tc <- brm(
  63. bf(
  64. allocation_ratio ~ task * condition + (1 | subject)
  65. ),
  66. data = combinedData,
  67. family = zero_one_inflated_beta(),
  68. chains = 8, cores = 8, iter = 3000, warmup = 1000
  69. )
  70. summary(fit_zoib_tc)
  71. saveRDS(fit_zoib_tc, file = "multilevel_model/output/fit_zoib_tc.rds")
  72. # task + condition
  73. fit_zoib_tc_noInt <- brm(
  74. bf(
  75. allocation_ratio ~ task + condition + (1 | subject)
  76. ),
  77. data = combinedData,
  78. family = zero_one_inflated_beta(),
  79. chains = 8, cores = 8, iter = 3000, warmup = 1000
  80. )
  81. summary(fit_zoib_tc_noInt)
  82. saveRDS(fit_zoib_tc_noInt, file = "multilevel_model/output/fit_zoib_tc_noInt.rds")
  83. ## save model output
  84. fit_zoib_tc <- readRDS("multilevel_model/output/fit_zoib_tc.rds")
  85. summary(fit_zoib_tc)
  86. coef_table <- as.data.frame(summary(fit_zoib_tc)$fixed)
  87. coef_table <- round(coef_table, 2)
  88. write.csv(coef_table, "multilevel_model/output/tables/TabS1-1_fit_zoib_tc.csv", row.names = TRUE)
  89. ## compare model
  90. fit_zoib_tc <- readRDS("multilevel_model/output/fit_zoib_tc.rds")
  91. fit_zoib_tc_noInt <- readRDS("multilevel_model/output/fit_zoib_tc_noInt.rds")
  92. loo_compare(loo(fit_zoib_tc), loo(fit_zoib_tc_noInt)) #diff 2*SE
  93. # post hoc
  94. emm <- emmeans(fit_zoib_tc, ~ task * condition, type = "response")
  95. plot(emm)
  96. pairs(emm, by = "condition")
  97. pairs(emm, by = "task")
  98. contrast(emm, "pairwise")
  99. emm_2 <-emm %>% summary() %>% as.data.frame() %>%
  100. mutate(across(where(is.numeric), ~ round(.x, 2)))
  101. write.csv(emm_2, "multilevel_model/output/tables/TabS1-3_emms.csv", row.names = TRUE)
  102. # plot
  103. tc <- conditional_effects(fit_zoib_tc, effects = "task:condition")
  104. p <- plot(tc, plot = FALSE)[[1]]
  105. p +
  106. scale_color_manual(values = dark) +
  107. scale_fill_manual(values = dark) +
  108. theme_classic() +
  109. theme(text = element_text(size = 15)) +
  110. xlab("Task type") +
  111. ylab("Allocation Ratio")
  112. ## ------------- model 2: task * condition * SVO score ------------------------------------------
  113. # task * condition * SVOscore
  114. fit_zoib_tc_SVO <- brm(
  115. bf(
  116. allocation_ratio ~ task * condition * SVOscore_z + (1 | subject)
  117. ),
  118. data = combinedData,
  119. family = zero_one_inflated_beta(),
  120. chains = 8, cores = 8, iter = 3000, warmup = 1000
  121. )
  122. summary(fit_zoib_tc_SVO)
  123. saveRDS(fit_zoib_tc_SVO, file = "multilevel_model/output/fit_zoib_tc_SVO.rds")
  124. # compare model
  125. loo_compare(loo(fit_zoib_tc), loo(fit_zoib_tc_noInt), loo(fit_zoib_tc_SVO))
  126. # post hoc
  127. fit_zoib_tc_SVO <- readRDS("multilevel_model/output/fit_zoib_tc_SVO.rds")
  128. summary(fit_zoib_tc_SVO)
  129. coef_table <- as.data.frame(summary(fit_zoib_tc_SVO)$fixed)
  130. coef_table <- round(coef_table, 2)
  131. write.csv(coef_table, "multilevel_model/output/tables/TabS2-1_fit_zoib_tc_SVO.csv", row.names = TRUE)
  132. post_summary <- describe_posterior(fit_zoib_tc_SVO)
  133. tab_df(post_summary,
  134. title = "Posterior Estimates",
  135. file = "multilevel_model/output/fit_zoib_tc_SVO.html")
  136. slopes_SVO <- emtrends(fit_zoib_tc_SVO, ~ condition | task, var = "SVOscore_z")
  137. pairs(slopes_SVO)
  138. emm_2 <- slopes_SVO %>% summary() %>% as.data.frame() %>%
  139. mutate(across(where(is.numeric), ~ round(.x, 2)))
  140. write.csv(emm_2, "multilevel_model/output/tables/TabS2-3_emms.csv", row.names = TRUE)
  141. st <- conditional_effects(fit_zoib_tc_SVO,
  142. effects = "SVOscore_z:condition",
  143. conditions = list(task = c("Simple", "Additive", "Disjunctive")))
  144. p <- plot(st, plot = FALSE)[[1]]
  145. p + scale_color_manual(values = dark) +
  146. scale_fill_manual(values = dark) +
  147. theme_classic()+
  148. theme(text = element_text(size = 15))+
  149. xlab("SVOscore (z-score)")+
  150. ylab("Allocation Ratio") +
  151. facet_wrap(~task, labeller = labeller(task = c("Simple", "Additive", "Disjunctive"))) # custom facet names
  152. ## ----- model 3: performance ratio * task + performance ratio * condition -----
  153. ## model fitting
  154. # three way interaction
  155. fit_zoib_3way <- brm(
  156. bf(
  157. allocation_ratio ~ performance_ratio * task * condition + (1 | subject)
  158. ),
  159. data = combinedData,
  160. family = zero_one_inflated_beta(),
  161. chains = 8, cores = 8, iter = 3000, warmup = 1000
  162. )
  163. summary(fit_zoib_3way)
  164. saveRDS(fit_zoib_3way, file = "multilevel_model/output/fit_zoib_3way.rds")
  165. # two way interaction
  166. fit_zoib_2way <- brm(
  167. bf(
  168. allocation_ratio ~ performance_ratio * task + performance_ratio * condition + (1 | subject)
  169. ),
  170. data = combinedData,
  171. family = zero_one_inflated_beta(),
  172. chains = 8, cores = 8, iter = 3000, warmup = 1000
  173. )
  174. summary(fit_zoib_2way)
  175. saveRDS(fit_zoib_2way, file = "multilevel_model/output/fit_zoib_2way.rds")
  176. # no interaction
  177. fit_zoib_noInt <- brm(
  178. bf(
  179. allocation_ratio ~ performance_ratio + task + condition + (1 | subject)
  180. ),
  181. data = combinedData,
  182. family = zero_one_inflated_beta(),
  183. chains = 8, cores = 8, iter = 3000, warmup = 1000
  184. )
  185. summary(fit_zoib_noInt)
  186. saveRDS(fit_zoib_noInt, file = "multilevel_model/output/fit_zoib_noInt.rds")
  187. ## Compare model
  188. fit_zoib_3way <- readRDS("multilevel_model/output/fit_zoib_3way.rds")
  189. fit_zoib_2way <- readRDS("multilevel_model/output/fit_zoib_2way.rds")
  190. fit_zoib_noInt <- readRDS("multilevel_model/output/fit_zoib_noInt.rds")
  191. three_way_model <- loo(fit_zoib_3way)
  192. two_way_model <- loo(fit_zoib_2way)
  193. no_int_model <- loo(fit_zoib_noInt)
  194. loo_compare(three_way_model, two_way_model, no_int_model) #diff 2*SE
  195. ## post hoc
  196. # get the best model
  197. fit_zoib <- readRDS("multilevel_model/output/fit_zoib_2way.rds")
  198. summary(fit_zoib)
  199. coef_table <- as.data.frame(summary(fit_zoib)$fixed)
  200. coef_table <- round(coef_table, 2)
  201. write.csv(coef_table, "multilevel_model/output/tables/TabS3-1_fit_zoib.csv", row.names = TRUE)
  202. post_summary <- describe_posterior(fit_zoib)
  203. tab_df(post_summary,
  204. title = "Posterior Estimates",
  205. file = "multilevel_model/output/fit_zoib_2way.html")
  206. slopes_task <- emtrends(fit_zoib, ~ task, var = "performance_ratio")
  207. pairs(slopes_task)
  208. slopes_cond <- emtrends(fit_zoib, ~ condition, var = "performance_ratio")
  209. pairs(slopes_cond)
  210. emm_2 <- slopes_cond %>% summary() %>% as.data.frame() %>%
  211. mutate(across(where(is.numeric), ~ round(.x, 2)))
  212. write.csv(emm_2, "multilevel_model/output/tables/TabS3-2_emms.csv", row.names = TRUE)
  213. plot(fit_zoib, variable = c("b_performance_ratio"))
  214. plot(fit_zoib, variable = c("b_taskDisjunctive"))
  215. plot(fit_zoib, variable = c("b_conditionSelfMirrelevant"))
  216. pt <- conditional_effects(fit_zoib, effects = "performance_ratio:task")
  217. p1 <- plot(pt, plot = FALSE)[[1]]
  218. p1 + scale_color_manual(values = c( "grey85", "grey50","black")) +
  219. scale_fill_manual(values = c( "grey85", "grey50","black")) +
  220. theme_classic()+
  221. theme(text = element_text(size = 15))+
  222. xlab("Performance Ratio")+
  223. ylab("Allocation Ratio")
  224. pc <- conditional_effects(fit_zoib, effects = "performance_ratio:condition")
  225. p_2c <- plot(pc, plot = FALSE)[[1]]+
  226. scale_color_manual(values = dark) +
  227. scale_fill_manual(values = dark) +
  228. theme_bw() +
  229. theme(text = element_text(size=20),
  230. panel.grid.major = element_blank(),
  231. panel.grid.minor = element_blank(),
  232. plot.title = element_text(hjust = 0.5),
  233. axis.text.x = element_text(size = 15),
  234. axis.text.y = element_text(size = 15),
  235. panel.spacing.x = unit(0.8, "lines"),
  236. legend.text=element_text(size=15))+
  237. xlab("Relative Performance")+
  238. ylab("Relative Allocation")
  239. p_2c
  240. ## ------------------- plot Figure 2A,2B,2C ------------------------------------------
  241. # get data
  242. # combine two datasets and exclude loss trials
  243. combinedData_sub <- combinedData %>%
  244. filter(!is.na(allocation_ratio)) %>%
  245. dplyr::select(experiment,task,subject,condition,allocation_ratio,SVOscore_z) %>%
  246. group_by(experiment,task,subject,condition) %>%
  247. dplyr::summarize(mean_allocation_ratio = mean(allocation_ratio),
  248. SVOscore_z = first(SVOscore_z)) %>%
  249. select(experiment, task,condition, subject, mean_allocation_ratio, SVOscore_z)
  250. combinedData_sub$subject <- as.factor(combinedData_sub$subject)
  251. # plot Figure 2B
  252. p_2a <- ggplot(combinedData_sub, aes(x = condition, y = mean_allocation_ratio, fill = condition)) +
  253. geom_bar(stat = "summary", fun = "mean", colour = "black", position = "dodge") +
  254. geom_line(aes(group = subject),color = 'darkgray') +
  255. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  256. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  257. geom = "errorbar", width = .2)+
  258. geom_hline(yintercept = 0.5,linetype="dashed", color = "black") +
  259. facet_grid(~task) +
  260. scale_fill_manual(values = dark) +
  261. theme_bw()+
  262. theme(text = element_text(size=20),
  263. panel.grid.major = element_blank(),
  264. panel.grid.minor = element_blank(),
  265. axis.text.x = element_blank(),
  266. axis.ticks.x = element_blank(),
  267. axis.text.y = element_text(size = 15),
  268. plot.title = element_text(hjust = 0.5),
  269. legend.text=element_text(size=15)) +
  270. ylab("Relative allocation") +
  271. xlab(" ") +
  272. labs(fill = "Self-relevance")
  273. p_2a
  274. # plot Figure 2B
  275. p_2b<-combinedData_sub %>%
  276. ggplot(aes(x=SVOscore_z, y=mean_allocation_ratio, color=condition)) +
  277. geom_point(shape = 20,size=5,alpha = 0.5) +
  278. theme_bw() +
  279. theme(text = element_text(size=20),
  280. panel.grid.major = element_blank(),
  281. panel.grid.minor = element_blank(),
  282. plot.title = element_text(hjust = 0.5),
  283. axis.text.x = element_text(size = 15),
  284. axis.text.y = element_text(size = 15),
  285. panel.spacing.x = unit(0.8, "lines"),
  286. legend.text=element_text(size=15))+
  287. #legend.position="none")+
  288. geom_smooth(method=lm, se = FALSE)+
  289. #stat_cor()+
  290. facet_grid(~task,scales = "free")+
  291. #scale_shape_manual(values=c(3, 16))+
  292. #geom_vline(xintercept = 22.45,linetype="dashed", color = "black") +
  293. scale_color_manual(values=dark)+
  294. xlab("SVO score (z-scored)")+
  295. ylab("Relative allocation")+
  296. labs(color = "Self-relevance")
  297. p_2b
  298. ## -------------- model 4: contribution diff -----------------------------------
  299. # calculate the differnece between self-relevant and self-irrelevant based on trial
  300. combinedData_contribution <- combinedData %>%
  301. pivot_wider(id_cols = c(experiment,subject,SVOscore_z,SVOscore,trial,task,contribution,performance_ratio),
  302. names_from = condition,
  303. values_from = allocation_ratio) %>%
  304. mutate(difference = `Self-relevant` - `Self-irrelevant`)
  305. ## model fitting
  306. fit_gaussian_c_diff <- brm(
  307. bf(
  308. difference ~ contribution + (1 | subject)
  309. ),
  310. data = combinedData_contribution,
  311. family = gaussian(),
  312. chains = 8, cores = 8, iter = 3000, warmup = 1000
  313. )
  314. summary(fit_gaussian_c_diff)
  315. saveRDS(fit_gaussian_c_diff, file = "output/fit_gaussian_c_diff.rds")
  316. ## post hoc
  317. fit_gaussian_c_diff <- readRDS("multilevel_model/output/fit_gaussian_c_diff.rds")
  318. summary(fit_gaussian_c_diff)
  319. coef_table <- as.data.frame(summary(fit_gaussian_c_diff)$fixed)
  320. coef_table <- round(coef_table, 2)
  321. write.csv(coef_table, "multilevel_model/output/tables/TabS4-2_fit_zoib.csv", row.names = TRUE)
  322. post_summary <- describe_posterior(fit_gaussian_c_diff)
  323. tab_df(post_summary,
  324. title = "Posterior Estimates",
  325. file = "multilevel_model/output/fit_gaussian_c_diff.html")
  326. emm <- emmeans(fit_gaussian_c_diff, ~ contribution, type = "response")
  327. contrast(emm, "pairwise")
  328. emm_2 <- emm %>% summary() %>% as.data.frame() %>%
  329. mutate(across(where(is.numeric), ~ round(.x, 2)))
  330. write.csv(emm_2, "multilevel_model/output/tables/TabS4-3_emms.csv", row.names = TRUE)
  331. gaussian_c_diff <- conditional_effects(fit_gaussian_c_diff, effects = "contribution")
  332. p <- plot(gaussian_c_diff, plot = FALSE)[[1]]+
  333. aes(color = contribution, fill = contribution)
  334. p +
  335. scale_color_manual(values = contribution_color) +
  336. scale_fill_manual(values = contribution_color) +
  337. theme_classic() +
  338. theme(text = element_text(size = 15)) +
  339. xlab("Contribution") +
  340. ylab("Self-allocation Bias")
  341. ## ------------- model 5: including SVO score ---------------------------------
  342. # contribution*SVOscore_z
  343. fit_gaussian_c_diff_SVO <- brm(
  344. bf(
  345. difference ~ contribution * SVOscore_z + (1 | subject)
  346. ),
  347. data = combinedData_contribution,
  348. family = gaussian(),
  349. chains = 8, cores = 8, iter = 3000, warmup = 1000
  350. )
  351. summary(fit_gaussian_c_diff_SVO)
  352. saveRDS(fit_gaussian_c_diff_SVO, file = "output/fit_gaussian_c_diff_SVO.rds")
  353. ## compare model
  354. # get model
  355. fit_gaussian_c_diff <- readRDS("output/fit_gaussian_c_diff.rds")
  356. fit_gaussian_c_diff_SVO <- readRDS("output/fit_gaussian_c_diff_SVO.rds")
  357. # check distribution
  358. # pp_check(fit_gaussian_c_diff_SVO, type = "dens_overlay")
  359. loo_compare(loo(fit_gaussian_c_diff), loo(fit_gaussian_c_diff_SVO))
  360. ## post hoc
  361. fit_gaussian_c_diff_SVO <- readRDS("multilevel_model/output/fit_gaussian_c_diff_SVO.rds")
  362. post_summary <- describe_posterior(fit_gaussian_c_diff_SVO)
  363. tab_df(post_summary,
  364. title = "Posterior Estimates",
  365. file = "multilevel_model/output/fit_gaussian_c_diff_SVO.html")
  366. slopes_SVO <- emtrends(fit_gaussian_c_diff_SVO, ~ contribution, var = "SVOscore_z")
  367. pairs(slopes_SVO)
  368. emm_2 <- slopes_SVO %>% summary() %>% as.data.frame() %>%
  369. mutate(across(where(is.numeric), ~ round(.x, 2)))
  370. write.csv(emm_2, "multilevel_model/output/tables/TabS4-5_emms.csv", row.names = TRUE)
  371. c_diff_svo <- conditional_effects(fit_gaussian_c_diff_SVO,
  372. effects = "SVOscore_z:contribution")
  373. p <- plot(c_diff_svo, plot = FALSE)[[1]]
  374. p + scale_color_manual(values = contribution_color) +
  375. scale_fill_manual(values = contribution_color) +
  376. theme_classic()+
  377. theme(text = element_text(size = 15))+
  378. xlab("SVOscore (z-score)")+
  379. ylab("Allocation Ratio")
  380. ## post hoc
  381. emm <- emmeans(fit_gaussian_c_diff_SVO, ~ contribution, type = "response")
  382. contrast(emm, "pairwise")
  383. gaussian_c_diff <- conditional_effects(fit_gaussian_c_diff_SVO, effects = "contribution")
  384. p <- plot(gaussian_c_diff, plot = FALSE)[[1]] +
  385. aes(color = contribution, fill = contribution)
  386. p +
  387. scale_color_manual(values = contribution_color) +
  388. scale_fill_manual(values = contribution_color) +
  389. theme_classic() +
  390. theme(text = element_text(size = 15)) +
  391. xlab("Contribution") +
  392. ylab("Self-allocation Bias")
  393. ## ---------------------- plot Figure 3B 3C ------------------------------------
  394. combinedData_contribution_sub <- combinedData_contribution %>%
  395. filter(!is.na(difference)) %>%
  396. dplyr::select(experiment,task,subject,contribution,difference,SVOscore_z) %>%
  397. group_by(experiment,subject,contribution) %>%
  398. dplyr::summarize(mean_diff = mean(difference),
  399. SVOscore_z = first(SVOscore_z)) %>%
  400. select(experiment,contribution, subject, mean_diff, SVOscore_z)
  401. combinedData_contribution_sub$subject <- as.factor(combinedData_contribution_sub$subject)
  402. # plot 3B
  403. p_3b<-ggplot(combinedData_contribution_sub, aes(x = contribution, y = mean_diff, fill = contribution)) +
  404. geom_bar(stat = "summary", fun = "mean", colour = "black")+
  405. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  406. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  407. geom = "errorbar", width = .2)+
  408. scale_fill_manual(values = contribution_color) +
  409. theme_bw()+
  410. theme(text = element_text(size=20),
  411. panel.grid.major = element_blank(),
  412. panel.grid.minor = element_blank(),
  413. axis.ticks.x = element_blank(),
  414. axis.text.y = element_text(size = 15)) +
  415. ylab("Self allocation bias") +
  416. xlab(" ")
  417. p_3b
  418. # plot 3c
  419. p_3c <- combinedData_contribution_sub %>%
  420. ggplot(aes(x=SVOscore_z, y=mean_diff, color=contribution)) +
  421. geom_point(shape = 20,size=5,alpha = 0.8) +
  422. theme_bw() +
  423. theme(text = element_text(size=20),
  424. panel.grid.major = element_blank(),
  425. panel.grid.minor = element_blank(),
  426. plot.title = element_text(hjust = 0.5),
  427. axis.text.x = element_text(size = 15),
  428. axis.text.y = element_text(size = 15),
  429. panel.spacing.x = unit(0.8, "lines"),
  430. )+
  431. #legend.position = "none"
  432. geom_smooth(method=lm, se = FALSE)+
  433. scale_color_manual("Contribution",values=contribution_color)+
  434. # stat_cor(p.accuracy = 0.001,size = 6)+
  435. xlab("SVO score (z-scored)")+ylab("Self allocation bias")
  436. p_3c
  437. ## -------------- Experiment 1 and 2 separately -------------------------------
  438. ## -------------- model S1: task * condition ------------------------------------
  439. ## prepare data
  440. exp1Data <- combinedData %>%
  441. filter(experiment == "Experiment1")
  442. exp2Data <- combinedData %>%
  443. filter(experiment == "Experiment2")
  444. ## model fitting
  445. # exp1
  446. fit_zoib_tc_exp1 <- brm(
  447. bf(
  448. allocation_ratio ~ task * condition + (1 | subject)
  449. ),
  450. data = exp1Data,
  451. family = zero_one_inflated_beta(),
  452. chains = 8, cores = 8, iter = 3000, warmup = 1000
  453. )
  454. summary(fit_zoib_tc_exp1)
  455. saveRDS(fit_zoib_tc_exp1, file = "output/exp1_fit_zoib_tc.rds")
  456. # exp2
  457. fit_zoib_tc_exp2 <- brm(
  458. bf(
  459. allocation_ratio ~ task * condition + (1 | subject)
  460. ),
  461. data = exp2Data,
  462. family = zero_one_inflated_beta(),
  463. chains = 8, cores = 8, iter = 3000, warmup = 1000
  464. )
  465. summary(fit_zoib_tc_exp2)
  466. saveRDS(fit_zoib_tc_exp2, file = "output/exp2_fit_zoib_tc.rds")
  467. ## post hoc
  468. # get the interaction model
  469. fit_zoib_tc_exp1 <- readRDS("multilevel_model/output/exp1_fit_zoib_tc.rds")
  470. summary(fit_zoib_tc_exp1)
  471. coef_table <- as.data.frame(summary(fit_zoib_tc_exp1)$fixed)
  472. coef_table <- round(coef_table, 2)
  473. write.csv(coef_table, "multilevel_model/output/tables/TabS1-4_fit_zoib_tc.csv", row.names = TRUE)
  474. fit_zoib_tc_exp2 <- readRDS("multilevel_model/output/exp2_fit_zoib_tc.rds")
  475. summary(fit_zoib_tc_exp2)
  476. coef_table <- as.data.frame(summary(fit_zoib_tc_exp2)$fixed)
  477. coef_table <- round(coef_table, 2)
  478. write.csv(coef_table, "multilevel_model/output/tables/TabS1-7_fit_zoib_tc.csv", row.names = TRUE)
  479. # exp1
  480. emm <- emmeans(fit_zoib_tc_exp1, ~ task * condition, type = "response")
  481. plot(emm)
  482. pairs(emm, by = "condition")
  483. pairs(emm, by = "task")
  484. contrast(emm, "pairwise")
  485. emm_2 <-emm %>% summary() %>% as.data.frame() %>%
  486. mutate(across(where(is.numeric), ~ round(.x, 2)))
  487. write.csv(emm_2, "multilevel_model/output/tables/TabS1-6_emms.csv", row.names = TRUE)
  488. tc_exp1 <- conditional_effects(fit_zoib_tc_exp1, effects = "task:condition")
  489. p <- plot(tc_exp1, plot = FALSE)[[1]]
  490. p +
  491. scale_color_manual(values = dark) +
  492. scale_fill_manual(values = dark) +
  493. theme_classic() +
  494. theme(text = element_text(size = 15)) +
  495. xlab("Task type") +
  496. ylab("Allocation Ratio") +
  497. ggtitle("Experiment 1")
  498. # exp2
  499. emm <- emmeans(fit_zoib_tc_exp2, ~ task * condition, type = "response")
  500. plot(emm)
  501. pairs(emm, by = "condition")
  502. pairs(emm, by = "task")
  503. contrast(emm, "pairwise")
  504. emm_2 <-emm %>% summary() %>% as.data.frame() %>%
  505. mutate(across(where(is.numeric), ~ round(.x, 2)))
  506. write.csv(emm_2, "multilevel_model/output/tables/TabS1-9_emms.csv", row.names = TRUE)
  507. tc_exp2 <- conditional_effects(fit_zoib_tc_exp2, effects = "task:condition")
  508. p <- plot(tc_exp2, plot = FALSE)[[1]]
  509. p +
  510. scale_color_manual(values = dark) +
  511. scale_fill_manual(values = dark) +
  512. theme_classic() +
  513. theme(text = element_text(size = 15)) +
  514. xlab("Task type") +
  515. ylab("Allocation Ratio") +
  516. ggtitle("Experiment 2")
  517. # ------------- model S2: including SVO score ------------------------------------------
  518. # task * condition * SVOscore
  519. fit_zoib_tc_SVO_exp1 <- brm(
  520. bf(
  521. allocation_ratio ~ task * condition * SVOscore_z + (1 | subject)
  522. ),
  523. data = exp1Data,
  524. family = zero_one_inflated_beta(),
  525. chains = 8, cores = 8, iter = 3000, warmup = 1000
  526. )
  527. summary(fit_zoib_tc_SVO_exp1)
  528. saveRDS(fit_zoib_tc_SVO_exp1, file = "output/exp1_fit_zoib_tc_SVO.rds")
  529. # exp2
  530. fit_zoib_tc_SVO_exp2 <- brm(
  531. bf(
  532. allocation_ratio ~ task * condition * SVOscore_z + (1 | subject)
  533. ),
  534. data = exp2Data,
  535. family = zero_one_inflated_beta(),
  536. chains = 8, cores = 8, iter = 3000, warmup = 1000
  537. )
  538. summary(fit_zoib_tc_SVO_exp2)
  539. saveRDS(fit_zoib_tc_SVO_exp2, file = "output/exp2_fit_zoib_tc_SVO.rds")
  540. # post hoc
  541. fit_zoib_tc_SVO_exp1 <- readRDS("multilevel_model/output/exp1_fit_zoib_tc_SVO.rds")
  542. summary(fit_zoib_tc_SVO_exp1)
  543. coef_table <- as.data.frame(summary(fit_zoib_tc_SVO_exp1)$fixed)
  544. coef_table <- round(coef_table, 2)
  545. write.csv(coef_table, "multilevel_model/output/tables/TabS2-4_fit_zoib_tc_SVO.csv", row.names = TRUE)
  546. fit_zoib_tc_SVO_exp2 <- readRDS("multilevel_model/output/exp2_fit_zoib_tc_SVO.rds")
  547. summary(fit_zoib_tc_SVO_exp2)
  548. coef_table <- as.data.frame(summary(fit_zoib_tc_SVO_exp2)$fixed)
  549. coef_table <- round(coef_table, 2)
  550. write.csv(coef_table, "multilevel_model/output/tables/TabS2-7_fit_zoib_tc_SVO.csv", row.names = TRUE)
  551. # exp1
  552. slopes_SVO <- emtrends(fit_zoib_tc_SVO_exp1, ~ condition | task, var = "SVOscore_z")
  553. pairs(slopes_SVO)
  554. emm_2 <-slopes_SVO %>% summary() %>% as.data.frame() %>%
  555. mutate(across(where(is.numeric), ~ round(.x, 2)))
  556. write.csv(emm_2, "multilevel_model/output/tables/TabS2-6_emms.csv", row.names = TRUE)
  557. st <- conditional_effects(fit_zoib_tc_SVO_exp1,
  558. effects = "SVOscore_z:condition",
  559. conditions = list(task = c("Simple", "Additive", "Disjunctive")))
  560. p <- plot(st, plot = FALSE)[[1]]
  561. p + scale_color_manual(values = dark) +
  562. scale_fill_manual(values = dark) +
  563. theme_classic()+
  564. theme(text = element_text(size = 15))+
  565. xlab("SVOscore (z-score)")+
  566. ylab("Allocation Ratio") +
  567. ggtitle("Experiment 1") +
  568. facet_wrap(~task, labeller = labeller(task = c("Simple", "Additive", "Disjunctive"))) # custom facet names
  569. # exp2
  570. slopes_SVO <- emtrends(fit_zoib_tc_SVO_exp2, ~ condition | task, var = "SVOscore_z")
  571. pairs(slopes_SVO)
  572. emm_2 <-slopes_SVO %>% summary() %>% as.data.frame() %>%
  573. mutate(across(where(is.numeric), ~ round(.x, 2)))
  574. write.csv(emm_2, "multilevel_model/output/tables/TabS2-9_emms.csv", row.names = TRUE)
  575. st <- conditional_effects(fit_zoib_tc_SVO_exp2,
  576. effects = "SVOscore_z:condition",
  577. conditions = list(task = c("Simple", "Additive", "Disjunctive")))
  578. p <- plot(st, plot = FALSE)[[1]]
  579. p + scale_color_manual(values = dark) +
  580. scale_fill_manual(values = dark) +
  581. theme_classic()+
  582. theme(text = element_text(size = 15))+
  583. xlab("SVOscore (z-score)")+
  584. ylab("Allocation Ratio") +
  585. ggtitle("Experiment 2") +
  586. facet_wrap(~task, labeller = labeller(task = c("Simple", "Additive", "Disjunctive"))) # custom facet names
  587. ## ----- model S3: performance ratio * task + performance ratio * condition -----
  588. ## model fitting
  589. # exp1
  590. fit_zoib_2way_exp1 <- brm(
  591. bf(
  592. allocation_ratio ~ performance_ratio * task + performance_ratio * condition + (1 | subject)
  593. ),
  594. data = exp1Data,
  595. family = zero_one_inflated_beta(),
  596. chains = 8, cores = 8, iter = 3000, warmup = 1000
  597. )
  598. summary(fit_zoib_2way_exp1)
  599. saveRDS(fit_zoib_2way_exp1, file = "output/exp1_fit_zoib_2way.rds")
  600. # exp2
  601. fit_zoib_2way_exp2 <- brm(
  602. bf(
  603. allocation_ratio ~ performance_ratio * task + performance_ratio * condition + (1 | subject)
  604. ),
  605. data = exp2Data,
  606. family = zero_one_inflated_beta(),
  607. chains = 8, cores = 8, iter = 3000, warmup = 1000
  608. )
  609. summary(fit_zoib_2way_exp2)
  610. saveRDS(fit_zoib_2way_exp2, file = "output/exp2_fit_zoib_2way.rds")
  611. # post hoc
  612. fit_zoib_2way_exp1 <- readRDS("multilevel_model/output/exp1_fit_zoib_2way.rds")
  613. summary(fit_zoib_2way_exp1)
  614. coef_table <- as.data.frame(summary(fit_zoib_2way_exp1)$fixed)
  615. coef_table <- round(coef_table, 2)
  616. write.csv(coef_table, "multilevel_model/output/tables/TabS3-4_fit_zoib.csv", row.names = TRUE)
  617. fit_zoib_2way_exp2 <- readRDS("multilevel_model/output/exp2_fit_zoib_2way.rds")
  618. summary(fit_zoib_2way_exp2)
  619. coef_table <- as.data.frame(summary(fit_zoib_2way_exp2)$fixed)
  620. coef_table <- round(coef_table, 2)
  621. write.csv(coef_table, "multilevel_model/output/tables/TabS3-7_fit_zoib.csv", row.names = TRUE)
  622. #exp1
  623. slopes_task <- emtrends(fit_zoib_2way_exp1, ~ task, var = "performance_ratio")
  624. pairs(slopes_task)
  625. slopes_cond <- emtrends(fit_zoib_2way_exp1, ~ condition, var = "performance_ratio")
  626. pairs(slopes_cond)
  627. emm_2 <- slopes_cond %>% summary() %>% as.data.frame() %>%
  628. mutate(across(where(is.numeric), ~ round(.x, 2)))
  629. write.csv(emm_2, "multilevel_model/output/tables/TabS3-5_emms.csv", row.names = TRUE)
  630. plot(fit_zoib_2way_exp1, variable = c("b_performance_ratio"))
  631. plot(fit_zoib_2way_exp1, variable = c("b_taskDisjunctive"))
  632. plot(fit_zoib_2way_exp1, variable = c("b_conditionSelfMirrelevant"))
  633. pc <- conditional_effects(fit_zoib_2way_exp1, effects = "performance_ratio:condition")
  634. p_s2c <- plot(pc, plot = FALSE)[[1]] +
  635. scale_color_manual(values = dark) +
  636. scale_fill_manual(values = dark) +
  637. theme_bw() +
  638. theme(text = element_text(size=20),
  639. panel.grid.major = element_blank(),
  640. panel.grid.minor = element_blank(),
  641. plot.title = element_text(hjust = 0.5),
  642. axis.text.x = element_text(size = 15),
  643. axis.text.y = element_text(size = 15),
  644. panel.spacing.x = unit(0.8, "lines"),
  645. legend.text=element_text(size=15))+
  646. xlab("Performance Ratio")+
  647. ylab("Allocation Ratio")+
  648. ggtitle("Experiment 1")
  649. p_s2c
  650. pt <- conditional_effects(fit_zoib_2way_exp1, effects = "performance_ratio:task")
  651. p_s2d <- plot(pt, plot = FALSE)[[1]] +
  652. scale_color_manual(values = c( "grey85", "grey50","black")) +
  653. scale_fill_manual(values = c( "grey85", "grey50","black")) +
  654. theme_bw() +
  655. theme(text = element_text(size=20),
  656. panel.grid.major = element_blank(),
  657. panel.grid.minor = element_blank(),
  658. plot.title = element_text(hjust = 0.5),
  659. axis.text.x = element_text(size = 15),
  660. axis.text.y = element_text(size = 15),
  661. panel.spacing.x = unit(0.8, "lines"),
  662. legend.text=element_text(size=15))+
  663. xlab("Performance Ratio")+
  664. ylab("Allocation Ratio")+
  665. ggtitle("Experiment 1")
  666. p_s2d
  667. #exp2
  668. slopes_task <- emtrends(fit_zoib_2way_exp2, ~ task, var = "performance_ratio")
  669. pairs(slopes_task)
  670. slopes_cond <- emtrends(fit_zoib_2way_exp2, ~ condition, var = "performance_ratio")
  671. pairs(slopes_cond)
  672. emm_2 <- slopes_cond %>% summary() %>% as.data.frame() %>%
  673. mutate(across(where(is.numeric), ~ round(.x, 2)))
  674. write.csv(emm_2, "multilevel_model/output/tables/TabS3-8_emms.csv", row.names = TRUE)
  675. plot(fit_zoib_2way_exp2, variable = c("b_performance_ratio"))
  676. plot(fit_zoib_2way_exp2, variable = c("b_taskDisjunctive"))
  677. plot(fit_zoib_2way_exp2, variable = c("b_conditionSelfMirrelevant"))
  678. pc <- conditional_effects(fit_zoib_2way_exp2, effects = "performance_ratio:condition")
  679. p_s2g <- plot(pc, plot = FALSE)[[1]] +
  680. scale_color_manual(values = dark) +
  681. scale_fill_manual(values = dark) +
  682. theme_bw() +
  683. theme(text = element_text(size=20),
  684. panel.grid.major = element_blank(),
  685. panel.grid.minor = element_blank(),
  686. plot.title = element_text(hjust = 0.5),
  687. axis.text.x = element_text(size = 15),
  688. axis.text.y = element_text(size = 15),
  689. panel.spacing.x = unit(0.8, "lines"),
  690. legend.text=element_text(size=15))+
  691. xlab("Performance Ratio")+
  692. ylab("Allocation Ratio")+
  693. ggtitle("Experiment 2")
  694. p_s2g
  695. pt <- conditional_effects(fit_zoib_2way_exp2, effects = "performance_ratio:task")
  696. p_s2h <- plot(pt, plot = FALSE)[[1]] +
  697. scale_color_manual(values = c( "grey85", "grey50","black")) +
  698. scale_fill_manual(values = c( "grey85", "grey50","black")) +
  699. theme_bw() +
  700. theme(text = element_text(size=20),
  701. panel.grid.major = element_blank(),
  702. panel.grid.minor = element_blank(),
  703. plot.title = element_text(hjust = 0.5),
  704. axis.text.x = element_text(size = 15),
  705. axis.text.y = element_text(size = 15),
  706. panel.spacing.x = unit(0.8, "lines"),
  707. legend.text=element_text(size=15))+
  708. xlab("Performance Ratio")+
  709. ylab("Allocation Ratio")+
  710. ggtitle("Experiment 2")
  711. p_s2h
  712. ## --------------------------- plot Figure S2: Experiment 1 --------------------
  713. # plot Figure S2A
  714. Exp1_sub <- combinedData_sub %>%
  715. filter(experiment == "Experiment1")
  716. p_S2a <- ggplot(Exp1_sub, aes(x = condition, y = mean_allocation_ratio, fill = condition)) +
  717. geom_bar(stat = "summary", fun = "mean", colour = "black", position = "dodge") +
  718. geom_line(aes(group = subject),color = 'darkgray') +
  719. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  720. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  721. geom = "errorbar", width = .2)+
  722. geom_hline(yintercept = 0.5,linetype="dashed", color = "black") +
  723. facet_grid(~task) +
  724. scale_fill_manual(values = dark) +
  725. theme_bw()+
  726. theme(text = element_text(size=20),
  727. panel.grid.major = element_blank(),
  728. panel.grid.minor = element_blank(),
  729. axis.text.x = element_blank(),
  730. axis.ticks.x = element_blank(),
  731. axis.text.y = element_text(size = 15),
  732. plot.title = element_text(hjust = 0.5),
  733. legend.text=element_text(size=15)) +
  734. ylab("Relative allocation") +
  735. xlab(" ") +
  736. labs(fill = "Self-relevance", title = "Experiment 1")
  737. p_S2a
  738. # plot Figure S2B
  739. p_s2b<-Exp1_sub %>%
  740. ggplot(aes(x=SVOscore_z, y=mean_allocation_ratio, color=condition)) +
  741. geom_point(shape = 20,size=5,alpha = 0.5) +
  742. theme_bw() +
  743. theme(text = element_text(size=20),
  744. panel.grid.major = element_blank(),
  745. panel.grid.minor = element_blank(),
  746. plot.title = element_text(hjust = 0.5),
  747. axis.text.x = element_text(size = 15),
  748. axis.text.y = element_text(size = 15),
  749. panel.spacing.x = unit(0.8, "lines"),
  750. legend.text=element_text(size=15))+
  751. #legend.position="none")+
  752. geom_smooth(method=lm, se = FALSE)+
  753. #stat_cor()+
  754. facet_grid(~task,scales = "free")+
  755. #scale_shape_manual(values=c(3, 16))+
  756. #geom_vline(xintercept = 22.45,linetype="dashed", color = "black") +
  757. scale_color_manual(values=dark)+
  758. xlab("SVO score (z-scored)")+
  759. ylab("Relative allocation")+
  760. labs(color = "Self-relevance")
  761. p_s2b
  762. ## Experiment 2
  763. Exp2_sub <- combinedData_sub %>%
  764. filter(experiment == "Experiment2")
  765. # figure S2e
  766. p_S2e <- ggplot(Exp2_sub, aes(x = condition, y = mean_allocation_ratio, fill = condition)) +
  767. geom_bar(stat = "summary", fun = "mean", colour = "black", position = "dodge") +
  768. geom_line(aes(group = subject),color = 'darkgray') +
  769. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  770. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  771. geom = "errorbar", width = .2)+
  772. geom_hline(yintercept = 0.5,linetype="dashed", color = "black") +
  773. facet_grid(~task) +
  774. scale_fill_manual(values = dark) +
  775. theme_bw()+
  776. theme(text = element_text(size=20),
  777. panel.grid.major = element_blank(),
  778. panel.grid.minor = element_blank(),
  779. axis.text.x = element_blank(),
  780. axis.ticks.x = element_blank(),
  781. axis.text.y = element_text(size = 15),
  782. plot.title = element_text(hjust = 0.5),
  783. legend.text=element_text(size=15)) +
  784. ylab("Relative allocation") +
  785. xlab(" ") +
  786. labs(fill = "Self-relevance", title = "Experiment 2")
  787. p_S2e
  788. # plot Figure S2f
  789. p_s2f<-Exp2_sub %>%
  790. ggplot(aes(x=SVOscore_z, y=mean_allocation_ratio, color=condition)) +
  791. geom_point(shape = 20,size=5,alpha = 0.5) +
  792. theme_bw() +
  793. theme(text = element_text(size=20),
  794. panel.grid.major = element_blank(),
  795. panel.grid.minor = element_blank(),
  796. plot.title = element_text(hjust = 0.5),
  797. axis.text.x = element_text(size = 15),
  798. axis.text.y = element_text(size = 15),
  799. panel.spacing.x = unit(0.8, "lines"),
  800. legend.text=element_text(size=15))+
  801. #legend.position="none")+
  802. geom_smooth(method=lm, se = FALSE)+
  803. #stat_cor()+
  804. facet_grid(~task,scales = "free")+
  805. #scale_shape_manual(values=c(3, 16))+
  806. #geom_vline(xintercept = 22.45,linetype="dashed", color = "black") +
  807. scale_color_manual(values=dark)+
  808. xlab("SVO score (z-scored)")+
  809. ylab("Relative allocation")+
  810. labs(color = "Self-relevance")
  811. p_s2f
  812. ## -------------- model S4: contribution on diff -------------------------------
  813. ## prepare data
  814. # calculate the differnece between self-relevant and self-irrelevant based on trial
  815. combinedData_contribution <- combinedData %>%
  816. pivot_wider(id_cols = c(experiment,subject,SVOscore_z,SVOscore,trial,task,contribution,performance_ratio),
  817. names_from = condition,
  818. values_from = allocation_ratio) %>%
  819. mutate(difference = `Self-relevant` - `Self-irrelevant`)
  820. exp1Data_contribution <- combinedData_contribution %>%
  821. filter(experiment == "Experiment1")
  822. exp2Data_contribution <- combinedData_contribution %>%
  823. filter(experiment == "Experiment2")
  824. ## model fitting
  825. #exp1
  826. fit_gaussian_c_diff_exp1 <- brm(
  827. bf(
  828. difference ~ contribution + (1 | subject)
  829. ),
  830. data = exp1Data_contribution,
  831. family = gaussian(),
  832. chains = 8, cores = 8, iter = 3000, warmup = 1000
  833. )
  834. summary(fit_gaussian_c_diff_exp1)
  835. saveRDS(fit_gaussian_c_diff_exp1, file = "output/exp1_fit_gaussian_c_diff.rds")
  836. #exp2
  837. fit_gaussian_c_diff_exp2 <- brm(
  838. bf(
  839. difference ~ contribution + (1 | subject)
  840. ),
  841. data = exp2Data_contribution,
  842. family = gaussian(),
  843. chains = 8, cores = 8, iter = 3000, warmup = 1000
  844. )
  845. summary(fit_gaussian_c_diff_exp2)
  846. saveRDS(fit_gaussian_c_diff_exp2, file = "output/exp2_fit_gaussian_c_diff.rds")
  847. ## post hoc
  848. fit_gaussian_c_diff_exp1 <- readRDS("multilevel_model/output/exp1_fit_gaussian_c_diff.rds")
  849. summary(fit_gaussian_c_diff_exp1)
  850. coef_table <- as.data.frame(summary(fit_gaussian_c_diff_exp1)$fixed)
  851. coef_table <- round(coef_table, 2)
  852. write.csv(coef_table, "multilevel_model/output/tables/TabS4-7_fit_zoib.csv", row.names = TRUE)
  853. fit_gaussian_c_diff_exp2 <- readRDS("multilevel_model/output/exp2_fit_gaussian_c_diff.rds")
  854. summary(fit_gaussian_c_diff_exp2)
  855. coef_table <- as.data.frame(summary(fit_gaussian_c_diff_exp2)$fixed)
  856. coef_table <- round(coef_table, 2)
  857. write.csv(coef_table, "multilevel_model/output/tables/TabS4-12_fit_zoib.csv", row.names = TRUE)
  858. # exp1
  859. emm <- emmeans(fit_gaussian_c_diff_exp1, ~ contribution, type = "response")
  860. contrast(emm, "pairwise")
  861. emm_2 <- emm %>% summary() %>% as.data.frame() %>%
  862. mutate(across(where(is.numeric), ~ round(.x, 2)))
  863. write.csv(emm_2, "multilevel_model/output/tables/TabS4-8_emms.csv", row.names = TRUE)
  864. gaussian_c_diff <- conditional_effects(fit_gaussian_c_diff_exp1, effects = "contribution")
  865. p <- plot(gaussian_c_diff, plot = FALSE)[[1]]+
  866. aes(color = contribution, fill = contribution)
  867. p +
  868. scale_color_manual(values = contribution_color) +
  869. scale_fill_manual(values = contribution_color) +
  870. theme_classic() +
  871. theme(text = element_text(size = 15)) +
  872. xlab("Contribution") +
  873. ylab("Self-allocation Bias") +
  874. ggtitle("Experiment 1")
  875. #exp2
  876. emm <- emmeans(fit_gaussian_c_diff_exp2, ~ contribution, type = "response")
  877. contrast(emm, "pairwise")
  878. emm_2 <- emm %>% summary() %>% as.data.frame() %>%
  879. mutate(across(where(is.numeric), ~ round(.x, 2)))
  880. write.csv(emm_2, "multilevel_model/output/tables/TabS4-13_emms.csv", row.names = TRUE)
  881. gaussian_c_diff <- conditional_effects(fit_gaussian_c_diff_exp2, effects = "contribution")
  882. p <- plot(gaussian_c_diff, plot = FALSE)[[1]]+
  883. aes(color = contribution, fill = contribution)
  884. p +
  885. scale_color_manual(values = contribution_color) +
  886. scale_fill_manual(values = contribution_color) +
  887. theme_classic() +
  888. theme(text = element_text(size = 15)) +
  889. xlab("Contribution") +
  890. ylab("Self-allocation Bias") +
  891. ggtitle("Experiment 2")
  892. ## ------------- model S5: including SVO score ------------------------------------------
  893. # exp1
  894. fit_gaussian_c_diff_SVO_exp1 <- brm(
  895. bf(
  896. difference ~ contribution * SVOscore_z + (1 | subject)
  897. ),
  898. data = exp1Data_contribution,
  899. family = gaussian(),
  900. chains = 8, cores = 8, iter = 3000, warmup = 1000
  901. )
  902. summary(fit_gaussian_c_diff_SVO_exp1)
  903. saveRDS(fit_gaussian_c_diff_SVO_exp1, file = "output/exp1_fit_gaussian_c_diff_SVO.rds")
  904. #exp2
  905. fit_gaussian_c_diff_SVO_exp2 <- brm(
  906. bf(
  907. difference ~ contribution * SVOscore_z + (1 | subject)
  908. ),
  909. data = exp2Data_contribution,
  910. family = gaussian(),
  911. chains = 8, cores = 8, iter = 3000, warmup = 1000
  912. )
  913. summary(fit_gaussian_c_diff_SVO_exp2)
  914. saveRDS(fit_gaussian_c_diff_SVO_exp2, file = "output/exp2_fit_gaussian_c_diff_SVO.rds")
  915. ## post hoc
  916. #exp1
  917. fit_gaussian_c_diff_SVO_exp1 <- readRDS("multilevel_model/output/exp1_fit_gaussian_c_diff_SVO.rds")
  918. slopes_SVO <- emtrends(fit_gaussian_c_diff_SVO_exp1, ~ contribution, var = "SVOscore_z")
  919. pairs(slopes_SVO)
  920. emm_2 <- slopes_SVO %>% summary() %>% as.data.frame() %>%
  921. mutate(across(where(is.numeric), ~ round(.x, 2)))
  922. write.csv(emm_2, "multilevel_model/output/tables/TabS4-10_emms.csv", row.names = TRUE)
  923. c_diff_svo <- conditional_effects(fit_gaussian_c_diff_SVO_exp1,
  924. effects = "SVOscore_z:contribution")
  925. p <- plot(c_diff_svo, plot = FALSE)[[1]]
  926. p + scale_color_manual(values = contribution_color) +
  927. scale_fill_manual(values = contribution_color) +
  928. theme_classic()+
  929. theme(text = element_text(size = 15))+
  930. xlab("SVOscore (z-score)")+
  931. ylab("Allocation Ratio") +
  932. ggtitle("Experiment 1")
  933. #exp2
  934. fit_gaussian_c_diff_SVO_exp2 <- readRDS("multilevel_model/output/exp2_fit_gaussian_c_diff_SVO.rds")
  935. slopes_SVO <- emtrends(fit_gaussian_c_diff_SVO_exp2, ~ contribution, var = "SVOscore_z")
  936. pairs(slopes_SVO)
  937. emm_2 <- slopes_SVO %>% summary() %>% as.data.frame() %>%
  938. mutate(across(where(is.numeric), ~ round(.x, 2)))
  939. write.csv(emm_2, "multilevel_model/output/tables/TabS4-15_emms.csv", row.names = TRUE)
  940. slopes_SVO <- emtrends(fit_gaussian_c_diff_SVO_exp2, ~ contribution, var = "SVOscore_z")
  941. pairs(slopes_SVO)
  942. c_diff_svo <- conditional_effects(fit_gaussian_c_diff_SVO_exp2,
  943. effects = "SVOscore_z:contribution")
  944. p <- plot(c_diff_svo, plot = FALSE)[[1]]
  945. p + scale_color_manual(values = contribution_color) +
  946. scale_fill_manual(values = contribution_color) +
  947. theme_classic()+
  948. theme(text = element_text(size = 15))+
  949. xlab("SVOscore (z-score)")+
  950. ylab("Allocation Ratio") +
  951. ggtitle("Experiment 2")
  952. ## ---------------------- plot Figure S3 ------------------------------------
  953. exp1Data_contribution_sub <- combinedData_contribution_sub %>%
  954. filter(experiment == "Experiment1")
  955. exp2Data_contribution_sub <- combinedData_contribution_sub %>%
  956. filter(experiment == "Experiment2")
  957. ## experiment 1
  958. # plot S3a
  959. p_s3a<-ggplot(exp1Data_contribution_sub, aes(x = contribution, y = mean_diff, fill = contribution)) +
  960. geom_bar(stat = "summary", fun = "mean", colour = "black")+
  961. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  962. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  963. geom = "errorbar", width = .2)+
  964. scale_fill_manual(values = contribution_color) +
  965. theme_bw()+
  966. theme(text = element_text(size=20),
  967. panel.grid.major = element_blank(),
  968. panel.grid.minor = element_blank(),
  969. axis.ticks.x = element_blank(),
  970. axis.text.y = element_text(size = 15),
  971. legend.position = "none") +
  972. ylab("Self allocation bias") +
  973. xlab(" ")
  974. p_s3a
  975. # plot s3b
  976. p_s3b <- exp1Data_contribution_sub %>%
  977. ggplot(aes(x=SVOscore_z, y=mean_diff, color=contribution)) +
  978. geom_point(shape = 20,size=5,alpha = 0.8) +
  979. theme_bw() +
  980. theme(text = element_text(size=20),
  981. panel.grid.major = element_blank(),
  982. panel.grid.minor = element_blank(),
  983. plot.title = element_text(hjust = 0.5),
  984. axis.text.x = element_text(size = 15),
  985. axis.text.y = element_text(size = 15),
  986. panel.spacing.x = unit(0.8, "lines"),
  987. legend.position = "none")+
  988. geom_smooth(method=lm, se = FALSE)+
  989. scale_color_manual("Contribution",values=contribution_color)+
  990. # stat_cor(p.accuracy = 0.001,size = 6)+
  991. xlab("SVO score (z-scored)")+ylab("Self allocation bias")
  992. p_s3b
  993. ## experiment 2
  994. # plot S3c
  995. p_s3c<-ggplot(exp2Data_contribution_sub, aes(x = contribution, y = mean_diff, fill = contribution)) +
  996. geom_bar(stat = "summary", fun = "mean", colour = "black")+
  997. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  998. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  999. geom = "errorbar", width = .2)+
  1000. scale_fill_manual(values = contribution_color) +
  1001. theme_bw()+
  1002. theme(text = element_text(size=20),
  1003. panel.grid.major = element_blank(),
  1004. panel.grid.minor = element_blank(),
  1005. axis.ticks.x = element_blank(),
  1006. axis.text.y = element_text(size = 15),
  1007. legend.position = "none") +
  1008. ylab("Self allocation bias") +
  1009. xlab(" ")
  1010. p_s3c
  1011. # plot s3d
  1012. p_s3d <- exp2Data_contribution_sub %>%
  1013. ggplot(aes(x=SVOscore_z, y=mean_diff, color=contribution)) +
  1014. geom_point(shape = 20,size=5,alpha = 0.8) +
  1015. theme_bw() +
  1016. theme(text = element_text(size=20),
  1017. panel.grid.major = element_blank(),
  1018. panel.grid.minor = element_blank(),
  1019. plot.title = element_text(hjust = 0.5),
  1020. axis.text.x = element_text(size = 15),
  1021. axis.text.y = element_text(size = 15),
  1022. panel.spacing.x = unit(0.8, "lines"),
  1023. legend.position = "none" )+
  1024. geom_smooth(method=lm, se = FALSE)+
  1025. scale_color_manual("Contribution",values=contribution_color)+
  1026. # stat_cor(p.accuracy = 0.001,size = 6)+
  1027. xlab("SVO score (z-scored)")+ylab("Self allocation bias")
  1028. p_s3d
  1029. ## -------------- Plot: contribution * contribution -----------------------
  1030. combinedData_conditionContribution_cub <- combinedData %>%
  1031. filter(!is.na(allocation_ratio)) %>%
  1032. dplyr::select(experiment,contribution,subject,condition,allocation_ratio,SVOscore_z) %>%
  1033. group_by(experiment,contribution,subject,condition) %>%
  1034. dplyr::summarize(mean_allocation_ratio = mean(allocation_ratio),
  1035. SVOscore_z = first(SVOscore_z)) %>%
  1036. select(experiment, contribution,condition, subject, mean_allocation_ratio, SVOscore_z)
  1037. combinedData_conditionContribution_cub$subject <- as.factor(combinedData_conditionContribution_cub$subject)
  1038. p_s3 <- ggplot(combinedData_conditionContribution_cub, aes(x = condition, y = mean_allocation_ratio, fill = condition)) +
  1039. geom_bar(stat = "summary", fun = "mean", colour = "black", position = "dodge") +
  1040. geom_line(aes(group = subject),color = 'darkgray') +
  1041. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  1042. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  1043. geom = "errorbar", width = .2)+
  1044. geom_hline(yintercept = 0.5,linetype="dashed", color = "black") +
  1045. facet_grid(~contribution) +
  1046. scale_fill_manual(values = dark) +
  1047. theme_bw()+
  1048. theme(text = element_text(size=20),
  1049. panel.grid.major = element_blank(),
  1050. panel.grid.minor = element_blank(),
  1051. axis.text.x = element_blank(),
  1052. axis.ticks.x = element_blank(),
  1053. axis.text.y = element_text(size = 15),
  1054. plot.title = element_text(hjust = 0.5),
  1055. legend.text=element_text(size=15)) +
  1056. ylab("Relative allocation") +
  1057. xlab(" ") +
  1058. labs(fill = "Self-relevance")
  1059. p_s3
  1060. ## ------------------- Experiment 3 --------------------------------------------
  1061. ## ------------------- prepare data --------------------------------------------
  1062. Exp3_data <- read.csv(".../Exp3_data.csv", header = TRUE)
  1063. # add svo score
  1064. SVOdataExp3 <-read.csv(".../Exp3_SVOscore.csv", header = TRUE)
  1065. Exp3_data <- Exp3_data %>%
  1066. left_join(SVOdataExp3, by = "subject") %>%
  1067. mutate(experiment = 'Experiment3')
  1068. Exp3_data <- Exp3_data %>%
  1069. filter( winorloss=="Rewards") %>%
  1070. mutate( contribution = case_when((performance1 >= threshold & performance2 < threshold)~"Player1 only",
  1071. (performance2 >= threshold & performance1 < threshold)~"Player2 only",
  1072. TRUE ~"Both"),
  1073. p_source = case_when((condition == "SforS" | condition == "SforO") ~"Self-relevant",
  1074. (condition == "OforS" | condition == "OforO") ~"Self-irrelevant"),
  1075. a_target = case_when((condition == "SforS" | condition == "OforS") ~"Self-relevant",
  1076. (condition == "SforO" | condition == "OforO") ~"Self-irrelevant")) %>%
  1077. dplyr::select(subject,trial,task,condition,contribution,p_source, a_target, allocation_ratio,performance_ratio,SVOscore,experiment)
  1078. # factorize variables
  1079. Exp3_data$task <-factor(Exp3_data$task,c('Simple','Additive','Disjunctive'))
  1080. Exp3_data$condition <- factor(Exp3_data$condition, c("SforS","OforS","SforO","OforO"))
  1081. Exp3_data$p_source <- factor(Exp3_data$p_source,levels = c('Self-relevant','Self-irrelevant'))
  1082. Exp3_data$a_target <- factor(Exp3_data$a_target,levels = c('Self-relevant','Self-irrelevant'))
  1083. Exp3_data$contribution<-factor(Exp3_data$contribution,levels = c('Player1 only','Both','Player2 only'))
  1084. Exp3_data$SVOscore_z <- scale(Exp3_data$SVOscore)
  1085. ## ----------- model 1 task * performance source * allocation target -----------
  1086. # task * performance source * allocation target
  1087. fit_zoib_tpa <- brm(
  1088. bf(
  1089. allocation_ratio ~ task * p_source * a_target + (1 | subject)
  1090. ),
  1091. data = Exp3_data,
  1092. family = zero_one_inflated_beta(),
  1093. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1094. )
  1095. summary(fit_zoib_tpa)
  1096. saveRDS(fit_zoib_tpa, file = "output/exp3_fit_zoib_tpa.rds")
  1097. # task + performance source + allocation target
  1098. fit_zoib_tpa_noInt <- brm(
  1099. bf(
  1100. allocation_ratio ~ task + p_source + a_target + (1 | subject)
  1101. ),
  1102. data = Exp3_data,
  1103. family = zero_one_inflated_beta(),
  1104. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1105. )
  1106. summary(fit_zoib_tpa_noInt)
  1107. saveRDS(fit_zoib_tpa_noInt, file = "output/exp3_fit_zoib_tpa_noInt.rds")
  1108. # allocation target
  1109. fit_zoib_a <- brm(
  1110. bf(
  1111. allocation_ratio ~ a_target + (1 | subject)
  1112. ),
  1113. data = Exp3_data,
  1114. family = zero_one_inflated_beta(),
  1115. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1116. )
  1117. summary(fit_zoib_a)
  1118. saveRDS(fit_zoib_a, file = "output/exp3_fit_zoib_a.rds")
  1119. ## compare model
  1120. fit_zoib_tpa <- readRDS("multilevel_model/output/exp3_fit_zoib_tpa.rds")
  1121. coef_table <- as.data.frame(summary(fit_zoib_tpa)$fixed)
  1122. coef_table <- round(coef_table, 2)
  1123. write.csv(coef_table, "multilevel_model/output/tables/TabS7-1_fit_zoib_tc.csv", row.names = TRUE)
  1124. fit_zoib_tpa_noInt <- readRDS("output/exp3_fit_zoib_tpa_noInt.rds")
  1125. fit_zoib_a <- readRDS("output/exp3_fit_zoib_a.rds")
  1126. tpa_model <- loo(fit_zoib_tpa)
  1127. tpa_noInt_model <- loo(fit_zoib_tpa_noInt)
  1128. a_model <- loo(fit_zoib_a)
  1129. loo_compare(tpa_model,tpa_noInt_model,a_model) #diff 2*SE
  1130. ## post hoc
  1131. # get the full model
  1132. fit_zoib_tpa <- readRDS("multilevel_model/output/exp3_fit_zoib_tpa.rds")
  1133. post_summary <- describe_posterior(fit_zoib_tpa)
  1134. tab_df(post_summary,
  1135. title = "Posterior Estimates",
  1136. file = "multilevel_model/output/exp3_fit_zoib_tpa.html")
  1137. # get the best model
  1138. fit_zoib_a <- readRDS("multilevel_model/output/exp3_fit_zoib_a.rds")
  1139. post_summary <- describe_posterior(fit_zoib_a)
  1140. tab_df(post_summary,
  1141. title = "Posterior Estimates",
  1142. file = "multilevel_model/output/exp3_fit_zoib_a.html")
  1143. summary(fit_zoib_a)
  1144. # post hoc
  1145. emm <- emmeans(fit_zoib_a, ~ a_target, type = "response")
  1146. plot(emm)
  1147. contrast(emm, "pairwise")
  1148. # plot
  1149. a <- conditional_effects(fit_zoib_a, effects = "a_target")
  1150. p <- plot(a, plot = FALSE)[[1]]+
  1151. aes(color = a_target)
  1152. p +
  1153. scale_color_manual(values = dark) +
  1154. scale_fill_manual(values = dark) +
  1155. theme_classic() +
  1156. theme(text = element_text(size = 15)) +
  1157. xlab("Allocation Target") +
  1158. ylab("Allocation Ratio")
  1159. ## post hoc
  1160. # get the full model
  1161. fit_zoib_tpa <- readRDS("multilevel_model/output/exp3_fit_zoib_tpa.rds")
  1162. summary(fit_zoib_tpa)
  1163. # post hoc
  1164. emm <- emmeans(fit_zoib_tpa, ~ p_source|a_target, type = "response")
  1165. plot(emm)
  1166. contrast(emm, "pairwise")
  1167. emm <- emmeans(fit_zoib_tpa, ~ a_target|p_source, type = "response")
  1168. plot(emm)
  1169. contrast(emm, "pairwise")
  1170. # plot
  1171. a <- conditional_effects(fit_zoib_tpa, effects = "p_source:a_target",
  1172. conditions = list(task = c("Simple", "Additive", "Disjunctive")))
  1173. p <- plot(a, plot = FALSE)[[1]]+
  1174. aes(color = a_target)
  1175. p +
  1176. scale_color_manual(values = dark) +
  1177. scale_fill_manual(values = dark) +
  1178. theme_classic() +
  1179. theme(text = element_text(size = 15)) +
  1180. xlab("Performance source") +
  1181. ylab("Allocation Ratio") +
  1182. facet_wrap(~task, labeller = labeller(task = c("Simple", "Additive", "Disjunctive"))) # custom facet names
  1183. ## ------------- model 2: task * p_source * a_target * SVO score ------------------------------------------
  1184. # task * condition * SVOscore
  1185. fit_zoib_tpa_SVO <- brm(
  1186. bf(
  1187. allocation_ratio ~ task * p_source * a_target * SVOscore_z + (1 | subject)
  1188. ),
  1189. data = Exp3_data,
  1190. family = zero_one_inflated_beta(),
  1191. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1192. )
  1193. summary(fit_zoib_tpa_SVO)
  1194. saveRDS(fit_zoib_tpa_SVO, file = "output/exp3_fit_zoib_tpa_SVO.rds")
  1195. # a * SVOscore
  1196. fit_zoib_a_SVO <- brm(
  1197. bf(
  1198. allocation_ratio ~ a_target * SVOscore_z + (1 | subject)
  1199. ),
  1200. data = Exp3_data,
  1201. family = zero_one_inflated_beta(),
  1202. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1203. )
  1204. summary(fit_zoib_a_SVO)
  1205. saveRDS(fit_zoib_a_SVO, file = "output/exp3_fit_zoib_a_SVO.rds")
  1206. # compare model
  1207. fit_zoib_tpa_SVO <- readRDS("multilevel_model/output/exp3_fit_zoib_tpa_SVO.rds")
  1208. fit_zoib_a_SVO <- readRDS("multilevel_model/output/exp3_fit_zoib_a_SVO.rds")
  1209. loo_compare( loo(fit_zoib_tpa_SVO), loo(fit_zoib_a_SVO))
  1210. coef_table <- as.data.frame(summary(fit_zoib_a_SVO)$fixed)
  1211. coef_table <- round(coef_table, 2)
  1212. write.csv(coef_table, "multilevel_model/output/tables/TabS7-4_fit_zoib.csv", row.names = TRUE)
  1213. # post hoc
  1214. post_summary <- describe_posterior(fit_zoib_a_SVO)
  1215. tab_df(post_summary,
  1216. title = "Posterior Estimates",
  1217. file = "multilevel_model/output/exp3_fit_zoib_a_SVO.html")
  1218. slopes_SVO <- emtrends(fit_zoib_a_SVO, ~ a_target, var = "SVOscore_z")
  1219. pairs(slopes_SVO)
  1220. a_svo <- conditional_effects(fit_zoib_a_SVO,
  1221. effects = "SVOscore_z:a_target")
  1222. p <- plot(a_svo, plot = FALSE)[[1]]
  1223. p + scale_color_manual(values = dark) +
  1224. scale_fill_manual(values = dark) +
  1225. theme_classic()+
  1226. theme(text = element_text(size = 15))+
  1227. xlab("SVOscore (z-score)")+
  1228. ylab("Allocation Ratio")
  1229. ## -------------------- model 3: performance ratio * a target -----------------
  1230. ## model fitting
  1231. fit_zoib_pa <- brm(
  1232. bf(
  1233. allocation_ratio ~ performance_ratio * a_target + (1 | subject)
  1234. ),
  1235. data = Exp3_data,
  1236. family = zero_one_inflated_beta(),
  1237. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1238. )
  1239. summary(fit_zoib_pa)
  1240. saveRDS(fit_zoib_pa, file = "output/exp3_fit_zoib_pa.rds")
  1241. ## post hoc
  1242. fit_zoib_pa <- readRDS("multilevel_model/output/exp3_fit_zoib_pa.rds")
  1243. coef_table <- as.data.frame(summary(fit_zoib_pa)$fixed)
  1244. coef_table <- round(coef_table, 2)
  1245. write.csv(coef_table, "multilevel_model/output/tables/TabS7-5_fit_zoib.csv", row.names = TRUE)
  1246. post_summary <- describe_posterior(fit_zoib_pa)
  1247. tab_df(post_summary,
  1248. title = "Posterior Estimates",
  1249. file = "multilevel_model/output/exp3_fit_zoib_pa.html")
  1250. slopes_a <- emtrends(fit_zoib_pa, ~ a_target, var = "performance_ratio")
  1251. pairs(slopes_a)
  1252. pa <- conditional_effects(fit_zoib_pa, effects = "performance_ratio:a_target")
  1253. p_exp3_2c <- plot(pa, plot = FALSE)[[1]] +
  1254. scale_color_manual(values = dark) +
  1255. scale_fill_manual(values = dark) +
  1256. theme_bw() +
  1257. theme(text = element_text(size=20),
  1258. panel.grid.major = element_blank(),
  1259. panel.grid.minor = element_blank(),
  1260. plot.title = element_text(hjust = 0.5),
  1261. axis.text.x = element_text(size = 15),
  1262. axis.text.y = element_text(size = 15),
  1263. panel.spacing.x = unit(0.8, "lines"),
  1264. legend.text=element_text(size=15))+
  1265. xlab("Relative Performance")+
  1266. ylab("Relative Allocation") +
  1267. labs(color = "Allocation target", fill = "Allocation target")
  1268. p_exp3_2c
  1269. ## ---------------------- plot Figure exp3 2 A-C -------------------------------
  1270. # data
  1271. Exp3_data_sub <- Exp3_data %>%
  1272. filter(!is.na(allocation_ratio)) %>%
  1273. dplyr::select(experiment,task,subject,condition,allocation_ratio,SVOscore_z) %>%
  1274. group_by(experiment,task,subject,condition) %>%
  1275. dplyr::summarize(mean_allocation_ratio = mean(allocation_ratio),
  1276. SVOscore_z = first(SVOscore_z)) %>%
  1277. select(experiment, task,condition, subject, mean_allocation_ratio, SVOscore_z)
  1278. Exp3_data_sub$subject <- as.factor(Exp3_data_sub$subject)
  1279. p_exp3_2a <- ggplot(Exp3_data_sub, aes(x = condition, y = mean_allocation_ratio, fill = condition)) +
  1280. geom_bar(stat = "summary", fun = "mean", colour = "black", position = "dodge") +
  1281. # geom_line(aes(group = subject),color = 'gray') +
  1282. geom_point(aes(group = subject), shape = 21, color = 'darkgray',size = 3) +
  1283. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  1284. geom = "errorbar", width = .2)+
  1285. geom_hline(yintercept = 0.5,linetype="dashed", color = "black") +
  1286. facet_grid(~task) +
  1287. scale_fill_manual(values = color_four) +
  1288. theme_bw()+
  1289. theme(text = element_text(size=20),
  1290. panel.grid.major = element_blank(),
  1291. panel.grid.minor = element_blank(),
  1292. axis.text.x = element_blank(),
  1293. axis.ticks.x = element_blank(),
  1294. axis.text.y = element_text(size = 15),
  1295. plot.title = element_text(hjust = 0.5),
  1296. legend.text=element_text(size=15)) +
  1297. ylab("Relative allocation") +
  1298. xlab(" ") +
  1299. labs(fill = "Self-relevance")
  1300. p_exp3_2a
  1301. p_exp3_2b<-Exp3_data_sub %>%
  1302. ggplot(aes(x=SVOscore_z, y=mean_allocation_ratio, color=condition)) +
  1303. geom_point(shape = 20,size=5,alpha = 0.5) +
  1304. theme_bw() +
  1305. theme(text = element_text(size=20),
  1306. panel.grid.major = element_blank(),
  1307. panel.grid.minor = element_blank(),
  1308. plot.title = element_text(hjust = 0.5),
  1309. axis.text.x = element_text(size = 15),
  1310. axis.text.y = element_text(size = 15),
  1311. panel.spacing.x = unit(0.8, "lines"),
  1312. legend.text=element_text(size=15))+
  1313. #legend.position="none")+
  1314. geom_smooth(method=lm, se = FALSE)+
  1315. #stat_cor()+
  1316. facet_grid(~task,scales = "free")+
  1317. #scale_shape_manual(values=c(3, 16))+
  1318. scale_color_manual(values=color_four)+
  1319. xlab("SVO score (z-scored)")+
  1320. ylab("Relative allocation")+
  1321. labs(color = "Allocation target")
  1322. p_exp3_2b
  1323. # plot Figure exp3 2b
  1324. Exp3_data_sub <- Exp3_data %>%
  1325. filter(!is.na(allocation_ratio)) %>%
  1326. dplyr::select(experiment,task,subject,a_target,allocation_ratio,SVOscore_z) %>%
  1327. group_by(experiment,task,subject,a_target) %>%
  1328. dplyr::summarize(mean_allocation_ratio = mean(allocation_ratio),
  1329. SVOscore_z = first(SVOscore_z)) %>%
  1330. select(experiment, task,a_target, subject, mean_allocation_ratio, SVOscore_z)
  1331. Exp3_data_sub$subject <- as.factor(Exp3_data_sub$subject)
  1332. p_exp3_2b<-Exp3_data_sub %>%
  1333. ggplot(aes(x=SVOscore_z, y=mean_allocation_ratio, color=a_target)) +
  1334. geom_point(shape = 20,size=5,alpha = 0.5) +
  1335. theme_bw() +
  1336. theme(text = element_text(size=20),
  1337. panel.grid.major = element_blank(),
  1338. panel.grid.minor = element_blank(),
  1339. plot.title = element_text(hjust = 0.5),
  1340. axis.text.x = element_text(size = 15),
  1341. axis.text.y = element_text(size = 15),
  1342. panel.spacing.x = unit(0.8, "lines"),
  1343. legend.text=element_text(size=15))+
  1344. #legend.position="none")+
  1345. geom_smooth(method=lm, se = FALSE)+
  1346. #stat_cor()+
  1347. facet_grid(~task,scales = "free")+
  1348. #scale_shape_manual(values=c(3, 16))+
  1349. scale_color_manual(values=dark)+
  1350. xlab("SVO score (z-scored)")+
  1351. ylab("Relative allocation")+
  1352. labs(color = "Allocation target")
  1353. p_exp3_2b
  1354. ## -------------- model 4: contribution on diff -------------------------------
  1355. ## prepare data
  1356. # calculate the differnece between self-relevant and self-irrelevant based on trial
  1357. Exp3_Data_contribution <- Exp3_data %>%
  1358. pivot_wider(id_cols = c(subject,SVOscore_z,SVOscore,trial,task,contribution,performance_ratio, p_source),
  1359. names_from = a_target,
  1360. values_from = allocation_ratio) %>%
  1361. mutate(difference = `Self-relevant` - `Self-irrelevant`)
  1362. ## model fitting
  1363. fit_gaussian_a_diff <- brm(
  1364. bf(
  1365. difference ~ contribution + (1 | subject)
  1366. ),
  1367. data = Exp3_Data_contribution,
  1368. family = gaussian(),
  1369. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1370. )
  1371. summary(fit_gaussian_a_diff)
  1372. saveRDS(fit_gaussian_a_diff, file = "output/exp3_fit_gaussian_a_diff.rds")
  1373. ## post hoc
  1374. fit_gaussian_a_diff <- readRDS("multilevel_model/output/exp3_fit_gaussian_a_diff.rds")
  1375. post_summary <- describe_posterior(fit_gaussian_a_diff)
  1376. tab_df(post_summary,
  1377. title = "Posterior Estimates",
  1378. file = "multilevel_model/output/exp3_fit_gaussian_a_diff.html")
  1379. emm <- emmeans(fit_gaussian_a_diff, ~ contribution, type = "response")
  1380. contrast(emm, "pairwise")
  1381. gaussian_a_diff <- conditional_effects(fit_gaussian_a_diff, effects = "contribution")
  1382. p <- plot(gaussian_a_diff, plot = FALSE)[[1]]+
  1383. aes(color = contribution, fill = contribution)
  1384. p +
  1385. scale_color_manual(values = contribution_color) +
  1386. scale_fill_manual(values = contribution_color) +
  1387. theme_classic() +
  1388. theme(text = element_text(size = 15)) +
  1389. xlab("Contribution") +
  1390. ylab("Self-allocation Bias")
  1391. ## ------------- model 5: including SVO score ------------------------------------------
  1392. fit_gaussian_a_diff_SVO <- brm(
  1393. bf(
  1394. difference ~ contribution * SVOscore_z + (1 | subject)
  1395. ),
  1396. data = Exp3_Data_contribution,
  1397. family = gaussian(),
  1398. chains = 8, cores = 8, iter = 3000, warmup = 1000
  1399. )
  1400. summary(fit_gaussian_a_diff_SVO)
  1401. saveRDS(fit_gaussian_a_diff_SVO, file = "output/exp3_fit_gaussian_a_diff_SVO.rds")
  1402. ## post hoc
  1403. fit_gaussian_a_diff_SVO <- readRDS("multilevel_model/output/exp3_fit_gaussian_a_diff_SVO.rds")
  1404. post_summary <- describe_posterior(fit_gaussian_a_diff_SVO)
  1405. tab_df(post_summary,
  1406. title = "Posterior Estimates",
  1407. file = "multilevel_model/output/exp3_fit_gaussian_a_diff_SVO.html")
  1408. slopes_SVO <- emtrends(fit_gaussian_a_diff_SVO, ~ contribution, var = "SVOscore_z")
  1409. pairs(slopes_SVO)
  1410. c_diff_svo <- conditional_effects(fit_gaussian_a_diff_SVO,
  1411. effects = "SVOscore_z:contribution")
  1412. p <- plot(c_diff_svo, plot = FALSE)[[1]]
  1413. p + scale_color_manual(values = contribution_color) +
  1414. scale_fill_manual(values = contribution_color) +
  1415. theme_classic()+
  1416. theme(text = element_text(size = 15))+
  1417. xlab("SVOscore (z-score)")+
  1418. ylab("Allocation Ratio")
  1419. ## contribution data prep
  1420. Exp3_Data_contribution_sub <- Exp3_Data_contribution %>%
  1421. filter(!is.na(difference)) %>%
  1422. dplyr::select(task,subject,contribution,difference,SVOscore_z) %>%
  1423. group_by(subject,contribution) %>%
  1424. dplyr::summarize(mean_diff = mean(difference),
  1425. SVOscore_z = first(SVOscore_z)) %>%
  1426. select(contribution, subject, mean_diff, SVOscore_z)
  1427. Exp3_Data_contribution_sub$subject <- as.factor(Exp3_Data_contribution_sub$subject)
  1428. # ---------------------------plot Figure exp3 2 DE------------------------------
  1429. p_exp3_2d<-ggplot(Exp3_Data_contribution_sub, aes(x = contribution, y = mean_diff, fill = contribution)) +
  1430. geom_bar(stat = "summary", fun = "mean", colour = "black")+
  1431. geom_point(aes(group = subject), shape = 21, color = 'darkgray') +
  1432. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  1433. geom = "errorbar", width = .2)+
  1434. scale_fill_manual(values = contribution_color) +
  1435. theme_bw()+
  1436. theme(text = element_text(size=20),
  1437. panel.grid.major = element_blank(),
  1438. panel.grid.minor = element_blank(),
  1439. axis.ticks.x = element_blank(),
  1440. axis.text.y = element_text(size = 15),
  1441. legend.position = "none") +
  1442. ylab("Self allocation bias") +
  1443. xlab(" ")
  1444. p_exp3_2d
  1445. # plot 2e
  1446. p_exp3_2e <- Exp3_Data_contribution_sub %>%
  1447. ggplot(aes(x=SVOscore_z, y=mean_diff, color=contribution)) +
  1448. geom_point(shape = 20,size=5,alpha = 0.8) +
  1449. theme_bw() +
  1450. theme(text = element_text(size=20),
  1451. panel.grid.major = element_blank(),
  1452. panel.grid.minor = element_blank(),
  1453. plot.title = element_text(hjust = 0.5),
  1454. axis.text.x = element_text(size = 15),
  1455. axis.text.y = element_text(size = 15),
  1456. panel.spacing.x = unit(0.8, "lines"),
  1457. legend.position = "none")+
  1458. geom_smooth(method=lm, se = FALSE)+
  1459. scale_color_manual("Contribution",values=contribution_color)+
  1460. # stat_cor(p.accuracy = 0.001,size = 6)+
  1461. xlab("SVO score (z-scored)")+ylab("Self allocation bias")
  1462. p_exp3_2e
  1463. ## ---------------------- ROI plots ------------------------------------------
  1464. # dmPFC
  1465. ROI_data <- read.csv(".../ROI_pmod_Main_effect_of_factor_2_12_28_52.csv", header = TRUE)
  1466. # OFC r
  1467. ROI_data <- read.csv(".../ROI_pmod_Main_effect_of_factor_2_40_48_-12.csv", header = TRUE)
  1468. # OFC l
  1469. ROI_data <- read.csv(".../ROI_pmod_Main_effect_of_factor_2_-42_50_-6.csv", header = TRUE)
  1470. # TPJ r
  1471. ROI_data <- read.csv(".../ROI_pmod_Main_effect_of_factor_2_44_-64_42.csv", header = TRUE)
  1472. # TPJ l
  1473. ROI_data <- read.csv(".../ROI_pmod_Main_effect_of_factor_2_-56_-64_30.csv", header = TRUE)
  1474. # temporal r
  1475. ROI_data <- read.csv(".../ROI_pmod_Main_effect_of_factor_2_64_-38_-4.csv", header = TRUE)
  1476. ROI_data <- ROI_data %>%
  1477. mutate(
  1478. Condition = case_when(Contribution < 4~"Self-relevant", Contribution >= 4~"Self-irrelevant"),
  1479. Contribution = case_when(Contribution == 1|Contribution == 4~"Both", Contribution == 2|Contribution == 5~"Player1 only",Contribution == 3|Contribution == 6~"Player2 only"),
  1480. Subject = Subject + 100) %>%
  1481. arrange(Contribution,Condition,Subject)
  1482. ROI_data$Subject<-factor(ROI_data$Subject)
  1483. ROI_data$Condition<-factor(ROI_data$Condition, levels = c('Self-relevant','Self-irrelevant'))
  1484. ROI_data$Contribution<-factor(ROI_data$Contribution, levels = c('Player1 only','Both','Player2 only'))
  1485. ROI_data_contribution <- ROI_data %>%
  1486. group_by(Contribution, Subject) %>%
  1487. dplyr::summarize(ROI_beta_mean = mean(ROI_beta)) %>%
  1488. ungroup()
  1489. # plot
  1490. p_roi<-ggplot(ROI_data_contribution, aes(x = Contribution, y = ROI_beta_mean, fill = Contribution)) +
  1491. geom_bar(stat = "summary", fun = "mean", colour = "black")+
  1492. geom_point(aes(group = Subject), shape = 21, color = 'darkgray', size = 4) +
  1493. stat_summary(fun.data = mean_cl_normal, na.rm =TRUE,
  1494. geom = "errorbar", width = .2)+
  1495. scale_fill_manual(values = contribution_color) +
  1496. theme_bw()+
  1497. theme(text = element_text(size=25),
  1498. panel.grid.major = element_blank(),
  1499. panel.grid.minor = element_blank(),
  1500. axis.ticks.x = element_blank(),
  1501. axis.text.y = element_text(size = 25),
  1502. legend.position = "none") +
  1503. ylab("Beta estimates") +
  1504. xlab(" ")
  1505. p_roi

GA_analysis_plot_code.R, no license · at the source

Overview

Authors: Sihui Zhang1,2, Xue Yong1, Yina Ma1,3, Christoph W. Korn2,4
ORCID iDs: Sihui Zhang, Yina Ma
  1. State Key Laboratory of Cognitive Neuroscience and Learning & IDG/McGovern Institute for Brain Research, Faculty of Psychology, Beijing Normal University, Beijing, China
  2. Section Social Neuroscience, Department of General Psychiatry, University of Heidelberg, Heidelberg, Germany
  3. Chinese Institute for Brain Research, Beijing, China
  4. Institute for Systems Neuroscience, University Medical Center Hamburg-Eppendorf, Hamburg, Germany
Journal: PLoS biology, volume 24, issue 3, article e3003694
Dates: received 13 June 2025; accepted 23 February 2026; published online 26 March 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1371/journal.pbio.3003694 · PMID 41886463 · PMCID PMC13020808 · OpenAlex W7140359916
Open access: gold, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: structural MRI / diffusion (modality), human (organism), cognitive (subfield)
Methods: Statistics, Machine learning, fMRI & imaging
MeSH: Cooperative Behavior*, Decision Making*, Adult, Female, Humans, Magnetic Resonance Imaging, Male, Prefrontal Cortex, Reward, Young Adult (* major topic)
Journal subjects: Biology and Life Sciences, Psychology, Behavior, Social Sciences, Neuroscience, Cognitive Science, Cognitive Psychology, Decision Making, Cognition, Brain Mapping, Functional Magnetic Resonance Imaging, Medicine and Health Sciences, Diagnostic Medicine, Diagnostic Radiology, Magnetic Resonance Imaging, Research and Analysis Methods, Imaging Techniques, Radiology and Imaging, Neuroimaging, Human Performance, Anatomy, Brain, Prefrontal Cortex, Physical Sciences, Mathematics, Applied Mathematics, Game Theory, Statistics, Statistical Data
Topic: Neural and Behavioral Psychology Studies (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: National Natural Science Foundation of China (32430041, 32125019); STI 2030–Major Projects (2022ZD0211000); Fundamental Research Funds for the Central Universities (2233300002); Deutsche Forschungsgemeinschaft (392443797); China Scholarship Council
Citations: cited by 1 paper (Europe PMC); 102 references in the paper
Notices: A correction to this paper has been published (42627763, from Europe PMC)

Abstract

Human cooperation often involves performing joint tasks, where success relies on how collective rewards are allocated among cooperating parties based on their individual performance and contribution to task outcomes. However, it remains unclear whether and how individual performance and contribution give rise to self-related biases in such allocation decisions. Here, we developed a novel performance-based social allocation task that manipulated how individual performance contributed to joint outcomes. Across two experiments, participants exhibited a robust self-allocation bias: they allocated more rewards to themselves and disproportionately disregarded their own performance, particularly when their performance did not causally contribute to the joint outcome. This self-allocation bias was amplified in individuals with stronger individualistic social preferences, as measured by social value orientation. At the neural level, self-relevant (versus self-irrelevant) allocation decisions were associated with increased activity in the medial prefrontal cortex extending into the anterior cingulate cortex, insula, and temporoparietal junction (TPJ). Moreover, the dorsomedial prefrontal cortex, lateral orbitofrontal cortex, and TPJ tracked trial-by-trial variations in relative performance as a function of contribution structure, independent of self-relevance. Together, these findings suggest that self-allocation bias in performance-based decisions is unlikely to arise from distorted neural encodings of performance. Instead, self-interest may shape how contribution-structured performance information is used in social-allocation choices, providing a more precise account of how self-serving behavior emerges in cooperative contexts.

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 3 matches between paragraphs and lines of code.

OSF afdqs

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Languages: R (1)
Size: 3 files, 1 script
Software Heritage: not checked
Found in: the supplementary material
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: brms (1 file), cowplot (1 file), easystats (1 file), emmeans (1 file), ggplot2 (1 file), ggpubr (1 file), tidyverse (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers (HTTP 200)
  • 30 September 2026: the link answers (HTTP 200)
1 file

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;
  • 1 script, each with its path and the digest of its content;
  • 3 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 codes related to this paper are available and archived in Open Science Framework at https://doi.org/10.17605/OSF.IO/AFDQS.

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, 30 September 2026: the first record

Recorded: type, language, journal, volume, issue, pages, dates, 4 authors, 10 MeSH terms, 5 funders, 91 references, 1 integrity notice.

Cite

This paper

Zhang, S., Yong, X., Ma, Y., & Korn, C. W. (2026). Self-allocation bias in performance-based cooperative decisions is driven by self-interest rather than distorted performance encoding. PLoS biology, 24(3), e3003694. https://doi.org/10.1371/journal.pbio.3003694

BibTeX

@article{zhang2026self,
author = {Zhang, Sihui and Yong, Xue and Ma, Yina and Korn, Christoph W.},
title = {{Self-allocation bias in performance-based cooperative decisions is driven by self-interest rather than distorted performance encoding}},
journal = {PLoS biology},
year = {2026},
month = mar,
volume = {24},
number = {3},
pages = {e3003694},
publisher = {PLOS},
issn = {1544-9173},
doi = {10.1371/journal.pbio.3003694},
url = {https://doi.org/10.1371/journal.pbio.3003694},
pmid = {41886463},
pmcid = {PMC13020808}
}

RIS

TY - JOUR
AU - Zhang, Sihui
AU - Yong, Xue
AU - Ma, Yina
AU - Korn, Christoph W.
TI - Self-allocation bias in performance-based cooperative decisions is driven by self-interest rather than distorted performance encoding
T2 - PLoS biology
J2 - PLoS Biol
PY - 2026
DA - 2026/03/26
VL - 24
IS - 3
SP - e3003694
SN - 1544-9173
PB - PLOS
DO - 10.1371/journal.pbio.3003694
UR - https://doi.org/10.1371/journal.pbio.3003694
LA - en
ER -

CSL-JSON

{
"id": "10.1371/journal.pbio.3003694",
"type": "article-journal",
"title": "Self-allocation bias in performance-based cooperative decisions is driven by self-interest rather than distorted performance encoding",
"container-title": "PLoS biology",
"author": [
{
"family": "Zhang",
"given": "Sihui"
},
{
"family": "Yong",
"given": "Xue"
},
{
"family": "Ma",
"given": "Yina"
},
{
"family": "Korn",
"given": "Christoph W."
}
],
"container-title-short": "PLoS Biol",
"volume": "24",
"issue": "3",
"page": "e3003694",
"DOI": "10.1371/journal.pbio.3003694",
"PMID": "41886463",
"PMCID": "PMC13020808",
"ISSN": "1544-9173",
"publisher": "PLOS",
"URL": "https://doi.org/10.1371/journal.pbio.3003694",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
26
]
]
}
}

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.1371/journal.pbio.3003079 [code]
Dorsomedial and ventromedial prefrontal cortex lesions differentially impact social influence and temporal discounting.
Journal: PLoS biology
In common: easystats, emmeans, ggpubr, 2 other tools, cognitive, 8 references
[2] doi:10.1038/s41586-025-08705-9 [code]
Basis functions for complex social decisions in dorsomedial frontal cortex.
Journal: Nature
In common: ggpubr, ggplot2, tidyverse, cognitive, 8 references
[3] doi:10.1038/s42003-022-04329-1 [code]
Behavioral and neuro-cognitive bases for emergence of norms and socially shared realities via dynamic interaction.
Journal: Communications biology
In common: brms, tidyverse, 8 references
[4] doi:10.1093/scan/nsad023 [code]
Mentalizing in an economic games context is associated with enhanced activation and connectivity in the left temporoparietal junction.
Journal: Social cognitive and affective neuroscience
In common: cognitive, 9 references
[5] doi:10.3758/s13415-026-01425-1 [code]
Mindful minds: How group identity shapes brain and behavior in social decision-making.
Journal: Cognitive, affective & behavioral neuroscience
In common: cognitive, 9 references
[6] doi:10.1093/scan/nsag030 [code]
Delaying rewards reduces egoism bias during prosocial acts.
Journal: Social cognitive and affective neuroscience
In common: easystats, emmeans, ggpubr, 2 other tools, cognitive, 4 references
[7] doi:10.7554/elife.87271 [code]
Acute stress reduces effortful prosocial behaviour.
Journal: eLife
In common: emmeans, cowplot, ggpubr, 2 other tools, cognitive, 4 references
[8] doi:10.7554/elife.92539 [code]
A neurocomputational account of the link between social perception and social action.
Journal: eLife
In common: cognitive, 8 references
[9] doi: [code]
Neural integration of affective prosodic and semantic cues in non-literal forms of speech understanding
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: easystats, emmeans, cowplot, 3 other tools, cognitive, 3 references
[10] doi:10.1038/s41467-025-67853-8 [code]
Active disambiguation guides inferring controllability and cause in social interactions.
Journal: Nature communications
In common: brms, ggpubr, ggplot2, 1 other tool, 4 references

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.

Add the badge to the code's README

OSCR: the badge of this paper

If you are an author or a maintainer of this paper's code, you can add this badge. It says what OSCR knows of the paper (its code, its validated tracing map) and links the code to this page. Paste one of these snippets under the README's title. Keep the two marks around it, so that the badge can be replaced in place and is never added twice. OSCR changes nothing in your repository.

Markdown
<!-- oscr-badge:start -->
[![OSCR](https://openscicode.org/badge/doi/10.1371/journal.pbio.3003694.svg)](https://openscicode.org/badge/doi/10.1371/journal.pbio.3003694)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1371/journal.pbio.3003694.svg
   :target: https://openscicode.org/badge/doi/10.1371/journal.pbio.3003694
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1371/journal.pbio.3003694"><img src="https://openscicode.org/badge/doi/10.1371/journal.pbio.3003694.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

If you choose to, you can have the badge kept up to date for you, with oscr badge --write from the command line or with the GitHub Action in your repository's workflows. Every other form and option (a card, AsciiDoc, LaTeX, shields.io) is on the badge 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: code errors and mismatches between the code and the paper about this paper and its code, from readers and its authors, beside the paper and its tracing map.

Report a mismatch between the code and the paper · Report a code error (signed in)

Reproductions: reports from readers who ran the authors' code and did not get the paper's result, what they ran, with which environment, commit and data.

Report a reproduction failure (signed in)

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