Data Import and adjustments

Data import

# Inserting the full dataset
ParticipantFullData <- DataImport(current_experiment, current_environment, WholePptDiscard, ExcessEprimeTrials, ExcessLabChartTrials, TrialDiscard)

Experiment specific Data adjustments

# Count trials before filtering
trial_count_before <- nrow(ParticipantFullData)

# Apply filtering and transformation as usual
AdjustedFullData <- ParticipantFullData %>%
  mutate(
    cP2P = `RH P2P`,
    iP2P = `LH P2P`,
    cNoise = `RH P2P Prestim`,
    iNoise = `LH P2P Prestim`,
    StimNo = (Block - 1) * 50 + Trial,
    Cond = Predictable_stimulation
  ) %>%
  FilterNoisyPrestim() %>%
  CalcZ()

# Count trials after filtering
trial_count_after <- nrow(AdjustedFullData)

# Calculate number and percent of trials removed
trials_removed <- trial_count_before - trial_count_after
percent_removed <- (trials_removed / trial_count_before) * 100

# Print summary
cat("Trials excluded due to noise:", trials_removed, "\n")
## Trials excluded due to noise: 21
cat("Percent of trials excluded:", round(percent_removed, 2), "%\n")
## Percent of trials excluded: 2.63 %
# Finding condition-wise average of the z-value of the contralateral peak-to-peak amplitude for each participant. 
PATAverageData <- AdjustedFullData %>%
  group_by(Subject, Predictable_stimulation) %>%
  summarise(across(where(is.numeric), mean, na.rm = TRUE),
            across(where(is.character), first), .groups = "keep") %>%
  select(Subject, Predictable_stimulation, StimIntensity, Age, Gender, Handedness,
         cP2PPeakTime = `RH MEP peak time`, cP2P,
         ZcP2P)

#Average
PATAverageData %>%
  group_by(Subject) %>%
  summarise(mean_handedness = mean(Handedness, na.rm = TRUE)) %>%
  summarise(
    overall_mean = mean(mean_handedness),
    overall_se = sd(mean_handedness) / sqrt(n())
  )
## # A tibble: 1 × 2
##   overall_mean overall_se
##          <dbl>      <dbl>
## 1           79       3.30
AdjustedFullData %>%
  group_by(Subject) %>%
  summarise(mean_stim = mean(StimIntensity, na.rm = TRUE)) %>%
  summarise(
    overall_mean = mean(mean_stim),
    overall_se = sd(mean_stim) / sqrt(n())
  )
## # A tibble: 1 × 2
##   overall_mean overall_se
##          <dbl>      <dbl>
## 1         52.6       2.25

Raw Data Import

Overwrite <- 0
frequencies <- c(0)  # Define your frequencies (used early in the experiment to check for errors for differen frequencies)
ExecMultiplePptRawToAverageRaw(current_environment, AdjustedFullData, current_experiment, Overwrite, WholePptDiscard, frequencies, TimeFrom = "-3.5", TimeTo = "5.5")

frequency <- 20
MEPSummary <- RawDataSummary(current_environment, WholePptDiscard, frequency)
# LH P2P Prestim 1500-5 RH P2P Prestim 1500-5 data missing from adjusted raw data. It's all good since all of the data is in the MEPSummary anyway

folder_path <- paste(current_environment,"/pre-analysis export/Highpass 20/LabChart Averaged Full", sep = "")

# Create an empty list to cache raw files so that you don't re-read the same file repeatedly.
raw_data_cache <- list()

# Create a logical vector to mark rows that have matching raw data.
has_data <- rep(TRUE, nrow(AdjustedFullData))

