Changes in Aperiodic (1/f Slope) Activity During a Picture-Word Interference Task: Effects of Congruency and Sequence Manipulations.
The 2 matches
- [1] § Method › Cluster‐Based Permutation Analyses (FWER‐Corrected) ↔ code_afterR1.Rmd, lines 1193–1254 · score 0.57 · sign flip, cluster statistic, FWER, permutation
- [2] § Method › Exploratory Analyses (No Correction for Multiple Comparisons) ↔ code_afterR1.Rmd, lines 1193–1254 · score 0.56 · global stimulus induced, Baseline correction, threshold, post, interactions
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 Markdown · 1,689 lines · 61 KB · no license · 2 matches
- ---
- title: "Code to reproduce the spectral slope analyses from the project (section 3.2.3)."
- output: html_document
- date: "2024-04-04"
- ---
- Load libraries
- ```{r setup, include=FALSE}
- knitr::opts_chunk$set(echo = TRUE)
- setwd("C:/Users/patry/Documents/Paranauka/Projekty/Illinois/virginia/r1/")
- rm(list = ls())
- options(scipen = 999)
- library(plyr)
- library(tidyverse)
- library(psych)
- library(stringr)
- library(data.table)
- library(readxl)
- library(eegUtils)
- # Time intervals
- time_intervals <- c(-160, 0, 160, 320, 480, 640, 800, 960, 1120, 1280)
- # Define the correct order of the levels
- time_chunk_levels <- c("[-160,0]", "(0,160]", "(160,320]", "(320,480]", "(480,640]", "(640,800]", "(800,960]", "(960,1120]", "(1120,1280]")
- # Shading for plots
- shading_data <- data.frame(
- xmin = time_intervals[-length(time_intervals)], # All but the last element
- xmax = time_intervals[-1], # All but the first element
- ymin = -Inf, # Extend shading to the bottom
- ymax = Inf, # Extend shading to the top
- brightness = c(0.0, 0.6,0.1, 0.6,0.1, 0.6,0.1, 0.6,0.1) # Different brightness values
- )
- ```
- Raw data vizualization
- ```{r}
- load("data_raw.RData")
- # Collapse across non-focal dimensions (mean within cells)
- reg_pcongr2 = data.table::dcast(setDT(reg), ID + channel + time + PrevCongr + Congr ~ ., value.var = c("value"), mean, na.rm = TRUE)
- setnames(reg_pcongr2, old = ".", new = "value")
- # Harmonize factors & keep only levels of interest
- reg_pcongr2$Congr <- factor(reg_pcongr2$Congr, levels = c("Con", "Inc"))
- reg_pcongr2$PrevCongr <- factor(reg_pcongr2$PrevCongr, levels = c("pCon", "pInc"))
- reg_pcongr3 = reg_pcongr2[reg_pcongr2$channel %in% c("Fz", "Cz", "Pz", "Oz")]
- reg_pcongr3$channel <- factor(reg_pcongr3$channel, levels = c("Fz", "Cz", "Pz", "Oz"))
- # Define ROIs
- reg_pcongr2 <- reg_pcongr2 %>%
- mutate(
- ROI = case_when(
- channel %in% c("F1","F2","Fz") ~ "Frontal",
- channel %in% c("FC1","FC2","FCz") ~ "Fronto-Central",
- channel %in% c("C1","C2","Cz") ~ "Central",
- channel %in% c("CP1","CP2","CPz") ~ "Centro-Parietal",
- channel %in% c("P1","P2","Pz") ~ "Parietal",
- channel %in% c("O1","O2","Oz") ~ "Occipital",
- TRUE ~ NA_character_ # for any channels not listed
- )
- )
- reg_pcongr4 <- reg_pcongr2 %>%
- group_by(ID, time, PrevCongr, Congr, ROI) %>%
- summarise(value = mean(value, na.rm = TRUE)) %>%
- ungroup()
- reg_pcongr4$ROI <- factor(reg_pcongr4$ROI, levels = c("Frontal", "Fronto-Central", "Central", "Centro-Parietal", "Parietal", "Occipital"))
- reg_pcongr4 = na.omit(reg_pcongr4)
- ### Plot (midline electrodes)
- ggplot(reg_pcongr3, aes(x = time, y = value, color = Congr, linetype = PrevCongr)) +
- facet_wrap(channel ~ ., ncol = 1) +
- # Mean lines only
- stat_summary(fun = "mean", geom = "line", size = .2) +
- # Manual color: Con = blue, Inc = red
- scale_color_manual(values = c("Con" = "blue", "Inc" = "red")) +
- # Theme and layout
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "top"
- ) +
- # Reference lines
- #geom_hline(yintercept = 0, linetype = "dashed") +
- geom_vline(xintercept = 0, linetype = "dashed") +
- #geom_vline(xintercept = 500, linetype = "dashed", color = "blue") +
- # Axes and labels
- coord_cartesian(ylim = c(-1.5,-.5)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Values [a.u.]"),
- color = "Congruency", # Current trial
- linetype = "Previous Congr." # Previous trial
- ) +
- ggtitle("")
- # ggsave(file.path(folder_name, "raw_overview.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "raw_overview.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- ### Plot (electrode averages)
- ggplot(reg_pcongr4[reg_pcongr4$ROI %in% c("Frontal", "Central", "Occipital"),], aes(x = time, y = value, color = Congr, linetype = PrevCongr)) +
- facet_wrap(ROI ~ ., ncol = 1) +
- # Mean lines only
- stat_summary(fun = "mean", geom = "line", size = .2) +
- # Manual color: Con = blue, Inc = red
- scale_color_manual(values = c("Con" = "blue", "Inc" = "red")) +
- # Theme and layout
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "top"
- ) +
- # Reference lines
- #geom_hline(yintercept = 0, linetype = "dashed") +
- geom_vline(xintercept = 0, linetype = "dashed") +
- #geom_vline(xintercept = 500, linetype = "dashed", color = "blue") +
- # Axes and labels
- coord_cartesian(ylim = c(-1.5,-.5)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Values [a.u.]"),
- color = "Congruency", # Current trial
- linetype = "Previous Congr." # Previous trial
- ) +
- ggtitle("")
- # ggsave(file.path(folder_name, "raw_overview_av.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "raw_overview_av.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- rm(reg, reg_pcongr2, reg_pcongr3, reg_pcongr4)
- ```
- Create data sets and rename conditions
- ```{r}
- load("data_Pca.RData")
- reg <- scores
- #Rename and collapse across conditions
- # Create a named vector for bin labels
- bin_labels <- c(
- "Novel-RSI1000-Changed-pCon-Con",
- "Novel-RSI1000-Changed-pCon-Inc",
- "Novel-RSI1000-Changed-pInc-Con",
- "Novel-RSI1000-Changed-pInc-Inc",
- "Novel-RSI1000-Repeated-pCon-Con",
- "Novel-RSI1000-Repeated-pCon-Inc",
- "Novel-RSI1000-Repeated-pInc-Con",
- "Novel-RSI1000-Repeated-pInc-Inc",
- "Novel-RSI2000-Changed-pCon-Con",
- "Novel-RSI2000-Changed-pCon-Inc",
- "Novel-RSI2000-Changed-pInc-Con",
- "Novel-RSI2000-Changed-pInc-Inc",
- "Novel-RSI2000-Repeated-pCon-Con",
- "Novel-RSI2000-Repeated-pCon-Inc",
- "Novel-RSI2000-Repeated-pInc-Con",
- "Novel-RSI2000-Repeated-pInc-Inc",
- "Novel-RSI3000-Changed-pCon-Con",
- "Novel-RSI3000-Changed-pCon-Inc",
- "Novel-RSI3000-Changed-pInc-Con",
- "Novel-RSI3000-Changed-pInc-Inc",
- "Novel-RSI3000-Repeated-pCon-Con",
- "Novel-RSI3000-Repeated-pCon-Inc",
- "Novel-RSI3000-Repeated-pInc-Con",
- "Novel-RSI3000-Repeated-pInc-Inc",
- "Novel-RSI5000-Changed-pCon-Con",
- "Novel-RSI5000-Changed-pCon-Inc",
- "Novel-RSI5000-Changed-pInc-Con",
- "Novel-RSI5000-Changed-pInc-Inc",
- "Novel-RSI5000-Repeated-pCon-Con",
- "Novel-RSI5000-Repeated-pCon-Inc",
- "Novel-RSI5000-Repeated-pInc-Con",
- "Novel-RSI5000-Repeated-pInc-Inc",
- "Frequent-RSI1000-Changed-pCon-Con",
- "Frequent-RSI1000-Changed-pCon-Inc",
- "Frequent-RSI1000-Changed-pInc-Con",
- "Frequent-RSI1000-Changed-pInc-Inc",
- "Frequent-RSI1000-Repeated-pCon-Con",
- "Frequent-RSI1000-Repeated-pCon-Inc",
- "Frequent-RSI1000-Repeated-pInc-Con",
- "Frequent-RSI1000-Repeated-pInc-Inc",
- "Frequent-RSI2000-Changed-pCon-Con",
- "Frequent-RSI2000-Changed-pCon-Inc",
- "Frequent-RSI2000-Changed-pInc-Con",
- "Frequent-RSI2000-Changed-pInc-Inc",
- "Frequent-RSI2000-Repeated-pCon-Con",
- "Frequent-RSI2000-Repeated-pCon-Inc",
- "Frequent-RSI2000-Repeated-pInc-Con",
- "Frequent-RSI2000-Repeated-pInc-Inc",
- "Frequent-RSI3000-Changed-pCon-Con",
- "Frequent-RSI3000-Changed-pCon-Inc",
- "Frequent-RSI3000-Changed-pInc-Con",
- "Frequent-RSI3000-Changed-pInc-Inc",
- "Frequent-RSI3000-Repeated-pCon-Con",
- "Frequent-RSI3000-Repeated-pCon-Inc",
- "Frequent-RSI3000-Repeated-pInc-Con",
- "Frequent-RSI3000-Repeated-pInc-Inc",
- "Frequent-RSI5000-Changed-pCon-Con",
- "Frequent-RSI5000-Changed-pCon-Inc",
- "Frequent-RSI5000-Changed-pInc-Con",
- "Frequent-RSI5000-Changed-pInc-Inc",
- "Frequent-RSI5000-Repeated-pCon-Con",
- "Frequent-RSI5000-Repeated-pCon-Inc",
- "Frequent-RSI5000-Repeated-pInc-Con",
- "Frequent-RSI5000-Repeated-pInc-Inc"
- )
- names(bin_labels) <- as.character(1:64)
- # First, ensure the Bin column is numeric for matching
- reg$Bin <- as.numeric(as.character(reg$Bin))
- # Now, replace the numeric Bins with their corresponding labels
- reg$BinLabel <- bin_labels[as.character(reg$Bin)]
- # Separate the 'BinLabel' column into new columns
- reg <- separate(reg, col = BinLabel, into = c("StimulusRep", "RSI", "CategoryRep", "PrevCongr", "Congr"), sep = "-")
- #Reorder columns
- reg <- reg[,c("ID", "time", "Bin", "StimulusRep", "CategoryRep", "RSI", "PrevCongr", "Congr", "MR1", "MR2", "MR3", "MR4", "MR5")]
- #Narrow down the time window for analyses
- reg <- reg[reg$time %in% c(-160:1280),]
- #To the long format
- reg <- melt(reg, id.vars = c("ID", "time", "Bin", "StimulusRep", "CategoryRep", "RSI", "PrevCongr", "Congr"))
- #Factor order
- rotFit$variance_explained_percent
- unique(reg$variable)
- # Get the factor names ordered by variance explained
- ordered_factors <- names(sort(rotFit$variance_explained_percent, decreasing = TRUE))
- # Reorder reg$variable based on the ordered factors
- reg$variable <- factor(reg$variable, levels = ordered_factors)
- # Verify the order
- levels(reg$variable)
- # Rename levels of reg$variable
- levels(reg$variable) <- c("OCCIPITAL (MR3)", "FRONTAL (MR2)", "CENTRAL (MR1)", "TEMPORAL L (MR5)", "TEMPORAL R (MR4)")
- #Exclude factors with too small variance
- reg <- reg[!reg$variable %in% c("TEMPORAL L (MR5)", "TEMPORAL R (MR4)"),]
- reg <- droplevels(reg)
- # Reorder factor levels
- reg$variable <- factor(reg$variable, levels = c("FRONTAL (MR2)", "CENTRAL (MR1)", "OCCIPITAL (MR3)"))
- # Verify the new order
- levels(reg$variable)
- # Drop the last two elements
- variance_explained <- rotFit$variance_explained[1:3]
- # Rename the variables
- names(variance_explained) <- c("CENTRAL", "FRONTAL", "OCCIPITAL")
- # Reorder them: frontal, central, occipital
- variance_explained <- variance_explained[c("FRONTAL", "CENTRAL", "OCCIPITAL")]
- # Format the reordered variance explained as a text string for the caption
- caption_text <- paste(
- "Variance Explained:",
- paste(names(variance_explained), sprintf("%.2f%%", variance_explained), collapse = ", ")
- )
- ```
- Info for stats & plots
- ```{r}
- reg$value_to_stats = reg$value
- ```
- Global Changes in Spectral Slope Across Time Windows and Scalp Regions
- ```{r}
- ### Average across bins
- reg_av = data.table::dcast(setDT(reg), ID + time + variable ~ ., value.var = c("value_to_stats"), mean, na.rm = TRUE)
- setnames(reg_av, old = ".", new = "value")
- reg_av$time_chunk <- cut(reg_av$time, breaks = time_intervals, include.lowest = TRUE, ordered_result = TRUE, dig.lab = 5)
- reg_av$time_chunk <- factor(reg_av$time_chunk, levels = time_chunk_levels, ordered = FALSE)
- ### Statistics
- dat = reg_av
- dat = dat[complete.cases(dat$time_chunk)]
- dat <- setDT(dcast(dat, ID + variable + time_chunk ~ ., mean, value.var = c("value"), na.rm = TRUE))
- dat = data.table(droplevels(dat))
- dat = dat[complete.cases(dat$time_chunk)]
- # Create an empty data.table to store the t-test results
- pvals <- data.table(
- variable = character(), time_chunk = character(),
- t.value = numeric(), p.value = numeric(), cohen_d = numeric()
- )
- # Get unique levels
- unique_time <- unique(dat$time_chunk)
- unique_var <- unique(dat$variable)
- for (tpnt in unique_time) {
- for (var in unique_var) {
- subset_data <- dat[variable == var & time_chunk %in% c(tpnt, "[-160,0]")]
- # Get paired data
- baseline <- subset_data[time_chunk == "[-160,0]"][order(ID)]$.
- tp_data <- subset_data[time_chunk == tpnt][order(ID)]$.
- # Ensure same IDs are used for pairing
- common_ids <- intersect(
- subset_data[time_chunk == "[-160,0]"]$ID,
- subset_data[time_chunk == tpnt]$ID
- )
- baseline <- subset_data[time_chunk == "[-160,0]" & ID %in% common_ids][order(ID)]$.
- tp_data <- subset_data[time_chunk == tpnt & ID %in% common_ids][order(ID)]$.
- # Paired t-test
- t_test_result <- t.test(tp_data, baseline,
- alternative = "two.sided", paired = TRUE, conf.level = 0.95)
- # Cohen's d for paired samples
- diff_scores <- tp_data - baseline
- cohen_d <- mean(diff_scores) / sd(diff_scores)
- # Append results
- pvals <- rbind(
- pvals,
- data.table(
- variable = var, time_chunk = tpnt,
- t.value = t_test_result$statistic,
- p.value = t_test_result$p.value,
- cohen_d = cohen_d
- )
- )
- }
- }
- # Significance flags
- pvals$crit1 <- ifelse(pvals$p.value <= .05, 1, NA)
- pvals$crit2 <- ifelse(pvals$p.value <= .01, 1, NA)
- # Convert time_chunk to a factor with the specified levels
- pvals$time_chunk <- factor(pvals$time_chunk, levels = time_chunk_levels)
- pvals$variable <- factor(pvals$variable, levels = c("FRONTAL (MR2)", "CENTRAL (MR1)", "OCCIPITAL (MR3)"))
- writexl::write_xlsx(pvals, file.path("ttest_results.xlsx"))
- ### Plot with stats
- # Ensure shading_data$brightness is a factor
- shading_data$brightness <- as.factor(shading_data$brightness)
- ggplot(reg_av, aes(x = time, y = value)) +
- # Facet by variable
- facet_wrap(. ~ variable, ncol = 1, drop = FALSE) +
- # Add shaded regions
- geom_rect(data = shading_data,
- aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax,
- fill = factor(brightness)),
- alpha = 0.5, inherit.aes = FALSE, show.legend = FALSE) +
- scale_fill_manual(values = scales::alpha(
- c("lightgrey", "lightgrey", "grey", "lightgrey", "grey",
- "lightgrey", "grey", "lightgrey", "grey", "lightgrey", "grey"), 0.5)) +
- # Mean ± SE ribbon and mean line
- stat_summary(fun.data = mean_se, geom = "ribbon", alpha = .15, fill = "grey50") +
- stat_summary(fun = "mean", geom = "line", size = 1, color = "black") +
- # APA-style theme
- theme_bw(base_size = 12) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "none"
- ) +
- # Axes and labels
- geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Values [a.u.]"),
- title = ""
- ) +
- # Horizontal lines for significant time points (black for crit1)
- geom_segment(
- data = reg_av %>%
- inner_join(pvals[pvals$crit1 == 1], by = c("time_chunk", "variable")),
- aes(x = time - 20, xend = time + 20,
- y = min(value, na.rm = TRUE) - 0.1,
- yend = min(value, na.rm = TRUE) - 0.1),
- inherit.aes = FALSE, color = "black", size = 1.5
- ) +
- # Horizontal lines for significant time points (dark green for crit2)
- geom_segment(
- data = reg_av %>%
- inner_join(pvals[pvals$crit2 == 1], by = c("time_chunk", "variable")),
- aes(x = time - 20, xend = time + 20,
- y = min(value, na.rm = TRUE) - 0.1,
- yend = min(value, na.rm = TRUE) - 0.1),
- inherit.aes = FALSE, color = "darkgreen", size = 1.5
- ) +
- # Manual y-axis range
- coord_cartesian(ylim = c(min(reg_av$value, na.rm = TRUE) - 0.3, NA))
- # ggsave(file.path(folder_name, "global_ttest.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "global_ttest.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- ```
- Repeated-Measures ANOVA Assessing the Effects of Experimental Manipulation on Spectral Slope across Time Windows and Scalp Regions
- ```{r}
- ### Average across bins
- reg_pcongr2 = data.table::dcast(setDT(reg), ID + variable + time + PrevCongr + Congr ~ ., value.var = c("value_to_stats"), mean, na.rm = TRUE)
- setnames(reg_pcongr2, old = ".", new = "value")
- reg_pcongr2$Congr <- factor(reg_pcongr2$Congr, levels = c("Con", "Inc"))
- reg_pcongr2$PrevCongr <- factor(reg_pcongr2$PrevCongr, levels = c("pCon", "pInc"))
- reg_pcongr2$time_chunk <- cut(reg_pcongr2$time, breaks = time_intervals, include.lowest = TRUE, ordered_result = TRUE, dig.lab = 5)
- reg_pcongr2$time_chunk <- factor(reg_pcongr2$time_chunk, levels = time_chunk_levels, ordered = FALSE)
- ### Statistics
- dat = reg_pcongr2
- dat = data.table(droplevels(dat))
- dat = setDT(dat) %>% dcast(ID + variable + time_chunk + PrevCongr + Congr ~ ., mean, value.var = c("value"), na.rm = TRUE)
- dat = dat[complete.cases(dat$time_chunk)]
- dat$ID = as.factor(dat$ID)
- colnames(dat)[6] <- "value"
- # Create an empty data.table to store the ANOVA results
- pvals <- data.table(
- time_chunk = numeric(), variable = character(),
- Congr_F = numeric(), Congr_p = numeric(), Congr_eta2p = numeric(),
- PrevCongr_F = numeric(), PrevCongr_p = numeric(), PrevCongr_eta2p = numeric(),
- PrevCongrCongr_F = numeric(), PrevCongrCongr_p = numeric(), PrevCongrCongr_eta2p = numeric()
- )
- # Get unique levels
- unique_variables <- unique(dat$variable)
- unique_time <- droplevels(unique(dat$time_chunk)[-1])
- for (tpnt in unique_time) {
- for (var in unique_variables) {
- subset_data <- dat %>% filter(time_chunk == tpnt, variable == var)
- result <- summary(stats::aov(data = subset_data, value ~ PrevCongr * Congr + Error(ID/(PrevCongr * Congr))))
- # Congr
- congr_ss_effect <- result$`Error: ID:Congr`[[1]]$`Sum Sq`[1]
- congr_ss_error <- result$`Error: ID:Congr`[[1]]$`Sum Sq`[2]
- congr_f <- result$`Error: ID:Congr`[[1]]$`F value`[1]
- congr_p <- result$`Error: ID:Congr`[[1]]$`Pr(>F)`[1]
- congr_eta2p <- congr_ss_effect / (congr_ss_effect + congr_ss_error)
- # PrevCongr
- prevcongr_ss_effect <- result$`Error: ID:PrevCongr`[[1]]$`Sum Sq`[1]
- prevcongr_ss_error <- result$`Error: ID:PrevCongr`[[1]]$`Sum Sq`[2]
- prevcongr_f <- result$`Error: ID:PrevCongr`[[1]]$`F value`[1]
- prevcongr_p <- result$`Error: ID:PrevCongr`[[1]]$`Pr(>F)`[1]
- prevcongr_eta2p <- prevcongr_ss_effect / (prevcongr_ss_effect + prevcongr_ss_error)
- # Interaction
- inter_ss_effect <- result$`Error: ID:PrevCongr:Congr`[[1]]$`Sum Sq`[1]
- inter_ss_error <- result$`Error: ID:PrevCongr:Congr`[[1]]$`Sum Sq`[2]
- prevcongrcongr_f <- result$`Error: ID:PrevCongr:Congr`[[1]]$`F value`[1]
- prevcongrcongr_p <- result$`Error: ID:PrevCongr:Congr`[[1]]$`Pr(>F)`[1]
- prevcongrcongr_eta2p <- inter_ss_effect / (inter_ss_effect + inter_ss_error)
- # Append to results table
- pvals <- rbind(
- pvals,
- data.table(
- time_chunk = tpnt, variable = var,
- Congr_F = congr_f, Congr_p = congr_p, Congr_eta2p = congr_eta2p,
- PrevCongr_F = prevcongr_f, PrevCongr_p = prevcongr_p, PrevCongr_eta2p = prevcongr_eta2p,
- PrevCongrCongr_F = prevcongrcongr_f, PrevCongrCongr_p = prevcongrcongr_p, PrevCongrCongr_eta2p = prevcongrcongr_eta2p
- )
- )
- }
- }
- # Add significance flags
- pvals$Congr_crit1 <- ifelse(pvals$Congr_p <= .05, 1, NA)
- pvals$Congr_crit2 <- ifelse(pvals$Congr_p <= .01, 1, NA)
- pvals$PrevCongr_crit1 <- ifelse(pvals$PrevCongr_p <= .05, 1, NA)
- pvals$PrevCongr_crit2 <- ifelse(pvals$PrevCongr_p <= .01, 1, NA)
- pvals$PrevCongrCongr_crit1 <- ifelse(pvals$PrevCongrCongr_p <= .05, 1, NA)
- pvals$PrevCongrCongr_crit2 <- ifelse(pvals$PrevCongrCongr_p <= .01, 1, NA)
- # Convert time_chunk to a factor with the specified levels
- pvals$time_chunk <- factor(pvals$time_chunk, levels = time_chunk_levels, ordered = FALSE)
- pvals$variable <- factor(pvals$variable, levels = c("FRONTAL (MR2)", "CENTRAL (MR1)", "OCCIPITAL (MR3)"))
- writexl::write_xlsx(pvals, file.path("anova_results.xlsx"))
- ###DIFFERENCE WAVES TO PLOT
- ###Congr
- # Calculate difference between Incongruent and Congruent
- aov_congr <- reg_pcongr2 %>%
- pivot_wider(names_from = Congr, values_from = value) %>%
- mutate(value = Inc - Con) %>%
- select(time, time_chunk, variable, value)
- ggplot(aov_congr, aes(x = time, y = value)) +
- facet_wrap(. ~ variable, ncol = 1, drop = FALSE) +
- # Add shaded regions
- geom_rect(data = shading_data,
- aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax,
- fill = factor(brightness)),
- alpha = 0.5, inherit.aes = FALSE, show.legend = FALSE) +
- scale_fill_manual(values = scales::alpha(
- c("lightgrey", "lightgrey", "grey", "lightgrey", "grey",
- "lightgrey", "grey", "lightgrey", "grey", "lightgrey", "grey"), 0.5)) +
- # Mean ± SE ribbon and mean line
- stat_summary(fun.data = mean_se, geom = "ribbon", alpha = .1, fill = "grey50") +
- stat_summary(fun = "mean", geom = "line", size = 1.2, color = "black") +
- # Theme and layout
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "none"
- ) +
- # Axes and labels
- geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- coord_cartesian(ylim = c(-.12, .1)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Difference [a.u.]")
- ) +
- #ggtitle("Wavelet: Difference in 1/f slope (Incongruent – Congruent)") +
- # Horizontal lines for significant time points (black for crit1)
- geom_segment(
- data = aov_congr %>%
- inner_join(pvals[pvals$Congr_crit1 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20,
- y = -.1,
- yend = -.1),
- inherit.aes = FALSE, color = "black", size = 1.5
- ) +
- # Horizontal lines for significant time points (dark green for crit2)
- geom_segment(
- data = aov_congr %>%
- inner_join(pvals[pvals$Congr_crit2 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20,
- y = -.12,
- yend = - .12),
- inherit.aes = FALSE, color = "darkgreen", size = 1.5
- )
- # ggsave(file.path(folder_name, "anova_congr.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "anova_congr.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- ###Previous Congr
- # Calculate difference between Incongruent and Congruent
- aov_pcongr <- reg_pcongr2 %>%
- pivot_wider(names_from = PrevCongr, values_from = value) %>%
- mutate(value = pInc - pCon) %>%
- select(time, time_chunk, variable, value)
- ggplot(aov_pcongr, aes(x = time, y = value)) +
- facet_wrap(. ~ variable, ncol = 1, drop = FALSE) +
- # Add shaded regions
- geom_rect(data = shading_data,
- aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax,
- fill = factor(brightness)),
- alpha = 0.5, inherit.aes = FALSE, show.legend = FALSE) +
- scale_fill_manual(values = scales::alpha(
- c("lightgrey", "lightgrey", "grey", "lightgrey", "grey",
- "lightgrey", "grey", "lightgrey", "grey", "lightgrey", "grey"), 0.5)) +
- # Mean ± SE ribbon and mean line
- stat_summary(fun.data = mean_se, geom = "ribbon", alpha = .1, fill = "grey50") +
- stat_summary(fun = "mean", geom = "line", size = 1.2, color = "black") +
- # Theme and layout
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "none"
- ) +
- # Axes and labels
- geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- coord_cartesian(ylim = c(-.12, .1)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Difference [a.u.]")
- ) +
- #ggtitle("Wavelet: Difference in 1/f slope (Incongruent – Congruent)") +
- # Horizontal lines for significant time points (black for crit1)
- geom_segment(
- data = aov_pcongr %>%
- inner_join(pvals[pvals$PrevCongr_crit1 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20,
- y = -.1,
- yend = -.1),
- inherit.aes = FALSE, color = "black", size = 1.5
- ) +
- # Horizontal lines for significant time points (dark green for crit2)
- geom_segment(
- data = aov_pcongr %>%
- inner_join(pvals[pvals$PrevCongr_crit2 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20,
- y = -.12,
- yend = - .12),
- inherit.aes = FALSE, color = "darkgreen", size = 1.5
- )
- # ggsave(file.path(folder_name, "anova_pcongr.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "anova_pcongr.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- ###Interaction
- aov_pcongr_by_congr <- reg_pcongr2 %>%
- pivot_wider(names_from = PrevCongr, values_from = value) %>%
- mutate(value = pInc - pCon) %>%
- select(time, time_chunk, variable, Congr, value)
- ggplot(aov_pcongr_by_congr, aes(x = time, y = value, color = Congr)) +
- facet_wrap(. ~ variable, ncol = 1, drop = FALSE) +
- # Add shaded regions
- geom_rect(data = shading_data,
- aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax,
- fill = factor(brightness)),
- alpha = 0.5, inherit.aes = FALSE, show.legend = FALSE) +
- scale_fill_manual(values = scales::alpha(
- c("lightgrey", "lightgrey", "grey", "lightgrey", "grey",
- "lightgrey", "grey", "lightgrey", "grey", "lightgrey", "grey"), 0.5)) +
- # Mean ± SE and mean line per Congr level
- stat_summary(fun.data = mean_se, geom = "ribbon", aes(fill = Congr), alpha = .1, color = NA) +
- stat_summary(fun = mean, geom = "line", size = 1.2) +
- # Color mapping
- scale_color_manual(values = c("Con" = "blue", "Inc" = "red")) +
- # Theme
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "none"
- ) +
- # Axes and labels
- geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- coord_cartesian(ylim = c(-.12, .1)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Difference [a.u.]"),
- color = "Congruency"
- ) +
- # Significance for crit1
- geom_segment(
- data = aov_pcongr_by_congr %>%
- inner_join(pvals[pvals$PrevCongrCongr_crit1 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20, y = -.1, yend = -.1),
- inherit.aes = FALSE, color = "black", size = 1.5
- ) +
- # Significance for crit2
- geom_segment(
- data = aov_pcongr_by_congr %>%
- inner_join(pvals[pvals$PrevCongrCongr_crit2 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20, y = -.12, yend = -.12),
- inherit.aes = FALSE, color = "darkgreen", size = 1.5
- )
- # ggsave(file.path(folder_name, "anova_pcongrcongr.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "anova_pcongrcongr.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- aov_pcongr_by_congr1 <- reg_pcongr2 %>%
- pivot_wider(names_from = Congr, values_from = value) %>%
- mutate(value = Inc - Con) %>%
- select(time, time_chunk, variable, PrevCongr, value)
- ggplot(aov_pcongr_by_congr1, aes(x = time, y = value, color = PrevCongr)) +
- facet_wrap(. ~ variable, ncol = 1, drop = FALSE) +
- # Add shaded regions
- geom_rect(data = shading_data,
- aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax,
- fill = factor(brightness)),
- alpha = 0.5, inherit.aes = FALSE, show.legend = FALSE) +
- scale_fill_manual(values = scales::alpha(
- c("lightgrey", "lightgrey", "grey", "lightgrey", "grey",
- "lightgrey", "grey", "lightgrey", "grey", "lightgrey", "grey"), 0.5)) +
- # Mean ± SE and mean line per Congr level
- stat_summary(fun.data = mean_se, geom = "ribbon", aes(fill = PrevCongr), alpha = .1, color = NA) +
- stat_summary(fun = mean, geom = "line", size = 1.2) +
- # Color mapping
- scale_color_manual(values = c("pCon" = "blue", "pInc" = "red")) +
- # Theme
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "none"
- ) +
- # Axes and labels
- geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- coord_cartesian(ylim = c(-.12, .1)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Difference [a.u.]"),
- color = "Congruency"
- ) +
- # Significance for crit1
- geom_segment(
- data = aov_pcongr_by_congr %>%
- inner_join(pvals[pvals$PrevCongrCongr_crit1 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20, y = -.1, yend = -.1),
- inherit.aes = FALSE, color = "black", size = 1.5
- ) +
- # Significance for crit2
- geom_segment(
- data = aov_pcongr_by_congr %>%
- inner_join(pvals[pvals$PrevCongrCongr_crit2 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20, y = -.12, yend = -.12),
- inherit.aes = FALSE, color = "darkgreen", size = 1.5
- )
- # ggsave(file.path(folder_name, "anova_pcongrcongr1.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "anova_pcongrcongr1.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- ###Interaction combined
- head(aov_pcongr_by_congr)
- head(aov_pcongr_by_congr1)
- colnames(aov_pcongr_by_congr)[4] <- "Cond"
- colnames(aov_pcongr_by_congr1)[4] <- "Cond"
- aov_pcongr_by_congr2 <- rbind(aov_pcongr_by_congr, aov_pcongr_by_congr1)
- ggplot(aov_pcongr_by_congr2, aes(x = time, y = value, color = Cond)) +
- facet_wrap(. ~ variable, ncol = 1, drop = FALSE) +
- # Add shaded regions
- geom_rect(data = shading_data,
- aes(xmin = xmin, xmax = xmax, ymin = ymin, ymax = ymax,
- fill = factor(brightness)),
- alpha = 0.5, inherit.aes = FALSE, show.legend = FALSE) +
- scale_fill_manual(values = scales::alpha(
- c("lightgrey", "lightgrey", "grey", "lightgrey", "grey",
- "lightgrey", "grey", "lightgrey", "grey", "lightgrey", "grey"), 0.5)) +
- # Mean ± SE and mean line per Congr level
- stat_summary(fun.data = mean_se, geom = "ribbon", aes(fill = Cond), alpha = .1, color = NA) +
- stat_summary(fun = mean, geom = "line", size = 1.2) +
- # Color mapping
- scale_color_manual(values = c("pCon" = "#56B4E9", "pInc" = "#0072B2", "Con" = "#E69F00", "Inc" = "#D55E00")) +
- # Theme
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5),
- legend.position = "none"
- ) +
- # Axes and labels
- geom_hline(yintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- geom_vline(xintercept = 0, linetype = "dashed", color = "black", size = 0.3) +
- coord_cartesian(ylim = c(-.12, .1)) +
- labs(
- x = "Time (ms)",
- y = expression("Spectral Slope Difference [a.u.]"),
- color = "Congruency"
- ) +
- # Significance for crit1
- geom_segment(
- data = aov_pcongr_by_congr %>%
- inner_join(pvals[pvals$PrevCongrCongr_crit1 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20, y = -.1, yend = -.1),
- inherit.aes = FALSE, color = "black", size = 1.5
- ) +
- # Significance for crit2
- geom_segment(
- data = aov_pcongr_by_congr %>%
- inner_join(pvals[pvals$PrevCongrCongr_crit2 == 1], by = c("variable", "time_chunk")),
- aes(x = time - 20, xend = time + 20, y = -.12, yend = -.12),
- inherit.aes = FALSE, color = "darkgreen", size = 1.5
- )
- # ggsave(file.path(folder_name, "anova_pcongrcongr2.jpg"), width = 8, height = 15, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "anova_pcongrcongr2.pdf"), width = 8, height = 15, dpi = 600, scale = .5)
- ```
- Follow-ups for rmANOVA
- ```{r}
- #pCon vs pInc within Congr level, for selected ROI × time bin
- unique(time_chunk_levels) # sanity-check available bins
- #Boxplot to show distribution
- plot_box_all_conditions <- function(dat_roi,
- ylab = "Spectral Slope [a.u.]",
- ylim = c()) {
- dat_roi$Cond <- interaction(dat_roi$Congr, dat_roi$PrevCongr,
- sep = "-",
- lex.order = TRUE)
- dat_roi$Cond <- factor(dat_roi$Cond,
- levels = c("Con-pCon",
- "Con-pInc",
- "Inc-pCon",
- "Inc-pInc"))
- ggplot(dat_roi, aes(x = Cond, y = value, fill = Congr)) +
- facet_grid(. ~ variable + time_chunk) +
- geom_boxplot(
- width = .6,
- alpha = .6,
- outlier.shape = NA
- ) +
- geom_jitter(
- width = .08,
- alpha = .35,
- size = 1.5
- ) +
- stat_summary(
- fun = mean,
- geom = "point",
- size = 3.5,
- shape = 21,
- fill = "white",
- color = "black"
- ) +
- scale_fill_manual(values = c("Con" = "red", "Inc" = "blue")) +
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10)
- ) +
- labs(
- x = "Condition (Congruency × Previous Congruency)",
- y = ylab
- ) +
- coord_cartesian(ylim = ylim)
- }
- # ==============================================================================
- # 1) FRONTAL (MR2), time_chunk = (160,320]
- # ==============================================================================
- # -- Select the ROI × time bin -------------------------------------------------
- dat1 <- subset(dat, time_chunk == "(160,320]" & variable == "FRONTAL (MR2)")
- stopifnot(nrow(dat1) > 0)
- # -- Quick 2×2 cell means (Con/Inc × pCon/pInc) --------------------------------
- means_2x2 <- data.table::dcast(
- data.table::as.data.table(dat1),
- Congr + PrevCongr ~ .,
- value.var = "value",
- fun.aggregate = mean, na.rm = TRUE
- )
- data.table::setnames(means_2x2, ".", "mean")
- print(means_2x2)
- # -- Paired t-tests: pCon vs pInc within Congr = "Con" -------------------------
- w_con <- dat1[dat1$Congr == "Con", c("ID","PrevCongr","value")]
- w_con <- tidyr::pivot_wider(w_con, names_from = PrevCongr, values_from = value)
- w_con <- subset(w_con, !is.na(pCon) & !is.na(pInc)) # ensure the same IDs contribute to both levels
- w_con <- w_con[order(w_con$ID), ]
- t.test(w_con$pInc, w_con$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- # -- Paired t-tests: pCon vs pInc within Congr = "Inc" -------------------------
- w_inc <- dat1[dat1$Congr == "Inc", c("ID","PrevCongr","value")]
- w_inc <- tidyr::pivot_wider(w_inc, names_from = PrevCongr, values_from = value)
- w_inc <- subset(w_inc, !is.na(pCon) & !is.na(pInc))
- w_inc <- w_inc[order(w_inc$ID), ]
- t.test(w_inc$pInc, w_inc$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- # -- Plot (within-subject SE via Rmisc::summarySEwithin) ----------------------
- library(Rmisc) # summarySEwithin
- dat1$PrevCongr <- factor(dat1$PrevCongr, levels = c("pCon","pInc"))
- dat1$Congr <- factor(dat1$Congr, levels = c("Con","Inc"))
- summary_dat <- summarySEwithin(
- dat1,
- measurevar = "value",
- withinvars = c("variable","time_chunk","PrevCongr","Congr"),
- idvar = "ID"
- )
- ggplot(summary_dat, aes(x = PrevCongr, y = value, color = Congr, group = Congr)) +
- facet_grid(. ~ variable + time_chunk) +
- geom_line(position = position_dodge(0.2), size = 0.8) +
- geom_point(position = position_dodge(0.2), size = 3) +
- geom_errorbar(aes(ymin = value - se, ymax = value + se),
- width = 0.1, position = position_dodge(0.2)) +
- scale_color_manual(values = c("Con" = "red", "Inc" = "blue")) +
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5)
- ) +
- labs(x = "Previous Congruency", y = "Spectral Slope [a.u.]", title = NULL) +
- coord_cartesian(ylim = c(-1.35, -0.68))
- # ggsave(file.path(folder_name, "ttest_frontal_160.jpg"), width = 7, height = 6, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "ttest_frontal_160.pdf"), width = 7, height = 6, dpi = 600, scale = .5)
- plot_box_all_conditions(dat1)
- # ==============================================================================
- # 2) CENTRAL (MR1), time_chunk = (160,320]
- # ==============================================================================
- dat1 <- subset(dat, time_chunk == "(160,320]" & variable == "CENTRAL (MR1)")
- stopifnot(nrow(dat1) > 0)
- means_2x2 <- data.table::dcast(
- data.table::as.data.table(dat1),
- Congr + PrevCongr ~ .,
- value.var = "value",
- fun.aggregate = mean, na.rm = TRUE
- )
- data.table::setnames(means_2x2, ".", "mean")
- print(means_2x2)
- w_con <- dat1[dat1$Congr == "Con", c("ID","PrevCongr","value")]
- w_con <- tidyr::pivot_wider(w_con, names_from = PrevCongr, values_from = value)
- w_con <- subset(w_con, !is.na(pCon) & !is.na(pInc))
- w_con <- w_con[order(w_con$ID), ]
- t.test(w_con$pInc, w_con$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- w_inc <- dat1[dat1$Congr == "Inc", c("ID","PrevCongr","value")]
- w_inc <- tidyr::pivot_wider(w_inc, names_from = PrevCongr, values_from = value)
- w_inc <- subset(w_inc, !is.na(pCon) & !is.na(pInc))
- w_inc <- w_inc[order(w_inc$ID), ]
- t.test(w_inc$pInc, w_inc$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- library(Rmisc)
- dat1$PrevCongr <- factor(dat1$PrevCongr, levels = c("pCon","pInc"))
- dat1$Congr <- factor(dat1$Congr, levels = c("Con","Inc"))
- summary_dat <- summarySEwithin(dat1, "value",
- withinvars = c("variable","time_chunk","PrevCongr","Congr"),
- idvar = "ID")
- ggplot(summary_dat, aes(x = PrevCongr, y = value, color = Congr, group = Congr)) +
- facet_grid(. ~ variable + time_chunk) +
- geom_line(position = position_dodge(0.2), size = 0.8) +
- geom_point(position = position_dodge(0.2), size = 3) +
- geom_errorbar(aes(ymin = value - se, ymax = value + se),
- width = 0.1, position = position_dodge(0.2)) +
- scale_color_manual(values = c("Con" = "red", "Inc" = "blue")) +
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5)
- ) +
- labs(x = "Previous Congruency", y = "Spectral Slope [a.u.]", title = NULL) +
- coord_cartesian(ylim = c(-1.35, -0.68))
- # ggsave(file.path(folder_name, "ttest_central_160.jpg"), width = 7, height = 6, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "ttest_central_160.pdf"), width = 7, height = 6, dpi = 600, scale = .5)
- plot_box_all_conditions(dat1)
- # ==============================================================================
- # 3) OCCIPITAL (MR3), time_chunk = (480,640]
- # ==============================================================================
- dat1 <- subset(dat, time_chunk == "(480,640]" & variable == "OCCIPITAL (MR3)")
- stopifnot(nrow(dat1) > 0)
- means_2x2 <- data.table::dcast(
- data.table::as.data.table(dat1),
- Congr + PrevCongr ~ .,
- value.var = "value",
- fun.aggregate = mean, na.rm = TRUE
- )
- data.table::setnames(means_2x2, ".", "mean")
- print(means_2x2)
- w_con <- dat1[dat1$Congr == "Con", c("ID","PrevCongr","value")]
- w_con <- tidyr::pivot_wider(w_con, names_from = PrevCongr, values_from = value)
- w_con <- subset(w_con, !is.na(pCon) & !is.na(pInc))
- w_con <- w_con[order(w_con$ID), ]
- t.test(w_con$pInc, w_con$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- w_inc <- dat1[dat1$Congr == "Inc", c("ID","PrevCongr","value")]
- w_inc <- tidyr::pivot_wider(w_inc, names_from = PrevCongr, values_from = value)
- w_inc <- subset(w_inc, !is.na(pCon) & !is.na(pInc))
- w_inc <- w_inc[order(w_inc$ID), ]
- t.test(w_inc$pInc, w_inc$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- library(Rmisc)
- dat1$PrevCongr <- factor(dat1$PrevCongr, levels = c("pCon","pInc"))
- dat1$Congr <- factor(dat1$Congr, levels = c("Con","Inc"))
- summary_dat <- summarySEwithin(dat1, "value",
- withinvars = c("variable","time_chunk","PrevCongr","Congr"),
- idvar = "ID")
- ggplot(summary_dat, aes(x = PrevCongr, y = value, color = Congr, group = Congr)) +
- facet_grid(. ~ variable + time_chunk) +
- geom_line(position = position_dodge(0.2), size = 0.8) +
- geom_point(position = position_dodge(0.2), size = 3) +
- geom_errorbar(aes(ymin = value - se, ymax = value + se),
- width = 0.1, position = position_dodge(0.2)) +
- scale_color_manual(values = c("Con" = "red", "Inc" = "blue")) +
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5)
- ) +
- labs(x = "Previous Congruency", y = "Spectral Slope [a.u.]", title = NULL) +
- coord_cartesian(ylim = c(-1.35, -0.68))
- # ggsave(file.path(folder_name, "ttest_occ_480.jpg"), width = 7, height = 6, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "ttest_occ_480.pdf"), width = 7, height = 6, dpi = 600, scale = .5)
- plot_box_all_conditions(dat1)
- # ==============================================================================
- # 4) FRONTAL (MR2), time_chunk = (960,1120]
- # ==============================================================================
- dat1 <- subset(dat, time_chunk == "(960,1120]" & variable == "FRONTAL (MR2)")
- stopifnot(nrow(dat1) > 0)
- means_2x2 <- data.table::dcast(
- data.table::as.data.table(dat1),
- Congr + PrevCongr ~ .,
- value.var = "value",
- fun.aggregate = mean, na.rm = TRUE
- )
- data.table::setnames(means_2x2, ".", "mean")
- print(means_2x2)
- w_con <- dat1[dat1$Congr == "Con", c("ID","PrevCongr","value")]
- w_con <- tidyr::pivot_wider(w_con, names_from = PrevCongr, values_from = value)
- w_con <- subset(w_con, !is.na(pCon) & !is.na(pInc))
- w_con <- w_con[order(w_con$ID), ]
- t.test(w_con$pInc, w_con$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- w_inc <- dat1[dat1$Congr == "Inc", c("ID","PrevCongr","value")]
- w_inc <- tidyr::pivot_wider(w_inc, names_from = PrevCongr, values_from = value)
- w_inc <- subset(w_inc, !is.na(pCon) & !is.na(pInc))
- w_inc <- w_inc[order(w_inc$ID), ]
- t.test(w_inc$pInc, w_inc$pCon, paired = TRUE, alternative = "two.sided", conf.level = 0.95)
- library(Rmisc)
- dat1$PrevCongr <- factor(dat1$PrevCongr, levels = c("pCon","pInc"))
- dat1$Congr <- factor(dat1$Congr, levels = c("Con","Inc"))
- summary_dat <- summarySEwithin(dat1, "value",
- withinvars = c("variable","time_chunk","PrevCongr","Congr"),
- idvar = "ID")
- ggplot(summary_dat, aes(x = PrevCongr, y = value, color = Congr, group = Congr)) +
- facet_grid(. ~ variable + time_chunk) +
- geom_line(position = position_dodge(0.2), size = 0.8) +
- geom_point(position = position_dodge(0.2), size = 3) +
- geom_errorbar(aes(ymin = value - se, ymax = value + se),
- width = 0.1, position = position_dodge(0.2)) +
- scale_color_manual(values = c("Con" = "red", "Inc" = "blue")) +
- theme_bw(base_size = 14) +
- theme(
- panel.grid = element_blank(),
- strip.background = element_rect(fill = "white"),
- strip.text = element_text(size = 12, face = "bold"),
- axis.title = element_text(size = 12),
- axis.text = element_text(size = 10),
- plot.title = element_text(size = 14, face = "bold", hjust = 0.5)
- ) +
- labs(x = "Previous Congruency", y = "Spectral Slope [a.u.]", title = NULL) +
- coord_cartesian(ylim = c(-1.35, -0.68))
- # ggsave(file.path(folder_name, "ttest_frontal_960.jpg"), width = 7, height = 6, dpi = 600, scale = .5)
- # ggsave(file.path(folder_name, "ttest_frontal_960.pdf"), width = 7, height = 6, dpi = 600, scale = .5)
- plot_box_all_conditions(dat1)
- ```
- Cluster-based permutations for global & experimental effects with figures
- ```{r}
- ## =========================================================
- ## Unified Z-based cluster permutation pipeline + plotting
- ## For:
- ## A) Global stimulus-induced change (baseline-corrected; time>=0 vs time<0)
- ## B) 2×2 effects (Congr, PrevCongr, Interaction) via within-subject contrasts
- ##
- ## Cluster permutation:
- ## - Observed statistic: Z(t) = (obs_mean(t) - perm_mu(t)) / perm_sd(t)
- ## - Permutations: sign-flip across subjects (within-subject scheme)
- ## - Cluster-forming threshold: |Z| >= 1.6449
- ## - Cluster statistic: max |Z| within cluster (max intensity)
- ## - FWER control: null = max cluster-stat across time per permutation
- ##
- ## Outputs:
- ## - Cluster table (t_start/t_end, max|Z|, mean Z, p_cluster, sig)
- ## - Plots: Z(t) time course + shaded significant clusters (pFWER <= .05)
- ## =========================================================
- library(data.table)
- library(ggplot2)
- library(patchwork)
- ## =========================================================
- ## 0) GLOBAL SETTINGS (edit here)
- ## =========================================================
- Z_THR <- 1.6449
- N_PERM <- 1000
- SEED <- 123
- POST_RANGE <- 0:1277
- TIME_RANGE <- 0:1277
- COMP_ORDER <- c("FRONTAL (MR2)", "CENTRAL (MR1)", "OCCIPITAL (MR3)")
- ## =========================================================
- ## 1) CORE HELPERS: clustering + permutation Z
- ## =========================================================
- clusters_maxint_1d <- function(stat, thr = Z_THR) {
- above <- abs(stat) >= thr
- if (!any(above)) return(list(idx = list(), cl_stat = numeric(0)))
- r <- rle(above)
- ends <- cumsum(r$lengths)
- starts <- ends - r$lengths + 1
- keep <- which(r$values)
- idx <- lapply(keep, function(k) starts[k]:ends[k])
- cl_stat <- vapply(idx, function(ix) max(abs(stat[ix]), na.rm = TRUE), numeric(1))
- list(idx = idx, cl_stat = cl_stat)
- }
- perm_cluster_maxint_1d_Z <- function(X, n_perm = N_PERM, seed = SEED,
- z_thr = Z_THR, keep_zperm = FALSE) {
- # X: N × T matrix (subjects × time) of values (baseline-corrected or contrasts)
- set.seed(seed)
- N <- nrow(X)
- Tt <- ncol(X)
- # Observed mean map
- obs_mean <- colMeans(X, na.rm = TRUE)
- # Permuted mean maps (n_perm × T)
- perm_means <- matrix(NA_real_, nrow = n_perm, ncol = Tt)
- for (p in seq_len(n_perm)) {
- signs <- sample(c(-1, 1), size = N, replace = TRUE)
- perm_means[p, ] <- colMeans(X * signs, na.rm = TRUE)
- }
- # Pointwise standardization parameters from permutations
- perm_mu <- colMeans(perm_means, na.rm = TRUE)
- perm_sd <- apply(perm_means, 2, sd, na.rm = TRUE)
- perm_sd[perm_sd == 0 | !is.finite(perm_sd)] <- NA_real_
- # Observed Z map
- z_obs <- (obs_mean - perm_mu) / perm_sd
- # Optional permuted Z maps (for diagnostics / pointwise descriptive p(t))
- z_perm <- NULL
- if (isTRUE(keep_zperm)) {
- z_perm <- sweep(perm_means, 2, perm_mu, "-")
- z_perm <- sweep(z_perm, 2, perm_sd, "/")
- }
- # Observed clusters + stats
- cl_obs <- clusters_maxint_1d(z_obs, thr = z_thr)
- # Null distribution: max cluster stat per permutation
- max_null <- numeric(n_perm)
- for (p in seq_len(n_perm)) {
- zp <- if (!is.null(z_perm)) z_perm[p, ] else (perm_means[p, ] - perm_mu) / perm_sd
- cl_p <- clusters_maxint_1d(zp, thr = z_thr)
- max_null[p] <- if (length(cl_p$cl_stat)) max(cl_p$cl_stat) else 0
- }
- # Cluster p-values (FWER-controlled)
- p_cluster <- if (length(cl_obs$cl_stat)) {
- vapply(cl_obs$cl_stat, function(v) (sum(max_null >= v) + 1) / (n_perm + 1), numeric(1))
- } else numeric(0)
- list(
- z_obs = z_obs,
- z_perm = z_perm,
- clusters = cl_obs$idx,
- cluster_stat = cl_obs$cl_stat,
- cluster_p = p_cluster,
- max_null = max_null,
- z_thr = z_thr,
- n_perm = n_perm,
- seed = seed
- )
- }
- summarize_clusters <- function(time_num, res, variable, effect = NA_character_) {
- if (length(res$clusters) == 0) {
- return(data.table(
- variable = variable,
- effect = effect,
- cluster = integer(),
- t_start = integer(),
- t_end = integer(),
- cl_maxabs_z = numeric(),
- mean_z = numeric(),
- mean_abs_z = numeric(),
- p_cluster = numeric(),
- sig = logical()
- ))
- }
- out <- data.table(
- variable = variable,
- effect = effect,
- cluster = seq_along(res$clusters),
- t_start = time_num[vapply(res$clusters, min, integer(1))],
- t_end = time_num[vapply(res$clusters, max, integer(1))],
- cl_maxabs_z = res$cluster_stat,
- mean_z = vapply(res$clusters, function(ix) mean(res$z_obs[ix], na.rm = TRUE), numeric(1)),
- mean_abs_z = vapply(res$clusters, function(ix) mean(abs(res$z_obs[ix]), na.rm = TRUE), numeric(1)),
- p_cluster = res$cluster_p
- )
- out[, sig := (p_cluster <= 0.05)]
- out[]
- }
- plot_z_timecourse_with_clusters <- function(time_num, z_obs, clusters, cluster_p,
- z_thr = Z_THR,
- title = NULL,
- subtitle = NULL) {
- df <- data.table(time = time_num, z = as.numeric(z_obs))
- shade <- NULL
- if (length(clusters) > 0) {
- sig_idx <- which(cluster_p <= 0.05)
- if (length(sig_idx) > 0) {
- shade <- rbindlist(lapply(sig_idx, function(k) {
- ix <- clusters[[k]]
- data.table(xmin = time_num[min(ix)], xmax = time_num[max(ix)])
- }))
- }
- }
- ggplot(df, aes(x = time, y = z)) +
- { if (!is.null(shade)) geom_rect(
- data = shade,
- aes(xmin = xmin, xmax = xmax, ymin = -Inf, ymax = Inf),
- inherit.aes = FALSE,
- alpha = .15
- )
- } +
- geom_hline(yintercept = c(-z_thr, z_thr), linetype = "dotted") +
- geom_hline(yintercept = 0, linetype = "solid") +
- geom_line(linewidth = 1) +
- theme_bw(base_size = 14) +
- theme(panel.grid = element_blank()) +
- labs(x = "Time (ms)", y = "Observed Z(t)", title = title, subtitle = subtitle)
- }
- ## =========================================================
- ## 2) A) GLOBAL: baseline-corrected post-stimulus change
- ## Input: reg_av must have columns ID, time, variable, value
- ## =========================================================
- run_global_baselinecorr_Z <- function(reg_av,
- post_time_range = POST_RANGE,
- n_perm = N_PERM,
- seed = SEED,
- z_thr = Z_THR) {
- DT <- as.data.table(reg_av)
- DT[, time := as.integer(time)]
- setorder(DT, ID, variable, time)
- # Baseline per subject × variable (time < 0)
- BL <- DT[time < 0, .(baseline = mean(value, na.rm = TRUE)), by = .(ID, variable)]
- # Post-stimulus only
- POST <- DT[time >= 0]
- POST <- merge(POST, BL, by = c("ID", "variable"), all.x = TRUE)
- # Baseline-corrected values
- POST[, value_bc := value - baseline]
- # Restrict post-stim time range
- if (!is.null(post_time_range)) POST <- POST[time %in% post_time_range]
- vars <- unique(POST$variable)
- # Cluster table
- cluster_table <- rbindlist(lapply(vars, function(v) {
- tmp <- POST[variable == v, .(ID, time, val = value_bc)]
- wide <- dcast(tmp, ID ~ time, value.var = "val")
- time_cols <- setdiff(names(wide), "ID")
- time_num <- as.integer(time_cols)
- o <- order(time_num)
- time_cols <- time_cols[o]
- time_num <- time_num[o]
- X <- as.matrix(wide[, ..time_cols])
- res <- perm_cluster_maxint_1d_Z(X, n_perm = n_perm, seed = seed, z_thr = z_thr, keep_zperm = FALSE)
- summarize_clusters(time_num, res, variable = v, effect = "global_bc")
- }), use.names = TRUE, fill = TRUE)
- # Z curves for plotting
- z_curves <- lapply(vars, function(v) {
- tmp <- POST[variable == v, .(ID, time, val = value_bc)]
- wide <- dcast(tmp, ID ~ time, value.var = "val")
- time_cols <- setdiff(names(wide), "ID")
- time_num <- as.integer(time_cols)
- o <- order(time_num)
- time_cols <- time_cols[o]
- time_num <- time_num[o]
- X <- as.matrix(wide[, ..time_cols])
- res <- perm_cluster_maxint_1d_Z(X, n_perm = n_perm, seed = seed, z_thr = z_thr, keep_zperm = FALSE)
- list(variable = v, time = time_num, res = res)
- })
- names(z_curves) <- vars
- list(
- POST = POST,
- cluster_table = cluster_table,
- z_curves = z_curves,
- settings = list(n_perm = n_perm, seed = seed, z_thr = z_thr)
- )
- }
- ## =========================================================
- ## 3) B) 2×2 EFFECTS: Congr / PrevCongr / Interaction
- ## Input: reg_pcongr2 must have columns:
- ## ID, variable, time, PrevCongr, Congr, value
- ## =========================================================
- run_2x2_effects_Z <- function(reg_pcongr2,
- time_range = TIME_RANGE,
- n_perm = N_PERM,
- seed = SEED,
- z_thr = Z_THR) {
- DT <- as.data.table(reg_pcongr2)
- DT[, Congr := factor(Congr, levels = c("Con","Inc"))]
- DT[, PrevCongr := factor(PrevCongr, levels = c("pCon","pInc"))]
- DT[, time := as.integer(time)]
- setorder(DT, ID, variable, time, PrevCongr, Congr)
- if (!is.null(time_range)) DT <- DT[time %in% time_range]
- # Wide 2×2 cells
- W <- dcast(
- DT,
- ID + variable + time ~ PrevCongr + Congr,
- value.var = "value"
- )
- required_cols <- c("pCon_Con","pCon_Inc","pInc_Con","pInc_Inc")
- miss <- setdiff(required_cols, names(W))
- if (length(miss) > 0) stop("Missing condition columns after dcast: ", paste(miss, collapse = ", "))
- # Within-subject contrasts
- EFF <- W[, .(
- eff_Congr = 0.5 * ((pCon_Inc - pCon_Con) + (pInc_Inc - pInc_Con)),
- eff_Prev = 0.5 * ((pInc_Con - pCon_Con) + (pInc_Inc - pCon_Inc)),
- eff_Int = (pCon_Inc - pCon_Con) - (pInc_Inc - pInc_Con)
- ), by = .(ID, variable, time)]
- effects <- c("eff_Congr","eff_Prev","eff_Int")
- vars <- unique(EFF$variable)
- # Cluster table
- cluster_table <- rbindlist(lapply(vars, function(v) {
- rbindlist(lapply(effects, function(eff) {
- tmp <- EFF[variable == v, .(ID, time, val = get(eff))]
- wide <- dcast(tmp, ID ~ time, value.var = "val")
- time_cols <- setdiff(names(wide), "ID")
- time_num <- as.integer(time_cols)
- o <- order(time_num)
- time_cols <- time_cols[o]
- time_num <- time_num[o]
- X <- as.matrix(wide[, ..time_cols])
- res <- perm_cluster_maxint_1d_Z(X, n_perm = n_perm, seed = seed, z_thr = z_thr, keep_zperm = FALSE)
- summarize_clusters(time_num, res, variable = v, effect = eff)
- }))
- }), use.names = TRUE, fill = TRUE)
- # Z curves for plotting
- z_curves <- list()
- for (v in vars) {
- for (eff in effects) {
- tmp <- EFF[variable == v, .(ID, time, val = get(eff))]
- wide <- dcast(tmp, ID ~ time, value.var = "val")
- time_cols <- setdiff(names(wide), "ID")
- time_num <- as.integer(time_cols)
- o <- order(time_num)
- time_cols <- time_cols[o]
- time_num <- time_num[o]
- X <- as.matrix(wide[, ..time_cols])
- res <- perm_cluster_maxint_1d_Z(X, n_perm = n_perm, seed = seed, z_thr = z_thr, keep_zperm = FALSE)
- key <- paste(v, eff, sep = " | ")
- z_curves[[key]] <- list(variable = v, effect = eff, time = time_num, res = res)
- }
- }
- list(
- EFF = EFF,
- cluster_table = cluster_table,
- z_curves = z_curves,
- settings = list(n_perm = n_perm, seed = seed, z_thr = z_thr)
- )
- }
- ## =========================================================
- ## 4) FIGURE BUILDERS
- ## =========================================================
- make_effect_3panel_Z <- function(effects_out,
- effect = c("eff_Congr","eff_Prev","eff_Int"),
- components = COMP_ORDER,
- z_thr = NULL,
- title = NULL) {
- effect <- match.arg(effect)
- if (is.null(z_thr)) z_thr <- effects_out$settings$z_thr
- if (is.null(title)) title <- paste0("Observed Z(t): ", effect, " (shaded clusters pFWER ≤ .05)")
- panels <- lapply(components, function(v) {
- key <- paste(v, effect, sep = " | ")
- if (!key %in% names(effects_out$z_curves)) stop("Missing z_curve for: ", key)
- item <- effects_out$z_curves[[key]]
- plot_z_timecourse_with_clusters(
- time_num = item$time,
- z_obs = item$res$z_obs,
- clusters = item$res$clusters,
- cluster_p = item$res$cluster_p,
- z_thr = z_thr,
- title = v,
- subtitle = NULL
- ) +
- theme(
- plot.title = element_text(size = 12, face = "bold"),
- axis.title.x = element_text(size = 11),
- axis.title.y = element_text(size = 11)
- )
- })
- wrap_plots(panels, ncol = 1) +
- plot_annotation(title = title) &
- theme(plot.title = element_text(size = 14, face = "bold", hjust = 0.5))
- }
- make_global_3panel_Z <- function(global_out,
- components = COMP_ORDER,
- z_thr = NULL,
- title = NULL) {
- if (is.null(z_thr)) z_thr <- global_out$settings$z_thr
- if (is.null(title)) title <- "Global stimulus-induced changes vs baseline (Observed Z(t); shaded clusters pFWER ≤ .05)"
- panels <- lapply(components, function(v) {
- if (!v %in% names(global_out$z_curves)) stop("Missing global z_curve for: ", v)
- item <- global_out$z_curves[[v]]
- plot_z_timecourse_with_clusters(
- time_num = item$time,
- z_obs = item$res$z_obs,
- clusters = item$res$clusters,
- cluster_p = item$res$cluster_p,
- z_thr = z_thr,
- title = v,
- subtitle = NULL
- ) +
- theme(
- plot.title = element_text(size = 12, face = "bold"),
- axis.title.x = element_text(size = 11),
- axis.title.y = element_text(size = 11)
- )
- })
- wrap_plots(panels, ncol = 1) +
- plot_annotation(title = title) &
- theme(plot.title = element_text(size = 14, face = "bold", hjust = 0.5))
- }
- ## =========================================================
- ## 5) RUN PIPELINES
- ## =========================================================
- # ---- A) Global (baseline-corrected) ----
- global_out <- run_global_baselinecorr_Z(
- reg_av,
- post_time_range = POST_RANGE,
- n_perm = N_PERM,
- seed = SEED,
- z_thr = Z_THR
- )
- global_out$cluster_table[]
- global_out$cluster_table[sig == TRUE]
- # ---- B) 2×2 effects ----
- effects_out <- run_2x2_effects_Z(
- reg_pcongr2,
- time_range = TIME_RANGE,
- n_perm = N_PERM,
- seed = SEED,
- z_thr = Z_THR
- )
- effects_out$cluster_table[]
- effects_out$cluster_table[sig == TRUE]
- ## =========================================================
- ## 6) MAKE THE 3-PANEL FIGURES
- ## =========================================================
- fig_global_3panel <- make_global_3panel_Z(
- global_out,
- components = COMP_ORDER,
- title = "Global post-stimulus deviations from baseline (Observed Z(t); shaded clusters pFWER ≤ .05)"
- )
- fig_congr_3panel <- make_effect_3panel_Z(
- effects_out,
- effect = "eff_Congr",
- components = COMP_ORDER,
- title = "Main effect of Congruency (Observed Z(t); shaded clusters pFWER ≤ .05)"
- )
- fig_prev_3panel <- make_effect_3panel_Z(
- effects_out,
- effect = "eff_Prev",
- components = COMP_ORDER,
- title = "Main effect of Previous Congruency (Observed Z(t); shaded clusters pFWER ≤ .05)"
- )
- fig_int_3panel <- make_effect_3panel_Z(
- effects_out,
- effect = "eff_Int",
- components = COMP_ORDER,
- title = "Congruency × Previous Congruency (Observed Z(t); shaded clusters pFWER ≤ .05)"
- )
- fig_global_3panel
- ggsave("fit_global.pdf", width = 6, height = 15, dpi = 600, scale = .5)
- fig_congr_3panel
- ggsave("fit_congr.pdf", width = 6, height = 15, dpi = 600, scale = .5)
- fig_prev_3panel
- ggsave("fit_prev.pdf", width = 6, height = 15, dpi = 600, scale = .5)
- fig_int_3panel
- ggsave("fit_int.pdf", width = 6, height = 15, dpi = 600, scale = .5)
- ```
code_afterR1.Rmd, no license · at the source
Overview
- Center for Mind/Brain Sciences (CIMeC), Universitá Degli Studi di Trento‐Rovereto, Trento, Italy
- Department of Psychology, Universitá Degli Studi di Bologna, Bologna, Italy
- Centre for Cognitive Science, Jagiellonian University, Kraków, Poland
- Department of Psychology, University of Illinois Urbana‐Champaign, Champaign, Illinois, USA
- Beckman Institute for Advanced Science and Technology, University of Illinois Urbana‐Champaign, Champaign, Illinois, USA
- School of Psychology, University of East Anglia, Norwich, UK
Abstract
Aperiodic neural activity (1/
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 z3qsg
Availability: 1 check, the latest on 26 September 2026: the link answers (HTTP 200)
- 26 September 2026: the link answers (HTTP 200)
2 files
- code.Rmd, R, 1,129 lines
- code_afterR1.Rmd, R, 1,689 lines, 2 matches
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;
- 2 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 Availability Statement
Data and code necessary to reproduce the statistical analyses (Section 3.2.3) are available at https://
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 3, 28 September 2026
- Publisher: n/a → Wiley
Version 1, 27 September 2026: the first record
Recorded: type, language, journal, volume, issue, pages, dates, 8 authors, 6 keywords, 13 MeSH terms, 2 funders, 73 references.
Cite
This paper
Tronelli, V., Kałamała, P., Gratton, G., Fabiani, M., Gyurkovics, M., Low, K. A., Codispoti, M., & De Cesarei, A. (2026). Changes in Aperiodic (1/
BibTeX
@article{tronelli2026cha
author = {Tronelli, Virginia and Kałamała, Patrycja and Gratton, Gabriele and Fabiani, Monica and Gyurkovics, Mate and Low, Kathy A and Codispoti, Maurizio and De Cesarei, Andrea},
title = {{Changes in Aperiodic (1/
journal = {Psychophysiology},
year = {2026},
month = aug,
volume = {63},
number = {8},
pages = {e70376},
publisher = {Wiley},
issn = {0048-5772},
doi = {10.1111/
url = {https://
pmid = {42568317},
pmcid = {PMC13451924}
}
RIS
TY - JOUR
AU - Tronelli, Virginia
AU - Kałamała, Patrycja
AU - Gratton, Gabriele
AU - Fabiani, Monica
AU - Gyurkovics, Mate
AU - Low, Kathy A
AU - Codispoti, Maurizio
AU - De Cesarei, Andrea
TI - Changes in Aperiodic (1/
T2 - Psychophysiology
J2 - Psychophysiology
PY - 2026
DA - 2026/
VL - 63
IS - 8
SP - e70376
SN - 0048-5772
PB - Wiley
DO - 10.1111/
UR - https://
LA - en
ER -
CSL-JSON
{
"id": "10.1111/
"type": "article-journal",
"title": "Changes in Aperiodic (1/
"container-title": "Psychophysiology",
"author": [
{
"family": "Tronelli",
"given": "Virginia"
},
{
"family": "Kałamała",
"given": "Patrycja"
},
{
"family": "Gratton",
"given": "Gabriele"
},
{
"family": "Fabiani",
"given": "Monica"
},
{
"family": "Gyurkovics",
"given": "Mate"
},
{
"family": "Low",
"given": "Kathy A"
},
{
"family": "Codispoti",
"given": "Maurizio"
},
{
"family": "De Cesarei",
"given": "Andrea"
}
],
"container-title-short":
"volume": "63",
"issue": "8",
"page": "e70376",
"DOI": "10.1111/
"PMID": "42568317",
"PMCID": "PMC13451924",
"ISSN": "0048-5772",
"publisher": "Wiley",
"URL": "https://
"language": "en",
"issued": {
"date-parts": [
[
2026,
8,
1
]
]
}
}
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.1111/psyp.70272 [code]
- How to Improve the Reliability of Aperiodic Parameter Estimates in M/
EEG: A Method Comparison. Journal: PsychophysiologyIn common: EEG, 15 references, 4 authors - [2] doi:10.1016/j.isci.2026.116936 [code]
- Beyond neural oscillations: Stress-related aperiodic activity and aperiodic-oscillatory spectral covariation.Journal: iScienceIn common: eegUtils, data.table, patchwork, 2 other tools, EEG, 5 references
- [3] doi:10.1111/ejn.70255 [code]
- A Systematic Review of Aperiodic Neural Activity in Clinical InvestigationsJournal: n/aIn common: EEG, 9 references
- [4] doi:10.1093/braincomms/fcag351 [code]
- Time-resolved aperiodic dynamics in event segmentation in attention-deficit/
hyperactivity disorder. Journal: Brain communicationsIn common: ggplot2, tidyverse, EEG, cognitive, 6 references - [5] doi:10.7554/elife.108673 [code]
- Adaptive behavior is guided by integrated representations of controlled and non-controlled information.Journal: eLifeIn common: EEG, 6 references
- [6] doi:10.1111/ejn.70543 [code]
- Neural Oscillations Track Subjective and Pupillary Arousal During Naturalistic Movie Viewing.Journal: The European journal of neuroscienceIn common: EEG, cognitive, 7 references
- [7] doi:10.1371/journal.pone.0328318
- Education shapes the link between EEG aperiodic components and cognitive aging.Journal: PloS oneIn common: EEG, 7 references
- [8] doi:10.3390/bioengineering13030323 [code]
- Scale-Free Neurodynamics as Functional Fingerprint of Brain Regions.Journal: Bioengineering (Basel, Switzerland)In common: 7 references
- [9] doi:10.1093/cercor/bhag113 [code]
- Long-term reliability and stability of parameterized resting state EEG: evidence from a five-year follow-up.Journal: Cerebral cortex (New York, N.Y. : 1991)In common: psych, ggplot2, tidyverse, EEG, 4 references
- [10] doi:10.1162/imag.a.1298 [code]
- Frontoparietal control-default mode connectivity predicts TMS effects on cognitive control.Journal: Imaging neuroscience (Cambridge, Mass.)In common: psych, data.table, patchwork, 2 other tools, cognitive, 1 reference
Contribute
The authors of this paper can claim it, correct its record and validate its tracing map, and the maintainers of its code (its owner, or a public member of its organization) correct what it says of their repository; anyone signed in can ask for its removal. Every request goes to OSCR's own machine, which answers it; your account page follows them.
Sign in with ORCID to claim this paper as one of its authors, correct its record or validate its tracing map: when the paper's metadata lists your ORCID iD, you are recognized at once. Maintainers of its code: sign in with GitHub, then claim the repository on your account page.
Claim this paper
Correct its record
Say what each link of this record is, remove the ones that are not the paper's, add the ones that are missing. The correction becomes a new version of the record, in its Versions section.
Validate its tracing map
You validate the map as this page shows it: 1 repository of the authors' code, each at its verified commit and with its license, 2 scripts, and 2 matches between paragraphs and code (see the Code and Map sections). It then receives a DOI on Zenodo, with you (your ORCID iD) and OSCR as its creators; the code itself is not deposited.
The map's fingerprint: sha256:fd0bad9dda29415b…
Add the badge to its README
The badge links the code to this page. Copy one of these into the README of the paper's code: only you decide where it goes, and nothing is changed for you.
Markdown
[.
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.
