OSCR

Locus coeruleus modulation of neurophysiological sensory selectivity differs in autism and other mental health conditions.

Code ↔ Paper

11 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 11 matches
  1. [1] § Methods › Pupillometry ↔ data_preprocessing_visual_oddball.R, lines 84 to 143 · score 0.88 · dilation speed outliers, median absolute deviation, corrected pupil, gaps, imputed, blink · Report a mismatch
  2. [2] § Methods › Pupillometry ↔ data_preprocessing_auditory_oddball.R, lines 330 to 443 · score 0.87 · dilation speed outliers, median absolute deviation, corrected pupil diameter, blink, preprocessed, eye · Report a mismatch
  3. [3] § Results › Stimulus effects ↔ data_analysis_auditory_oddball.R, lines 60 to 122 · score 0.83 · 100–150 ms, 150–250 ms, 500–1500 ms, Baseline, pupil, P3a · Report a mismatch
  4. [4] § Methods › Electroencephalography ↔ data_analysis_auditory_oddball.R, lines 1150 to 1206 · score 0.71 · 100–150 ms, 150–250 ms, cut, ERPs, P3a, 100 ms · Report a mismatch
  5. [5] § Methods › Measures ↔ SEGA_Preprocessing.Rmd, lines 1783 to 1880 · score 0.66 · matrix reasoning, block design, subtests, vocabulary, WAIS, CBCL · Report a mismatch
  6. [6] § Methods › Measures ↔ data_preprocessing_auditory_oddball.R, lines 1749 to 1793 · score 0.66 · matrix reasoning, block design, subtests, vocabulary, WAIS, CBCL · Report a mismatch
  7. [7] § Methods › Auditory oddball task ↔ data_preprocessing_auditory_oddball.R, lines 614 to 660 · score 0.56 · hand dynamometer, Grip strength, counterbalanced, oddballs, Auditory, blocks · Report a mismatch
  8. [8] § Results › Associations of the pupillometric measures ↔ SEGA_supplements.Rmd, lines 796 to 849 · score 0.56 · exploratory model fit, BIC, linear, predictor, SEPR, ERPs · Report a mismatch
  9. [9] § Results › Covariate effects ↔ SEGA_Preprocessing.Rmd, lines 1783 to 1880 · score 0.55 · verbal IQ, Grip strength, dependent variables, MMN latency, gender, age · Report a mismatch
  10. [10] § Results › Covariate effects ↔ data_analysis_auditory_oddball.R, lines 1670 to 1717 · score 0.51 · verbal IQ, Grip strength, MMN latency, covariates, P3a amplitude, models · Report a mismatch
  11. [11] § Results › Associations of the pupillometric measures ↔ data_analysis_auditory_oddball.R, lines 1446 to 1496 · score 0.51 · exploratory model fit, predictor, pupillometric, SEPR, ERPs, BPS · 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 · 2,188 lines · 81 KB · no license · 4 matches

  1. ### --- LOADS preprocessed auditory oddball data and analysis ERPs and pupillometry variables
  2. # SETUP ####
  3. # REQUIRED PACKAGES
  4. require(performance) # marginal + conditional R2
  5. require(lme4) # linear-mixed-effects models
  6. require(lmerTest, warn.conflicts = FALSE) # linear-mixed-effects models
  7. require(emmeans, warn.conflicts = FALSE) # estimated marginal means (EMMs)
  8. library(ggpubr, warn.conflicts = FALSE) # ggscatter()-function
  9. library(knitr) # dynamic report generation
  10. library(kableExtra) # table formatting
  11. library(tidyverse)
  12. library(cowplot, warn.conflicts = FALSE) # get only legend from plot
  13. library(simr) # power analysis
  14. library(gridExtra) # arrange ggplots
  15. # PATHS
  16. if (Sys.info()["sysname"] == "Linux") {
  17. home_path <- "~"
  18. project_path <- "/PowerFolders/project_sega"
  19. data_path <- "/PowerFolders/project_sega/data/AuditoryOddball"
  20. data_path_eeg <- "/PowerFolders/project_sega/data/AuditoryOddball_EEG"
  21. datapath <- paste0(home_path, data_path) # .csv + .hdf5 input files
  22. datapath_eeg <- paste0(home_path, data_path_eeg) # .txt input files (eeg)
  23. # List all .hdf and .csv files
  24. data_files <- list.files(path = datapath, full.names = TRUE)
  25. }
  26. if (Sys.info()["sysname"] == "Windows") {
  27. home_path <- "C:/Users/Nico"
  28. project_path <- "/PowerFolders/project_sega"
  29. data_path <- "/PowerFolders/project_sega/data/et auditory oddball"
  30. data_path_task<-"/PowerFolders/project_sega/data/task auditory oddball"
  31. data_path_eeg <- "/PowerFolders/project_sega/data/tests/eeg preprocessed auditory oddball"
  32. datapath <- paste0(home_path, data_path) # hdf5 input files
  33. datapath_task <- paste0(home_path, data_path_task) # hdf5 input files
  34. datapath_eeg <- paste0(home_path, data_path_eeg) # .txt input files (eeg)
  35. # List all .hdf and .csv files
  36. data_files <- c(list.files(path = datapath, full.names = TRUE),
  37. list.files(path = datapath_task, full.names = TRUE))
  38. }
  39. if (Sys.info()["sysname"] == "Darwin") {
  40. home_path <- "/Volumes/common/"
  41. project_path <- "/code"
  42. data_path <- "/code/input/AuditoryOddball/eyetracking"
  43. data_path_task <- "/code/input/AuditoryOddball/taskdata"
  44. data_path_eeg <- "/code/input/AuditoryOddball/eeg"
  45. datapath <- paste0(home_path, data_path) # .hdf5 input files
  46. datapath_task <- paste0(home_path, data_path_task) # .csv input files
  47. datapath_eeg <- paste0(home_path, data_path_eeg) # .txt input files (eeg)
  48. data_path_single_trial_eeg <- "/code/input/AuditoryOddball/eeg_single_trial"
  49. datapath_single_eeg <- paste0(home_path, data_path_single_trial_eeg)
  50. # List all .hdf and .csv files
  51. data_files <- c(
  52. list.files(path = datapath, full.names = TRUE),
  53. list.files(path = datapath_task, full.names = TRUE))
  54. }
  55. # Can be used to skip preprocessing and directly read proprocessed data from .rds file:
  56. df_trial <- readRDS(paste0(home_path,project_path,'/data/preprocessed_auditory_ETdata.rds')) # trial pupil data including ALL trials
  57. df <- readRDS(paste0(home_path, project_path,'/data/preprocessed_auditory_df.rds')) # pupil data (all data points for visualizing)
  58. et_erp_subject <- readRDS(paste0(home_path,project_path,'/data/preprocessed_auditory_ET_ERP_subject.rds')) # eeg + pupil (subject level, only oddball(rev) blocks)
  59. et_erp_trial <- readRDS(paste0(home_path,project_path,'/data/preprocessed_auditory_ET_ERP_trial.rds')) # eeg + pupil(single-trial, only oddball(rev) blocks)
  60. MMN_diff <- readRDS(paste0(home_path,project_path,'/data/preprocessed_auditory_MMN_diff.rds'))
  61. # Renaming the variable "trial" into "stimulus" to match terminology in the paper
  62. names(et_erp_subject)[names(et_erp_subject) == "trial"] <- "stimulus"
  63. names(et_erp_trial)[names(et_erp_trial) == "trial"] <- "stimulus"
  64. names(df_trial)[names(df_trial) == "trial"] <- "stimulus"
  65. names(df)[names(df) == "trial"] <- "stimulus"
  66. # DATA ANALYSIS ON SUBJECT LEVEL ####
  67. # Distributions of dependent variables
  68. par(mfrow = c(3,2), mar = c(4, 4, 2, 1))
  69. hist(et_erp_subject$z_rpd,
  70. main = "Distribution of rpd (500-1500 ms)",
  71. xlab = "rpd",
  72. xlim = c(-4, 6),
  73. breaks = 200)
  74. hist(et_erp_subject$z_rpd_low,
  75. main = "Distribution of rpd_low (0-250 ms)",
  76. xlab = "rpd_low",
  77. xlim = c(-4, 6),
  78. breaks = 200)
  79. hist(et_erp_subject$z_rpd_block,
  80. main = "Distribution of rpd_block",
  81. xlab = "rpd_block",
  82. xlim = c(-4, 4),
  83. breaks = 200)
  84. hist(et_erp_subject$z_MMN_amplitude,
  85. main = "Distribution of MMN amplitude (100-150 ms)",
  86. xlab = "MMN amplitude (FC1, FC2, FCz, Fz)",
  87. breaks = 200)
  88. hist(et_erp_subject$z_P3a_amplitude,
  89. main = "Distribution of P3a amplitude (150-250 ms)",
  90. xlab = "P3a amplitude (Cz, FCz)",
  91. ylim = c(0, 30),
  92. xlim = c(-4, 6),
  93. breaks = 200)
  94. hist(et_erp_subject$z_P3b_amplitude,
  95. main = "Distribution of P3b amplitude (250-500 ms)",
  96. xlab = "P3b amplitude (Pz)",
  97. xlim = c(-6, 8),
  98. breaks = 200)
  99. par(mfrow = c(1, 1))
  100. # New data frame: 1 row per subject containing sample description data (consistent across conditions)
  101. sample_description_df <- et_erp_subject %>%
  102. group_by(SEGA_ID) %>%
  103. summarise(across(everything(), ~ {
  104. vals <- na.omit(.x) # removes NAs so we only check actual values
  105. # keeps the column if all non-NA values are identical + returns that consistent value (or NA if all were NA)
  106. if (length(unique(vals)) <= 1) unique(vals)[1] else NA
  107. }), .groups = "drop") %>%
  108. # Keep columns that have at least some non-NA values + removes columns that are completely NA across all subjects
  109. select(where(~ any(!is.na(.))))
  110. sample_description_df$block_baseline_mean <- NULL
  111. # Sample size
  112. nrow(sample_description_df)
  113. table(sample_description_df$group)
  114. # Function returning group mean + sd
  115. fun_return_descriptives <- function(group){
  116. group_df <- sample_description_df[
  117. sample_description_df$group == group, ]
  118. # gender
  119. n <- length(unique(group_df$SEGA_ID))
  120. male <- (length(which(group_df$gender == "männlich")))
  121. female <- (length(which(group_df$gender == "weiblich")))
  122. gender_f_m <- paste(female,"/",male)
  123. # age
  124. age_mean <- round(mean(group_df$age, na.rm = TRUE), digits = 1)
  125. age_sd <- round(sd(group_df$age, na.rm = TRUE), digits = 1)
  126. age <- paste(age_mean, "(",age_sd,")" )
  127. # SRS
  128. SRS_mean <- round(mean(group_df$SRS, na.rm = TRUE), digits = 1)
  129. SRS_sd <- round(sd(group_df$SRS, na.rm = TRUE), digits = 1)
  130. SRS <- paste(SRS_mean, "(",SRS_sd,")")
  131. # CBCL
  132. CBCL_mean <- round(mean(group_df$CBCL, na.rm = TRUE), digits = 1)
  133. CBCL_sd <- round(sd(group_df$CBCL, na.rm = TRUE), digits = 1)
  134. CBCL <- paste(CBCL_mean, "(",CBCL_sd,")")
  135. # SCQ
  136. SCQ_mean <- round(mean(group_df$SCQ, na.rm = TRUE), digits = 1)
  137. SCQ_sd <- round(sd(group_df$SCQ, na.rm = TRUE), digits = 1)
  138. SCQ <- paste(SCQ_mean, "(", SCQ_sd, ")")
  139. # YSR
  140. YSR_mean <- round(mean(group_df$YSR, na.rm = TRUE), digits = 1)
  141. YSR_sd <- round(sd(group_df$YSR, na.rm = TRUE), digits = 1)
  142. YSR <- paste(YSR_mean, "(", YSR_sd, ")")
  143. # SP2
  144. SP2_mean <- round(mean(group_df$SP2, na.rm = TRUE), digits = 1)
  145. SP2_sd <- round(sd(group_df$SP2, na.rm = TRUE), digits = 1)
  146. SP2 <- paste(SP2_mean, "(", SP2_sd, ")")
  147. # grip strength
  148. grip_strength_mean <- round(mean(group_df$z_grip_strength, na.rm = TRUE), digits = 1)
  149. grip_strength_sd <- round(sd(group_df$z_grip_strength, na.rm = TRUE), digits = 1)
  150. grip_strength <- paste(grip_strength_mean, "(", grip_strength_sd, ")")
  151. # verbal IQ
  152. verbal_IQ_mean <- round(mean(group_df$verbal_IQ, na.rm = TRUE), digits = 1)
  153. verbal_IQ_sd <- round(sd(group_df$verbal_IQ, na.rm = TRUE), digits = 1)
  154. verbal_IQ <- paste(verbal_IQ_mean, "(", verbal_IQ_sd, ")")
  155. # non-verbal IQ
  156. non_verbal_IQ_mean <- round(mean(group_df$non_verbal_IQ, na.rm = TRUE), digits = 1)
  157. non_verbal_IQ_sd <- round(sd(group_df$non_verbal_IQ, na.rm = TRUE), digits = 1)
  158. non_verbal_IQ <- paste(non_verbal_IQ_mean, "(", non_verbal_IQ_sd, ")")
  159. # included trials eeg
  160. included_trials_eeg_mean <- round((mean(group_df$included_trials_eeg))*100, digits = 1)
  161. included_trials_eeg_sd <- round((sd(group_df$included_trials_eeg))*100, digits = 1 )
  162. included_trials_eeg <- paste(included_trials_eeg_mean, "(", included_trials_eeg_sd, ")")
  163. # included trials et
  164. included_trials_et_mean <- round((mean(group_df$included_trials_et))*100, digits = 1)
  165. included_trials_et_sd <- round((sd(group_df$included_trials_et))*100, digits = 1)
  166. included_trials_et <- paste(included_trials_et_mean, "(", included_trials_et_sd, ")")
  167. group_description <- data.frame(
  168. n,
  169. gender_f_m,
  170. age,
  171. verbal_IQ,
  172. non_verbal_IQ,
  173. CBCL,
  174. YSR,
  175. SRS,
  176. SCQ,
  177. SP2,
  178. grip_strength,
  179. included_trials_et,
  180. included_trials_eeg)
  181. t(group_description)
  182. }
  183. asd_description <- fun_return_descriptives(group = "ASD")
  184. colnames(asd_description) <- "ASD"
  185. con_description <- fun_return_descriptives(group = "CON")
  186. colnames(con_description) <- "CON"
  187. mhc_description <- fun_return_descriptives(group = "MHC")
  188. colnames(mhc_description) <- "MHC"
  189. ## p-values for descriptive statistics
  190. SCQ_anova <- aov(SCQ ~ group, data = sample_description_df)
  191. SCQ_anova_p <- summary(SCQ_anova)[[1]][["Pr(>F)"]][[1]]
  192. age_anova <- aov(age ~ group, data = sample_description_df)
  193. age_anova_p <- summary(age_anova)[[1]][["Pr(>F)"]][[1]]
  194. CBCL_anova <- aov(CBCL ~ group, data = sample_description_df)
  195. CBCL_anova_p <- summary(CBCL_anova)[[1]][["Pr(>F)"]][[1]]
  196. SRS_anova <- aov(SRS ~ group, data = sample_description_df)
  197. SRS_anova_p <- summary(SRS_anova)[[1]][["Pr(>F)"]][[1]]
  198. YSR_anova <- aov(YSR ~ group, data = sample_description_df)
  199. YSR_anova_p <- summary(YSR_anova)[[1]][["Pr(>F)"]][[1]]
  200. SP2_anova <- aov(SP2 ~ group, data = sample_description_df)
  201. SP2_anova_p <- summary(SP2_anova)[[1]][["Pr(>F)"]][[1]]
  202. grip_strength_anova <- aov(z_grip_strength ~ group, data = sample_description_df)
  203. grip_strength_anova_p <- summary(grip_strength_anova)[[1]][["Pr(>F)"]][[1]]
  204. verbal_IQ_anova <- aov(verbal_IQ ~ group, data = sample_description_df)
  205. verbal_IQ_anova_p <- summary(verbal_IQ_anova)[[1]][["Pr(>F)"]][[1]]
  206. non_verbal_IQ_anova <- aov(non_verbal_IQ ~ group, data = sample_description_df)
  207. non_verbal_IQ_anova_p <- summary(non_verbal_IQ_anova)[[1]][["Pr(>F)"]][[1]]
  208. gender_chi2 <- chisq.test(sample_description_df$gender, sample_description_df$group)
  209. gender_chi2_p <- gender_chi2$p.value
  210. included_trials_et_anova <- aov(included_trials_et ~ group, data = sample_description_df)
  211. included_trials_et_p <- summary(included_trials_et_anova)[[1]][["Pr(>F)"]][[1]]
  212. included_trials_eeg_anova <- aov(included_trials_eeg ~ group, data = sample_description_df)
  213. included_trials_eeg_p <- summary(included_trials_eeg_anova)[[1]][["Pr(>F)"]][[1]]
  214. p_values <- c(
  215. NA,
  216. gender_chi2_p,
  217. age_anova_p,
  218. SRS_anova_p,
  219. CBCL_anova_p,
  220. SCQ_anova_p,
  221. SP2_anova_p,
  222. YSR_anova_p,
  223. grip_strength_anova_p,
  224. verbal_IQ_anova_p,
  225. non_verbal_IQ_anova_p,
  226. included_trials_et_p,
  227. included_trials_eeg_p)
  228. p_value <- sapply(p_values, function(p) {
  229. if (is.na(p)) {
  230. NA
  231. } else if (p < 0.001) {
  232. "< 0.001"
  233. } else {
  234. format(p, scientific = F)
  235. round(p, 3)
  236. }
  237. })
  238. sample_table <- cbind(asd_description, con_description, mhc_description, p_value)
  239. # Redo table row and column names
  240. rownames(sample_table)[rownames(sample_table) == "grip_strength"] <- "grip strength [z]"
  241. rownames(sample_table)[rownames(sample_table) == "gender_f_m"] <- "gender (f/m)"
  242. rownames(sample_table)[rownames(sample_table) == "verbal_IQ"] <- "verbal IQ"
  243. rownames(sample_table)[rownames(sample_table) == "non_verbal_IQ"] <- "non verbal IQ"
  244. rownames(sample_table)[rownames(sample_table) == "included_trials_eeg"] <- "included eeg trials [%]"
  245. rownames(sample_table)[rownames(sample_table) == "included_trials_et"] <- "included et trials [%]"
  246. colnames(sample_table)[colnames(sample_table) == "p_value"] <- "p value"
  247. sample_description_table <- kable(sample_table, caption = "Sample description", digits = 4) %>%
  248. kable_classic(full_width = F, html_font = "Cambria") %>% kable_styling
  249. sample_description_table
  250. # Supplements: No of trials per condition
  251. fun_trials_per_cond <- function(group, variable){
  252. group_df <- droplevels(et_erp_trial[et_erp_trial$group == group, ])
  253. # subjects starting with 500 Hz oddball
  254. ## block 1
  255. df_before_forward_O500_S750 <- group_df %>% filter(
  256. (manipulation == "before" & phase == "oddball_block" & stimulus == "oddball" & pitch == "500") |
  257. (manipulation == "before" & phase == "oddball_block" & stimulus == "standard" & pitch == "750"))
  258. sample_size <- length(unique(df_before_forward_O500_S750$SEGA_ID))
  259. max_trials <- sample_size *100
  260. before_forward_O500_S750 <- paste(round(((sum(!is.na(df_before_forward_O500_S750[variable]), na.rm = T))/max_trials)*100, 2), "%")
  261. ## block 2
  262. df_before_reverse_O750_S500 <- group_df %>% filter(
  263. (manipulation == "before" & phase == "oddball_block_rev" & stimulus == "oddball" & pitch == "750") |
  264. (manipulation == "before" & phase == "oddball_block_rev" & stimulus == "standard" & pitch == "500"))
  265. before_reverse_O750_S500 <- paste(round(((sum(!is.na(df_before_reverse_O750_S500[variable]), na.rm = T))/max_trials)*100, 2), "%")
  266. ## block 3
  267. df_after_forward_O500S750 <- group_df %>% filter(
  268. (manipulation == "after" & phase == "oddball_block" & stimulus == "oddball" & pitch == "500") |
  269. (manipulation == "after" & phase == "oddball_block" & stimulus == "standard" & pitch == "750"))
  270. after_forward_O500S750 <- paste(round(((sum(!is.na(df_after_forward_O500S750[variable]), na.rm = T))/max_trials)*100, 2), "%")
  271. # block 4
  272. df_after_reverse_O750S500 <- group_df %>% filter(
  273. (manipulation == "after" & phase == "oddball_block_rev" & stimulus == "oddball" & pitch == "750") |
  274. (manipulation == "after" & phase == "oddball_block_rev" & stimulus == "standard" & pitch == "500"))
  275. after_reverse_O750S500 <- paste(round(((sum(!is.na(df_after_reverse_O750S500[variable]), na.rm = T))/max_trials)*100, 2), "%")
  276. # subjects starting with 750 Hz oddball
  277. ## block 1
  278. df_before_forward_O750_S500 <- group_df %>% filter(
  279. (manipulation == "before" & phase == "oddball_block" & stimulus == "oddball" & pitch == "750") |
  280. (manipulation == "before" & phase == "oddball_block" & stimulus == "standard" & pitch == "500"))
  281. sample_size <- length(unique(df_before_forward_O750_S500$SEGA_ID))
  282. max_trials <- sample_size *100
  283. before_forward_O750_S500 <- paste(round(((sum(!is.na(df_before_forward_O750_S500[variable]), na.rm = T))/max_trials)*100, 2), "%")
  284. ## block 2
  285. df_before_reverse_O500S750 <- group_df %>% filter(
  286. (manipulation == "before" & phase == "oddball_block_rev" & stimulus == "oddball" & pitch == "500") |
  287. (manipulation == "before" & phase == "oddball_block_rev" & stimulus == "standard" & pitch == "750"))
  288. before_reverse_O500S750 <- paste(round(((sum(!is.na(df_before_reverse_O500S750[variable]), na.rm = T))/max_trials)*100, 2), "%")
  289. ## block 3
  290. df_after_forward_O750_S500 <- group_df %>% filter(
  291. (manipulation == "after" & phase == "oddball_block" & stimulus == "oddball" & pitch == "750") |
  292. (manipulation == "after" & phase == "oddball_block" & stimulus == "standard" & pitch == "500"))
  293. after_forward_O750_S500 <- paste(round(((sum(!is.na(df_after_forward_O750_S500[variable]), na.rm = T))/max_trials)*100, 2), "%")
  294. ## block 4
  295. df_after_reverse_O500S750 <- group_df %>% filter(
  296. (manipulation == "after" & phase == "oddball_block_rev" & stimulus == "oddball" & pitch == "500") |
  297. (manipulation == "after" & phase == "oddball_block_rev" & stimulus == "standard" & pitch == "750"))
  298. after_reverse_O500S750 <- paste(round(((sum(!is.na(df_after_reverse_O500S750[variable]), na.rm = T))/max_trials)*100, 2), "%")
  299. trial_per_condition <- data.frame(
  300. before_forward_O500_S750,
  301. before_reverse_O750_S500,
  302. after_forward_O500S750,
  303. after_reverse_O750S500,
  304. before_forward_O750_S500,
  305. before_reverse_O500S750,
  306. after_forward_O750_S500,
  307. after_reverse_O500S750)
  308. t(trial_per_condition)
  309. }
  310. # Call function for each group for EEG
  311. asd_trials_per_cond_eeg <- fun_trials_per_cond(group = "ASD", variable = "z_MMN_amplitude")
  312. colnames(asd_trials_per_cond_eeg) <- "ASD"
  313. con_trials_per_cond_eeg <- fun_trials_per_cond(group = "CON", variable = "z_MMN_amplitude")
  314. colnames(con_trials_per_cond_eeg) <- "CON"
  315. mhc_trials_per_cond_eeg <- fun_trials_per_cond(group = "MHC", variable = "z_MMN_amplitude")
  316. colnames(mhc_trials_per_cond_eeg) <- "MHC"
  317. # Call function for each group for ET
  318. asd_trials_per_cond_et <- fun_trials_per_cond(group = "ASD", variable = "z_rpd")
  319. colnames(asd_trials_per_cond_et) <- "ASD"
  320. con_trials_per_cond_et <- fun_trials_per_cond(group = "CON", variable = "z_rpd")
  321. colnames(con_trials_per_cond_et) <- "CON"
  322. mhc_trials_per_cond_et <- fun_trials_per_cond(group = "MHC", variable = "z_rpd")
  323. colnames(mhc_trials_per_cond_et) <- "MHC"
  324. condition_table <- cbind(
  325. asd_trials_per_cond_eeg, con_trials_per_cond_eeg, mhc_trials_per_cond_eeg,
  326. asd_trials_per_cond_et, con_trials_per_cond_et, mhc_trials_per_cond_et)
  327. condition_trials_table <- kable(
  328. condition_table, align = "c", caption = "Number of included trials per condition") %>%
  329. kable_classic(full_width = F, html_font = "Cambria") %>%
  330. kable_styling() %>%
  331. add_header_above(c(" " = 1, "Eye Tracking" = 3, "EEG" = 3))
  332. condition_trials_table
  333. ## Plot SCQ
  334. ggplot(sample_description_df, aes(x = group, y = SCQ), col = "group") +
  335. geom_boxplot(fill = "grey") +
  336. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  337. map_signif_level=TRUE,
  338. y_position = c(24, 25.5, 21)) +
  339. theme_bw() +
  340. theme_classic() +
  341. ggtitle("SCQ") +
  342. theme(plot.title = element_text(face = "bold"))
  343. ## Plot SRS
  344. ggplot(sample_description_df, aes(x = group, y = SRS), col = "group") +
  345. geom_boxplot(fill = "grey") +
  346. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  347. map_signif_level=TRUE,
  348. y_position = c(42, 45, 40)) +
  349. theme_bw() +
  350. theme_classic() +
  351. ggtitle("SRS") +
  352. theme(plot.title = element_text(face = "bold"))
  353. ## Plot CBCL
  354. ggplot(sample_description_df, aes(x = group, y = CBCL), col = "group") +
  355. geom_boxplot(fill = "grey") +
  356. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  357. map_signif_level=TRUE,
  358. y_position = c(87, 90, 84)) +
  359. theme_bw() +
  360. theme_classic() +
  361. ggtitle("CBCL") +
  362. theme(plot.title = element_text(face = "bold"))
  363. ## Plot: YSR
  364. ggplot(sample_description_df, aes(x = group, y = YSR), col = "group") +
  365. geom_boxplot(fill = "grey") +
  366. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  367. map_signif_level=TRUE,
  368. y_position = c(87, 90, 84)) +
  369. theme_bw() +
  370. theme_classic() +
  371. ggtitle("YSR") +
  372. theme(plot.title = element_text(face="bold"))
  373. ## Plot: SP2-Auditiv
  374. ggplot(sample_description_df, aes(x = group, y = SP2), col = "group") +
  375. geom_boxplot(fill = "grey") +
  376. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  377. map_signif_level=TRUE,
  378. y_position = c(43, 46, 40)) +
  379. theme_bw() +
  380. theme_classic() +
  381. ggtitle("SP2-Auditiv") +
  382. theme(plot.title = element_text(face="bold"))
  383. ## Plot: Age
  384. ggplot(sample_description_df, aes(x = group, y = age), col = group) +
  385. geom_boxplot(fill = "grey") +
  386. geom_jitter() +
  387. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  388. map_signif_level=TRUE,
  389. y_position = c(19.5, 20, 19)) +
  390. theme_bw() +
  391. theme_classic() +
  392. ggtitle("Age") +
  393. theme(plot.title = element_text(face="bold"))
  394. ## Plot: IQ-verbal
  395. plot_verbal_iq <- ggplot(sample_description_df, aes(x = group, y = verbal_IQ), col = group) +
  396. geom_boxplot(fill = "grey") +
  397. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  398. map_signif_level=TRUE,
  399. y_position = c(135, 140, 130)) +
  400. theme_bw() +
  401. theme_classic() +
  402. ggtitle("IQ-verbal") +
  403. theme(plot.title = element_text(face="bold")) +
  404. theme(plot.margin = unit(c(1, 0.5, 0.5, 0.5), "cm"))
  405. ## Plot: IQ-non-verbal
  406. plot_non_verbal_iq <- ggplot(sample_description_df, aes(x = group, y = non_verbal_IQ), col = "group") +
  407. geom_boxplot(fill = "grey") +
  408. geom_signif(comparisons = list(c("ASD", "CON"), c("ASD", "MHC"), c("MHC", "CON")),
  409. map_signif_level=TRUE,
  410. y_position = c(135, 140, 130)) +
  411. theme_bw() +
  412. theme_classic() +
  413. ggtitle("IQ-non-verbal") +
  414. theme(plot.title = element_text(face="bold")) +
  415. theme(plot.margin = unit(c(1, 0.5, 0.5, 0.5), "cm"))
  416. grid.arrange(plot_verbal_iq, plot_non_verbal_iq, ncol = 2)
  417. # Trial duration by group (REVIEWER 2025-10)
  418. ## on TRIAL level
  419. et_erp_trial$stimulus_isi_duration <- et_erp_trial$stimulus_duration + et_erp_trial$ISI_duration
  420. ggplot(et_erp_trial, aes(x = stimulus_isi_duration)) +
  421. geom_histogram(binwidth = 0.020, fill = "grey", color = "white") +
  422. labs(x = "Duration (s)", y = "Count") +
  423. coord_cartesian(xlim = c(1.85, 3.4)) +
  424. facet_wrap(~ group) + # separate histogram per group
  425. theme_minimal() +
  426. theme(
  427. strip.text = element_text(face = "bold"))
  428. et_erp_trial %>%
  429. group_by(group) %>%
  430. summarise(
  431. mean_stimulus_isi = round(mean(stimulus_isi_duration, na.rm = TRUE), 1),
  432. sd_stimulus_isi = round(sd(stimulus_isi_duration, na.rm = TRUE), 1))
  433. stimulus_isi_duration_anova <- aov(stimulus_isi_duration ~ group, data = et_erp_trial)
  434. stimulus_isi_duration_p <- summary(stimulus_isi_duration_anova)[[1]][["Pr(>F)"]][[1]]
  435. ## on PARTICIPANT level
  436. et_erp_trial <- et_erp_trial %>% # same aggregated value repeated in each trial within participant
  437. group_by(SEGA_ID) %>%
  438. mutate(stimulus_isi_duration_aggregated = mean(stimulus_isi_duration, na.rm = TRUE)) %>%
  439. ungroup()
  440. df_stimulus_isi_duration_aggregated <- et_erp_trial %>% # new data frame with 1 participant per row for anova
  441. group_by(SEGA_ID, group) %>%
  442. summarise(stimulus_isi_duration_aggregated = first(stimulus_isi_duration_aggregated),
  443. .groups = "drop")
  444. ggplot(df_stimulus_isi_duration_aggregated, aes(x = stimulus_isi_duration_aggregated)) +
  445. geom_histogram(binwidth = 0.2, fill = "grey", color = "white") +
  446. labs(x = "Duration (s)", y = "Count") +
  447. coord_cartesian(xlim = c(1.85, 3.4)) +
  448. facet_wrap(~ group) + # separate histogram per group
  449. theme_minimal() +
  450. theme(
  451. strip.text = element_text(face = "bold"))
  452. stats_stimulus_isi_duration_aggregated <- df_stimulus_isi_duration_aggregated %>%
  453. group_by(group) %>%
  454. summarise(
  455. mean_stimulus_isi_duration = mean(stimulus_isi_duration_aggregated, na.rm = TRUE),
  456. sd_stimulus_isi_duration = sd(stimulus_isi_duration_aggregated, na.rm = TRUE))
  457. stats_stimulus_isi_duration_aggregated
  458. anova_stimulus_isi_duration_aggregated <- aov(
  459. stimulus_isi_duration_aggregated ~ group, data = df_stimulus_isi_duration_aggregated)
  460. summary(anova_stimulus_isi_duration_aggregated)
  461. ggplot(df_stimulus_isi_duration_aggregated, aes(x = group, y = stimulus_isi_duration_aggregated, fill = group)) +
  462. geom_boxplot(outlier.shape = 16, alpha = 0.6) +
  463. geom_jitter(width = 0.2, alpha = 0.7, color = "black") +
  464. labs(
  465. x = NULL, # remioves x-axs label "group"
  466. y = "Stimulus_ISI_Duration (aggregated on particiopant level)") +
  467. theme_minimal() +
  468. theme(
  469. legend.position = "none",
  470. axis.text.x = element_text(face = "bold", size = "14"))
  471. # Power Analysis
  472. n_size<- 150 # sample size
  473. k_size<-4*100 # number of trials --> auditory oddball:
  474. subj <- factor(1:n_size)
  475. trial_id <- 1:k_size # remains integer variable
  476. condition <- c("before", "after")
  477. group <- c("ASD", "MHC", "CON")
  478. subj_full <- rep(subj, k_size)
  479. trial_full <- rep(trial_id, each=n_size)
  480. condition_full <- rep(condition, each=k_size*n_size/2)
  481. group_full <- rep(group, k_size*n_size/3)
  482. covars <- data.frame(id=subj_full, trial=trial_full, condition=condition_full, group=group_full)
  483. fixed <- c(0.1, 0.2, 0.2, 0.2, 0.1, 0.1) # effect sizes
  484. rand <- list(0.05) # random intercept
  485. res <- 1.2 # residual standard deviation
  486. model <- makeLmer(
  487. y ~ group*condition + (1|id), fixef=fixed, VarCorr=rand, sigma=res, data=covars) # create model
  488. summary(model) # model
  489. power_interaction <- powerSim(model, nsim=1000, test = fcompare(y ~ group + condition))
  490. print(power_interaction)
  491. power_curve_interaction <- powerCurve(model, test = fcompare(y ~ group + condition), along = "id")
  492. plot(power_curve_interaction)
  493. # EXPLORATORY (Reviewer's comment): Correlation SP2-P3a amplitude
  494. ## new df with mean P3a amplitude across conditions per participant
  495. df_SP2_P3a <- et_erp_subject %>%
  496. group_by(SEGA_ID) %>%
  497. summarise(
  498. mean_z_P3a_amplitude = mean(z_P3a_amplitude),
  499. SP2 = first(SP2)) %>% # just take the first value, is the same
  500. ungroup()
  501. corr_Sp2_P3a <- df_SP2_P3a %>%
  502. summarise(
  503. cor = cor(mean_z_P3a_amplitude, SP2, use = "complete.obs"),
  504. p_value = cor.test(mean_z_P3a_amplitude, SP2)$p.value,
  505. conf_low = cor.test(mean_z_P3a_amplitude, SP2)$conf.int[1],
  506. conf_high = cor.test(mean_z_P3a_amplitude, SP2)$conf.int[2]
  507. )
  508. print(corr_Sp2_P3a)
  509. ggplot(df_SP2_P3a, aes(x = SP2, y = mean_z_P3a_amplitude)) +
  510. geom_point(size = 3, color = "steelblue") +
  511. geom_smooth(method = "lm", color = "darkred", se = TRUE) +
  512. labs(
  513. x = "SP2",
  514. y = "Mean z_P3a amplitude",
  515. title = "Correlation between SP2 and Mean z_P3a amplitude"
  516. ) +
  517. annotate(
  518. "text",
  519. x = min(df_SP2_P3a$SP2),
  520. y = max(df_SP2_P3a$mean_z_P3a_amplitude),
  521. label = paste0("r = ", round(corr_test$estimate, 2),
  522. "\n95% CI [", round(corr_test$conf.int[1],2),
  523. ", ", round(corr_test$conf.int[2],2), "]\n",
  524. "p = ", round(corr_test$p.value, 3)),
  525. hjust = 0, vjust = 1, size = 4
  526. ) +
  527. theme_minimal(base_size = 14)
  528. # CORRELATION: BLOCK-BASELINE vs. TRIALBASELINE
  529. corr_block_trial_bl <- et_erp_subject %>%
  530. summarise(
  531. cor = cor(block_baseline_mean, rpd_low, use = "complete.obs"),
  532. p_value = cor.test(block_baseline_mean, rpd_low)$p.value,
  533. conf_low = cor.test(block_baseline_mean, rpd_low)$conf.int[1],
  534. conf_high = cor.test(block_baseline_mean, rpd_low)$conf.int[2]
  535. )
  536. print(corr_block_trial_bl)
  537. # Scatter plot with regression line and annotated correlation
  538. ggplot(et_erp_subject, aes(x = block_baseline_mean, y = rpd_low)) +
  539. geom_point(alpha = 0.6, color = "#0072B2", size = 3) + # points
  540. geom_smooth(method = "lm", se = TRUE, color = "#D55E00") + # regression line + CI
  541. annotate("text", x = Inf, y = -Inf,
  542. hjust = 1.1, vjust = -0.5,
  543. label = sprintf("r = %.2f, p < .001", corr_block_trial_bl$cor), # add correlation
  544. size = 5) +
  545. labs(
  546. x = "separate baseline phase",
  547. y = "BPS",
  548. title = "Correlation between separate baseline phase and BPS"
  549. ) +
  550. theme_minimal(base_size = 14)
  551. # RESULT 1: SEPR ON SUBJECT LEVEL
  552. lmm <- lmer(
  553. z_rpd ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  554. data = et_erp_subject)
  555. anova(lmm)
  556. r2_nakagawa(lmm)
  557. ## Post-hoc: stimulus
  558. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  559. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  560. # RESULT 2: BPS ON SUBJECT LEVEL
  561. lmm <- lmer(
  562. z_rpd_low ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  563. data = et_erp_subject)
  564. anova(lmm)
  565. r2_nakagawa(lmm)
  566. ## post-hoc: manipulation * group
  567. contrast(emmeans(lmm, ~ manipulation|group), method = "revpairwise")
  568. confint(contrast(emmeans(lmm, ~ manipulation|group), method = "revpairwise"))
  569. emmip(lmm, ~ manipulation | group, linearg = list(linetype = "blank"), CIs = T)
  570. ## Plot WTAS: manipulation * group
  571. emm_data <- emmip(lmm, ~ manipulation | group, CIs = TRUE, plotit = FALSE)
  572. ggplot(emm_data, aes(x = manipulation, y = yvar, color = group)) +
  573. geom_point(size = 3) + # Increased point size
  574. geom_errorbar(aes(ymin = LCL, ymax = UCL), width = 0.2, linewidth = 1) +
  575. facet_wrap(~ group) +
  576. labs(x = "Manipulation", y = "Estimated Marginal Mean") +
  577. theme_bw() +
  578. scale_color_manual(values = c("ASD" = "red", "CON" = "#045D5D", "MHC" = "#A05000")) +
  579. theme(plot.title = element_text(face = "bold"), legend.position = "none") +
  580. theme(axis.text.x = element_text(face = "bold")) +
  581. theme(axis.text.y = element_text(face = "bold")) +
  582. theme(text = element_text(size = 14))
  583. ### exploratory: custom contrast: group comparisons of BPS before manipulation
  584. emm <- emmeans(lmm, ~ group * manipulation)
  585. contrast(emm, method = list(
  586. "ASD.before vs CON.before" = c(-1, 1, 0, 0, 0, 0)), infer = T)
  587. contrast(emm, method = list(
  588. "ASD.before vs MHC.before" = c(-1, 0, 1, 0, 0, 0)), infer = T)
  589. contrast(emm, method = list(
  590. "CON.before vs MHC.before" = c(0, 0, 1, 0, 0, 0)), infer = T)
  591. ## Post-hoc: manipulation * block
  592. contrast(emmeans(lmm, ~ manipulation|block), "revpairwise")
  593. confint(contrast(emmeans(lmm, ~ manipulation|block), "revpairwise"))
  594. emmip(lmm, ~ manipulation | block, linearg = list(linetype = "blank"), CIs = T)
  595. ## Plot: manipulation x block interaction
  596. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  597. plot_data <- na.omit(plot_data)
  598. interaction_plot_BPS <- ggplot(plot_data) +
  599. geom_crossbar(aes(
  600. x = manipulation, y = emmean, color = block,
  601. ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  602. alpha = 0.8,
  603. position = position_dodge(width = 0.7),
  604. width = 0.3) +
  605. geom_errorbar(aes(
  606. x = manipulation, y = emmean, color = block, fill = block,
  607. ymin = lower.CL, ymax = upper.CL),
  608. position = position_dodge(width = 0.7),
  609. width = 0.2) +
  610. scale_color_manual(values = c("blue", "orange")) +
  611. scale_fill_manual(values = c("blue", "orange")) +
  612. theme_bw() +
  613. labs(title = "Manipulation x block interaction on BPS",
  614. x = "Manipulation",
  615. y = "BPS [z]") +
  616. theme(plot.title = element_text(face = "bold"), legend.position = "none")
  617. print(interaction_plot_BPS)
  618. ## Plot BPS for WTAS 2025: manipulation x block interaction
  619. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  620. plot_data <- na.omit(plot_data)
  621. interaction_plot_BPS <- ggplot(plot_data) +
  622. geom_crossbar(aes(
  623. x = manipulation, y = emmean, color = block,
  624. ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  625. alpha = 0.8,
  626. position = position_dodge(width = 0.9),
  627. width = 0.3,
  628. linewidth = 0.8) +
  629. geom_errorbar(aes(
  630. x = manipulation, y = emmean, color = block,
  631. ymin = lower.CL, ymax = upper.CL),
  632. position = position_dodge(width = 0.9),
  633. width = 0.3,
  634. linewidth = 0.8) +
  635. scale_color_manual(values = c("blue", "orange")) +
  636. scale_fill_manual(values = c("blue", "orange")) +
  637. theme_bw() +
  638. labs(title = "Manipulation x block interaction on BPS",
  639. x = "Manipulation",
  640. y = "BPS [z]") +
  641. theme(plot.title = element_text(face = "bold"), legend.position = "none") +
  642. theme(axis.text.x = element_text(face = "bold")) +
  643. theme(axis.text.y = element_text(face = "bold")) +
  644. theme(text = element_text(size = 14))
  645. print(interaction_plot_BPS)
  646. ## Plot BPS: manipulation x block interaction (SEGA_Paper)
  647. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  648. plot_data <- na.omit(plot_data)
  649. interaction_plot_BPS <- ggplot(plot_data) +
  650. geom_crossbar(aes(
  651. x = manipulation, y = emmean, color = block,
  652. ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  653. alpha = 0.8,
  654. position = position_dodge(width = 0.9),
  655. width = 0.3,
  656. linewidth = 0.8) +
  657. geom_errorbar(aes(
  658. x = manipulation, y = emmean, color = block,
  659. ymin = lower.CL, ymax = upper.CL),
  660. position = position_dodge(width = 0.9),
  661. width = 0.3,
  662. linewidth = 0.8) +
  663. scale_color_manual(values = c("blue", "orange")) +
  664. scale_fill_manual(values = c("blue", "orange")) +
  665. theme_bw() +
  666. labs(x = "Manipulation", y = "BPS [z]") +
  667. theme(legend.position = "none") +
  668. theme(axis.text.x = element_text(face = "bold")) +
  669. theme(axis.text.y = element_text(face = "bold")) +
  670. theme(text = element_text(size = 18))
  671. print(interaction_plot_BPS)
  672. ## custom contrast: Manipulation effect in block 3? (before.reverse vs. after.forward)
  673. emm <- emmeans(lmm, ~ block * manipulation)
  674. contrast(emm, method = list(
  675. "reverse.before vs forward.after" = c(0, -1, 1, 0)), infer = T)
  676. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  677. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  678. ### custom contrast: Manipulation effect in block 4? (before.reverse vs. after.reverse).
  679. emm <- emmeans(lmm, ~ block * manipulation)
  680. contrast(emm, method = list(
  681. "reverse.before vs reverse.after" = c(0, -1, 0, 1)), infer = T)
  682. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  683. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  684. ### custom contrast: Habituation from block 1 to block 2?
  685. emm <- emmeans(lmm, ~ block * manipulation)
  686. contrast(emm, method = list(
  687. "reverse.before vs forward.before" = c(-1, 1, 0, 0)), infer = T)
  688. ### custom contrast: Habituation from block 3 to 4
  689. emm <- emmeans(lmm, ~ block * manipulation)
  690. contrast(emm, method = list(
  691. "reverse.after vs forward.after" = c(0, 0, -1, 1)), infer = T)
  692. # RESULT 3: MMN AMPLITUDE ON SUBJECT LEVEL
  693. lmm <- lmer(
  694. z_MMN_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  695. data = et_erp_subject)
  696. anova(lmm)
  697. r2_nakagawa(lmm)
  698. ## Post-hoc: stimulus
  699. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  700. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  701. ## Post-hoc: manipulation * block
  702. contrast(emmeans(lmm, ~ manipulation|block), "revpairwise")
  703. confint(contrast(emmeans(lmm, ~ manipulation|block), "revpairwise"))
  704. emm <- emmeans(lmm, ~ block * manipulation)
  705. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  706. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  707. ## Plot 1: manipulation x block interaction
  708. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  709. plot_data <- na.omit(plot_data)
  710. interaction_plot_MMN <- ggplot(plot_data) +
  711. geom_crossbar(aes(
  712. x = manipulation, y = emmean, color = block,
  713. ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  714. alpha = 0.8,
  715. position = position_dodge(width = 0.7),
  716. width = 0.3) +
  717. geom_errorbar(aes(
  718. x = manipulation, y = emmean, color = block, fill = block,
  719. ymin = lower.CL, ymax = upper.CL),
  720. position = position_dodge(width = 0.7),
  721. width = 0.2) +
  722. scale_color_manual(values = c("blue", "orange")) +
  723. scale_fill_manual(values = c("blue", "orange")) +
  724. theme_bw() +
  725. labs(title = "Manipulation x block interaction on MMN amplitude",
  726. x = "Manipulation",
  727. y = "MMN_amplitude [z]") +
  728. theme(plot.title = element_text(face = "bold"), legend.position = "none")
  729. print(interaction_plot_MMN)
  730. legend <- cowplot::get_legend(interaction_plot_MMN + theme(legend.position="right"))
  731. legend_plot <- ggdraw() + draw_plot(legend)
  732. print(legend_plot)
  733. ## Slightly modified plot for WTAS 2025
  734. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  735. plot_data <- na.omit(plot_data)
  736. interaction_plot_MMN <- ggplot(plot_data) +
  737. geom_crossbar(aes(
  738. x = manipulation, y = emmean, color = block,
  739. ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  740. alpha = 0.8,
  741. position = position_dodge(width = 0.9),
  742. width = 0.3,
  743. linewidth = 0.8) +
  744. geom_errorbar(aes(
  745. x = manipulation, y = emmean, color = block,
  746. ymin = lower.CL, ymax = upper.CL),
  747. position = position_dodge(width = 0.9),
  748. width = 0.3,
  749. linewidth = 0.8) +
  750. scale_color_manual(values = c("blue", "orange")) +
  751. scale_fill_manual(values = c("blue", "orange")) +
  752. theme_bw() +
  753. labs(title = "Manipulation x block interaction on MMN amplitude",
  754. x = "Manipulation",
  755. y = "MMN_amplitude [z]") +
  756. theme(plot.title = element_text(face = "bold"), legend.position = "none") +
  757. theme(axis.text.x = element_text(face = "bold")) +
  758. theme(axis.text.y = element_text(face = "bold")) +
  759. theme(text = element_text(size = 14))
  760. print(interaction_plot_MMN)
  761. ## Plot MMN amplitude (SEGA-Paper)
  762. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  763. plot_data <- na.omit(plot_data)
  764. interaction_plot_MMN <- ggplot(plot_data) +
  765. geom_crossbar(aes(
  766. x = manipulation, y = emmean, color = block,
  767. ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  768. alpha = 0.8,
  769. position = position_dodge(width = 0.9),
  770. width = 0.3,
  771. linewidth = 0.8) +
  772. geom_errorbar(aes(
  773. x = manipulation, y = emmean, color = block,
  774. ymin = lower.CL, ymax = upper.CL),
  775. position = position_dodge(width = 0.9),
  776. width = 0.3,
  777. linewidth = 0.8) +
  778. scale_color_manual(values = c("blue", "orange")) +
  779. scale_fill_manual(values = c("blue", "orange")) +
  780. theme_bw() +
  781. labs(x = "Manipulation", y = "MMN_amplitude [z]") +
  782. theme(legend.position = "none") +
  783. theme(axis.text.x = element_text(face = "bold")) +
  784. theme(axis.text.y = element_text(face = "bold")) +
  785. theme(text = element_text(size = 18))
  786. print(interaction_plot_MMN)
  787. ## Custom contrast: Manipulation effect in block 3? (block 2 vs. 3).
  788. emm <- emmeans(lmm, ~ block * manipulation)
  789. contrast(emm, method = list(
  790. "reverse.before vs forward.after" = c(0, -1, 1, 0)), infer = T)
  791. ## Custom contrast: Manipulation effect in block 4? (block 2 vs 4).
  792. emm <- emmeans(lmm, ~ block * manipulation)
  793. contrast(emm, method = list(
  794. "reverse.before vs reverse.after" = c(0, -1, 0, 1)), infer = T)
  795. ## Correlation with age
  796. corr_by_group <- et_erp_subject %>%
  797. group_by(group) %>%
  798. summarise(cor = cor(age, z_MMN_latency, use = "complete.obs"),
  799. p_value = cor.test(age, z_MMN_latency)$p.value)
  800. print(corr_by_group)
  801. # RESULT 4: MMN LATENCY ON SUBJECT LEVEL
  802. lmm <- lmer(
  803. z_MMN_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age,
  804. data = et_erp_subject)
  805. anova(lmm)
  806. r2_nakagawa(lmm)
  807. ## Correlation with age
  808. corr_by_group <- et_erp_subject %>%
  809. group_by(group) %>%
  810. summarise(cor = cor(age, z_MMN_amplitude, use = "complete.obs"),
  811. p_value = cor.test(age, z_MMN_latency)$p.value)
  812. print(corr_by_group)
  813. # RESULT 5: MMN DIFF AMPLITUDE ON SUBJECT LEVEL
  814. lmm <- lmer(
  815. z_MMN_diff_amplitude ~ manipulation * group * block + (1|SEGA_ID) + gender + age,
  816. data = MMN_diff)
  817. anova(lmm)
  818. r2_nakagawa(lmm)
  819. # RESULT 6: MMN DIFF LATENCY ON SUBJECT LEVEL
  820. lmm <- lmer(
  821. z_MMN_diff_latency ~ manipulation * group * block + (1|SEGA_ID) + gender + age,
  822. data = MMN_diff)
  823. anova(lmm)
  824. r2_nakagawa(lmm)
  825. # RESULT 7: P3A AMPLITUDE ON SUBJECT LEVEL
  826. lmm <- lmer(
  827. z_P3a_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age,
  828. data = et_erp_subject)
  829. anova(lmm)
  830. r2_nakagawa(lmm)
  831. ## Post-hoc: stimulus * group * block
  832. emm <- emmeans(lmm, ~ group * stimulus * block)
  833. stimulus_diff <- contrast(emm, method = "pairwise", by = c("group", "block"))
  834. stimulus_diff_emm <- as.emm_list(stimulus_diff)
  835. group_diff <- contrast(stimulus_diff_emm, method = "pairwise", by = "block")
  836. summary(group_diff)
  837. confint(group_diff)
  838. ## WTAS: Plot with stimulus * group
  839. emm_data <- emmip(lmm, ~ stimulus | group, CIs = TRUE, plotit = FALSE)
  840. ggplot(emm_data, aes(x = xvar, y = yvar, color = stimulus)) +
  841. geom_point(size = 3) +
  842. geom_errorbar(aes(ymin = LCL, ymax = UCL), width = 0.2, size = 1) +
  843. facet_wrap(~ group) +
  844. labs(x = "Stimulus", y = "Estimated Marginal Mean") +
  845. theme_bw() +
  846. scale_color_manual(values = c("Oddball" = "red", "Standard" = "black")) +
  847. theme(plot.title = element_text(face = "bold"), legend.position = "none") +
  848. theme(axis.text.x = element_text(face = "bold")) +
  849. theme(axis.text.y = element_text(face = "bold")) +
  850. theme(text = element_text(size = 14))
  851. ## Post-hoc: manipulation * block
  852. emmeans(lmm, ~ manipulation|block)
  853. contrast(emmeans(lmm, ~ manipulation|block), "revpairwise")
  854. confint(contrast(emmeans(lmm, ~ manipulation|block), "revpairwise"))
  855. emm <- emmeans(lmm, ~ block * manipulation)
  856. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  857. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  858. ## Plot: manipulation * block
  859. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  860. plot_data <- na.omit(plot_data)
  861. interaction_plot_P3a <- ggplot(plot_data, aes(x = manipulation, y = emmean, group = block, color = block)) +
  862. geom_crossbar(aes(ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  863. alpha = 0.8,
  864. position = position_dodge(width = 0.9),
  865. width = 0.3) +
  866. geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL),
  867. position = position_dodge(width = 0.9),
  868. width = 0.2) +
  869. scale_color_manual(values = c("blue", "orange")) +
  870. scale_fill_manual(values = c("blue", "orange")) +
  871. scale_x_discrete(expand = expansion(mult = c(0.5, 0.5))) +
  872. theme_bw() +
  873. labs(title = "Manipulation x block interaction on P3a amplitude",
  874. x = "Manipulation",
  875. y = "P3a_amplitude [z]") +
  876. theme(plot.title = element_text(face = "bold"), legend.position = "none")
  877. print(interaction_plot_P3a)
  878. ## Slightly modified for WTAS 2025
  879. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  880. plot_data <- na.omit(plot_data)
  881. interaction_plot_P3a <- ggplot(plot_data, aes(x = manipulation, y = emmean, group = block, color = block)) +
  882. geom_crossbar(aes(ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  883. alpha = 0.8,
  884. position = position_dodge(width = 0.9),
  885. width = 0.3,
  886. size = 0.8) +
  887. geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL),
  888. position = position_dodge(width = 0.9),
  889. width = 0.2,
  890. size = 0.8) +
  891. scale_color_manual(values = c("blue", "orange")) +
  892. scale_fill_manual(values = c("blue", "orange")) +
  893. scale_x_discrete(expand = expansion(mult = c(0.5, 0.5))) +
  894. theme_bw() +
  895. labs(title = "Manipulation x block interaction on P3a amplitude",
  896. x = "Manipulation",
  897. y = "P3a_amplitude [z]") +
  898. theme(plot.title = element_text(face = "bold"), legend.position = "none") +
  899. theme(axis.text.x = element_text(face = "bold")) +
  900. theme(axis.text.y = element_text(face = "bold")) +
  901. theme(text = element_text(size = 14))
  902. print(interaction_plot_P3a)
  903. legend <- cowplot::get_legend(interaction_plot_MMN + theme(legend.position="right"))
  904. legend_plot <- ggdraw() + draw_plot(legend)
  905. print(legend_plot)
  906. ## Plot P3a: Manipulation effect (SEGA Paper)
  907. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  908. plot_data <- na.omit(plot_data)
  909. interaction_plot_P3a <- ggplot(plot_data, aes(x = manipulation, y = emmean, group = block, color = block)) +
  910. geom_crossbar(aes(ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  911. alpha = 0.8,
  912. position = position_dodge(width = 0.9),
  913. width = 0.3,
  914. size = 0.8) +
  915. geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL),
  916. position = position_dodge(width = 0.9),
  917. width = 0.2,
  918. size = 0.8) +
  919. scale_color_manual(values = c("blue", "orange")) +
  920. scale_fill_manual(values = c("blue", "orange")) +
  921. scale_x_discrete(expand = expansion(mult = c(0.5, 0.5))) +
  922. theme_bw() +
  923. labs(x = "Manipulation", y = "P3a_amplitude [z]") +
  924. theme(legend.position = "none") +
  925. theme(axis.text.x = element_text(face = "bold")) +
  926. theme(axis.text.y = element_text(face = "bold")) +
  927. theme(text = element_text(size = 18))
  928. print(interaction_plot_P3a)
  929. ## custom contrast: Manipulation effect in block 3? (before.reverse vs. after.forward)
  930. emm <- emmeans(lmm, ~ block * manipulation)
  931. contrast(emm, method = list(
  932. "reverse.before vs forward.after" = c(0, -1, 1, 0)), infer = T)
  933. ## custom contrast: Manipulation effect in block 4? (before.reverse vs. after.reverse)
  934. emm <- emmeans(lmm, ~ block * manipulation)
  935. contrast(emm, method = list(
  936. "reverse.before vs reverse.after" = c(0, 1, 0, -1)), infer = T)
  937. # RESULT 8: P3A LATENCY ON SUBJECT LEVEL
  938. lmm <- lmer(
  939. z_P3a_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age,
  940. data = et_erp_subject)
  941. anova(lmm)
  942. r2_nakagawa(lmm)
  943. ## Post-hoc: stimulus
  944. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  945. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  946. # RESULT 9: P3B AMPLITUDE ON SUBJECT LEVEL
  947. lmm <- lmer(
  948. z_P3b_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age,
  949. data = et_erp_subject)
  950. anova(lmm)
  951. r2_nakagawa(lmm)
  952. ## Post-hoc: stimulus
  953. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  954. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  955. ## Post-hoc: manipulation
  956. contrast(emmeans(lmm, ~ manipulation), "pairwise")
  957. confint(contrast(emmeans(lmm, ~ manipulation), "pairwise"))
  958. emmip(lmm, ~ manipulation, linearg = list(linetype = "blank"), CI = T)
  959. # RESULT 10: P3B LATENCY ON SUBJECT LEVEL
  960. lmm <- lmer(
  961. z_P3b_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age,
  962. data = et_erp_subject)
  963. anova(lmm)
  964. r2_nakagawa(lmm)
  965. # Post-hoc: stimulus * manipulation * group
  966. contrast(emmeans(lmm, ~ group|manipulation*stimulus), "pairwise")
  967. confint(contrast(emmeans(lmm, ~ group|manipulation*stimulus), "pairwise"))
  968. emmip(lmm, ~ group|manipulation*stimulus, CI = T)
  969. contrast(emmeans(lmm, ~ manipulation|group*stimulus), "pairwise")
  970. # RESULT 11: ASSOCIATIONS OF PUPILLOMETRIC MEASURES
  971. lmm <- lmer(
  972. z_rpd ~ z_rpd_low * stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  973. data = et_erp_subject)
  974. anova(lmm)
  975. r2_nakagawa(lmm)
  976. ## Post-hoc: BPS
  977. emtrends(lmm, ~ z_rpd_low, var = "z_rpd_low")
  978. summary(emtrends(lmm, ~ z_rpd_low, var = "z_rpd_low"), infer = T)
  979. # RESULT 12: ASSOCIATIONS: PUPIL DATA- ERPs ON SUBJECT LEVEL
  980. ## MMN amplitude
  981. lmm <- lmer(
  982. z_MMN_amplitude ~ z_rpd * z_rpd_low * stimulus * manipulation * group + (1|SEGA_ID) + age + gender,
  983. data = et_erp_subject)
  984. anova(lmm)
  985. r2_nakagawa(lmm)
  986. ## Post-hoc: SEPR * BPS * stimulus
  987. emt <- emtrends(lmm, ~ z_rpd_low * z_rpd | stimulus, var = 'z_rpd', at = list(z_rpd_low = c(-2,-1,0,1,2)))
  988. summary(emt, infer = T)
  989. ## P3a amplitude
  990. lmm <- lmer(
  991. z_P3a_amplitude ~ z_rpd * z_rpd_low * stimulus * manipulation * group + (1|SEGA_ID) + age + gender,
  992. data = et_erp_subject)
  993. anova(lmm)
  994. r2_nakagawa(lmm)
  995. ### post-hoc: SEPR x manipulation x group x stimulus
  996. emt <- emtrends(lmm, ~ z_rpd * manipulation | group * stimulus, var = 'z_rpd')
  997. summary(emt, infer = T)
  998. ### post-hoc: BPS x stimulus x group
  999. emt <- emtrends(lmm, ~ z_rpd_low * group | stimulus, var = 'z_rpd_low', at = list(z_rpd_low = c(-2,-1,0,1,2)))
  1000. summary(emt, infer = T)
  1001. lmm <- lmer(
  1002. z_P3b_amplitude ~ z_rpd * z_rpd_low * stimulus * manipulation * group + (1|SEGA_ID) + age + gender,
  1003. data = et_erp_subject)
  1004. anova(lmm)
  1005. r2_nakagawa(lmm)
  1006. crl <- cor(et_erp_subject[et_erp_subject$stimulus == "Oddball", c(
  1007. "z_rpd_low",
  1008. "z_rpd",
  1009. "z_MMN_amplitude",
  1010. "z_P3a_amplitude",
  1011. "z_P3b_amplitude"
  1012. )],
  1013. use="complete.obs")
  1014. crl
  1015. corrplot::corrplot(
  1016. crl,
  1017. method = "circle",
  1018. title = "Association between pupil data and ERPs in oddball trials",
  1019. mar=c(0,0,1,0))
  1020. crl <- cor(et_erp_subject[et_erp_subject$stimulus == "Standard", c(
  1021. "z_rpd_low",
  1022. "z_rpd",
  1023. "z_MMN_amplitude",
  1024. "z_P3a_amplitude",
  1025. "z_P3b_amplitude"
  1026. )],
  1027. use="complete.obs")
  1028. crl
  1029. corrplot::corrplot(
  1030. crl,
  1031. method = "circle",
  1032. title = "Association between pupil data and ERPs in standard trials",
  1033. mar=c(0,0,1,0))
  1034. # DATA ANALYSIS ON TRIAL LEVEL ####
  1035. # Distributions of dependent variables
  1036. par(mfrow = c(2,2), mar = c(4, 4, 2, 1))
  1037. hist(et_erp_trial$z_rpd,
  1038. main = "Distribution of rpd (500-1500 ms)",
  1039. xlab = "z_rpd",
  1040. xlim = c(-6, 6),
  1041. breaks = 200)
  1042. hist(et_erp_trial$z_rpd_low,
  1043. main = "Distribution of rpd_low (0-250 ms)",
  1044. xlab = "rpd_low",
  1045. xlim = c(-4, 6),
  1046. breaks = 200)
  1047. hist(et_erp_trial$z_MMN_amplitude,
  1048. main = "Distribution of MMN amplitude (100-150 ms)",
  1049. xlab = "MMN amplitude (FC1, FC2, FCz, Fz)",
  1050. xlim = c(-6, 6),
  1051. breaks = 200)
  1052. hist(et_erp_trial$z_P3a_amplitude,
  1053. main = "Distribution of P3a amplitude (150-250 ms)",
  1054. xlab = "P3a amplitude (Cz, FCz)",
  1055. xlim = c(-4, 6),
  1056. breaks = 200)
  1057. par(mfrow = c(1, 1))
  1058. # RESULT 12: SEPR ON TRIAL LEVEL
  1059. lmm <- lmer(
  1060. z_rpd ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1061. data = et_erp_trial)
  1062. anova(lmm)
  1063. r2_nakagawa(lmm)
  1064. ## Post-hoc: stimulus
  1065. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  1066. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  1067. # EXPLORATORY: SEPR OVER TASK
  1068. lmm <- lmer(
  1069. z_rpd ~ stimulus * manipulation * group * block * oddball_trial_counter + (1|SEGA_ID),
  1070. data = et_erp_trial)
  1071. anova(lmm)
  1072. r2_nakagawa(lmm)
  1073. emt <- emtrends(lmm, pairwise ~ manipulation, var = "oddball_trial_counter")
  1074. summary(emt, infer = T)
  1075. emt <- emtrends(lmm,~ stimulus * group * block, var = 'oddball_trial_counter')
  1076. summary(emt, infer = T)
  1077. et_erp_trial$binned_trial_number <- cut(
  1078. et_erp_trial$oddball_trial_counter, c(
  1079. 1, 103, 206, 309, 412))
  1080. ggplot(et_erp_trial[et_erp_trial$stimulus == "oddball", ]) + geom_boxplot(aes(binned_trial_number, z_rpd)) +
  1081. facet_grid(cols = vars(group)) +
  1082. ggtitle("SEPR in oddball trials during the task, \nsplit by group") +
  1083. theme(plot.title = element_text(face = "bold", size = 14))
  1084. # EXPLORATORY: SEPR OVER BLOCK
  1085. lmm <- lmer(
  1086. z_rpd ~ stimulus * manipulation * group * block * trial_number_in_block + (1|SEGA_ID),
  1087. data = et_erp_trial)
  1088. anova(lmm)
  1089. r2_nakagawa(lmm)
  1090. emt <- emtrends(lmm, pairwise ~ manipulation, var = "trial_number_in_block")
  1091. summary(emt, infer = T)
  1092. emt <- emtrends(lmm,~ stimulus * group * block, var = 'trial_number_in_block')
  1093. summary(emt, infer = T)
  1094. bin_size <- 20
  1095. df_trial <- df_trial %>%
  1096. mutate(trial_number_in_block_binned = factor(trial_number_in_block%/%bin_size*20))
  1097. ggplot(
  1098. df_trial[df_trial$phase %in% c("oddball_block", "oddball_block_rev") & df_trial$stimulus == "oddball", ],
  1099. aes(x = trial_number_in_block_binned,
  1100. y = scale(rpd))) +
  1101. geom_boxplot() +
  1102. facet_grid(
  1103. rows = vars(block),
  1104. cols = vars(manipulation)) +
  1105. theme_bw() +
  1106. ggtitle("SEPR in oddball trials during blocks, \nsplit by forward + reverse and before + after manipulation") +
  1107. theme(plot.title = element_text(face = "bold", size = 14))
  1108. et_erp_trial$binned_trial_number <- cut(
  1109. et_erp_trial$trial_number_in_block, c(
  1110. 0, 20, 40, 60, 80, 100))
  1111. ggplot(et_erp_trial[et_erp_trial$stimulus == "oddball", ]) + geom_boxplot(aes(binned_trial_number, z_rpd)) +
  1112. facet_grid(cols = vars(group)) +
  1113. ggtitle("SEPR in oddball trials during blocks, split by group") +
  1114. theme(plot.title = element_text(face = "bold", size = 14))
  1115. # RESULT 13: BPS ON TRIAL LEVEL
  1116. lmm <- lmer(
  1117. z_rpd_low ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1118. data = et_erp_trial)
  1119. anova(lmm)
  1120. r2_nakagawa(lmm)
  1121. ## Post-hoc: manipulation * group
  1122. contrast(emmeans(lmm, ~ manipulation|group), "revpairwise")
  1123. confint(contrast(emmeans(lmm, ~ manipulation|group), "revpairwise"))
  1124. emm <- emmeans(lmm, ~ manipulation * group)
  1125. emmip(emm, ~ manipulation|group, linearg = list(linetype = "blank"), CI = TRUE) +
  1126. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  1127. ## Post-hoc: manipulation * block
  1128. contrast(emmeans(lmm, ~ manipulation|block), "revpairwise")
  1129. confint(contrast(emmeans(lmm, ~ manipulation|block), "revpairwise"))
  1130. emm <- emmeans(lmm, ~ block * manipulation)
  1131. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  1132. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  1133. ## custom contrast: manipulation effect in block 3? (block 2 vs. 3).
  1134. emm <- emmeans(lmm, ~ block * manipulation)
  1135. contrast(emm, method = list(
  1136. "reverse.before vs forward.after" = c(0, -1, 1, 0)), infer = T)
  1137. ## custom contrast: manipulation effect in block 4? (block 2 vs 4).
  1138. emm <- emmeans(lmm, ~ block * manipulation)
  1139. contrast(emm, method = list(
  1140. "reverse.before vs reverse.after" = c(0, -1, 0, 1)), infer = T)
  1141. ## Post-hoc: group * block
  1142. contrast(emmeans(lmm, ~ block|group), "pairwise")
  1143. confint(contrast(emmeans(lmm, ~ block|group), "pairwise"))
  1144. emm <- emmeans(lmm, ~ block | group)
  1145. emmip(emm, ~ block | group, linearg = list(linetype = "blank"), CI = TRUE) +
  1146. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  1147. # EXPLORATORY: BPS OVER TASK
  1148. lmm <- lmer(
  1149. z_rpd_low ~ stimulus * manipulation * group * block * oddball_trial_counter + (1|SEGA_ID),
  1150. data = et_erp_trial)
  1151. anova(lmm)
  1152. r2_nakagawa(lmm)
  1153. emt <- emtrends(lmm,~ manipulation * group * block, var = 'oddball_trial_counter')
  1154. summary(emt, infer = T)
  1155. et_erp_trial$binned_trial_number <- cut(
  1156. et_erp_trial$oddball_trial_counter, c(
  1157. 1, 103, 206, 309, 412))
  1158. ggplot(et_erp_trial[et_erp_trial$stimulus == "standard", ]) + geom_boxplot(aes(binned_trial_number, z_rpd_low)) +
  1159. facet_grid(cols = vars(group)) +
  1160. ggtitle("BPS in standard trials during the task, split by group") +
  1161. theme(plot.title = element_text(face = "bold", size = 14))
  1162. # EXPLORATORY: BPS OVER BLOCK
  1163. lmm <- lmer(
  1164. z_rpd_low ~ stimulus * manipulation * group * block * trial_number_in_block + (1|SEGA_ID),
  1165. data = et_erp_trial)
  1166. anova(lmm)
  1167. r2_nakagawa(lmm)
  1168. emt <- emtrends(lmm,~ manipulation * group * block, var = 'trial_number_in_block')
  1169. summary(emt, infer = T)
  1170. bin_size <- 20
  1171. df_trial <- df_trial %>%
  1172. mutate(trial_number_in_block_binned = factor(trial_number_in_block%/%bin_size*20))
  1173. ggplot(
  1174. df_trial[df_trial$phase %in% c("oddball_block", "oddball_block_rev") & df_trial$stimulus == "standard", ],
  1175. aes(x = trial_number_in_block_binned,
  1176. y = scale(rpd_low))) +
  1177. geom_boxplot() +
  1178. facet_grid(
  1179. rows = vars(block),
  1180. cols = vars(manipulation)) +
  1181. theme_bw() +
  1182. ggtitle("BPS in standard trials during blocks, \nsplit by forward + reverse and before + after manipulation") +
  1183. theme(plot.title = element_text(face = "bold", size = 14))
  1184. # RESULT 8: MMN AMPLITUDE ON TRIAL LEVEL
  1185. lmm <- lmer(
  1186. z_MMN_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1187. data = et_erp_trial)
  1188. anova(lmm)
  1189. r2_nakagawa(lmm)
  1190. ## Post-hoc: stimulus
  1191. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  1192. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  1193. # RESULT 9: MMN LATENCY ON TRIAL LEVEL
  1194. lmm <- lmer(
  1195. z_MMN_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1196. data = et_erp_trial)
  1197. anova(lmm)
  1198. r2_nakagawa(lmm)
  1199. ## Post-hoc: stimulus
  1200. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  1201. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  1202. ## Post-hoc: manipulation * block
  1203. contrast(emmeans(lmm, ~ manipulation|block), "revpairwise")
  1204. confint(contrast(emmeans(lmm, ~ manipulation|block), "revpairwise"))
  1205. emm <- emmeans(lmm, ~ block * manipulation)
  1206. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  1207. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  1208. ## Plot Manipulation effect on MMN Latency
  1209. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  1210. plot_data <- na.omit(plot_data)
  1211. interaction_plot_MNN_latency <- ggplot(plot_data, aes(x = manipulation, y = emmean, group = block, color = block)) +
  1212. geom_crossbar(aes(ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  1213. alpha = 0.8,
  1214. position = position_dodge(width = 0.7),
  1215. width = 0.3) +
  1216. geom_errorbar(aes(ymin = asymp.LCL, ymax = asymp.UCL),
  1217. position = position_dodge(width = 0.7),
  1218. width = 0.2) +
  1219. scale_color_manual(values = c("blue", "orange")) +
  1220. scale_fill_manual(values = c("blue", "orange")) +
  1221. theme_bw() +
  1222. labs(title = "Manipulation x block interaction on MMN latency",
  1223. x = "Manipulation",
  1224. y = "MMN latency [z]") +
  1225. theme(plot.title = element_text(face = "bold"), legend.position = "none")
  1226. print(interaction_plot_MNN_latency)
  1227. ## Slightly modified plot for WTAS 2025
  1228. plot_data <- as.data.frame(emmeans(lmm, ~ block * manipulation))
  1229. plot_data <- na.omit(plot_data)
  1230. interaction_plot_MNN_latency <- ggplot(plot_data, aes(x = manipulation, y = emmean, group = block, color = block)) +
  1231. geom_crossbar(aes(ymin = emmean - 1 * SE, ymax = emmean + 1 * SE),
  1232. alpha = 0.8,
  1233. position = position_dodge(width = 0.9),
  1234. width = 0.3,
  1235. linewidth = 0.8) +
  1236. geom_errorbar(aes(ymin = asymp.LCL, ymax = asymp.UCL),
  1237. position = position_dodge(width = 0.9),
  1238. width = 0.2,
  1239. linewidth = 0.8) +
  1240. scale_color_manual(values = c("blue", "orange")) +
  1241. scale_fill_manual(values = c("blue", "orange")) +
  1242. theme_bw() +
  1243. labs(title = "Manipulation x block interaction on MMN latency",
  1244. x = "Manipulation",
  1245. y = "MMN latency [z]") +
  1246. theme(plot.title = element_text(face = "bold"), legend.position = "none") +
  1247. theme(axis.text = element_text(face = "bold")) +
  1248. theme(text = element_text(size = 14))
  1249. print(interaction_plot_MNN_latency)
  1250. grid.arrange(interaction_plot_BPS,
  1251. interaction_plot_MMN,
  1252. interaction_plot_P3a)
  1253. # RESULT 10: P3A AMPLITUDE ON TRIAL LEVEL
  1254. lmm <- lmer(
  1255. z_P3a_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1256. data = et_erp_trial)
  1257. anova(lmm)
  1258. r2_nakagawa(lmm)
  1259. ## Post-hoc: stimulus * group * block
  1260. emm <- emmeans(lmm, ~ group * stimulus * block)
  1261. stimulus_diff <- contrast(emm, method = "pairwise", by = c("group", "block"))
  1262. stimulus_diff_emm <- as.emm_list(stimulus_diff)
  1263. group_diff <- contrast(stimulus_diff_emm, method = "pairwise", by = "block")
  1264. summary(group_diff)
  1265. confint(group_diff)
  1266. # Post-hoc: manipulation * block
  1267. contrast(emmeans(lmm, ~ manipulation|block), "pairwise")
  1268. confint(contrast(emmeans(lmm, ~ manipulation|block), "pairwise"))
  1269. emm <- emmeans(lmm, ~ block * manipulation)
  1270. emmip(emm, ~ block * manipulation, linearg = list(linetype = "blank"), CI = TRUE) +
  1271. theme_bw() + labs(x = "task block", y = "Estimated Marginal Means")
  1272. ## custom contrast: Manipulation effect in block 3? (block 2 vs. 3).
  1273. emm <- emmeans(lmm, ~ block * manipulation)
  1274. contrast(emm, method = list(
  1275. "reverse.before vs forward.after" = c(0, -1, 1, 0)), infer = T)
  1276. ## custom contrast: Manipulation effect in block 4? (block 2 vs 4).
  1277. contrast(emm, method = list(
  1278. "reverse.before vs reverse.after" = c(0, 1, 0, -1)), infer = T)
  1279. # RESULT 11: P3A LATENCY ON TRIAL LEVEL
  1280. lmm <- lmer(
  1281. z_P3a_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1282. data = et_erp_trial)
  1283. anova(lmm)
  1284. r2_nakagawa(lmm)
  1285. # Post-hoc: stimulus
  1286. contrast(emmeans(lmm, ~ stimulus), "pairwise")
  1287. confint(contrast(emmeans(lmm, ~ stimulus), "pairwise"))
  1288. # RESULT 14: ASSOCIATION BETWEEN PUPILLOMETRIC MEASURES
  1289. ggscatter(et_erp_trial[et_erp_trial$stimulus == "oddball", ],
  1290. x = "z_rpd_low",
  1291. y = "z_rpd",
  1292. add = "reg.line",
  1293. conf.int = TRUE,
  1294. cor.coef = TRUE,
  1295. cor.method = "pearson",
  1296. xlab = "scaled BPS (rpd_low)",
  1297. ylab = "scaled SEPR (rpd)",
  1298. title = "Association between SEPR + BPS in oddball trials")
  1299. ggscatter(et_erp_trial[et_erp_trial$stimulus == "standard", ],
  1300. x = "z_rpd_low",
  1301. y = "z_rpd",
  1302. add = "reg.line",
  1303. conf.int = TRUE,
  1304. cor.coef = TRUE,
  1305. cor.method = "pearson",
  1306. xlab = "scaled BPS (rpd_low)",
  1307. ylab = "scaled SEPR (rpd)",
  1308. title = "Association between SEPR + BPS in standard trials")
  1309. # Associations of the pupillometric measures
  1310. lmm <- lmer(
  1311. z_rpd ~ z_rpd_low * stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1312. data = et_erp_trial)
  1313. anova(lmm)
  1314. r2_nakagawa(lmm)
  1315. ### post-hoc: BPS
  1316. summary(emtrends(lmm, ~ z_rpd_low, var = "z_rpd_low"), infer = T)
  1317. ### post-hoc: BPS x manipulation x block
  1318. emt <- emtrends(lmm, ~ manipulation|block, var = "z_rpd_low")
  1319. contrast(emt, "revpairwise")
  1320. confint(contrast(emt, "revpairwise"))
  1321. ### EXPLORATORY (Reviewer's comment, 2025-10-27)
  1322. # lmer()-, but not poly()-function can handle NAs in the predictors, so
  1323. # et_erp_trial_for_model_fit excludes NAs for these exploratory model fit comparisons.
  1324. et_erp_trial_for_model_fit <- na.omit(et_erp_trial[ , c(
  1325. "z_rpd",
  1326. "z_rpd_low",
  1327. "stimulus",
  1328. "manipulation",
  1329. "group",
  1330. "block",
  1331. "SEGA_ID",
  1332. "age",
  1333. "gender")])
  1334. # linear
  1335. lmm_linear_fit <- lmer(
  1336. z_rpd ~ z_rpd_low * stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1337. data = et_erp_trial_for_model_fit, REML = F)
  1338. anova(lmm_linear_fit)
  1339. r2_nakagawa(lmm_linear_fit)
  1340. # quadratic
  1341. lmm_quadratic_fit <- lmer(
  1342. z_rpd ~ poly(z_rpd_low, 2) * stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1343. data = et_erp_trial_for_model_fit, REML = F)
  1344. anova(lmm_quadratic_fit)
  1345. r2_nakagawa(lmm_quadratic_fit)
  1346. # cubic
  1347. lmm_cubic_fit <- lmer(
  1348. z_rpd ~ poly(z_rpd_low, 3) * stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender,
  1349. data = et_erp_trial_for_model_fit, REML = F)
  1350. anova(lmm_cubic_fit)
  1351. r2_nakagawa(lmm_cubic_fit)
  1352. table_model_compare <- anova(lmm_linear_fit, lmm_quadratic_fit, lmm_cubic_fit)
  1353. table_model_compare <- cbind(
  1354. c("linear_fit", "quadratic_fit", "cubic_fit"),
  1355. table_model_compare)
  1356. table_formatted_BPS_SEPR <- table_model_compare %>%
  1357. kbl(caption = "Model comparision of BPS-SEPR association",
  1358. col.names = c("","number of parameters",'AIC','BIC','log likelihood','deviance','Chi-squared','df','p-value'),
  1359. row.names = F) %>%
  1360. kable_classic(full_width = F, html_font = "Cambria")
  1361. table_formatted_BPS_SEPR
  1362. # RESULT 15: Correlation: Pupil-ERP
  1363. crl <- cor(et_erp_trial[et_erp_trial$stimulus == "oddball", c(
  1364. "z_rpd_low",
  1365. "z_rpd",
  1366. "z_MMN_amplitude",
  1367. "z_P3a_amplitude"
  1368. )],
  1369. use="complete.obs")
  1370. crl
  1371. corrplot::corrplot(
  1372. crl,
  1373. method = "circle",
  1374. title = "Association between pupil data and ERPs in oddball trials",
  1375. mar=c(0,0,1,0))
  1376. crl <- cor(et_erp_trial[et_erp_trial$stimulus == "standard", c(
  1377. "z_rpd_low",
  1378. "z_rpd",
  1379. "z_MMN_amplitude",
  1380. "z_P3a_amplitude"
  1381. )],
  1382. use="complete.obs")
  1383. crl
  1384. corrplot::corrplot(
  1385. crl,
  1386. method = "circle",
  1387. title = "Association between pupil data and ERPs in standard trials",
  1388. mar=c(0,0,1,0))
  1389. # RESULT 16: Association between pupillometric indices and ERPs
  1390. ## MMN amplitude
  1391. lmm <- lmer(
  1392. z_MMN_amplitude ~ z_rpd * z_rpd_low * stimulus * manipulation * group + (1|SEGA_ID) + age + gender,
  1393. data = et_erp_trial)
  1394. anova(lmm)
  1395. r2_nakagawa(lmm)
  1396. ### post-hoc: SEPR
  1397. summary(emtrends(lmm, ~ z_rpd, var = "z_rpd"), infer = T)
  1398. ### post-hoc: BPS
  1399. summary(emtrends(lmm, ~ z_rpd_low, var = "z_rpd_low"), infer = T)
  1400. ### post-hoc: SEPR * BPS *group
  1401. summary(emtrends(lmm, ~ z_rpd * z_rpd_low|group, var = 'z_rpd', at = list(z_rpd_low = c(-2,0, 2))), infer = T)
  1402. emtr <- emtrends(lmm, ~ group | z_rpd_low, var = "z_rpd", at = list(z_rpd_low = c(-2, 0, 2)))
  1403. contrast_summary <- summary(pairs(emtr), infer = TRUE)
  1404. print(contrast_summary)
  1405. ## P3a amplitude
  1406. lmm <- lmer(
  1407. z_P3a_amplitude ~ z_rpd * z_rpd_low * stimulus * manipulation * group + (1|SEGA_ID) + age + gender,
  1408. data = et_erp_trial)
  1409. anova(lmm)
  1410. r2_nakagawa(lmm)
  1411. ### Post-hoc: SEPR
  1412. summary(emtrends(lmm, ~ z_rpd, var = "z_rpd"), infer = T)
  1413. ## BPS * group
  1414. summary(emtrends(lmm, ~ z_rpd_low|group, var = 'z_rpd_low'), infer = T)
  1415. # RESULT 17: EXPLORATORY ANALYSIS OF MODEL FIT FOR "trial_number_in_block" ON BPS
  1416. linear_fit <- lmer(
  1417. z_rpd_low ~ stimulus * manipulation * group * trial_number_in_block * block + (1|SEGA_ID) + age + gender,
  1418. data = et_erp_trial, REML = F)
  1419. anova(linear_fit)
  1420. quadratic_fit <- lmer(
  1421. z_rpd_low ~ stimulus * manipulation * group * poly(trial_number_in_block, 2) * block + (1|SEGA_ID) + age + gender,
  1422. data = et_erp_trial, REML = F)
  1423. anova(quadratic_fit)
  1424. r2_nakagawa(quadratic_fit)
  1425. cubic_fit <- lmer(
  1426. z_rpd_low ~ stimulus * manipulation * group * poly(trial_number_in_block, 3) * block + (1|SEGA_ID) + age + gender,
  1427. data = et_erp_trial, REML = F)
  1428. anova(cubic_fit)
  1429. r2_nakagawa(cubic_fit)
  1430. table_model_compare <- anova(linear_fit, quadratic_fit, cubic_fit)
  1431. table_model_compare <- cbind(
  1432. c("linear_fit", "quadratic_fit", "cubic_fit"),
  1433. table_model_compare
  1434. )
  1435. table_formatted_BPS <- table_model_compare %>%
  1436. kbl(caption = "Model comparision of trial_number_in_block on BPS",
  1437. col.names = c("","number of parameters",'AIC','BIC','log likelihood','deviance','Chi-squared','df','p-value'),
  1438. row.names = F) %>%
  1439. kable_classic(full_width = F, html_font = "Cambria")
  1440. table_formatted_BPS
  1441. # RESULT 18: EXPLORATIVE ANALYSIS OF MODEL FIT FOR "trial_number_in_block" on SEPR**
  1442. linear_fit <- lmer(
  1443. z_rpd ~ stimulus * manipulation * group * trial_number_in_block * block+ (1|SEGA_ID) + pitch + age + gender,
  1444. data = et_erp_trial, REML = F)
  1445. anova(linear_fit)
  1446. r2_nakagawa(linear_fit)
  1447. quadratic_fit <- lmer(
  1448. z_rpd ~ stimulus * manipulation * group * poly(trial_number_in_block, 2) * block + (1|SEGA_ID) + pitch + age + gender,
  1449. data = et_erp_trial, REML = F)
  1450. anova(quadratic_fit)
  1451. r2_nakagawa(quadratic_fit)
  1452. cubic_fit <- lmer(
  1453. z_rpd ~ stimulus * manipulation * group * poly(trial_number_in_block, 3) * block + (1|SEGA_ID) + pitch + age + gender,
  1454. data = et_erp_trial, REML = F)
  1455. anova(cubic_fit)
  1456. r2_nakagawa(cubic_fit)
  1457. table_model_compare <- anova(linear_fit, quadratic_fit, cubic_fit)
  1458. table_model_compare <- cbind(
  1459. c("linear_fit", "quadratic_fit", "cubic_fit"),
  1460. table_model_compare
  1461. )
  1462. table_formatted_SEPR <- table_model_compare %>%
  1463. kbl(caption = "Model comparision of trial_number_in_block on SEPR",
  1464. col.names = c("","number of parameters",'AIC','BIC','log likelihood','deviance','Chi-squared','df','p-value'),
  1465. row.names = F) %>%
  1466. kable_classic(full_width = F, html_font = "Cambria")
  1467. table_formatted_SEPR
  1468. # RESULT 19: ANALYSIS OF GRIP STRENGTH EFFECT
  1469. ## MNN amplitude
  1470. lmm <- lmer(
  1471. z_MMN_amplitude ~ stimulus * group * block * z_grip_strength + (1|SEGA_ID) + age + gender,
  1472. data = et_erp_subject[et_erp_subject$manipulation == "after", ])
  1473. anova(lmm)
  1474. r2_nakagawa(lmm)
  1475. ## MMN latency
  1476. lmm <- lmer(
  1477. z_MMN_latency ~ stimulus * group * block * z_grip_strength+ (1|SEGA_ID) + age + gender,
  1478. data = et_erp_subject[et_erp_subject$manipulation == "after", ])
  1479. anova(lmm)
  1480. r2_nakagawa(lmm)
  1481. ## P3a amplitude
  1482. lmm <- lmer(
  1483. z_P3a_amplitude ~ stimulus * group * block * z_grip_strength + (1|SEGA_ID) + age + gender,
  1484. data = et_erp_subject[et_erp_subject$manipulation == "after", ])
  1485. anova(lmm)
  1486. r2_nakagawa(lmm)
  1487. ## P3a latency
  1488. lmm <- lmer(
  1489. z_P3a_latency ~ stimulus * group * block * z_grip_strength+ (1|SEGA_ID) + age + gender,
  1490. data = et_erp_subject[et_erp_subject$manipulation == "after", ])
  1491. anova(lmm)
  1492. r2_nakagawa(lmm)
  1493. ## SEPR
  1494. lmm <- lmer(
  1495. z_rpd ~ stimulus * group * block * z_grip_strength + (1|SEGA_ID) + age + gender,
  1496. data = et_erp_subject[et_erp_subject$manipulation == "after", ])
  1497. anova(lmm)
  1498. r2_nakagawa(lmm)
  1499. ## BPS
  1500. lmm <- lmer(
  1501. z_rpd_low ~ stimulus * group * block * z_grip_strength + (1|SEGA_ID) + age + gender,
  1502. data = et_erp_subject[et_erp_subject$manipulation == "after", ])
  1503. anova(lmm)
  1504. r2_nakagawa(lmm)
  1505. # RESULT 20: Covariates Models (on subject + trial level)
  1506. ## MMN amplitude
  1507. lmm <- lmer(
  1508. z_MMN_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender + verbal_IQ + non_verbal_IQ,
  1509. data = et_erp_subject)
  1510. anova(lmm)
  1511. r2_nakagawa(lmm)
  1512. lmm <- lmer(
  1513. z_MMN_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender + verbal_IQ + non_verbal_IQ,
  1514. data = et_erp_trial)
  1515. anova(lmm)
  1516. r2_nakagawa(lmm)
  1517. ## MMN latency
  1518. lmm <- lmer(
  1519. z_MMN_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1520. data = et_erp_subject)
  1521. anova(lmm)
  1522. r2_nakagawa(lmm)
  1523. ## Post-hoc: age
  1524. emtrends(lmm, ~ age, var = "age")
  1525. lmm <- lmer(
  1526. z_MMN_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1527. data = et_erp_trial)
  1528. anova(lmm)
  1529. r2_nakagawa(lmm)
  1530. ## MMN diff amplitude
  1531. lmm <- lmer(
  1532. z_MMN_diff_amplitude ~ manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1533. data = MMN_diff)
  1534. anova(lmm)
  1535. r2_nakagawa(lmm)
  1536. ## MMN diff latency
  1537. lmm <- lmer(
  1538. z_MMN_diff_latency ~ manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1539. data = MMN_diff)
  1540. anova(lmm)
  1541. r2_nakagawa(lmm)
  1542. ## P3a amplitude
  1543. lmm <- lmer(
  1544. z_P3a_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1545. data = et_erp_subject)
  1546. anova(lmm)
  1547. r2_nakagawa(lmm)
  1548. ## Post-hoc: age
  1549. emtrends(lmm, ~ age, var = "age")
  1550. lmm <- lmer(
  1551. z_P3a_amplitude ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1552. data = et_erp_trial)
  1553. anova(lmm)
  1554. r2_nakagawa(lmm)
  1555. ## P3a latency
  1556. lmm <- lmer(
  1557. z_P3a_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1558. data = et_erp_subject)
  1559. anova(lmm)
  1560. r2_nakagawa(lmm)
  1561. lmm <- lmer(
  1562. z_P3a_latency ~ stimulus * manipulation * group * block + (1|SEGA_ID) + gender + age + verbal_IQ + non_verbal_IQ,
  1563. data = et_erp_trial)
  1564. anova(lmm)
  1565. r2_nakagawa(lmm)
  1566. ## SEPR
  1567. lmm <- lmer(
  1568. z_rpd ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender + verbal_IQ + non_verbal_IQ,
  1569. data = et_erp_subject)
  1570. anova(lmm)
  1571. r2_nakagawa(lmm)
  1572. lmm <- lmer(
  1573. z_rpd ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender + verbal_IQ + non_verbal_IQ,
  1574. data = et_erp_trial)
  1575. anova(lmm)
  1576. r2_nakagawa(lmm)
  1577. ## BPS
  1578. lmm <- lmer(
  1579. z_rpd_low ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender + verbal_IQ + non_verbal_IQ,
  1580. data = et_erp_subject)
  1581. anova(lmm)
  1582. r2_nakagawa(lmm)
  1583. ## Post-hoc: age
  1584. emtrends(lmm, ~ age, var = "age")
  1585. lmm <- lmer(
  1586. z_rpd ~ stimulus * manipulation * group * block + (1|SEGA_ID) + age + gender + verbal_IQ + non_verbal_IQ,
  1587. data = et_erp_trial)
  1588. anova(lmm)
  1589. r2_nakagawa(lmm)
  1590. # ANALYSIS OF df (ONLY PUPIL DATA-ALL DATA POINTS) ####
  1591. # Baseline phase
  1592. df_baseline <- df[df$phase %in% c("baseline", "baseline_calibration"), ]
  1593. df_baseline <- df_baseline[is.finite(df_baseline$pd), ]
  1594. # Number of pupil data per baseline trial (white, black and grey slide)
  1595. with(df_baseline[df_baseline$phase == "baseline_calibration", ], table(stimulus))
  1596. # Check: Block counter should be in line with aforementioned table
  1597. with(df_baseline, table(stimulus, block_counter))
  1598. with(df_baseline, by(
  1599. timestamp_exp, interaction(baseline_trial_counter, phase, id),
  1600. mean, na.rm = TRUE))
  1601. # mean_pd (subject baseline) is defined as mean of baseline trial during calibration phase
  1602. df_meanpd <- with(
  1603. df_baseline[df_baseline$phase == "baseline_calibration" &
  1604. df_baseline$stimulus == "baseline" , ], by(as.numeric(pd), id, mean))
  1605. df_meanpd <- data.frame(names(df_meanpd), as.numeric(df_meanpd))
  1606. names(df_meanpd) <- c("id", "mean_pd")
  1607. df_baseline <- merge(df_baseline, df_meanpd, by = "id")
  1608. # Visualization: LAPR group comparison
  1609. # New df with baseline trial only from calibration phase
  1610. df_baseline_calibration <- df_baseline[
  1611. df_baseline$phase == "baseline_calibration", ]
  1612. # Plot 1: LAPR_Subplots with trial_baseline corrected pd
  1613. ggplot(
  1614. # Baseline trial duration is theoretically 5 seconds.
  1615. df_baseline_calibration[df_baseline_calibration$ts_trial < 5.0, ],
  1616. aes(x = ts_trial,
  1617. y = pd,
  1618. group = group,
  1619. color = group)) +
  1620. geom_smooth() +
  1621. theme_bw() +
  1622. xlab("trial duration [s]") +
  1623. ylab("pupil dilation [mm]") +
  1624. labs(title = "LAPR for group and trial") +
  1625. facet_wrap(~ factor(stimulus,
  1626. levels = c("baseline", "baseline_whiteslide", "baseline_blackslide")))
  1627. ggsave(
  1628. "output/baseline_calibration_pd.tiff",
  1629. device = "tiff",
  1630. width = 6,
  1631. height = 4,
  1632. units = "in",
  1633. compression = "lzw",
  1634. dpi = 800
  1635. )
  1636. # Oddball phase
  1637. df_oddball <- df[df$phase %in% c("oddball_block", "oddball_block_rev"), ]
  1638. table(df_oddball$stimulus)
  1639. # merge with baseline PD
  1640. df_oddball <- merge(df_oddball, df_meanpd, by = "id")
  1641. # subject-baseline corrected pd
  1642. df_oddball$subj_corr_rpd <- df_oddball$pd - df_oddball$mean_pd
  1643. hist(df_oddball$subj_corr_rpd, 50)
  1644. # correct for non-finite values
  1645. df_oddball <- df_oddball[is.finite(df_oddball$subj_corr_rpd), ]
  1646. df_oddball <- df_oddball[is.finite(df_oddball$trial_corr_rpd), ]
  1647. # trial type (standard versus oddball)
  1648. df_oddball$trial_type <- substr(df_oddball$stimulus, 1, 7)
  1649. table(df_oddball$block_counter, df_oddball$stimulus)
  1650. df_oddball$manipulation <- factor(ifelse(df_oddball$block_counter < 8, "before",
  1651. ifelse(df_oddball$block_counter > 8, "after", "manipulation")),
  1652. levels = c("before", "after"))
  1653. df_oddball$order <- ifelse(grepl("rev", df_oddball$stimulus), "reverse", "normal")
  1654. table(df_oddball$order, df_oddball$block_counter)
  1655. # define trials in oddball phase
  1656. df_oddball$trial_index_oddballphase <- with(
  1657. # name to indentify individual trials
  1658. df_oddball, interaction(block_counter, .thisRepN, .thisTrialN))
  1659. # all trials including empty trials
  1660. df_oddball$trial_number_oddballphase <- with(
  1661. df_oddball, rep(seq_along(table(trial_index_oddballphase)),
  1662. times = table(trial_index_oddballphase)))
  1663. df_oddball$trial_number_oddballphase <- with(
  1664. df_oddball, rep(seq_along(table(trial_number_oddballphase)),
  1665. # rerun remove empty trials from trial number
  1666. times = table(trial_number_oddballphase)))
  1667. # Number of pupil data per trial number
  1668. table(df_oddball$trial_number)
  1669. hist(df_oddball$trial_number_oddballphase)
  1670. # Plot: Pupillary response across experiment
  1671. ggplot(
  1672. df_oddball,
  1673. aes(x = trial_number_oddballphase, y = rpd)) +
  1674. geom_smooth(method = "lm") + facet_wrap(~stimulus + manipulation)
  1675. dev.off()
  1676. # Plot: Density of manipulation per condition
  1677. ggplot(df_oddball,
  1678. aes(rpd, fill = interaction(manipulation))) +
  1679. geom_density(alpha = 0.2) + facet_wrap(~stimulus)
  1680. dev.off()
  1681. # Plot: Pupil response over a trial (only forward)
  1682. ggplot(
  1683. df_oddball[df_oddball$ts_trial < 1.8 & df_oddball$order == "normal", ],
  1684. aes(x = ts_trial,
  1685. y = scale(rpd),
  1686. group = interaction(group, trial_type),
  1687. color = group,
  1688. linetype = trial_type)) +
  1689. geom_smooth() +
  1690. theme_bw() +
  1691. labs(x = "trial duration (s)",
  1692. y = "standardized pupil response (z)",
  1693. title = "effect of manipulation of pupil response")
  1694. dev.off()
  1695. # Plot: Pupil response over a trial
  1696. ggplot(
  1697. df_oddball[df_oddball$ts_trial < 1.8, ],
  1698. aes(x = ts_trial,
  1699. y = scale(rpd),
  1700. group = interaction(order, manipulation),
  1701. color = order,
  1702. linetype = trial_type)) +
  1703. geom_smooth() +
  1704. theme_bw() +
  1705. labs(x = "trial duration (s)",
  1706. y = "standardized pupil response (z)",
  1707. title = "effect of manipulation of pupil response by block")
  1708. dev.off()
  1709. # Plot: Pupil response over a trial across groups (SEGA Paper Fig 2)
  1710. plot_dgkjp <- ggplot(
  1711. df_oddball[df_oddball$ts_trial < 1.9, ],
  1712. aes(x = ts_trial,
  1713. y = pd,
  1714. group = trial_type,
  1715. color = trial_type)) +
  1716. geom_smooth(formula = y ~ x + poly(x, 5)) +
  1717. theme_bw() +
  1718. theme(axis.text.x = element_text(face = "bold", size = 14),
  1719. axis.text.y = element_text(face = "bold", size = 14),
  1720. axis.title.x = element_text(face = "bold", size = 16),
  1721. axis.title.y = element_text(face = "bold", size = 16)) +
  1722. labs(x = "trial duration [s]",
  1723. y = "standardized pupil response [z]",
  1724. title = "Oddball Effect on pupillary response") +
  1725. scale_color_manual(values = c("red", "black"))
  1726. plot_dgkjp
  1727. dev.off()
  1728. # get legend only and save it
  1729. legend_plot_dgkjp <- get_legend(plot_dgkjp)
  1730. as_ggplot(legend_plot_dgkjp)
  1731. ggsave(
  1732. "output/plot_legend.tiff",
  1733. device = "tiff",
  1734. width = 3,
  1735. height = 2,
  1736. units = "in",
  1737. compression = "lzw",
  1738. dpi = 800
  1739. )
  1740. # Plot: Effect of manipulation on pupillary response
  1741. ggplot(
  1742. df_oddball[df_oddball$ts_trial < 1.8 & df_oddball$order == "normal", ],
  1743. aes(x = ts_trial,
  1744. y = scale(rpd),
  1745. group = interaction(group, trial_type),
  1746. color = group,
  1747. linetype = trial_type)) +
  1748. geom_smooth() +
  1749. theme_bw() +
  1750. labs(x = "trial duration (s)",
  1751. y = "standardized pupil response (z)",
  1752. title = "effect of manipulation of pupil response") +
  1753. facet_wrap(~manipulation)
  1754. dev.off()
  1755. lmm_interaction <- lmerTest::lmer(
  1756. rpd ~ trial_type * manipulation * group + (1|id),
  1757. data = df_oddball)
  1758. anova(lmm_interaction)
  1759. confint(contrast(emmeans::emmeans(
  1760. lmm_interaction, ~ group + trial_type + manipulation), method = 'pairwise'))
  1761. confint(contrast(emmeans::emmeans(
  1762. lmm_interaction, ~ manipulation + trial_type | group), method = 'pairwise'))
  1763. # Pupil response to manipulation and conditions within block
  1764. ggplot(
  1765. df_oddball[df_oddball$ts_trial < 2 & is.finite(df_oddball$rpd), ],
  1766. aes(x = trial_number_in_block,
  1767. y = scale(rpd),
  1768. group = interaction(manipulation, order, trial_type),
  1769. color = interaction(manipulation, order),
  1770. linetype = trial_type)) +
  1771. geom_smooth() + theme_bw() +
  1772. xlab("trial within block") +
  1773. ylab("relative pupil size (z)")
  1774. dev.off()
  1775. # DATA ANALYSIS: gaze data - raw pupil data ####
  1776. hist(df_oddball$left_pupil_measure1)
  1777. hist(df_oddball$right_pupil_measure1)
  1778. # raw gaze data
  1779. hist(
  1780. df_oddball$left_gaze_x[df_oddball$left_gaze_x < 200 &
  1781. df_oddball$left_gaze_x > -200])
  1782. hist(
  1783. df_oddball$right_gaze_x[df_oddball$right_gaze_x < 200 &
  1784. df_oddball$right_gaze_x > -200])
  1785. hist(
  1786. df_oddball$left_gaze_y[df_oddball$left_gaze_y < 200 &
  1787. df_oddball$left_gaze_y > -200])
  1788. hist(
  1789. df_oddball$right_gaze_y[df_oddball$right_gaze_y < 200 &
  1790. df_oddball$right_gaze_y > -200])
  1791. # refined heatmap
  1792. ggplot(
  1793. df_oddball[df_oddball$ts_trial < 2 & is.finite(df_oddball$rpd) &
  1794. is.finite(df_oddball$left_gaze_x) & is.finite(df_oddball$left_gaze_y), ],
  1795. aes(x = left_gaze_x, y = left_gaze_y)) +
  1796. stat_density_2d(aes(fill = after_stat(density)),
  1797. n = 50,
  1798. geom = "raster",
  1799. contour = FALSE) +
  1800. xlim(-200, 200) +
  1801. ylim(-200, 200) +
  1802. scale_fill_gradientn(colours = rev(rainbow(3)))
  1803. # Manipulation phase
  1804. df_manip <- df[df$phase %in% c("manipulation_block"), ]
  1805. table(df_manip$stimulus)
  1806. table(df_manip$manipulation_trial_counter)
  1807. with(df_manip, table(stimulus, manipulation_trial_counter))
  1808. # merge with baseline PD
  1809. df_manip <- merge(df_manip, df_meanpd, by = "id")
  1810. # baselinecorrected pd
  1811. df_manip$rpd <- df_manip$pd - df_manip$mean_pd
  1812. hist(df_manip$rpd)
  1813. # correct for non-finite values
  1814. df_manip <- df_manip[is.finite(df_manip$rpd), ]
  1815. # define different baseline scenarios
  1816. df_manip$trial_type <- with(
  1817. df_manip, ifelse(
  1818. manipulation_trial_counter %in% c(3, 7, 11, 15, 19),
  1819. "baseline_after_squeeze", ifelse(
  1820. manipulation_trial_counter %in% c(5, 9, 13, 17), "baseline_after_relax",
  1821. ifelse(manipulation_trial_counter %in% c(2, 6, 10, 14, 18), "squeeze",
  1822. ifelse(manipulation_trial_counter %in% c(4, 8, 12, 16, 20),
  1823. "relax", "baseline_start")))))
  1824. # 18 is duration of squeeze phase
  1825. ggplot(
  1826. df_manip[df_manip$ts_trial < 18 & df_manip$stimulus != "baseline", ],
  1827. aes(x = ts_trial,
  1828. y = rpd,
  1829. group = stimulus,
  1830. color = stimulus)) +
  1831. geom_smooth() +
  1832. theme_bw() +
  1833. labs(x = "trial duration (s)",
  1834. y = "standardized pupillary response (z)",
  1835. title = "pupil response between manipulation phases")
  1836. ggplot(
  1837. df_manip[df_manip$trial_type != "baseline_start", ],
  1838. aes(x = trial_type,
  1839. y = rpd,
  1840. fill = trial_type)) +
  1841. geom_boxplot() +
  1842. theme_bw() +
  1843. labs(x = "manipulation phase (s)",
  1844. y = "standardized pupillary response (z)",
  1845. title = "pupil response between manipulation phases")
  1846. ggplot(
  1847. df_manip,
  1848. aes(x = manipulation_trial_counter,
  1849. y = rpd,
  1850. group = manipulation_trial_counter,
  1851. fill = trial_type)) +
  1852. geom_boxplot() +
  1853. theme_bw()
  1854. lmm <- lmer(
  1855. rpd ~ trial_type + (1 | manipulation_trial_counter),
  1856. data = df_manip[df_manip$trial_type != "baseline_start", ])
  1857. anova(lmm)
  1858. plot(contrast(emmeans(lmm, ~ trial_type), "pairwise"))
  1859. # Grip strength ####
  1860. hist(df_trial$mean_grip_strength)
  1861. df_trial$mean_grip_strength_z<-scale(df_trial$mean_grip_strength)
  1862. #pupillary response - SEPR
  1863. lmm<-lmer(scale(rpd)~mean_grip_strength_z*manipulation*stimulus*group*block+(1|id),data=df_trial[df_trial$phase %in% c('oddball_block','oddball_block_rev'),])
  1864. anova(lmm) #--> no effect of hand grip strength
  1865. #pupillary response - BPS
  1866. lmm<-lmer(scale(rpd_low)~mean_grip_strength_z*manipulation*stimulus*group*block+(1|id),data=df_trial[df_trial$phase %in% c('oddball_block','oddball_block_rev'),])
  1867. anova(lmm)
  1868. fixef(lmm) #higher hand grip is assoicated with lower bps
  1869. emtrends(lmm,~manipulation|group+block,var = 'mean_grip_strength_z') ##--> higher pupil size after manipulation
  1870. #the hand grip strength has an effect on rpd only in the TD group
  1871. # Visualization
  1872. g1 <- ggplot(
  1873. df_baseline[df_baseline$phase == "baseline_calibration" &
  1874. df_baseline$ts_trial < 6, ],
  1875. aes(x = ts_trial,
  1876. y = pd,
  1877. group = stimulus,
  1878. color = stimulus)) +
  1879. geom_smooth() +
  1880. theme_bw() +
  1881. xlab("time (s)") +
  1882. ylab("pupil size (mm)") +
  1883. labs(title = "change of PD during initial baseline between IDs")
  1884. g2 <- ggplot(
  1885. df_manip[df_manip$ts_trial < 18 & df_manip$stimulus != "baseline", ],
  1886. aes(x = ts_trial,
  1887. y = rpd,
  1888. group = stimulus,
  1889. color = stimulus)) +
  1890. geom_smooth() +
  1891. theme_bw() +
  1892. labs(x = "trial duration (s)",
  1893. y = "standardized pupillary response (z)",
  1894. title = "pupil response during manipulation")
  1895. g3 <- ggplot(
  1896. df_manip[df_manip$trial_type != "baseline_start", ],
  1897. aes(x = trial_type,
  1898. y = rpd,
  1899. fill = trial_type)) +
  1900. geom_boxplot() +
  1901. theme_bw() +
  1902. labs(x = "manipulation phase (s)",
  1903. y = "standardized pupillary response (z)",
  1904. title = "pupil response in manipulation phases")
  1905. g4 <- ggplot(
  1906. df_oddball[df_oddball$ts_trial < 1.8 & df_oddball$order == "normal", ],
  1907. aes(x = ts_trial,
  1908. y = scale(rpd),
  1909. group = trial_type,
  1910. color = trial_type)) +
  1911. geom_smooth() +
  1912. theme_bw() +
  1913. labs(x = "trial duration (s)",
  1914. y = "standardized pupil response (z)",
  1915. title = "effect of manipulation on stimulus-evoked pupillary response
  1916. (before vs. after manipulation)") +
  1917. facet_wrap(~manipulation) +
  1918. scale_color_brewer(palette = "Dark2")
  1919. tiff(
  1920. file = paste0(home_path, project_path,
  1921. "/output/figure_audio_results_testdata.tiff"),
  1922. width = 12,
  1923. height = 16,
  1924. units = "in",
  1925. res = 300,
  1926. compression = "lzw")
  1927. grid.arrange(g1, g2, g3, g4,
  1928. layout_matrix = rbind(c(1, 1), c(2, 3), c(4, 4)))
  1929. dev.off()
  1930. print("The End")

data_analysis_auditory_oddball.R at commit 43374b6, no license · at the source

Overview

  1. Department of Child and Adolescent Psychiatry, Psychosomatics and Psychotherapy, University Medicine Frankfurt, Goethe-University, Deutschordenstraße 50, 60528 Frankfurt, Germany
Institutions: Goethe University Frankfurt (Germany)
Journal: Translational psychiatry, volume 16, issue 1, article 200
Dates: received 7 July 2025; accepted 6 March 2026; published online 24 March 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1038/s41398-026-03948-0 · PMID 41872152 · PMCID PMC13039879 · OpenAlex W7140176029
Open access: gold, a free copy (OpenAlex)
Status: code verified (how the code is found and verified)
Categories: EEG (modality), human (organism), autism (population)
Methods: Spectral & time-frequency, Smoothing, state filtering, decompositions, Preprocessing, Evoked potentials, Statistics, Single-unit activity, calcium imaging, Physiology & signal measures
Keywords: Neuroscience, Diagnostic markers, Autism spectrum disorders, Psychology
MeSH: Auditory Perception*, Autism Spectrum Disorder*, Autistic Disorder*, Locus Coeruleus*, Adolescent, Attention, Case-Control Studies, Child, Electroencephalography, Evoked Potentials, Female, Humans, Male, Norepinephrine, Pupil (* major topic)
Topic: Autism Spectrum Disorder Research (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: Deutsche Forschungsgemeinschaft (492582254); Daimler und Benz Stiftung (32-01/22)
Citations: not cited yet (Europe PMC); 71 references in the paper

Abstract

Sensory symptoms are common in autism and may result from differences in sensory processing. The locus coeruleus-norepinephrine (LC-NE) system modulates sensory processing by increasing selectivity to salience. To specify this mechanism, we manipulated LC-NE activity and explored sensory selectivity in autistic and non-autistic adolescents. We assessed pupillometry and electroencephalography (EEG) in 52 autistic adolescents (ASD), 55 healthy controls (CON), and 43 adolescents with other mental health conditions (MHC) during a passive auditory oddball task. A handgrip exercise manipulated LC-NE activity. Baseline pupil size (BPS) and stimulus-evoked pupillary response (SEPR) measured LC-NE tonic and phasic activity, respectively. Sensory selectivity was estimated with mismatch negativity (MMN) as change detection and P3a as bottom-up attention. Oddballs versus standards elicited increased SEPR, MMN amplitude, and longer MMN and P3a latencies. Increased P3a amplitude was more consistent in ASD. Across oddballs and standards, the manipulation transiently increased MMN and P3a amplitudes. A manipulation-induced BPS increase was specific to ASD and MHC. Pupillometric measures (BPS, SEPR) modulated sensory selectivity measures (MMN, P3a) differently between clinical groups (ASD, MHC) and CON. Findings indicate an altered orienting response to sensory stimuli in autism. The manipulation did not increase sensory selectivity but temporarily enhanced sensory reactivity to all stimuli with an arousal upregulation in both clinical groups. LC-NE activity was differentially related to sensory selectivity in autism and other mental health conditions. The tonic upregulation is discussed as increased stress susceptibility across autism and other mental health conditions.

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

sega-studie/code

License: none: the authors keep all their rights
State: the link answers, verified on 30 September 2026
Evidence: files inventoried
Commit: 43374b6482e1ff5c52be6dc02f807be66200e4aa, 2 November 2025
Languages: R (10)
Size: 11 files, 10 scripts
Software Heritage: not archived
Found in: the text, “Pupillometry”
Holds: README, 4 notebooks
Not found: license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: tidyverse (8 files), emmeans (6 files), lme4 (6 files), lmerTest (6 files), easystats (5 files), ggplot2 (5 files), ggpubr (5 files), cowplot (4 files), data.table (4 files), reshape2 (2 files), psych (1 file)
Availability: 1 check, the latest on 30 September 2026: the link answers
  • 30 September 2026: the link answers
11 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;
  • 10 scripts, each with its path and the digest of its content;
  • 11 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

Scripts for pupil data preprocessing and full analysis can be found at github, accessible via the link provided in the methods. All data supporting this study are described in the text and in the supplementary material. Due to ethical considerations and data privacy, the raw data that is tied to person identifiable information cannot be publicly shared.

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, 4 keywords, 15 MeSH terms, 2 funders, 62 references.

Cite

This paper

Müller, A. K., Luckhardt, C., Freitag, C. M., & Bast, N. (2026). Locus coeruleus modulation of neurophysiological sensory selectivity differs in autism and other mental health conditions. Translational psychiatry, 16(1), 200. https://doi.org/10.1038/s41398-026-03948-0

BibTeX

@article{muller2026locus,
author = {Müller, Anna K and Luckhardt, Christina and Freitag, Christine M and Bast, Nico},
title = {{Locus coeruleus modulation of neurophysiological sensory selectivity differs in autism and other mental health conditions}},
journal = {Translational psychiatry},
year = {2026},
month = mar,
volume = {16},
number = {1},
pages = {200},
publisher = {Nature Publishing Group},
issn = {2158-3188},
doi = {10.1038/s41398-026-03948-0},
url = {https://doi.org/10.1038/s41398-026-03948-0},
pmid = {41872152},
pmcid = {PMC13039879}
}

RIS

TY - JOUR
AU - Müller, Anna K
AU - Luckhardt, Christina
AU - Freitag, Christine M
AU - Bast, Nico
TI - Locus coeruleus modulation of neurophysiological sensory selectivity differs in autism and other mental health conditions
T2 - Translational psychiatry
J2 - Transl Psychiatry
PY - 2026
DA - 2026/03/24
VL - 16
IS - 1
SP - 200
SN - 2158-3188
PB - Nature Publishing Group
DO - 10.1038/s41398-026-03948-0
UR - https://doi.org/10.1038/s41398-026-03948-0
LA - en
ER -

CSL-JSON

{
"id": "10.1038/s41398-026-03948-0",
"type": "article-journal",
"title": "Locus coeruleus modulation of neurophysiological sensory selectivity differs in autism and other mental health conditions",
"container-title": "Translational psychiatry",
"author": [
{
"family": "Müller",
"given": "Anna K"
},
{
"family": "Luckhardt",
"given": "Christina"
},
{
"family": "Freitag",
"given": "Christine M"
},
{
"family": "Bast",
"given": "Nico"
}
],
"container-title-short": "Transl Psychiatry",
"volume": "16",
"issue": "1",
"page": "200",
"DOI": "10.1038/s41398-026-03948-0",
"PMID": "41872152",
"PMCID": "PMC13039879",
"ISSN": "2158-3188",
"publisher": "Nature Publishing Group",
"URL": "https://doi.org/10.1038/s41398-026-03948-0",
"language": "en",
"issued": {
"date-parts": [
[
2026,
3,
24
]
]
}
}

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.1186/s13229-025-00678-w [code]
Locus coeruleus tonic upregulation increases selectivity to inconspicuous auditory information in autistic compared to non-autistic individuals: a combined pupillometry and electroencephalography study.
Journal: Molecular autism
In common: easystats, psych, emmeans, 6 other tools, autism, EEG, 18 references, 4 authors
[2] doi:10.1186/s13229-023-00537-6 [code]
Sensory salience processing moderates attenuated gazes on faces in autism spectrum disorder: a case-control study.
Journal: Molecular autism
In common: psych, emmeans, lmerTest, 4 other tools, autism, 13 references
[3] doi:10.1371/journal.pone.0355165 [code]
Pupillary dynamics during hands-off L2 driving and transitions of control under high cognitive load.
Journal: PloS one
In common: easystats, emmeans, lmerTest, 5 other tools, 7 references
[4] doi:10.1038/s41598-023-28781-z [code]
Changes in pupil dilation and P300 amplitude indicate the possible involvement of the locus coeruleus-norepinephrine (LC-NE) system in psychological flow.
Journal: Scientific reports
In common: easystats, lmerTest, lme4, 4 other tools, EEG, 7 references
[5] doi:10.7554/elife.109678 [code]
Strong mnemonic prediction errors increase cognitive control, attention, and arousal.
Journal: eLife
In common: easystats, psych, emmeans, 5 other tools, EEG, 4 references
[6] doi:10.3758/s13423-022-02124-x [code]
Explicitly predicting outcomes enhances learning of expectancy-violating information.
Journal: Psychonomic bulletin & review
In common: easystats, psych, emmeans, 6 other tools, 3 references
[7] doi:10.3758/s13415-023-01096-2 [code]
Testing locus coeruleus-norepinephrine accounts of working memory, attention control, and fluid intelligence.
Journal: Cognitive, affective & behavioral neuroscience
In common: psych, lmerTest, cowplot, 3 other tools, 6 references
[8] doi:10.1093/scan/nsag009 [code]
Covert neural and autonomic signatures of shared perception.
Journal: Social cognitive and affective neuroscience
In common: easystats, emmeans, lmerTest, 5 other tools, EEG, 2 references
[9] doi:10.7554/elife.84822 [code]
Pupil size reflects activation of subcortical ascending arousal system nuclei during rest.
Journal: eLife
In common: psych, lme4, ggpubr, 3 other tools, 4 references
[10] doi:10.1038/s41598-023-41357-1
Acceleration of inferred neural responses to oddball targets in an individual with bilateral amygdala lesion compared to healthy controls.
Journal: Scientific reports
In common: 8 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.1038/s41398-026-03948-0.svg)](https://openscicode.org/badge/doi/10.1038/s41398-026-03948-0)
<!-- oscr-badge:end -->
reStructuredText
.. oscr-badge:start

.. image:: https://openscicode.org/badge/doi/10.1038/s41398-026-03948-0.svg
   :target: https://openscicode.org/badge/doi/10.1038/s41398-026-03948-0
   :alt: OSCR

.. oscr-badge:end
HTML
<!-- oscr-badge:start -->
<a href="https://openscicode.org/badge/doi/10.1038/s41398-026-03948-0"><img src="https://openscicode.org/badge/doi/10.1038/s41398-026-03948-0.svg" alt="OSCR"></a>
<!-- oscr-badge:end -->

On GitHub, open the README, choose Edit (the pencil), paste the snippet under the title, then "Commit changes".

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)

Versions of its code: the releases of its code tied to a version of this paper (the preprint, the accepted manuscript, the version of record…), each with the tracing map versioned with it.

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