OSCR

Facial palsy reveals the sensorimotor contribution to facial-emotion recognition.

Code ↔ Paper

2 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 2 matches
  1. [1] § Results › Severity–Performance Coupling in Congenital Palsy (H2a). ↔ Study 2/Script/Study2_Confirmatory_Analyses_and_Plot.R, lines 789–848 · score 0.54 · Model projections, cross validation, facial motor, correlated, matched, predicted
  2. [2] § Materials and Methods ↔ Study 2/Script/Study2_Confirmatory_Analyses_and_Plot.R, lines 683–746 · score 0.50 · SFGS scores, ADFES accuracy, JeFEE, correlations, CI, bootstrap

Paper

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

The paper is loaded when this pane is shown.

The authors' code

R · 915 lines · 32 KB · no license · 2 matches

  1. ## HEADER ----
  2. # Experiment: CARIPARO
  3. # Programmer: QUETTIER THOMAS
  4. # Created: 04/06/2023
  5. # Updated: 24/07/2025
  6. # Description:
  7. # This script performs data analysis for the CARIPARO experiment,
  8. # specifically for the Accuracy and Intensity measures of the
  9. # Online student experiment.
  10. ## Clean up ----
  11. rm(list = ls()) # Remove all objects
  12. ## Load libraries ----
  13. library(tidyverse)
  14. library(afex)
  15. library(effectsize)
  16. library(BayesFactor)
  17. library(emmeans)
  18. library(dplyr)
  19. library(performance)
  20. library(brms)
  21. library(bayestestR)
  22. library(tidyverse)
  23. library(cowplot)
  24. library(ggplot2)
  25. library(ggrain)
  26. library(mediation)
  27. library(broom)
  28. library(boot)
  29. ## Define preprocessing function ----
  30. preprocessed_data <- function(file_path, value_col, ...) {
  31. read_csv(file_path) %>%
  32. group_by(...) %>%
  33. summarise(across(all_of(value_col), ~ mean(.x, na.rm = TRUE)), .groups = "drop") %>%
  34. mutate(label = paste0(subject,video_set),
  35. video_set = factor(video_set, levels = c("ADFES", "JeFEE")))
  36. }
  37. figure<-function(data, type){
  38. colors <- c("ADFES" = "#657d9a", "JeFEE" = "#b37269")
  39. colorgroup <- c(Moebius = "#F0E442", Control = "#C07DA5")
  40. # stat summary
  41. if(type == "acc"){
  42. df <- data %>% dplyr::select(-label) %>%
  43. 'colnames<-'(c("subject" , "group" ,"video_set", "mean"))%>%
  44. mutate(mean = mean*100,
  45. match = paste0(parse_number(subject),video_set))
  46. ytitle <- "Mean Accuracy (%)"
  47. } else if(type == "int"){
  48. df <- data %>% dplyr::select(-label) %>%
  49. 'colnames<-'(c("subject", "group" , "video_set", "mean"))%>%
  50. mutate(match = paste0(parse_number(subject),video_set))
  51. ytitle <- "Mean Intensity (px)"
  52. }
  53. descritive <- df %>%
  54. group_by(video_set, group) %>%
  55. summarise(sd = sd(mean),
  56. se = sd(mean)/sqrt(n()),
  57. mean = mean(mean),
  58. .groups = "drop")%>%
  59. mutate(x_pos = case_when(
  60. group == "Moebius" & video_set == "ADFES" ~ 2 - 0.1,
  61. group == "Moebius" & video_set == "JeFEE" ~ 2 - 0.1,
  62. group == "Control" & video_set == "ADFES" ~ 1 + 0.1,
  63. group == "Control" & video_set == "JeFEE" ~ 1 + 0.1
  64. ))
  65. p <- ggplot(df %>% filter(group %in% c("Moebius", "Control")),
  66. aes(x = group, y = mean, fill = video_set)) +
  67. geom_rain(alpha = 0.5, rain.side = 'f2x2', id.long.var = "match", cov = "group") +
  68. geom_point(data = descritive,
  69. aes(x = x_pos, y = mean, fill = video_set),
  70. size = 3, shape = 23, color = "black") +
  71. geom_errorbar(data = descritive,
  72. aes(x = x_pos, ymin = mean - se, ymax = mean + se),
  73. width = 0, color = "black", linewidth = 0.5, inherit.aes = FALSE) +
  74. scale_fill_manual(values = colors) +
  75. scale_color_manual(values = colorgroup) +
  76. labs(x = NULL, y = ytitle, fill = "Expression Type") +
  77. theme_minimal(base_size = 14) +
  78. theme(legend.position = "none") +
  79. theme(text=element_text(size=10, family="Helvetica"),
  80. panel.background = element_blank(),
  81. axis.line = element_line(colour = "black"),
  82. strip.text.x = element_text(size = 6.6),
  83. strip.text.y = element_text(size = 6.6),
  84. panel.grid.major = element_blank(), # Rimuove le griglie principali
  85. panel.grid.minor = element_blank() )
  86. return(p)
  87. }
  88. # Function to extract results from mediation analysis
  89. extract_med <- function(model, mediator_name, outcome_name) {
  90. summ <- summary(model)
  91. tibble(
  92. mediator = mediator_name,
  93. outcome = outcome_name,
  94. acme = summ$d0,
  95. acme_ci_low = summ$d0.ci[1],
  96. acme_ci_high = summ$d0.ci[2],
  97. acme_p = summ$d0.p,
  98. ade = summ$z0,
  99. ade_ci_low = summ$z0.ci[1],
  100. ade_ci_high = summ$z0.ci[2],
  101. ade_p = summ$z0.p,
  102. total_effect = summ$tau.coef,
  103. total_ci_low = summ$tau.ci[1],
  104. total_ci_high = summ$tau.ci[2],
  105. total_p = summ$tau.p
  106. )
  107. }
  108. # Generic function to bootstrap Pearson r
  109. cor_fun <- function(data, indices, x, y) {
  110. d <- data[indices, ]
  111. return(cor(d[[x]], d[[y]], method = "pearson"))
  112. }
  113. # Helper function to append test results
  114. add_result <- function(var, outcome, test, bf, eff = NA) {
  115. tibble::tibble(
  116. variable = var,
  117. outcome = outcome,
  118. stat_type = test$method,
  119. stat_value = unname(test$estimate),
  120. p_value = test$p.value,
  121. bf01 = bf,
  122. effect_size = eff
  123. )
  124. }
  125. # Pearson r with BCa 95 % CI (10 000 resamples)
  126. bcacor <- function(d, i, var){
  127. d <- d[i, ]
  128. cor(d$Sunnybrook, d[[var]], method = "pearson")
  129. }
  130. get_bca <- function(var){
  131. bt <- boot(dat, bcacor, R = 10000, var = var)
  132. ci <- boot.ci(bt, type = "bca")$bca[4:5]
  133. tibble(
  134. Variable = var,
  135. r = cor(dat$Sunnybrook, dat[[var]]),
  136. CI_low = ci[1],
  137. CI_high = ci[2],
  138. p = cor.test(dat$Sunnybrook, dat[[var]])$p.value
  139. )
  140. }
  141. # Leave-one-out cross-validated R² with percentile CI
  142. calc_loo <- function(y){
  143. n <- nrow(dat)
  144. yh <- numeric(n)
  145. for(i in seq_len(n)){
  146. fit <- lm(reformulate("Sunnybrook", y), data = dat[-i, ])
  147. yh[i] <- predict(fit, newdata = dat[i, ])
  148. }
  149. r2 <- 1 - sum((dat[[y]] - yh)^2) / sum((dat[[y]] - mean(dat[[y]]))^2)
  150. bt <- boot(dat, function(d, ind){
  151. d <- d[ind, ]
  152. n <- nrow(d); yh <- numeric(n)
  153. for(i in seq_len(n)){
  154. fit <- lm(reformulate("Sunnybrook", y), data = d[-i, ])
  155. yh[i] <- predict(fit, newdata = d[i, ])
  156. }
  157. 1 - sum((d[[y]] - yh)^2) / sum((d[[y]] - mean(d[[y]]))^2)
  158. }, R = 10000)
  159. ci <- boot.ci(bt, type = "perc")$percent[4:5]
  160. tibble(Variable = y, R2_CV = r2, CI_low = ci[1], CI_high = ci[2])
  161. }
  162. get_pred <- function(y){
  163. fit <- lm(reformulate("Sunnybrook", y), data = dat)
  164. predict(fit, newdata = grid, interval = "prediction", level = 0.95) %>%
  165. as_tibble() %>%
  166. mutate(Sunnybrook = grid$Sunnybrook, Variable = y)
  167. }
  168. ## Accuracy Analysis ----
  169. ### 0. Data preparation ----
  170. df_acc <- preprocessed_data("data/Study2_Mean_forEmotion_Accuracy.csv", "accuracy", subject, group, video_set, emotion)
  171. df_int <- preprocessed_data("data/Study2_Mean_forEmotion_intensity", "intensity", subject, group, video_set)
  172. df_acc$total <- 8 # Number of trials per observation
  173. ### 1. Descriptive statistics for accuracy ----
  174. df_subject_mean <- df_acc %>%
  175. group_by(subject, group, video_set) %>%
  176. summarise(accuracy = mean(accuracy, na.rm = TRUE), .groups = "drop")
  177. descriptive_accuracy <- df_subject_mean %>%
  178. group_by(video_set, group) %>%
  179. summarise(
  180. mean_acc = mean(accuracy) * 100,
  181. sd_acc = sd(accuracy) * 100,
  182. se_acc = sd(accuracy) / sqrt(n()) * 100,
  183. min_acc = min(accuracy) * 100,
  184. max_acc = max(accuracy) * 100,
  185. .groups = "drop"
  186. )
  187. print(descriptive_accuracy)
  188. # Compute % difference between ADFES and JeFEE
  189. diff_percent <- descriptive_accuracy %>%
  190. dplyr::select(video_set, group, mean_acc) %>%
  191. pivot_wider(names_from = video_set, values_from = mean_acc) %>%
  192. mutate(percent_diff = (ADFES - JeFEE) / ADFES * 100)
  193. ### 2. Fit GLMM on accuracy (binomial with weights) ----
  194. mod_glmer <- glmer(
  195. accuracy ~ video_set * group + (1 | subject),
  196. family = binomial(),
  197. weights = total,
  198. data = df_acc
  199. )
  200. summary(mod_glmer)
  201. ### 3. Estimated marginal means (response scale) ----
  202. emm_acc <- emmeans(mod_glmer, pairwise ~ video_set, type = "response")
  203. ### 4. Effect size from odds ratio ----
  204. odds_ratio <- summary(emm_acc$contrasts) %>% pull(odds.ratio)
  205. cohens_d <- oddsratio_to_d(odds_ratio)
  206. print(cohens_d)
  207. ### 5. R² from frequentist model ----
  208. r2(mod_glmer)
  209. ### 6. Welch's correction (variance == False -> apply correction) ----
  210. # data preparation
  211. ### 0. Data preparation
  212. df_welch <- preprocessed_data("Study2_Mean_forEmotion_Accuracy.csv", "accuracy", subject, video_set, group)
  213. # Subset data first
  214. adfes_data <- df_welch %>% filter(video_set == "ADFES")
  215. jefee_data <- df_welch %>% filter(video_set == "JeFEE")
  216. # Run Welch t-tests
  217. ADFES_ph <- t.test(accuracy ~ group, data = adfes_data, var.equal = FALSE)
  218. JeFEE_ph <- t.test(accuracy ~ group, data = jefee_data, var.equal = FALSE)
  219. # Compute Cohen's d from raw data
  220. ADFES_d <- cohens_d(accuracy ~ group, data = adfes_data)
  221. JeFEE_d <- cohens_d(accuracy ~ group, data = jefee_data)
  222. ### Bayesian Analysis (Accuracy) ----
  223. #### 1. Add success counts ----
  224. df_acc <- df_acc %>%
  225. mutate(successes = round(accuracy * total))
  226. #### 2. Fit full Bayesian model ----
  227. mod_full <- brm(
  228. successes | trials(total) ~ video_set * group + (1 | subject),
  229. family = binomial(),
  230. data = df_acc,
  231. prior = set_prior("normal(0, 5)", class = "b"),
  232. chains = 4, cores = 4, iter = 4000, seed = 123,
  233. save_pars = save_pars(all = TRUE)
  234. )
  235. #### 3. Fit null Bayesian model ----
  236. mod_null <- brm(
  237. successes | trials(total) ~ 1 + (1 | subject),
  238. family = binomial(),
  239. data = df_acc,
  240. prior = set_prior("normal(0, 5)", class = "Intercept"),
  241. chains = 4, cores = 4, iter = 4000, seed = 123,
  242. save_pars = save_pars(all = TRUE)
  243. )
  244. #### 4. Compute Bayes Factor ----
  245. BF <- bayesfactor_models(mod_full, mod_null)
  246. BF10 <- exp(abs(BF$log_BF[BF$Model == "1 + (1 | subject)"]))
  247. ## Intensity Analysis ----
  248. ### 1. Descriptive statistics for intensity ----
  249. descriptive_intensity <- df_int %>%
  250. group_by(video_set, group) %>%
  251. summarise(
  252. mean_int = mean(intensity, na.rm = TRUE),
  253. sd_int = sd(intensity, na.rm = TRUE),
  254. se_int = sd(intensity, na.rm = TRUE) / sqrt(n()),
  255. .groups = "drop"
  256. )
  257. print(descriptive_intensity)
  258. ### 2. Frequentist ANOVA ----
  259. anova_int <- aov_ez(id = "subject", dv = "intensity", within = "video_set", between = "group",data = df_int)
  260. summary(anova_int)
  261. ### 3. Effect size: η² ----
  262. eta2 <- eta_squared(anova_int, partial = TRUE)
  263. print(eta2)
  264. ### 4. Cohen’s d for repeated measures ----
  265. df_wide <- df_int %>%
  266. select(-label) %>%
  267. pivot_wider(names_from = video_set, values_from = intensity) %>%
  268. drop_na() %>%
  269. column_to_rownames("subject")
  270. d_rm <- cohens_d(df_wide$ADFES, df_wide$JeFEE, paired = TRUE, within = TRUE)
  271. print(d_rm)
  272. ### 5. Bayesian ANOVA ----
  273. df_int$subject <- as.factor(df_int$subject)
  274. df_int$video_set <- as.factor(df_int$video_set)
  275. df_int$group <- as.factor(df_int$group)
  276. bf_intensity <- anovaBF(
  277. intensity ~ video_set * group * subject,
  278. data = df_int ,
  279. whichRandom = "subject",
  280. iterations = 10000
  281. )
  282. BF <-extractBF(bf_intensity)
  283. ### 6. Welch's correction (variance == False -> apply correction)----
  284. # Subset data first
  285. adfes_data <- df_int %>% filter(video_set == "ADFES")
  286. jefee_data <- df_int %>% filter(video_set == "JeFEE")
  287. # Run Welch t-tests
  288. ADFES_ph <- t.test(intensity ~ group, data = adfes_data, var.equal = FALSE)
  289. JeFEE_ph <- t.test(intensity ~ group, data = jefee_data, var.equal = FALSE)
  290. # Compute Cohen's d from raw data
  291. ADFES_d <- cohens_d(intensity ~ group, data = adfes_data)
  292. JeFEE_d <- cohens_d(intensity ~ group, data = jefee_data)
  293. ### 7. Plot Figure 2S ----
  294. # Plots fig. 2S supp
  295. df_acc <- preprocessed_data("Study2_Mean_forEmotion_Accuracy.csv", "accuracy", subject, group, video_set)
  296. df_int <- preprocessed_data("Study2_Mean_forEmotion_intensity.csv", "intensity", subject, group, video_set)
  297. p1 <- figure(df_acc,"acc") # plot accuracy
  298. p2 <- figure(df_int,"int") # plot intensity
  299. p3 <- plot_grid(p1, p2, nrow = 1,labels = "AUTO") #combine plots
  300. # Export
  301. ggsave("figures/Fig_2S_finale.png", # export for draft
  302. plot = p3,
  303. device = "png",
  304. dpi = 300,
  305. width = 18,
  306. height = 12,
  307. units = "cm")
  308. ggsave("figures/Fig_2S.tiff", # export for journal
  309. plot = p3,
  310. device = "tiff",
  311. dpi = 1200,
  312. width = 18,
  313. height = 12,
  314. units = "cm")
  315. ## Normative sample comparison ----
  316. ### 1. Normative values ----
  317. df_acc_n <- read_csv("Study2_Mean_forEmotion_Accuracy.csv")%>%
  318. group_by(subject,video_set) %>%
  319. summarise( accuracy = mean(acc, na.rm = TRUE)) %>%
  320. mutate(video_set = as.factor(video_set),
  321. label = paste0(subject,video_set))
  322. df_int_n <- read_csv("Study2_Mean_forEmotion_intensity.csv")%>%
  323. group_by(subject,video_set) %>%
  324. summarise(intensity = mean(intensity, na.rm = TRUE)) %>%
  325. mutate(video_set = as.factor(video_set),
  326. label = paste0(subject,video_set)) %>%
  327. ungroup() %>%
  328. dplyr::select(-c(subject,video_set))
  329. df_norm <- left_join(df_acc_n, df_int_n, by = "label") %>%
  330. dplyr::select(-label) %>%
  331. group_by(video_set) %>%
  332. summarise(norm_acc = mean(accuracy),
  333. norm_int = mean(intensity),
  334. sd_acc = sd(accuracy),
  335. sd_int = sd(intensity))
  336. norm_ADFES <- df_norm$norm_acc[df_norm$video_set == "ADFES"]
  337. norm_JeFEE <- df_norm$norm_acc[df_norm$video_set == "JeFEE"]
  338. norm_ADFES_int <- df_norm$norm_int[df_norm$video_set == "ADFES"]
  339. norm_JeFEE_int <- df_norm$norm_int[df_norm$video_set == "JeFEE"]
  340. ### 2. Subset your data ----
  341. df_acc <- preprocessed_data("Study2_Mean_forEmotion_Accuracy.csv", "accuracy", subject, group, video_set)
  342. df_int <- preprocessed_data("Study2_Mean_forEmotion_intensity.csv", "intensity", subject, group, video_set)%>%
  343. select(intensity, label)
  344. df <- left_join(df_acc, df_int, by = "label") %>%
  345. select(-label)
  346. controls <- df %>% filter(group == "Control")
  347. moebius <- df %>% filter(group == "Moebius")
  348. ### 3. Compute per-subject means for each video_set ----
  349. control_means <- controls %>%
  350. group_by(subject, video_set) %>%
  351. summarise(acc = mean(accuracy),
  352. int = mean(intensity),
  353. .groups = "drop")
  354. moebius_means <- moebius %>%
  355. group_by(subject, video_set) %>%
  356. summarise(acc = mean(accuracy),
  357. int = mean(intensity),
  358. .groups = "drop")
  359. # --- Split by ADFES / JeFEE ---
  360. control_adfes <- control_means %>% filter(video_set == "ADFES") %>% pull(acc)
  361. control_jefee <- control_means %>% filter(video_set == "JeFEE") %>% pull(acc)
  362. moebius_adfes <- moebius_means %>% filter(video_set == "ADFES") %>% pull(acc)
  363. moebius_jefee <- moebius_means %>% filter(video_set == "JeFEE") %>% pull(acc)
  364. control_adfes_int <- control_means %>% filter(video_set == "ADFES") %>% pull(int)
  365. control_jefee_int <- control_means %>% filter(video_set == "JeFEE") %>% pull(int)
  366. moebius_adfes_int <- moebius_means %>% filter(video_set == "ADFES") %>% pull(int)
  367. moebius_jefee_int <- moebius_means %>% filter(video_set == "JeFEE") %>% pull(int)
  368. ### 4. Welch one-sample t-tests vs normative means X---
  369. # ADFES ACCURACY
  370. t_ctrl_adfes <- t.test(control_adfes, mu = norm_ADFES)
  371. d_ctrl_adfes <- cohens_d(control_adfes, mu = norm_ADFES)
  372. bf_ctrl_adfes <- ttestBF(x = control_adfes, mu = norm_ADFES)
  373. t_moeb_adfes <- t.test(moebius_adfes, mu = norm_ADFES)
  374. d_moeb_adfes <- cohens_d(moebius_adfes, mu = norm_ADFES)
  375. bf_moeb_adfes <- ttestBF(x = moebius_adfes, mu = norm_ADFES)
  376. # JeFEE ACCURACY
  377. t_ctrl_jefee <- t.test(control_jefee, mu = norm_JeFEE)
  378. d_ctrl_jefee <- cohens_d(control_jefee, mu = norm_JeFEE)
  379. bf_ctrl_jefee <- ttestBF(x = control_jefee, mu = norm_JeFEE)
  380. t_moeb_jefee <- t.test(moebius_jefee, mu = norm_JeFEE)
  381. d_moeb_jefee <- cohens_d(moebius_jefee, mu = norm_JeFEE)
  382. bf_moeb_jefee <- ttestBF(x = moebius_jefee, mu = norm_JeFEE)
  383. # ADFES INTENSITY
  384. t_ctrl_adfes_int <- t.test(control_adfes_int, mu = norm_ADFES_int)
  385. d_ctrl_adfes_int <- cohens_d(control_adfes_int, mu = norm_ADFES_int)
  386. bf_ctrl_adfes_int <- ttestBF(x = control_adfes_int, mu = norm_ADFES_int)
  387. t_moeb_adfes_int <- t.test(moebius_adfes_int, mu = norm_ADFES_int)
  388. d_moeb_adfes_int <- cohens_d(moebius_adfes_int, mu = norm_ADFES_int)
  389. bf_moeb_adfes_int <- ttestBF(x = moebius_adfes_int, mu = norm_ADFES_int)
  390. # JeFEE INTENSITY
  391. t_ctrl_jefee_int <- t.test(control_jefee_int, mu = norm_JeFEE_int)
  392. d_ctrl_jefee_int <- cohens_d(control_jefee_int, mu = norm_JeFEE_int)
  393. bf_ctrl_jefee_int <- ttestBF(x = control_jefee_int, mu = norm_JeFEE_int)
  394. t_moeb_jefee_int <- t.test(moebius_jefee_int, mu = norm_JeFEE_int)
  395. d_moeb_jefee_int <- cohens_d(moebius_jefee_int, mu = norm_JeFEE_int)
  396. bf_moeb_jefee_int <- ttestBF(x = moebius_jefee_int, mu = norm_JeFEE_int)
  397. ## Mediation Analysis ----
  398. ### 1. Data preparation----
  399. data <- read_csv("data/Study2_Complete_Dataset.csv") %>%
  400. filter(group == "moebius") %>%
  401. dplyr::select(subject, AQ_score, TAS_score, Sunnybrook, acc_ADFES, acc_JeFEE)
  402. ### 2. Total effect models ----
  403. model_adfes <- lm(acc_ADFES ~ Sunnybrook, data = data)
  404. model_jefee <- lm(acc_JeFEE ~ Sunnybrook, data = data)
  405. ### 3. Mediator Models -----
  406. model_tas <- lm(TAS_score ~ Sunnybrook, data = data)
  407. model_aq <- lm(AQ_score ~ Sunnybrook, data = data)
  408. ### 4. Mediation Models -----
  409. #### AQ mediation for ADFES ----
  410. med_model_aq_adfes <- lm(AQ_score ~ Sunnybrook, data = data)
  411. out_model_aq_adfes <- lm(acc_ADFES ~ Sunnybrook + AQ_score, data = data)
  412. mediation_aq_adfes <- mediate(med_model_aq_adfes, out_model_aq_adfes,
  413. treat = "Sunnybrook", mediator = "AQ_score",
  414. boot = TRUE, sims = 1000)
  415. #### AQ mediation for JeFEE ----
  416. med_model_aq_jefee <- lm(AQ_score ~ Sunnybrook, data = data)
  417. out_model_aq_jefee <- lm(acc_JeFEE ~ Sunnybrook + AQ_score, data = data)
  418. mediation_aq_jefee <- mediate(med_model_aq_jefee, out_model_aq_jefee,
  419. treat = "Sunnybrook", mediator = "AQ_score",
  420. boot = TRUE, sims = 1000)
  421. #### TAS mediation for ADFES ----
  422. med_model_tas_adfes <- lm(TAS_score ~ Sunnybrook, data = data)
  423. out_model_tas_adfes <- lm(acc_ADFES ~ Sunnybrook + TAS_score, data = data)
  424. mediation_tas_adfes <- mediate(med_model_tas_adfes, out_model_tas_adfes,
  425. treat = "Sunnybrook", mediator = "TAS_score",
  426. boot = TRUE, sims = 1000)
  427. #### TAS mediation for JeFEE ----
  428. med_model_tas_jefee <- lm(TAS_score ~ Sunnybrook, data = data)
  429. out_model_tas_jefee <- lm(acc_JeFEE ~ Sunnybrook + TAS_score, data = data)
  430. mediation_tas_jefee <- mediate(med_model_tas_jefee, out_model_tas_jefee,
  431. treat = "Sunnybrook", mediator = "TAS_score",
  432. boot = TRUE, sims = 1000)
  433. ### 5. Extract summary stats ----
  434. results <- bind_rows(
  435. extract_med(mediation_tas_adfes, "TAS", "ADFES"),
  436. extract_med(mediation_tas_jefee, "TAS", "JeFEE"),
  437. extract_med(mediation_aq_adfes, "AQ", "ADFES"),
  438. extract_med(mediation_aq_jefee, "AQ", "JeFEE")
  439. )
  440. ### 6. FDR correction
  441. results <- as.data.frame(results) %>%
  442. dplyr::select(
  443. mediator, outcome,
  444. total_effect, total_ci_low, total_ci_high, total_p, total_q,
  445. acme, acme_ci_low, acme_ci_high, acme_p, acme_q
  446. ) %>%
  447. print()
  448. # Extract tidy regression summaries
  449. tas_sum <- tidy(model_tas, conf.int = TRUE)
  450. aq_sum <- tidy(model_aq, conf.int = TRUE)
  451. # Extract only Sunnybrook rows
  452. tas_sunny <- filter(tas_sum, term == "Sunnybrook")
  453. aq_sunny <- filter(aq_sum, term == "Sunnybrook")
  454. # Combine and compute FDR-corrected q-values
  455. mediator_pred <- bind_rows(tas_sunny, aq_sunny) %>%
  456. mutate(mediator = c("TAS", "AQ"),
  457. q = p.adjust(p.value, method = "fdr"))
  458. print(mediator_pred)
  459. # Demography ----
  460. data <- read_csv("data/Study2_Complete_Dataset.csv") %>%
  461. filter(group == "moebius")
  462. ### 1. Inizialyse results matrix ----
  463. results <- tibble::tibble(
  464. variable = character(),
  465. outcome = character(),
  466. stat_type = character(),
  467. stat_value = numeric(),
  468. p_value = numeric(),
  469. bf01 = numeric(),
  470. effect_size = numeric()
  471. )
  472. ### 2. Palsy laterality (monolateral vs bilateral) ----
  473. for (outcome in c("acc_ADFES", "acc_JeFEE")) {
  474. x <- data[[outcome]][data$lateralisation == "monolateral"]
  475. y <- data[[outcome]][data$lateralisation == "bilateral"]
  476. t_res <- t.test(x, y)
  477. d <- cohens_d(x, y)$Cohens_d
  478. bf <- 1 / extractBF(ttestBF(x = x, y = y))$bf
  479. results <- dplyr::bind_rows(results, add_result("palsy_laterality", outcome, t_res, bf, d))
  480. }
  481. ### 3. Age (continuous predictor) ----
  482. for (outcome in c("acc_ADFES", "acc_JeFEE")) {
  483. cor_res <- cor.test(data[[outcome]], data$age, method = "pearson")
  484. bf <- 1 / extractBF(correlationBF(data[[outcome]], data$age))$bf
  485. results <- dplyr::bind_rows(results, add_result("age", outcome, cor_res, bf))
  486. }
  487. ### 4. Education (years) ----
  488. for (outcome in c("acc_ADFES", "acc_JeFEE")) {
  489. cor_res <- cor.test(data[[outcome]], data$y_ed, method = "pearson")
  490. bf <- 1 / extractBF(correlationBF(data[[outcome]], data$y_ed))$bf
  491. results <- dplyr::bind_rows(results, add_result("education", outcome, cor_res, bf))
  492. }
  493. ### 5. Gender (m vs f) ----
  494. for (outcome in c("acc_ADFES", "acc_JeFEE")) {
  495. x <- data[[outcome]][data$gender == "m"]
  496. y <- data[[outcome]][data$gender == "f"]
  497. t_res <- t.test(x, y)
  498. d <- cohens_d(x, y)$Cohens_d
  499. bf <- 1 / extractBF(ttestBF(x = x, y = y))$bf
  500. results <- dplyr::bind_rows(results, add_result("gender", outcome, t_res, bf, d))
  501. }
  502. ### 6. FDR correction ----
  503. results <- results %>%
  504. dplyr::mutate(q_value = p.adjust(p_value, method = "fdr"))
  505. # Correlation and Figure 2 ----
  506. ### 1. Data preparation ----
  507. moebius_data <- read_csv("data/Study2_Complete_Dataset.csv")%>%
  508. filter(group == "moebius") %>%
  509. mutate(acc_ADFES = acc_ADFES*100,
  510. acc_JeFEE = acc_JeFEE*100)
  511. ### 2. ADFES correlation ----
  512. cor_test_adfes <- cor.test(moebius_data$Sunnybrook, moebius_data$acc_ADFES, method = "pearson")
  513. print(cor_test_adfes)
  514. bf_test_adfes <- correlationBF(x = moebius_data$Sunnybrook, y = moebius_data$acc_ADFES)
  515. posterior_samples <- posterior(bf_test_adfes, iterations = 10000)
  516. p_r_greater_0 <- mean(posterior_samples[, "rho"] > 0)
  517. sprintf("P(r > 0) = %.3f", p_r_greater_0)
  518. ### 3. JeFEE correlation ----
  519. cor_test_jefee <- cor.test(moebius_data$Sunnybrook, moebius_data$acc_JeFEE, method = "pearson")
  520. print(cor_test_jefee)
  521. bf_test_jefee <- correlationBF(x = moebius_data$Sunnybrook, y = moebius_data$acc_JeFEE)
  522. posterior_samples <- posterior(bf_test_jefee, iterations = 10000)
  523. p_r_greater_0 <- mean(posterior_samples[, "rho"] > 0)
  524. sprintf("P(r > 0) = %.3f", p_r_greater_0)
  525. ### 4. Extract raw p-values ----
  526. p_values <- c(cor_test_adfes$p.value, cor_test_jefee$p.value)
  527. # Apply BH correction to get q-values
  528. q_values <- p.adjust(p_values, method = "BH")
  529. ### 5. Bootstrap ----
  530. set.seed(123) # for reproducibility
  531. # Bootstrap ADFES
  532. boot_adfes <- boot(data = moebius_data, statistic = cor_fun, R = 10000, x = "Sunnybrook", y = "acc_ADFES")
  533. ci_adfes <- boot.ci(boot_adfes, type = "perc")$percent[4:5]
  534. # Bootstrap JeFEE
  535. boot_jefee <- boot(data = moebius_data, statistic = cor_fun, R = 10000, x = "Sunnybrook", y = "acc_JeFEE")
  536. ci_jefee <- boot.ci(boot_jefee, type = "perc")$percent[4:5]
  537. # Prepare data frame
  538. df_boot <- data.frame(
  539. r = c(boot_adfes$t, boot_jefee$t),
  540. test = rep(c("ADFES", "JeFEE"), each = length(boot_adfes$t))
  541. )
  542. # Define colors
  543. color_map <- c("ADFES" = "#3271AD", "JeFEE" = "#C56637") # blue and violet
  544. # update data from R script
  545. r_JeFEE <- round(cor_test_jefee$estimate,2)
  546. r_ADFES <- round(cor_test_adfes$estimate,2)
  547. CI_JeFEE <- c(0.28, 0.81)
  548. CI_ADFES <- c(0.39, 0.8)
  549. ### 6. Plots Figure 2 ----
  550. p1 <- ggplot(moebius_data, aes(x = Sunnybrook, y = acc_ADFES)) +
  551. geom_point(color = "#3271AD") +
  552. geom_smooth(method = "lm", color = "#3271AD", fill = "#3271AD", alpha = 0.3) +
  553. labs(title = " ", x = "SFGS Score", y = "ADFES Accuracy (x)") +
  554. theme_minimal() +
  555. coord_cartesian(ylim = c(0, 100))+
  556. theme_minimal(base_size = 14) +
  557. theme(legend.position = "none",
  558. text = element_text(size = 10,
  559. family = "Helvetica"), # use Helvetica, size 16 for all text
  560. panel.background = element_blank(), # clean white background
  561. axis.line = element_line(colour = "black"), # black axis lines
  562. strip.text.x = element_text(size = 6.6), # facet labels (x): size 20
  563. strip.text.y = element_text(size = 6.6),
  564. panel.grid.major = element_blank(), # Rimuove le griglie principali
  565. panel.grid.minor = element_blank())
  566. p2 <- ggplot(moebius_data, aes(x = Sunnybrook, y = acc_JeFEE)) +
  567. geom_point(color = "#C56637") +
  568. geom_smooth(method = "lm", color = "#C56637", fill = "#C56637", alpha = 0.3) +
  569. labs(title = "", x = "SFGS Score", y = "JeFEE Accuracy (%)") +
  570. theme_minimal() +
  571. coord_cartesian(ylim = c(0, 100))+
  572. theme_minimal(base_size = 14) +
  573. theme(legend.position = "none",
  574. text = element_text(size = 10,
  575. family = "Helvetica"), # use Helvetica, size 16 for all text
  576. panel.background = element_blank(), # clean white background
  577. axis.line = element_line(colour = "black"), # black axis lines
  578. strip.text.x = element_text(size = 6.6), # facet labels (x): size 20
  579. strip.text.y = element_text(size = 6.6),
  580. panel.grid.major = element_blank(), # Rimuove le griglie principali
  581. panel.grid.minor = element_blank())
  582. p3 <- ggplot(df_boot, aes(x = r, fill = test)) +
  583. geom_density(alpha = 0.4) +
  584. geom_vline(xintercept = r_ADFES, color = "#3271AD", linetype = "solid", linewidth = 1) +
  585. geom_vline(xintercept = CI_ADFES, color = "#3271AD", linetype = "dashed", linewidth = 0.8) +
  586. geom_vline(xintercept = r_JeFEE, color = "#C56637", linetype = "solid", linewidth = 1) +
  587. geom_vline(xintercept = CI_JeFEE, color = "#C56637", linetype = "dashed", linewidth = 0.8) +
  588. scale_fill_manual(values = color_map) +
  589. labs(
  590. title = "",
  591. x = "Bootstrapped Correlation Coefficient (r)",
  592. y = "Density",
  593. fill = "Test"
  594. ) +
  595. theme_minimal() +
  596. theme(plot.title = element_text(hjust = 0.5))+
  597. theme_minimal(base_size = 14) +
  598. theme(legend.position = "none",
  599. text = element_text(size = 10,
  600. family = "Helvetica"), # use Helvetica, size 16 for all text
  601. panel.background = element_blank(), # clean white background
  602. axis.line = element_line(colour = "black"), # black axis lines
  603. strip.text.x = element_text(size = 6.6), # facet labels (x): size 20
  604. strip.text.y = element_text(size = 6.6),
  605. panel.grid.major = element_blank(), # Rimuove le griglie principali
  606. panel.grid.minor = element_blank()) +
  607. annotate("text", x = 0, y = 3,
  608. label = paste0("ADFES statistics:\nMean r = ",r_ADFES,"\n 95% CI: [",CI_ADFES[1],", 0.80]\nP(r > 0) = 0.987"), color = "#3271AD", size = 3) +
  609. annotate("text", x = 0, y = 1.2,
  610. label = paste0("JeFEE statistics:\nMean r = ",r_JeFEE,"\n 95% CI: [",CI_JeFEE[1],", 0.81]\nP(r > 0) = 0.972"), color = "#C56637", size = 3)
  611. # Plots
  612. row1 <- cowplot::plot_grid(p1, p2, labels = c("A", "B"))
  613. # Then: combine row1 with p3
  614. p4 <- cowplot::plot_grid(row1, p3, nrow = 2, labels = c("", "C"))
  615. # Export
  616. ggsave("figures/Fig_2_finale.png", # export for draft
  617. plot = p4,
  618. device = "png",
  619. dpi = 300,
  620. width = 18,
  621. height = 14,
  622. units = "cm")
  623. ggsave("figures/Fig_2.tiff", # export for journal
  624. plot = p4,
  625. device = "tiff",
  626. dpi = 1200,
  627. width = 18,
  628. height = 14,
  629. units = "cm")
  630. ### 7. R2_cv LOO ----
  631. # 1 Load data and keep Moebius participants
  632. dat <- moebius_data %>%
  633. dplyr::select(Sunnybrook,
  634. acc_ADFES,
  635. acc_JeFEE) %>%
  636. drop_na()
  637. set.seed(1)
  638. # 2 Pearson r with BCa 95 % CI (10 000 resamples)
  639. corr_tbl <- bind_rows(
  640. get_bca("acc_JeFEE"),
  641. get_bca("acc_ADFES")
  642. ) %>% mutate(q = p.adjust(p, method = "BH"))
  643. print(corr_tbl)
  644. # 3 Leave-one-out cross-validated R² with percentile CI
  645. loo_tbl <- bind_rows(
  646. calc_loo("acc_JeFEE"),
  647. calc_loo("acc_ADFES")
  648. )
  649. print(loo_tbl)
  650. # 4 Model projections
  651. grid <- tibble(Sunnybrook = c(20, 80))
  652. pred_tbl <- bind_rows(
  653. get_pred("acc_JeFEE"),
  654. get_pred("acc_ADFES")
  655. )
  656. print(pred_tbl)
  657. # OFMT correlation ----
  658. ### 1. Data preparation ----
  659. df_tot <- read_csv("data/Study2_Complete_Dataset.csv") %>%
  660. dplyr::select(subject, group, Sunnybrook,ofmt ) %>%
  661. mutate(match = parse_number(subject))
  662. df <- df_tot %>%
  663. filter(group == "moebius")
  664. ### 2. Correlation ----
  665. cor_test_Sunny <- cor.test(df$Sunnybrook, df$ofmt, method = "pearson")
  666. print(cor_test_Sunny)
  667. bf_test_Sunny <- correlationBF(x = df$Sunnybrook, y = df$ofmt, paired = TRUE)
  668. ### 3. Group difference ----
  669. anova <- aov_ez(id = "subject", dv = "ofmt", between = "group",data = df_tot)
  670. summary(anova)
  671. ### 4. Plot Figure 3 ----
  672. # Panel A: Scatterplot (no correlation)
  673. pA <- ggplot(df, aes(x = Sunnybrook, y = ofmt)) +
  674. geom_point(fill = "#F0E442", color = "gray" , shape = 21 ) +
  675. geom_smooth(method = "lm", se = TRUE, color = "#D1C436", fill = "#FAF6C2", alpha = 0.3) +
  676. labs(
  677. x = "Sunnybrook Score (Facial Motor Function)",
  678. y = "OFMT Accuracy (%)"
  679. ) +
  680. theme_minimal() +
  681. theme(plot.title = element_text(hjust = 0.5))+
  682. theme_minimal(base_size = 14) +
  683. theme(legend.position = "none",
  684. text = element_text(size = 10,
  685. family = "Helvetica"), # use Helvetica, size 16 for all text
  686. panel.background = element_blank(), # clean white background
  687. axis.line = element_line(colour = "black"), # black axis lines
  688. strip.text.x = element_text(size = 6.6), # facet labels (x): size 20
  689. strip.text.y = element_text(size = 6.6),
  690. panel.grid.major = element_blank(), # Rimuove le griglie principali
  691. panel.grid.minor = element_blank())
  692. # Colori per le condizioni
  693. colors <- c("moebius" = "#F0E442", "control" = "purple")
  694. descritive <- df_tot %>%
  695. filter(group %in% c("moebius", "control")) %>%
  696. group_by( group) %>%
  697. summarise(mean_acc = mean(ofmt, na.rm = TRUE),
  698. sd_acc = sd(ofmt, na.rm = TRUE),
  699. se = sd_acc / sqrt(n()),
  700. .groups = "drop") %>%
  701. mutate(x_pos = case_when(
  702. group == "moebius" ~ 2 - 0.1,
  703. group == "control" ~ 1 + 0.1,
  704. ))
  705. # Panel B: Group boxplot
  706. pB <- ggplot(df_tot,
  707. aes(x = group, y = ofmt, fill = group)) +
  708. geom_rain(alpha = 0.5, rain.side = 'f1x1', id.long.var = "match") +
  709. geom_point(data = descritive,
  710. aes(x = x_pos, y = mean_acc),
  711. color = "black",
  712. size = 2.5, shape = 18, inherit.aes = FALSE) +
  713. geom_errorbar(data = descritive,
  714. aes(x = x_pos, ymin = mean_acc - se, ymax = mean_acc + se),
  715. width = 0, color = "black", linewidth = 0.5, inherit.aes = FALSE) +
  716. scale_fill_manual(values = colors) +
  717. labs(
  718. x = "",
  719. y = "OFMT Accuracy (%)"
  720. ) + theme_minimal(base_size = 14) +
  721. theme(legend.position = "none",
  722. text = element_text(size = 10,
  723. family = "Helvetica"), # use Helvetica, size 16 for all text
  724. panel.background = element_blank(), # clean white background
  725. axis.line = element_line(colour = "black"), # black axis lines
  726. strip.text.x = element_text(size = 6.6), # facet labels (x): size 20
  727. strip.text.y = element_text(size = 6.6),
  728. panel.grid.major = element_blank(), # Rimuove le griglie principali
  729. panel.grid.minor = element_blank())+
  730. geom_text(data = descritive, aes(x = group, y = 0.62,
  731. label = paste0("M = ", round(mean_acc, 3),
  732. "\nSD = ", round(sd_acc, 3),"\n")),
  733. color = "black", size = 2.5)
  734. # Combine both panels
  735. figure3 <- cowplot::plot_grid(pA, pB, labels = "AUTO", nrow = 1)
  736. ggsave("figures/Fig_3_finale.png", # export for draft
  737. plot = figure3,
  738. device = "png",
  739. dpi = 300,
  740. width = 18,
  741. height = 9,
  742. units = "cm")
  743. ggsave("figures/Fig_3.tiff", # export for draft
  744. plot = figure3,
  745. device = "tiff",
  746. dpi = 1200,
  747. width = 18,
  748. height = 9,
  749. units = "cm")
  750. ## END ----