# Loop over each row in AdjustedFullData.
# Loop over each row in AdjustedFullData
for(i in seq_len(nrow(AdjustedFullData))){
  
  # Extract trial info from AdjustedFullData
  expName <- AdjustedFullData$ExperimentName[i]
  subj    <- AdjustedFullData$Subject[i]
  session <- AdjustedFullData$Session[i]
  block   <- AdjustedFullData$Block[i]
  trial   <- AdjustedFullData$Trial[i]   # StimNo is assumed to be the same as Trial
  cond    <- AdjustedFullData$Cond[i]
  
  # Construct the file name; e.g., "PAT_1_001 Edited Raw.csv" for subject 1.
  subj_str  <- sprintf("%03d", subj)
  file_name <- paste0(expName, "_", subj_str, " Edited Raw.csv")
  file_path <- file.path(folder_path, file_name)
  
  # Read the raw file if not already cached.
  if (!file_name %in% names(raw_data_cache)) {
    if (file.exists(file_path)) {
      raw_data <- read.csv(file_path, stringsAsFactors = FALSE)
      raw_data_cache[[file_name]] <- raw_data
    } else {
      warning("File not found: ", file_path, ". Skipping trial ", i)
      AdjustedFullData$`LH P2P Prestim 1500-5`[i] <- NA
      AdjustedFullData$`RH P2P Prestim 1500-5`[i] <- NA
      AdjustedFullData$`LH P2P Prestim 3000-1500`[i] <- NA
      AdjustedFullData$`RH P2P Prestim 3000-1500`[i] <- NA
      has_data[i] <- FALSE
      next
    }
  } else {
    raw_data <- raw_data_cache[[file_name]]
  }
  
  # Ensure key columns are numeric.
  raw_data$Session <- as.numeric(raw_data$Session)
  raw_data$Block   <- as.numeric(raw_data$Block)
  raw_data$StimNo  <- as.numeric(raw_data$StimNo)
  
  ### Filter the raw data for the two prestimulus windows
  
  # 1. For the 1500-5 window: time between -1.5 and -0.0005 seconds.
  trial_data_1500 <- raw_data %>%
    filter(Session == session,
           Block   == block,
           StimNo  == trial,
           Cond    == cond,
           Time    >= -1.5,
           Time    <= -0.0005)
  
  # 2. For the 3000-1500 window: time between -3.0 and -1.5 seconds.
  trial_data_3000 <- raw_data %>%
    filter(Session == session,
           Block   == block,
           StimNo  == trial,
           Cond    == cond,
           Time    >= -3.0,
           Time    <= -1.5)
  
  # Check that data exist in both time windows.
  if(nrow(trial_data_1500) == 0 || nrow(trial_data_3000) == 0) {
    warning("No data found for: ", file_name, 
            " with Session=", session, ", Block=", block, 
            ", StimNo=", trial, ", Cond=", cond, 
            " in one or both time windows.")
    AdjustedFullData$`LH P2P Prestim 1500-5`[i] <- NA
    AdjustedFullData$`RH P2P Prestim 1500-5`[i] <- NA
    AdjustedFullData$`LH P2P Prestim 3000-1500`[i] <- NA
    AdjustedFullData$`RH P2P Prestim 3000-1500`[i] <- NA
    has_data[i] <- FALSE
  } else {
    # Compute peak-to-peak amplitudes for the -1.5 to -0.0005 window.
    LH_p2p_1500 <- max(trial_data_1500$LH, na.rm = TRUE) - min(trial_data_1500$LH, na.rm = TRUE)
    RH_p2p_1500 <- max(trial_data_1500$RH, na.rm = TRUE) - min(trial_data_1500$RH, na.rm = TRUE)
    
    # Compute peak-to-peak amplitudes for the -3.0 to -1.5 window.
    LH_p2p_3000 <- max(trial_data_3000$LH, na.rm = TRUE) - min(trial_data_3000$LH, na.rm = TRUE)
    RH_p2p_3000 <- max(trial_data_3000$RH, na.rm = TRUE) - min(trial_data_3000$RH, na.rm = TRUE)
    
    # Update the corresponding columns in AdjustedFullData.
    AdjustedFullData$`LH P2P Prestim 1500-5`[i]    <- LH_p2p_1500
    AdjustedFullData$`RH P2P Prestim 1500-5`[i]    <- RH_p2p_1500
    AdjustedFullData$`LH P2P Prestim 3000-1500`[i]  <- LH_p2p_3000
    AdjustedFullData$`RH P2P Prestim 3000-1500`[i]  <- RH_p2p_3000
  }
}