Study2_Confirmatory_Analyses_and_Plot.R, no license · at the source

Overview

Authors: Paola Sessa1,2, Arianna Schiano Lomoriello1,2, Thomas Quettier1,2, Antonio Maffei1,2, Sara Costa3, Marta Nichele4, Pier Francesco Ferrari3,5
  1. Department of Developmental Psychology and Socialisation, University of Padova, Padova 35131, Italy
  2. Padova Neuroscience Center, Department of Developmental Psychology and Socialisation, University of Padova, Padova 35129, Italy
  3. Department of Medicine and Surgery, University of Parma, Parma 43126, Italy
  4. Independent Physiotherapist, Padova 35143, Italy
  5. Social Neuroscience and Comparative Development, Social Neuroscience and Comparative Development, Institut des Sciences Cognitives Marc Jeannerod, CNRS/Université Claude Bernard Lyon 1, Bron Cedex 69675, France
Dates: received 12 March 2026; accepted 21 July 2026; published online 11 September 2026; in print 15 September 2026
Type: Research article · Language: English
License: CC BY
Identifiers: DOI 10.1073/pnas.2608511123 · PMID 42726659 · PMCID PMC13578938 · OpenAlex W7212220682
Open access: hybrid, a free copy (OpenAlex)
Status: code verified
Categories: EEG (modality), human (organism)
Methods: Statistics, Machine learning, Connectivity, Spectral & time-frequency
Keywords: embodied cognition, facial paralysis, emotion recognition, sensorimotor calibration, Moebius syndrome
MeSH: Emotions*, Facial Expression*, Facial Paralysis*, Adult, Electroencephalography, Female, Humans, Male, Mobius Syndrome, Young Adult (* major topic)
Topic: Face Recognition and Perception (Cognitive Neuroscience, Neuroscience), according to OpenAlex
Funding: Fondazione Cassa di Risparmio di Padova e Rovigo (Foundation Cariparo) ("Ricerca Scientifica di Eccellenza" grant (2021))
Citations: cited by 1 paper (Europe PMC); 43 references in the paper

Abstract

Although recognizing emotions from facial expressions appears effortless, the field is divided between vision-based accounts, which posit matching to learned visual templates, and embodied accounts, which posit recruitment of facial motor circuits. We propose an ambiguity-gated, developmentally calibrated architecture in which the recognition system draws on sensorimotor information primarily when visual evidence is insufficient, with early motor experience proposed to shape the threshold and gain of this contribution. We tested this model across three studies (N = 185) integrating dynamic prototypical and nonprototypical expressions, congenital (Moebius syndrome) and acquired facial palsy, and standardized severity grading (Sunnybrook Facial Grading System; SFGS). Neurotypical adults (N = 117) confirmed a robust prototypicality-dependent cost on recognition. Both congenital (N = 15) and acquired (N = 19) cohorts showed severity–performance coupling for nonprototypical expressions, consistent with shared reliance on sensorimotor information when visual evidence is insufficient; only the Moebius cohort showed this coupling also for prototypical expressions, consistent with undercalibrated visual templates following lifelong atypical facial motor experience. Exploratory electroencephalography (EEG) revealed reduced sensorimotor–face-network functional connectivity in Moebius, consistent with altered cross-route integration. Reanalysis of an independent dataset of ultra-ambiguous static morphs replicated severity–performance coupling and revealed Moebius–control mean differences only under high perceptual demand. Together, the findings provide strong behavioral support for an ambiguity-gated, developmentally calibrated architecture and motivate direct tests of how developmental motor experience shapes when—and how strongly—the recognition system draws on sensorimotor information.

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