# Remove extra rows from AdjustedFullData that did not have matching raw data.
num_removed <- sum(!has_data)
if(num_removed > 0) {
  AdjustedFullData <- AdjustedFullData[has_data, ]
}

Data analysis

Raw Data Analysis

# Define your time window to replace
tms_start <- 0  # in ms
tms_window <- c(0, 6)  # from 0 ms to +6 ms
sampling_rate <- 2000  # Hz
time_step <- 1 / sampling_rate * 1000  # convert to ms

# Indices to interpolate (inclusive)
interpolation_window <- seq(tms_window[1], tms_window[2], by = time_step)

MEPSummary_interp <- MEPSummary %>%
  group_by(Subject, Session, Cond) %>%
  mutate(
    Contralateral = approx(
      x = Time[!Time %in% interpolation_window],
      y = Contralateral[!Time %in% interpolation_window],
      xout = Time,
      rule = 2
    )$y,
    Ipsilateral = approx(
      x = Time[!Time %in% interpolation_window],
      y = Ipsilateral[!Time %in% interpolation_window],
      xout = Time,
      rule = 2
    )$y
  ) %>%
  ungroup()

# Average post-interpolation
grouped_data_interp <- MEPSummary_interp %>%
  group_by(Cond, Time) %>%
  summarize(
    Contralateral = mean(Contralateral, na.rm = TRUE),
    Ipsilateral = mean(Ipsilateral, na.rm = TRUE),
    .groups = "drop"
  )

# Plot
generate_raw_plot(
  data = grouped_data_interp,
  cond_levels = c("Yes", "No"),
  plot_type = "group",
  frequency = frequency,
  plot_title = "Predictable Stimulation",
  TimeFrom = 0.0,
  TimeTo = 0.04
)

Demographics

# Custom function for power calculation and epsilon adjustment
repeated_measures_power <- function(num_subjects, num_levels_hand, num_levels_condition, 
                                    f_effect_size, sig_level = 0.05, power = 0.80, corr = 0.5) {
  # num_subjects: Number of participants
  # num_levels_hand: Number of levels for the Hand factor
  # num_levels_condition: Number of levels for the Condition factor
  # f_effect_size: Cohen's f effect size
  # corr: Within-subject correlation
  
  # Total repeated measures (product of both factors)
  num_measurements <- num_levels_hand * num_levels_condition
  
  # Calculate epsilon adjustment
  epsilon_adjustment <- sqrt((1 + (num_measurements - 1) * corr) / num_measurements)
  
  # Adjusted effect size
  f_adj <- f_effect_size / epsilon_adjustment
  
  # Calculate required sample size using pwr.anova.test
  power_result <- pwr.anova.test(k = num_measurements, f = f_adj, sig.level = sig_level, power = power)
  
  # Output results
  cat("Power Calculation for Two-Way Repeated-Measures ANOVA (Fully Within-Subjects):\n")
  cat("Number of Participants:", num_subjects, "\n")
  cat("Number of Levels for Hand Factor:", num_levels_hand, "\n")
  cat("Number of Levels for Condition Factor:", num_levels_condition, "\n")
  cat("Within-Subject Correlation:", corr, "\n")
  cat("Adjusted Effect Size (f):", round(f_adj, 3), "\n\n")
  print(power_result)
  
  # Return key calculations
  list(
    num_measurements = num_measurements,
    epsilon_adjustment = epsilon_adjustment,
    adjusted_effect_size = f_adj,
    power_result = power_result
  )
}

# Parameters
num_subjects <- 20          # Total number of participants
num_levels_hand <- 2        # Two levels: Contralateral, Ipsilateral
num_levels_condition <- 2   # 2 visual conditions
f_effect_size <- 0.3      # Adjusted effect size
sig_level <- 0.05           # Alpha level
power <- 0.80               # Desired power
corr <- 0.5                 # Assumed within-subject correlation