OSF 3yux4

License: none: the authors keep all their rights
State: the link answers, verified on 26 September 2026
Evidence: files inventoried
Languages: R (4)
Size: 21 files, 4 scripts
Software Heritage: not checked
Found in: the references
Not found: README, license file, CITATION.cff, environment file, tests, continuous integration, documentation
Tools: easystats (4 files), tidyverse (4 files), BayesFactor (3 files), afex (2 files), brms (2 files), broom (2 files), cowplot (2 files), emmeans (2 files), ggplot2 (2 files)
Availability: 1 check, the latest on 26 September 2026: the link answers (HTTP 200)
  • 26 September 2026: the link answers (HTTP 200)
4 files
At the source: osf.io/3yux4/

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;
  • 4 scripts, each with its path and the digest of its content;
  • 2 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, Materials, and Software Availability

Behavioral datasets, EEG data, R analysis scripts, and experimental protocols have been deposited in the Open Science Framework (OSF) (43) [Facial palsy reveals the sensorimotor contribution to facial-emotion recognition].

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

Recorded: type, language, journal, volume, issue, pages, dates, 7 authors, 5 keywords, 10 MeSH terms, 1 funder, 32 references.

Cite

This paper

Sessa, P., Schiano Lomoriello, A., Quettier, T., Maffei, A., Costa, S., Nichele, M., & Ferrari, P. F. (2026). Facial palsy reveals the sensorimotor contribution to facial-emotion recognition. Proceedings of the National Academy of Sciences of the United States of America, 123(37), e2608511123. https://doi.org/10.1073/pnas.2608511123