# Run the function
results <- repeated_measures_power(num_subjects, num_levels_hand, num_levels_condition, 
                                    f_effect_size, sig_level, power, corr)
## Power Calculation for Two-Way Repeated-Measures ANOVA (Fully Within-Subjects):
## Number of Participants: 20 
## Number of Levels for Hand Factor: 2 
## Number of Levels for Condition Factor: 2 
## Within-Subject Correlation: 0.5 
## Adjusted Effect Size (f): 0.379 
## 
## 
##      Balanced one-way analysis of variance power calculation 
## 
##               k = 4
##               n = 19.93247
##               f = 0.3794733
##       sig.level = 0.05
##           power = 0.8
## 
## NOTE: n is number in each group
# Are latency influenced by predictable stimulation?

# Calculate the mean cP2P peak time for each level of Predictable_stimulation
mean_cP2P_peak_time <- PATAverageData %>%
  group_by(Predictable_stimulation) %>%
  summarise(mean_cP2P_peak_time = mean(cP2PPeakTime, na.rm = TRUE))


# Summary statistics
summary_stats_peak_time <- PATAverageData %>%
  group_by(Predictable_stimulation) %>%
  summarise(mean_cP2P_peak_time = mean(cP2PPeakTime, na.rm = TRUE),
            sd_cP2P_peak_time = sd(cP2PPeakTime, na.rm = TRUE),
            n = n())

print(summary_stats_peak_time)
## # A tibble: 2 × 4
##   Predictable_stimulation mean_cP2P_peak_time sd_cP2P_peak_time     n
##   <chr>                                 <dbl>             <dbl> <int>
## 1 No                                   0.0272           0.00171    20
## 2 Yes                                  0.0273           0.00156    20
# Check for normality using Shapiro-Wilk test
shapiro_test <- PATAverageData %>%
  group_by(Predictable_stimulation) %>%
  summarise(p_value = shapiro.test(cP2PPeakTime)$p.value)
# Check for homogeneity of variances using Levene's Test
levene_test <- leveneTest(cP2PPeakTime ~ Predictable_stimulation, data = PATAverageData)

# Perform t-test if assumptions are met
if (all(shapiro_test$p_value > 0.05) && levene_test$`Pr(>F)`[1] > 0.05) {
  t_test <- t.test(cP2PPeakTime ~ Predictable_stimulation, data = PATAverageData)
  print(t_test)
} else {
  # Perform Mann-Whitney U test if assumptions are not met
  wilcox_test <- wilcox.test(cP2PPeakTime ~ Predictable_stimulation, data = PATAverageData)
  print(wilcox_test)
}
## 
##  Welch Two Sample t-test
## 
## data:  cP2PPeakTime by Predictable_stimulation
## t = -0.23405, df = 37.692, p-value = 0.8162
## alternative hypothesis: true difference in means between group No and group Yes is not equal to 0
## 95 percent confidence interval:
##  -0.0011686818  0.0009265152
## sample estimates:
##  mean in group No mean in group Yes 
##        0.02721203        0.02733312
run_emg_stats <- function(data, emg_col, label) {
  cat("\n===== Processing:", label, "=====\n")

  # Aggregate per participant per condition
  agg_data <- data %>%
    group_by(Subject, Predictable_stimulation) %>%
    summarise(avg_emg = mean(.data[[emg_col]], na.rm = TRUE)) %>%
    ungroup()
  
  # Shapiro-Wilk test output as text
  cat("\nShapiro-Wilk Test Results:\n")
  for (cond in unique(agg_data$Predictable_stimulation)) {
    emg_vals <- agg_data$avg_emg[agg_data$Predictable_stimulation == cond]
    shapiro_res <- shapiro.test(emg_vals)
    cat(paste("Condition:", cond, "| W =", round(shapiro_res$statistic, 4), 
              "| p =", signif(shapiro_res$p.value, 4), "\n"))
  }

  # Levene’s Test
  cat("\nLevene’s Test Result:\n")
  levene_result <- leveneTest(avg_emg ~ Predictable_stimulation, data = agg_data)
  print(levene_result)
  
  # Decide test based on assumptions
  shapiro_ok <- all(sapply(unique(agg_data$Predictable_stimulation), function(cond) {
    shapiro.test(agg_data$avg_emg[agg_data$Predictable_stimulation == cond])$p.value > 0.05
  }))
  levene_ok <- levene_result[1, "Pr(>F)"] > 0.05

  if (shapiro_ok && levene_ok) {
    cat("\nAssumptions met → Running t-test\n")
    t_result <- t.test(avg_emg ~ Predictable_stimulation, data = agg_data)
    print(t_result)
  } else {
    cat("\nAssumptions violated → Running Wilcoxon test\n")
    w_result <- wilcox.test(avg_emg ~ Predictable_stimulation, data = agg_data)
    print(w_result)
  }
}

# -1500 to -5 ms window
run_emg_stats(AdjustedFullData, "RH P2P Prestim 1500-5", "-1500 to -5 ms window")
## 
## ===== Processing: -1500 to -5 ms window =====
## `summarise()` has grouped output by 'Subject'. You can override using the
## `.groups` argument.
## 
## Shapiro-Wilk Test Results:
## Condition: No | W = 0.91 | p = 0.06366 
## Condition: Yes | W = 0.9538 | p = 0.4281 
## 
## Levene’s Test Result:
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group  1  0.0497 0.8248
##       38               
## 
## Assumptions met → Running t-test
## 
##  Welch Two Sample t-test
## 
## data:  avg_emg by Predictable_stimulation
## t = 0.61464, df = 37.666, p-value = 0.5425
## alternative hypothesis: true difference in means between group No and group Yes is not equal to 0
## 95 percent confidence interval:
##  -0.007738032  0.014482641
## sample estimates:
##  mean in group No mean in group Yes 
##        0.04543145        0.04205914
# -3000 to -1500 ms window
run_emg_stats(AdjustedFullData, "RH P2P Prestim 3000-1500", "-3000 to -1500 ms window")
## 
## ===== Processing: -3000 to -1500 ms window =====
## `summarise()` has grouped output by 'Subject'. You can override using the
## `.groups` argument.
## 
## Shapiro-Wilk Test Results:
## Condition: No | W = 0.6815 | p = 2.338e-05 
## Condition: Yes | W = 0.7963 | p = 0.0007615 
## 
## Levene’s Test Result:
## Levene's Test for Homogeneity of Variance (center = median)
##       Df F value Pr(>F)
## group  1  0.5958 0.4449
##       38               
## 
## Assumptions violated → Running Wilcoxon test
## 
##  Wilcoxon rank sum exact test
## 
## data:  avg_emg by Predictable_stimulation
## W = 221, p-value = 0.5831
## alternative hypothesis: true location shift is not equal to 0
differencesRaw <- PATAverageData$cP2P[PATAverageData$Predictable_stimulation == "No"] -
               PATAverageData$cP2P[PATAverageData$Predictable_stimulation == "Yes"]
shapiro.test(differencesRaw)
## 
##  Shapiro-Wilk normality test
## 
## data:  differencesRaw
## W = 0.93102, p-value = 0.1616
differencesZ <- PATAverageData$ZcP2P[PATAverageData$Predictable_stimulation == "No"] -
               PATAverageData$ZcP2P[PATAverageData$Predictable_stimulation == "Yes"]