BibTeX

@article{sessa2026facial,
author = {Sessa, Paola and Schiano Lomoriello, Arianna and Quettier, Thomas and Maffei, Antonio and Costa, Sara and Nichele, Marta and Ferrari, Pier Francesco},
title = {{Facial palsy reveals the sensorimotor contribution to facial-emotion recognition}},
journal = {Proceedings of the National Academy of Sciences of the United States of America},
year = {2026},
month = sep,
volume = {123},
number = {37},
pages = {e2608511123},
publisher = {National Academy of Sciences},
issn = {0027-8424},
doi = {10.1073/pnas.2608511123},
url = {https://doi.org/10.1073/pnas.2608511123},
pmid = {42726659},
pmcid = {PMC13578938}
}

RIS

TY - JOUR
AU - Sessa, Paola
AU - Schiano Lomoriello, Arianna
AU - Quettier, Thomas
AU - Maffei, Antonio
AU - Costa, Sara
AU - Nichele, Marta
AU - Ferrari, Pier Francesco
TI - Facial palsy reveals the sensorimotor contribution to facial-emotion recognition
T2 - Proceedings of the National Academy of Sciences of the United States of America
J2 - Proc Natl Acad Sci U S A
PY - 2026
DA - 2026/09/11
VL - 123
IS - 37
SP - e2608511123
SN - 0027-8424
PB - National Academy of Sciences
DO - 10.1073/pnas.2608511123
UR - https://doi.org/10.1073/pnas.2608511123
LA - en
ER -

CSL-JSON

{
"id": "10.1073/pnas.2608511123",
"type": "article-journal",
"title": "Facial palsy reveals the sensorimotor contribution to facial-emotion recognition",
"container-title": "Proceedings of the National Academy of Sciences of the United States of America",
"author": [
{
"family": "Sessa",
"given": "Paola"
},
{
"family": "Schiano Lomoriello",
"given": "Arianna"
},
{
"family": "Quettier",
"given": "Thomas"
},
{
"family": "Maffei",
"given": "Antonio"
},
{
"family": "Costa",
"given": "Sara"
},
{
"family": "Nichele",
"given": "Marta"
},
{
"family": "Ferrari",
"given": "Pier Francesco"
}
],
"container-title-short": "Proc Natl Acad Sci U S A",
"volume": "123",
"issue": "37",
"page": "e2608511123",
"DOI": "10.1073/pnas.2608511123",
"PMID": "42726659",
"PMCID": "PMC13578938",
"ISSN": "0027-8424",
"publisher": "National Academy of Sciences",
"URL": "https://doi.org/10.1073/pnas.2608511123",
"language": "en",
"issued": {
"date-parts": [
[
2026,
9,
11
]
]
}
}

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.1162/imag.a.1258 [code]
Non-specific increase in alpha power during a neurofeedback session targeting its downregulation.
Journal: Imaging neuroscience (Cambridge, Mass.)
In common: BayesFactor, afex, brms, 5 other tools, EEG
[2] doi:10.1038/s41467-026-73865-9 [code]
Histamine shapes the neurocomputational dynamics of human learning.
Journal: Nature communications
In common: BayesFactor, brms, easystats, 5 other tools
[3] doi:10.1093/nc/niag029 [code]
A data-driven approach to identifying and evaluating connectivity-based neural correlates of conscious visual perception.
Journal: Neuroscience of consciousness
In common: BayesFactor, afex, easystats, 5 other tools
[4] doi:10.1162/opmi.a.358 [code]
Tracking Visual Statistical Learning with Steady-State Visual Evoked Potentials: Effects of Exemplar and Category Information.
Journal: Open mind : discoveries in cognitive science
In common: BayesFactor, afex, brms, 4 other tools, EEG
[5] doi:10.1038/s41467-026-74565-0 [code]
The functional neurobiology of dispositions towards negative emotions.
Journal: Nature communications
In common: BayesFactor, afex, brms, 4 other tools
[6] 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: BayesFactor, brms, easystats, 4 other tools
[7] doi:10.1016/j.isci.2026.116747 [code]
Age and loneliness relate to reduced trust learning and alterations in amygdala function.
Journal: iScience
In common: brms, easystats, broom, 4 other tools
[8] doi:10.1038/s41597-026-07350-9 [code]
An open multi-center MEG-EEG dataset for studying conscious visual perception.
Journal: Scientific data
In common: BayesFactor, afex, easystats, 3 other tools, EEG
[9] doi:10.1038/s42003-026-10229-5 [code]
The neurocomputational mechanisms underlying the impact of social comparison on effort investment.
Journal: Communications biology
In common: afex, brms, easystats, 3 other tools, EEG
[10] doi:10.1523/eneuro.0076-26.2026 [code]
Exogenously Driven Neural Reactivation of Spatially Matching Visual Working-Memory Contents.
Journal: eNeuro
In common: BayesFactor, brms, emmeans, 3 other tools, EEG

Contribute

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

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

Request its removal

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

Discussion, reproductions, activity

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

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

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