shapiro.test(differencesZ)
## 
##  Shapiro-Wilk normality test
## 
## data:  differencesZ
## W = 0.98082, p-value = 0.9443
# Perform t-test on ZcP2P with respect to different factors
PredictabilityTTestZ <- t.test(
  PATAverageData$ZcP2P[PATAverageData$Predictable_stimulation == "No"], 
  PATAverageData$ZcP2P[PATAverageData$Predictable_stimulation == "Yes"], 
  paired = TRUE
)
PredictabilityTTestZ
## 
##  Paired t-test
## 
## data:  PATAverageData$ZcP2P[PATAverageData$Predictable_stimulation == "No"] and PATAverageData$ZcP2P[PATAverageData$Predictable_stimulation == "Yes"]
## t = 4.1514, df = 19, p-value = 0.0005423
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
##  0.1815736 0.5508418
## sample estimates:
## mean difference 
##       0.3662077
PredictabilityTTest <- t.test(
  PATAverageData$cP2P[PATAverageData$Predictable_stimulation == "No"], 
  PATAverageData$cP2P[PATAverageData$Predictable_stimulation == "Yes"], 
  paired = TRUE
)
PredictabilityTTest
## 
##  Paired t-test
## 
## data:  PATAverageData$cP2P[PATAverageData$Predictable_stimulation == "No"] and PATAverageData$cP2P[PATAverageData$Predictable_stimulation == "Yes"]
## t = 3.6931, df = 19, p-value = 0.001544
## alternative hypothesis: true mean difference is not equal to 0
## 95 percent confidence interval:
##  0.07722638 0.27926608
## sample estimates:
## mean difference 
##       0.1782462
# Effect Sizes
# Load the package
library(effectsize)

# Compute Cohen's d for paired data (raw MEP amplitudes)
PATAverageData_wide <- PATAverageData %>%
  select(Subject, Predictable_stimulation, cP2P) %>%
  tidyr::pivot_wider(names_from = Predictable_stimulation, values_from = cP2P)

# Compute Cohen's d for paired data
cohens_d_result <- effectsize::cohens_d(PATAverageData_wide$No, PATAverageData_wide$Yes, paired = TRUE)
## For paired samples, 'repeated_measures_d()' provides more options.
print(cohens_d_result)
## Cohen's d |       95% CI
## ------------------------
## 0.83      | [0.31, 1.33]
# Calculate mean and standard error
descriptives_cP2P <- PATAverageData %>%
  group_by(Predictable_stimulation) %>%
  summarize(
    Mean_cP2P = mean(cP2P, na.rm = TRUE),
    SE_cP2P = sd(cP2P, na.rm = TRUE) / sqrt(n()),
    n = n(),
    .groups = "drop"
  )

Plotting graphs

# Calculate mean and standard error for ZcP2P
summary_data <- PATAverageData %>%
  group_by(Predictable_stimulation) %>%
  summarise(mean_ZcP2P = mean(ZcP2P, na.rm = TRUE),
            se_ZcP2P = sd(ZcP2P, na.rm = TRUE) / sqrt(n()))

# Find the maximum ZcP2P value to position the significance line above it
max_jitter <- max(PATAverageData$ZcP2P, na.rm = TRUE)
line_position <- max_jitter + 0.2

# Adjusted plot: Boxplot with jittered data points
plot <- ggplot(PATAverageData, aes(x = Predictable_stimulation, y = ZcP2P, fill = Predictable_stimulation)) +
  
  # Boxplot to display median and variability
  geom_boxplot(width = 0.4, alpha = 0.7, outlier.shape = NA) +
  
  # Jittered points for individual data
  geom_jitter(width = 0.1, size = 1.5, color = "black", alpha = 0.7) +
  
  # Significance line and asterisk
  geom_segment(aes(x = 1, xend = 2, y = max(ZcP2P, na.rm = TRUE) + 0.2, yend = max(ZcP2P, na.rm = TRUE) + 0.2)) +
  annotate("text", x = 1.5, y = max(PATAverageData$ZcP2P, na.rm = TRUE) + 0.25, label = "***", size = 6) +
  
  # Customize visuals
  scale_fill_manual(values = c("red", "orange")) +
  labs(x = "Predictable Stimulation", y = "MEP Amplitude (z-scores)") +
  geom_hline(yintercept = 0, linetype = "dashed") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white", color = NA),
        plot.background = element_rect(fill = "white", color = NA))

# Display and save the plot
print(plot)

ggsave("figure/MEP_Amplitude_Boxplot.png", plot, width = 4, height = 3)
# Calculate mean and standard error for cP2P
summary_data_raw <- PATAverageData %>%
  group_by(Predictable_stimulation) %>%
  summarise(mean_cP2P = mean(cP2P, na.rm = TRUE),
            se_cP2P = sd(cP2P, na.rm = TRUE) / sqrt(n()))

# Find the max cP2P value to place significance line
max_jitter_raw <- max(PATAverageData$cP2P, na.rm = TRUE)
line_position_raw <- max_jitter_raw + 0.05  # adjust as needed

# Plot for raw cP2P
plot_raw <- ggplot(PATAverageData, aes(x = Predictable_stimulation, y = cP2P, fill = Predictable_stimulation)) +
  geom_boxplot(width = 0.4, alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.1, size = 1.5, color = "black", alpha = 0.7) +
  geom_segment(aes(x = 1, xend = 2, y = line_position_raw, yend = line_position_raw)) +
  annotate("text", x = 1.5, y = line_position_raw + 0.02, label = "**", size = 6) +
  scale_fill_manual(values = c("red", "orange")) +
  labs(x = "Predictable Stimulation", y = "MEP Amplitude (mV)") +
  theme_minimal(base_size = 12) +
  theme(legend.position = "none",
        panel.background = element_rect(fill = "white", color = NA),
        plot.background = element_rect(fill = "white", color = NA))

# Display and save
print(plot_raw)

ggsave("figure/MEP_Amplitude_Boxplot_Raw.png", plot_raw, width = 4, height = 3)

Post hoc

lm_model <- lm(cP2P ~ Predictable_stimulation + StimIntensity + Age + Gender + Handedness , data = PATAverageData)
summary(lm_model)
## 
## Call:
## lm(formula = cP2P ~ Predictable_stimulation + StimIntensity + 
##     Age + Gender + Handedness, data = PATAverageData)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.69868 -0.32918 -0.05178  0.16202  0.96823 
## 
## Coefficients:
##                             Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 3.743391   0.658146   5.688 2.42e-06 ***
## Predictable_stimulationYes -0.178246   0.140104  -1.272  0.21218    
## StimIntensity              -0.030559   0.008917  -3.427  0.00165 ** 
## Age                         0.006835   0.021664   0.316  0.75436    
## GenderF                    -0.161489   0.339934  -0.475  0.63787    
## GenderM                    -0.070461   0.164397  -0.429  0.67100    
## Handedness                 -0.017124   0.005605  -3.055  0.00443 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.443 on 33 degrees of freedom
## Multiple R-squared:  0.4036, Adjusted R-squared:  0.2952 
## F-statistic: 3.722 on 6 and 33 DF,  p-value: 0.006165
lm_model_Z <- lm(ZcP2P ~ Predictable_stimulation + StimIntensity + Age + Gender + Handedness , data = PATAverageData)
summary(lm_model_Z)
## 
## Call:
## lm(formula = ZcP2P ~ Predictable_stimulation + StimIntensity + 
##     Age + Gender + Handedness, data = PATAverageData)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.46117 -0.12574 -0.01003  0.13750  0.47430 
## 
## Coefficients:
##                              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)                 0.1167213  0.3155082   0.370    0.714    
## Predictable_stimulationYes -0.3662077  0.0671645  -5.452 4.85e-06 ***
## StimIntensity               0.0011537  0.0042748   0.270    0.789    
## Age                        -0.0013453  0.0103856  -0.130    0.898    
## GenderF                     0.0154054  0.1629607   0.095    0.925    
## GenderM                     0.0228906  0.0788103   0.290    0.773    
## Handedness                  0.0004134  0.0026871   0.154    0.879    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.2124 on 33 degrees of freedom
## Multiple R-squared:  0.4752, Adjusted R-squared:  0.3798 
## F-statistic:  4.98 on 6 and 33 DF,  p-value: 0.0009937