library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.1     ✔ stringr   1.5.2
## ✔ ggplot2   4.0.0     ✔ tibble    3.3.0
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.1.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(lme4)
## Loading required package: Matrix
## 
## Attaching package: 'Matrix'
## 
## The following objects are masked from 'package:tidyr':
## 
##     expand, pack, unpack
library(lmerTest)
## 
## Attaching package: 'lmerTest'
## 
## The following object is masked from 'package:lme4':
## 
##     lmer
## 
## The following object is masked from 'package:stats':
## 
##     step
library(ggplot2)
library(ggeffects)
library(dplyr)
library(patchwork)
library(emmeans)
## Welcome to emmeans.
## Caution: You lose important information if you filter this package's results.
## See '? untidy'
library(scales)
## 
## Attaching package: 'scales'
## 
## The following object is masked from 'package:purrr':
## 
##     discard
## 
## The following object is masked from 'package:readr':
## 
##     col_factor
library(cluster)
library(factoextra)
## Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(tidyr)
library(broom)
library(plotly)
## 
## Attaching package: 'plotly'
## 
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## 
## The following object is masked from 'package:stats':
## 
##     filter
## 
## The following object is masked from 'package:graphics':
## 
##     layout
# Configuration (must match Python script settings)
PARTICIPANT_IDS <- c(2, 3, 4, 5, 7, 8, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 22, 23) # Placeholder for the participant IDs being analyzed
BASE_XSENS_DIR <- "/Users/vivi/UT/Thesis/Data/Xsens/Participants"
LYE_FAILURE_SENTINEL <- -9999.0 # Value used by the Python script for failed LLE calculations
load_lyap_data <- function(pid, period) {
  period_to_folder_map <- list(
    "prep" = "Movement Preparation Period",
    "exec" = "Movement Execution Period"
  )
  period_to_name_map <- list(
    "prep" = "Prep",
    "exec" = "Exec"
  )
  
  lyap_col_name <- paste0("Lyap_", period)
  
  folder_name <- period_to_folder_map[[period]]
  name_part <- period_to_name_map[[period]]
  
  file_name <- paste0("ID", pid, "_", name_part, "_LyE.csv")
  file_path <- file.path(BASE_XSENS_DIR, folder_name, file_name)
  
  if (!file.exists(file_path)) {
    stop(paste("Error: Data file not found:", file_path))
  }
  
  #message(paste("Loading data from:", file_path))
  
  df <- read_csv(file_path, show_col_types = FALSE)

  if (!(lyap_col_name %in% names(df))) {
    stop(paste("Error: Expected column", lyap_col_name, "not found in file:", file_name))
  }
    
  df <- df %>%
    # Filter out LLE failures (where Python used the sentinel value)
    filter(.data[[lyap_col_name]] != LYE_FAILURE_SENTINEL) %>%
    mutate(
      Subject = as.factor(Subject),
      Block = as.factor(Block),
      Trial = as.factor(Trial),
      Difficulty = as.factor(Sequence),
      Trial_RT = trial.RTS, 
      COM_acc = as.character(COM_acc)
    )
  
    df <- df %>%
      arrange(Subject, Block, Trial) %>%
      group_by(Subject) %>%
      mutate(Total_Trial = row_number()) %>% 
      ungroup() %>%
      mutate(log_RT = log(Trial_RT)) %>%
      mutate(
        Phase = case_when(
          Block %in% 1:3 ~ "Learning",
          Block == 4 ~ "Retention",
          Block == 5 ~ "Transfer",
          TRUE ~ "Other" # Safety net
          ),
        Phase = factor(Phase, levels = c("Learning", "Retention", "Transfer"))) %>%
      select(Subject, Block, Phase, Trial, Difficulty, Trial_RT, log_RT, Trial_Acc, COM_acc, all_of(lyap_col_name), Total_Trial)
}

# List to hold data for all participants
all_prep_data_list <- list()
all_exec_data_list <- list()

for (pid in PARTICIPANT_IDS) {
  # Temporarily set the current PID for the function 
  current_prep <- load_lyap_data(pid, "prep")
  current_exec <- load_lyap_data(pid, "exec")
  
  all_prep_data_list[[as.character(pid)]] <- current_prep
  all_exec_data_list[[as.character(pid)]] <- current_exec
}

# Combine all data frames
data_prep_combined <- bind_rows(all_prep_data_list)
data_exec_combined <- bind_rows(all_exec_data_list)

# 2. Prepare Execution Data 
data_exec_renamed <- data_exec_combined %>%
    select(Subject, Block, Trial, Lyap_exec, COM_acc) %>%
    rename(COM_acc_Exec = COM_acc)

# 3. Prepare Preparation Data 
data_prep_renamed <- data_prep_combined %>%
    select(Subject, Block, Trial, Phase, Difficulty, Total_Trial, 
           Trial_RT, log_RT, Trial_Acc, Lyap_prep, COM_acc) %>%
    rename(COM_acc_Prep = COM_acc)

# 4. Final Join and Standardization
data_all_combined <- data_prep_renamed %>%
    left_join(data_exec_renamed, by = c("Subject", "Block", "Trial")) %>%
    mutate(PE = (100 - Trial_Acc)/100)

sd_rt_global <- sd(data_all_combined$Trial_RT, na.rm = TRUE)
sd_pe_global <- sd(data_all_combined$PE, na.rm = TRUE)
LISAS_weight <- sd_rt_global / sd_pe_global

data_all_combined <- data_all_combined %>%
  mutate(LISAS = Trial_RT + (PE *  LISAS_weight)) 

data_all_learning <- data_all_combined %>% filter(Phase == "Learning")
data_all_testing <- data_all_combined %>% filter(Phase %in% c("Retention", "Transfer"))
data_all_retention <- data_all_combined %>% filter(Phase == "Retention")
data_all_transfer <- data_all_combined %>% filter(Phase == "Transfer")
data_all_lr <- data_all_combined %>% filter(Phase %in% c("Learning", "Retention"))
model_LISAS_learn <- lmer(LISAS ~ Difficulty + (1 | Subject), data = data_all_learning)
summary(model_LISAS_learn)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: LISAS ~ Difficulty + (1 | Subject)
##    Data: data_all_learning
## 
## REML criterion at convergence: 3173.6
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -2.0055 -0.6145 -0.3021  0.3345 10.6325 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Subject  (Intercept) 0.0843   0.2904  
##  Residual             0.2067   0.4546  
## Number of obs: 2449, groups:  Subject, 18
## 
## Fixed effects:
##               Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)  6.642e-01  7.020e-02 1.816e+01   9.462 1.91e-08 ***
## Difficulty12 8.724e-02  2.213e-02 2.429e+03   3.942 8.30e-05 ***
## Difficulty18 1.610e-01  2.272e-02 2.429e+03   7.084 1.83e-12 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Dffc12
## Difficlty12 -0.157       
## Difficlty18 -0.153  0.486
anova(model_LISAS_learn)
## Type III Analysis of Variance Table with Satterthwaite's method
##            Sum Sq Mean Sq NumDF DenDF F value    Pr(>F)    
## Difficulty 10.438  5.2188     2  2429  25.253 1.398e-11 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emmeans(model_LISAS_learn, specs = ~ Difficulty, cov.reduce = range)
##  Difficulty emmean     SE   df lower.CL upper.CL
##  6           0.664 0.0702 18.2    0.517    0.812
##  12          0.751 0.0702 18.2    0.604    0.899
##  18          0.825 0.0704 18.4    0.678    0.973
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95
model_LISAS_test <- lmer(LISAS ~ Difficulty * Block + (1 | Subject), data = data_all_testing)
summary(model_LISAS_test)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: LISAS ~ Difficulty * Block + (1 | Subject)
##    Data: data_all_testing
## 
## REML criterion at convergence: 1793.7
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -1.9505 -0.6284 -0.2779  0.3787  5.7532 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Subject  (Intercept) 0.05899  0.2429  
##  Residual             0.16219  0.4027  
## Number of obs: 1674, groups:  Subject, 18
## 
## Fixed effects:
##                      Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)         5.578e-01  6.224e-02 2.241e+01   8.963 7.27e-09 ***
## Difficulty12        5.816e-02  3.435e-02 1.651e+03   1.693  0.09065 .  
## Difficulty18        1.508e-01  3.426e-02 1.651e+03   4.400 1.15e-05 ***
## Block5              1.869e-01  3.417e-02 1.651e+03   5.468 5.24e-08 ***
## Difficulty12:Block5 1.408e-01  4.828e-02 1.651e+03   2.916  0.00359 ** 
## Difficulty18:Block5 1.129e-01  4.824e-02 1.651e+03   2.339  0.01944 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Dffc12 Dffc18 Block5 D12:B5
## Difficlty12 -0.279                            
## Difficlty18 -0.280  0.507                     
## Block5      -0.281  0.508  0.510              
## Dffclt12:B5  0.199 -0.712 -0.361 -0.708       
## Dffclt18:B5  0.199 -0.360 -0.710 -0.709  0.502
anova(model_LISAS_test)
## Type III Analysis of Variance Table with Satterthwaite's method
##                  Sum Sq Mean Sq NumDF DenDF  F value    Pr(>F)    
## Difficulty       12.196  6.0978     2  1651  37.5960 < 2.2e-16 ***
## Block            30.820 30.8198     1  1651 190.0199 < 2.2e-16 ***
## Difficulty:Block  1.546  0.7730     2  1651   4.7661  0.008631 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
emmeans(model_LISAS_test, specs = ~ Difficulty, cov.reduce = range)
## NOTE: Results may be misleading due to involvement in interactions
##  Difficulty emmean     SE df lower.CL upper.CL
##  6           0.651 0.0597 19    0.526    0.776
##  12          0.780 0.0597 19    0.655    0.905
##  18          0.858 0.0597 19    0.733    0.983
## 
## Results are averaged over the levels of: Block 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95
plot_data_LISAS_raw <- data_all_combined %>%
  group_by(Block, Difficulty) %>%
  summarise(
    Num_Trial = as.numeric(Trial),
    LISAS = as.numeric(LISAS),
    mean_LISAS = mean(LISAS, na.rm = TRUE),
    sd_LISAS = sd(LISAS, na.rm = TRUE),
    n = n(),
    se_LISAS = sd_LISAS / sqrt(n)
  )
## Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
## dplyr 1.1.0.
## ℹ Please use `reframe()` instead.
## ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
##   always returns an ungrouped data frame and adjust accordingly.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `summarise()` has grouped output by 'Block', 'Difficulty'. You can override
## using the `.groups` argument.
block_names <- c(
  "1" = "Block 1: Learning",
  "2" = "Block 2: Learning",
  "3" = "Block 3: Learning",
  "4" = "Block 4: Retention",
  "5" = "Block 5: Transfer"
)

p_LISAS_raw <- ggplot(plot_data_LISAS_raw, aes(x = Num_Trial, y = LISAS, color = Difficulty, fill = Difficulty)) +
  geom_boxplot(alpha = 0.7, outlier.shape = NA) +
  geom_jitter(width = 0.2, alpha = 0.1) +
  facet_wrap(~ Block, labeller = as_labeller(block_names)) +
  scale_x_continuous(breaks = c(12, 24, 36, 48)) +
  labs(
    title = "Performance Across Learning, Retention, and Transfer Blocks",
    x = "Trial Number",
    y = "LISAS"
    #color = "Difficulty"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "bold"),
    axis.title = element_text(size = 14),
    legend.position = "bottom"
  )




plot_data_LISAS_block <- data_all_combined %>%
  group_by(Block) %>%
  summarise(
    mean_LISAS = mean(LISAS, na.rm = TRUE),
    sd_LISAS = sd(LISAS, na.rm = TRUE),
    n = n(),
    se_LISAS = sd_LISAS / sqrt(n)
  )

p_LISAS_block <- ggplot(plot_data_LISAS_block, aes(x = as.factor(Block), y =  mean_LISAS)) +
  geom_vline(xintercept = 3.5, color = "red", linewidth = 1) +
  geom_errorbar(aes(ymin =  mean_LISAS - se_LISAS, 
                    ymax =  mean_LISAS + se_LISAS), 
                width = 0.2, color = "darkblue", linewidth = 0.8) +
  geom_point(size = 4, color = "darkblue") +
  labs(
    title = "LISAS ~ Block",
    x = "Block",
    y = "Mean LISAS"
  ) +
  theme_classic() +
  theme(
    plot.title = element_text(hjust = 0.5, size = 16, face = "plain"),
    axis.title = element_text(size = 14),
    axis.text = element_text(size = 12)
  )

p_LISAS_raw

p_LISAS_block

Individual learning curves

# 1. Prepare Data
# Filter data to only include the Learning Phase (Blocks 1-3)
# Ensure Total_Trial is numeric and Subject and Difficulty are factors
data_learning_individual <- data_all_learning %>%
  mutate(
    Trial = as.numeric(Trial),
    Total_Trial = as.numeric(Total_Trial),
    Subject = as.factor(Subject),
    Difficulty = as.factor(Difficulty)
  )

# 2. Generate Individual Plots using a Loop or facet_wrap
p_individual_exec_learning_curves <- ggplot(data_learning_individual, 
       aes(x = Total_Trial, y = Lyap_exec, color = Difficulty)) +
  geom_point(alpha = 0.4, size = 1) +
  geom_smooth(method = "gam", 
              formula = y ~ s(x), 
              se = FALSE, 
              linewidth = 0.8) +
  facet_wrap(~ Subject, scales = "free_y") +
  scale_color_manual(values = c("6" = "red", "12" = "green", "18" = "blue"),
                     name = "Sequence\nDifficulty") +
  labs(
    title = "Individual Learning Curves: Execution Stability",
    subtitle = "Progression across Learning Trials (Blocks 1-3) by Sequence Difficulty",
    x = "Total Trial Number",
    y = expression("Lyapunov Exponent")
  ) +
  theme_bw(base_size = 10) +
  theme(
    strip.text = element_text(face = "bold"), 
    legend.position = "bottom"
  )
print(p_individual_exec_learning_curves)

p_individual_prep_learning_curves <- ggplot(data_learning_individual, 
       aes(x = Total_Trial, y = Lyap_prep, color = Difficulty)) +
  geom_point(alpha = 0.4, size = 1) +
  geom_smooth(method = "gam", 
              formula = y ~ s(x), 
              se = FALSE,
              linewidth = 0.8) +
  facet_wrap(~ Subject, scales = "free_y") + 
  scale_color_manual(values = c("6" = "red", "12" = "green", "18" = "blue"),
                     name = "Sequence\nDifficulty") +
  labs(
    title = "Individual Learning Curves: Preparation Stability",
    subtitle = "Progression across Learning Trials (Blocks 1-3) by Sequence Difficulty",
    x = "Total Trial Number",
    y = expression("Lyapunov Exponent" )
  ) +
  theme_bw(base_size = 10) +
  theme(
    strip.text = element_text(face = "bold"), 
    legend.position = "bottom"
  )
print(p_individual_prep_learning_curves)

Learning Phase

print("Difficulty effect on Preparation (Learning)")
## [1] "Difficulty effect on Preparation (Learning)"
model_lyap_prep_learning <- lmer(Lyap_prep ~ Difficulty * Block + (1 | Subject), data = data_all_learning)
## fixed-effect model matrix is rank deficient so dropping 6 columns / coefficients
summary(model_lyap_prep_learning)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Lyap_prep ~ Difficulty * Block + (1 | Subject)
##    Data: data_all_learning
## 
## REML criterion at convergence: -13629.5
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.8554 -0.5196 -0.0662  0.5434  4.8712 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev.
##  Subject  (Intercept) 1.049e-05 0.003239
##  Residual             2.177e-04 0.014755
## Number of obs: 2449, groups:  Subject, 18
## 
## Fixed effects:
##               Estimate Std. Error        df t value Pr(>|t|)    
## (Intercept)  4.310e-02  9.167e-04 2.658e+01  47.018  < 2e-16 ***
## Difficulty12 2.372e-03  7.183e-04 2.429e+03   3.302 0.000972 ***
## Difficulty18 3.357e-03  7.375e-04 2.429e+03   4.552 5.57e-06 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Dffc12
## Difficlty12 -0.391       
## Difficlty18 -0.381  0.486
## fit warnings:
## fixed-effect model matrix is rank deficient so dropping 6 columns / coefficients
anova(model_lyap_prep_learning)
## Missing cells for: Difficulty12:Block1, Difficulty18:Block1, Difficulty6:Block2, Difficulty18:Block2, Difficulty6:Block3, Difficulty12:Block3.  
## Interpret type III hypotheses with care.
## Type III Analysis of Variance Table with Satterthwaite's method
##                     Sum Sq   Mean Sq NumDF  DenDF F value    Pr(>F)    
## Difficulty       0.0048496 0.0024248     2 2429.1  11.137 1.531e-05 ***
## Block                                                                  
## Difficulty:Block                                                       
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
print("Difficulty effect on Execution (Learning)")
## [1] "Difficulty effect on Execution (Learning)"
model_lyap_exec_learning <- lmer(Lyap_exec ~ Difficulty * Block + (1 | Subject), data = data_all_learning)
## fixed-effect model matrix is rank deficient so dropping 6 columns / coefficients
summary(model_lyap_exec_learning)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Lyap_exec ~ Difficulty * Block + (1 | Subject)
##    Data: data_all_learning
## 
## REML criterion at convergence: -13463.2
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -6.1935 -0.5928 -0.0478  0.5799  3.3795 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev.
##  Subject  (Intercept) 2.908e-05 0.005392
##  Residual             2.316e-04 0.015219
## Number of obs: 2449, groups:  Subject, 18
## 
## Fixed effects:
##                Estimate Std. Error         df t value Pr(>|t|)    
## (Intercept)   5.383e-02  1.375e-03  2.075e+01  39.161   <2e-16 ***
## Difficulty12  7.528e-04  7.409e-04  2.429e+03   1.016    0.310    
## Difficulty18 -3.750e-05  7.606e-04  2.429e+03  -0.049    0.961    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Dffc12
## Difficlty12 -0.269       
## Difficlty18 -0.262  0.486
## fit warnings:
## fixed-effect model matrix is rank deficient so dropping 6 columns / coefficients
anova(model_lyap_exec_learning)
## Missing cells for: Difficulty12:Block1, Difficulty18:Block1, Difficulty6:Block2, Difficulty18:Block2, Difficulty6:Block3, Difficulty12:Block3.  
## Interpret type III hypotheses with care.
## Type III Analysis of Variance Table with Satterthwaite's method
##                      Sum Sq   Mean Sq NumDF DenDF F value Pr(>F)
## Difficulty       0.00032879 0.0001644     2  2429  0.7098 0.4919
## Block                                                           
## Difficulty:Block
emm_exec_learning <- emmeans(model_lyap_exec_learning, specs = ~ Difficulty, cov.reduce = range)
## NOTE: A nesting structure was detected in the fitted model:
##     Difficulty %in% Block
print(emm_exec_learning)
##  Difficulty Block emmean      SE   df lower.CL upper.CL
##  6          1     0.0538 0.00137 20.8   0.0510   0.0567
##  12         2     0.0546 0.00137 20.8   0.0517   0.0574
##  18         3     0.0538 0.00139 21.4   0.0509   0.0567
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95
emm_prep_learning <- emmeans(model_lyap_prep_learning, specs = ~ Difficulty, cov.reduce = range)
## NOTE: A nesting structure was detected in the fitted model:
##     Difficulty %in% Block
print(emm_prep_learning)
##  Difficulty Block emmean       SE   df lower.CL upper.CL
##  6          1     0.0431 0.000917 26.6   0.0412   0.0450
##  12         2     0.0455 0.000917 26.6   0.0436   0.0474
##  18         3     0.0465 0.000932 28.4   0.0446   0.0484
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95
learn_prep_emms <- emmeans(model_lyap_prep_learning, ~ Difficulty)
## NOTE: A nesting structure was detected in the fitted model:
##     Difficulty %in% Block
learn_prep_df <- as.data.frame(learn_prep_emms)

ggplot(learn_prep_df, aes(x = Difficulty, y = emmean, group = 1)) +
  geom_line(size = 1, color = "darkblue") +
  geom_point(size = 4, color = "darkblue") +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.1, size = 1, color = "black") +
  labs(title = "Preparation Stability Across Sequence Difficulty",
       x = "Sequence Length (Difficulty)",
       y = "Estimated Marginal Mean (sLyE Prep)",
       caption = "Error bars represent 95% Confidence Intervals") +
  theme_classic() +
  theme(text = element_text(size = 14))
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

learn_exec_emms <- emmeans(model_lyap_exec_learning, ~ Difficulty)
## NOTE: A nesting structure was detected in the fitted model:
##     Difficulty %in% Block
learn_exec_df <- as.data.frame(learn_exec_emms)

ggplot(learn_exec_df, aes(x = Difficulty, y = emmean, group = 1)) +
  geom_line(size = 1, color = "darkred") +
  geom_point(size = 4, color = "darkred") +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.1, size = 1, color = "black") +
  labs(title = "Execution Stability Across Sequence Difficulty",
       x = "Sequence Length (Difficulty)",
       y = "Estimated Marginal Mean (sLyE Exec)",
       caption = "Error bars represent 95% Confidence Intervals") +
  theme_classic() +
  theme(text = element_text(size = 14))

Test Phase

model_prep_test <- lmer(Lyap_prep ~ Block * Difficulty + (1 | Subject),
                        data = data_all_testing)
summary(model_prep_test)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Lyap_prep ~ Block * Difficulty + (1 | Subject)
##    Data: data_all_testing
## 
## REML criterion at convergence: -9177.5
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.4618 -0.5903 -0.0611  0.5932  4.1403 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev.
##  Subject  (Intercept) 1.921e-05 0.004382
##  Residual             2.289e-04 0.015128
## Number of obs: 1674, groups:  Subject, 18
## 
## Fixed effects:
##                       Estimate Std. Error         df t value Pr(>|t|)    
## (Intercept)          4.608e-02  1.382e-03  4.258e+01  33.350  < 2e-16 ***
## Block5               7.646e-04  1.284e-03  1.651e+03   0.596  0.55152    
## Difficulty12         3.522e-03  1.290e-03  1.651e+03   2.730  0.00641 ** 
## Difficulty18         2.818e-04  1.287e-03  1.651e+03   0.219  0.82670    
## Block5:Difficulty12 -8.599e-04  1.813e-03  1.651e+03  -0.474  0.63542    
## Block5:Difficulty18  7.956e-05  1.812e-03  1.651e+03   0.044  0.96498    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Block5 Dffc12 Dffc18 B5:D12
## Block5      -0.475                            
## Difficlty12 -0.472  0.508                     
## Difficlty18 -0.473  0.510  0.507              
## Blck5:Dff12  0.336 -0.708 -0.712 -0.361       
## Blck5:Dff18  0.336 -0.709 -0.360 -0.710  0.501
anova(model_prep_test)
## Type III Analysis of Variance Table with Satterthwaite's method
##                     Sum Sq    Mean Sq NumDF  DenDF F value    Pr(>F)    
## Block            0.0001065 0.00010646     1 1651.1  0.4652 0.4953172    
## Difficulty       0.0032232 0.00161160     2 1651.1  7.0420 0.0009009 ***
## Block:Difficulty 0.0000757 0.00003787     2 1651.1  0.1655 0.8475233    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
model_exec_test <- lmer(Lyap_exec ~ Block * Difficulty + (1 | Subject),
                        data = data_all_testing)
summary(model_exec_test)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: Lyap_exec ~ Block * Difficulty + (1 | Subject)
##    Data: data_all_testing
## 
## REML criterion at convergence: -9116.4
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -5.1105 -0.6538 -0.0588  0.6022  3.6113 
## 
## Random effects:
##  Groups   Name        Variance  Std.Dev.
##  Subject  (Intercept) 2.279e-05 0.004774
##  Residual             2.371e-04 0.015398
## Number of obs: 1674, groups:  Subject, 18
## 
## Fixed effects:
##                       Estimate Std. Error         df t value Pr(>|t|)    
## (Intercept)          5.425e-02  1.462e-03  3.912e+01  37.098  < 2e-16 ***
## Block5               3.547e-03  1.307e-03  1.651e+03   2.714  0.00671 ** 
## Difficulty12         3.428e-04  1.313e-03  1.651e+03   0.261  0.79411    
## Difficulty18         1.267e-03  1.310e-03  1.651e+03   0.968  0.33340    
## Block5:Difficulty12  7.864e-04  1.846e-03  1.651e+03   0.426  0.67013    
## Block5:Difficulty18 -1.998e-03  1.844e-03  1.651e+03  -1.083  0.27890    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Block5 Dffc12 Dffc18 B5:D12
## Block5      -0.457                            
## Difficlty12 -0.454  0.508                     
## Difficlty18 -0.455  0.510  0.507              
## Blck5:Dff12  0.323 -0.708 -0.712 -0.361       
## Blck5:Dff18  0.323 -0.709 -0.360 -0.710  0.501
anova(model_exec_test)
## Type III Analysis of Variance Table with Satterthwaite's method
##                     Sum Sq   Mean Sq NumDF  DenDF F value    Pr(>F)    
## Block            0.0041328 0.0041328     1 1651.1 17.4304 3.136e-05 ***
## Difficulty       0.0001545 0.0000773     2 1651.1  0.3259    0.7219    
## Block:Difficulty 0.0005758 0.0002879     2 1651.1  1.2142    0.2972    
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
test_prep_emms <- emmeans(model_prep_test, ~ Block * Difficulty)
test_prep_df <- as.data.frame(test_prep_emms)

block_names <- c(
  "1" = "Block 1: Learning",
  "2" = "Block 2: Learning",
  "3" = "Block 3: Learning",
  "4" = "Block 4: Retention",
  "5" = "Block 5: Transfer"
)

ggplot(test_prep_df, aes(x = Difficulty, y = emmean, group = 1, color = Difficulty)) +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.1, size = 1, color = "black") +
  geom_line(size = 1, color = "gray50") + 
  geom_point(size = 4) +
  facet_wrap(~Block, labeller = as_labeller(block_names)) +
  scale_color_brewer(palette = "Set1") +
  labs(title = "Preparation Stability Across Difficulties: Retention vs. Transfer",
       subtitle = "Model-estimated means by Difficulty",
       x = "Sequence Length (Difficulty)",
       y = "Estimated Marginal Mean (sLyE Prep)",
       caption = "Error bars represent 95% Confidence Intervals") +
  theme_classic() +
  theme(text = element_text(size = 14),
        legend.position = "right")

test_exec_emms <- emmeans(model_exec_test, ~ Block * Difficulty)
test_exec_df <- as.data.frame(test_exec_emms)

ggplot(test_exec_df, aes(x = Difficulty, y = emmean, group = 1, color = Difficulty)) +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.1, size = 1, color = "black") +
  geom_line(size = 1, color = "gray50") + 
  geom_point(size = 4) +
  facet_wrap(~Block, labeller = as_labeller(block_names)) +
  scale_color_brewer(palette = "Set1") +
  labs(title = "Execution Stability Across Difficulties: Retention vs. Transfer",
       subtitle = "Model-estimated means by Difficulty",
       x = "Sequence Length (Difficulty)",
       y = "Estimated Marginal Mean (sLyE Exec)",
       caption = "Error bars represent 95% Confidence Intervals") +
  theme_classic() +
  theme(text = element_text(size = 14),
        legend.position = "right")

LISAS

model_lisas_lr <- lmer(LISAS ~ Lyap_prep * Lyap_exec * Difficulty * Block + (1 | Subject), data = data_all_lr)
## fixed-effect model matrix is rank deficient so dropping 24 columns / coefficients
summary(model_lisas_lr)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: LISAS ~ Lyap_prep * Lyap_exec * Difficulty * Block + (1 | Subject)
##    Data: data_all_lr
## 
## REML criterion at convergence: 3812.8
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -1.9446 -0.6052 -0.2890  0.2878 11.0322 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Subject  (Intercept) 0.07624  0.2761  
##  Residual             0.18766  0.4332  
## Number of obs: 3280, groups:  Subject, 18
## 
## Fixed effects:
##                                   Estimate Std. Error        df t value
## (Intercept)                         0.8408     0.1715  674.3789   4.903
## Lyap_prep                          -0.9578     3.6019 3240.1200  -0.266
## Lyap_exec                          -5.5334     2.8056 3240.5581  -1.972
## Difficulty12                        0.6002     0.4304 3239.6171   1.394
## Difficulty18                        0.8613     0.4851 3239.2934   1.776
## Block2                             -0.9523     0.4952 3239.5953  -1.923
## Block3                             -1.0210     0.5377 3239.2426  -1.899
## Block4                             -0.8251     0.3517 3239.4295  -2.346
## Lyap_prep:Lyap_exec                69.9553    63.6511 3240.0758   1.099
## Lyap_prep:Difficulty12             -8.6969     8.3860 3239.6431  -1.037
## Lyap_prep:Difficulty18            -13.4878    10.1243 3239.3872  -1.332
## Lyap_exec:Difficulty12            -10.1262     7.5201 3239.6052  -1.347
## Lyap_exec:Difficulty18            -14.2107     8.7546 3239.2425  -1.623
## Lyap_prep:Block2                   16.9582    10.0023 3239.7155   1.695
## Lyap_prep:Block3                   18.0233    11.2822 3239.3762   1.598
## Lyap_prep:Block4                   10.2336     7.1037 3239.6161   1.441
## Lyap_exec:Block2                   20.1954     8.6831 3239.5567   2.326
## Lyap_exec:Block3                   21.9466     9.6750 3239.2148   2.268
## Lyap_exec:Block4                   15.6299     6.3983 3239.4637   2.443
## Lyap_prep:Lyap_exec:Difficulty12  164.2475   148.2606 3239.6408   1.108
## Lyap_prep:Lyap_exec:Difficulty18  273.1538   182.0302 3239.3216   1.501
## Lyap_prep:Lyap_exec:Block2       -360.9952   176.6519 3239.6684  -2.044
## Lyap_prep:Lyap_exec:Block3       -399.5020   202.3394 3239.3386  -1.974
## Lyap_prep:Lyap_exec:Block4       -244.9103   130.8697 3239.6462  -1.871
##                                  Pr(>|t|)    
## (Intercept)                      1.18e-06 ***
## Lyap_prep                          0.7903    
## Lyap_exec                          0.0487 *  
## Difficulty12                       0.1633    
## Difficulty18                       0.0759 .  
## Block2                             0.0546 .  
## Block3                             0.0577 .  
## Block4                             0.0190 *  
## Lyap_prep:Lyap_exec                0.2718    
## Lyap_prep:Difficulty12             0.2998    
## Lyap_prep:Difficulty18             0.1829    
## Lyap_exec:Difficulty12             0.1782    
## Lyap_exec:Difficulty18             0.1046    
## Lyap_prep:Block2                   0.0901 .  
## Lyap_prep:Block3                   0.1103    
## Lyap_prep:Block4                   0.1498    
## Lyap_exec:Block2                   0.0201 *  
## Lyap_exec:Block3                   0.0234 *  
## Lyap_exec:Block4                   0.0146 *  
## Lyap_prep:Lyap_exec:Difficulty12   0.2680    
## Lyap_prep:Lyap_exec:Difficulty18   0.1336    
## Lyap_prep:Lyap_exec:Block2         0.0411 *  
## Lyap_prep:Lyap_exec:Block3         0.0484 *  
## Lyap_prep:Lyap_exec:Block4         0.0614 .  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation matrix not shown by default, as p = 24 > 12.
## Use print(x, correlation=TRUE)  or
##     vcov(x)        if you need it
## fit warnings:
## fixed-effect model matrix is rank deficient so dropping 24 columns / coefficients
anova(model_lisas_lr)
## Missing cells for: Difficulty12:Block1, Difficulty18:Block1, Difficulty6:Block2, Difficulty18:Block2, Difficulty6:Block3, Difficulty12:Block3, Lyap_prep:Difficulty12:Block1, Lyap_prep:Difficulty18:Block1, Lyap_prep:Difficulty6:Block2, Lyap_prep:Difficulty18:Block2, Lyap_prep:Difficulty6:Block3, Lyap_prep:Difficulty12:Block3, Lyap_exec:Difficulty12:Block1, Lyap_exec:Difficulty18:Block1, Lyap_exec:Difficulty6:Block2, Lyap_exec:Difficulty18:Block2, Lyap_exec:Difficulty6:Block3, Lyap_exec:Difficulty12:Block3, Lyap_prep:Lyap_exec:Difficulty12:Block1, Lyap_prep:Lyap_exec:Difficulty18:Block1, Lyap_prep:Lyap_exec:Difficulty6:Block2, Lyap_prep:Lyap_exec:Difficulty18:Block2, Lyap_prep:Lyap_exec:Difficulty6:Block3, Lyap_prep:Lyap_exec:Difficulty12:Block3.  
## Interpret type III hypotheses with care.
## Type III Analysis of Variance Table with Satterthwaite's method
##                                       Sum Sq Mean Sq NumDF  DenDF F value
## Lyap_prep                            0.39851 0.39851     1 3240.8  2.1236
## Lyap_exec                            0.05929 0.05929     1 3243.0  0.3160
## Difficulty                           0.66581 0.33290     2 3239.5  1.7740
## Block                                1.10111 0.36704     3 3239.4  1.9559
## Lyap_prep:Lyap_exec                  0.19287 0.19287     1 3241.2  1.0278
## Lyap_prep:Difficulty                 0.37996 0.18998     2 3239.5  1.0124
## Lyap_exec:Difficulty                 0.56492 0.28246     2 3239.4  1.5052
## Lyap_prep:Block                      0.70892 0.23631     3 3239.4  1.2593
## Lyap_exec:Block                      1.37609 0.45870     3 3239.4  2.4443
## Lyap_prep:Lyap_exec:Difficulty       0.45815 0.22907     2 3239.5  1.2207
## Lyap_prep:Lyap_exec:Block            1.02564 0.34188     3 3239.5  1.8218
## Difficulty:Block                                                         
## Lyap_prep:Difficulty:Block                                               
## Lyap_exec:Difficulty:Block                                               
## Lyap_prep:Lyap_exec:Difficulty:Block                                     
##                                       Pr(>F)  
## Lyap_prep                            0.14514  
## Lyap_exec                            0.57408  
## Difficulty                           0.16982  
## Block                                0.11846  
## Lyap_prep:Lyap_exec                  0.31075  
## Lyap_prep:Difficulty                 0.36346  
## Lyap_exec:Difficulty                 0.22213  
## Lyap_prep:Block                      0.28667  
## Lyap_exec:Block                      0.06221 .
## Lyap_prep:Lyap_exec:Difficulty       0.29516  
## Lyap_prep:Lyap_exec:Block            0.14094  
## Difficulty:Block                              
## Lyap_prep:Difficulty:Block                    
## Lyap_exec:Difficulty:Block                    
## Lyap_prep:Lyap_exec:Difficulty:Block          
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
model_lisas_transfer <- lmer(LISAS ~ Lyap_prep * Lyap_exec * Difficulty + (1 | Subject), data = data_all_transfer)
summary(model_lisas_transfer)
## Linear mixed model fit by REML. t-tests use Satterthwaite's method [
## lmerModLmerTest]
## Formula: LISAS ~ Lyap_prep * Lyap_exec * Difficulty + (1 | Subject)
##    Data: data_all_transfer
## 
## REML criterion at convergence: 960.1
## 
## Scaled residuals: 
##     Min      1Q  Median      3Q     Max 
## -1.9502 -0.6701 -0.2827  0.5317  4.9577 
## 
## Random effects:
##  Groups   Name        Variance Std.Dev.
##  Subject  (Intercept) 0.07638  0.2764  
##  Residual             0.18152  0.4261  
## Number of obs: 843, groups:  Subject, 18
## 
## Fixed effects:
##                                   Estimate Std. Error        df t value
## (Intercept)                        0.61018    0.32722 809.39327   1.865
## Lyap_prep                          0.79771    6.63813 816.37953   0.120
## Lyap_exec                          3.21092    5.33416 816.58576   0.602
## Difficulty12                       0.58154    0.42576 815.67351   1.366
## Difficulty18                       0.24199    0.41588 817.14757   0.582
## Lyap_prep:Lyap_exec              -33.01318  112.48191 815.97206  -0.293
## Lyap_prep:Difficulty12           -10.74872    8.59110 815.60562  -1.251
## Lyap_prep:Difficulty18             0.08581    8.79569 816.31971   0.010
## Lyap_exec:Difficulty12            -8.90200    7.12980 815.83923  -1.249
## Lyap_exec:Difficulty18            -0.80852    6.83190 816.99994  -0.118
## Lyap_prep:Lyap_exec:Difficulty12 231.74975  145.74994 815.69611   1.590
## Lyap_prep:Lyap_exec:Difficulty18  25.00347  146.08705 816.19676   0.171
##                                  Pr(>|t|)  
## (Intercept)                        0.0626 .
## Lyap_prep                          0.9044  
## Lyap_exec                          0.5474  
## Difficulty12                       0.1723  
## Difficulty18                       0.5608  
## Lyap_prep:Lyap_exec                0.7692  
## Lyap_prep:Difficulty12             0.2112  
## Lyap_prep:Difficulty18             0.9922  
## Lyap_exec:Difficulty12             0.2122  
## Lyap_exec:Difficulty18             0.9058  
## Lyap_prep:Lyap_exec:Difficulty12   0.1122  
## Lyap_prep:Lyap_exec:Difficulty18   0.8641  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Correlation of Fixed Effects:
##             (Intr) Lyp_pr Lyp_xc Dffc12 Dffc18 Ly_:L_ Lyp_p:D12 Lyp_p:D18
## Lyap_prep   -0.937                                                       
## Lyap_exec   -0.944  0.930                                                
## Difficlty12 -0.731  0.715  0.720                                         
## Difficlty18 -0.753  0.734  0.742  0.575                                  
## Lyp_prp:Ly_  0.894 -0.964 -0.956 -0.684 -0.703                           
## Lyp_prp:D12  0.720 -0.769 -0.716 -0.951 -0.564  0.743                    
## Lyp_prp:D18  0.706 -0.752 -0.703 -0.540 -0.951  0.727  0.578             
## Lyp_xc:Df12  0.702 -0.693 -0.745 -0.961 -0.555  0.713  0.921     0.526   
## Lyp_xc:Df18  0.735 -0.725 -0.780 -0.563 -0.958  0.746  0.558     0.916   
## Lyp_:L_:D12 -0.690  0.743  0.737  0.909  0.543 -0.771 -0.962    -0.561   
## Lyp_:L_:D18 -0.689  0.742  0.737  0.528  0.907 -0.770 -0.571    -0.961   
##             Lyp_x:D12 Lyp_x:D18 L_:L_:D12
## Lyap_prep                                
## Lyap_exec                                
## Difficlty12                              
## Difficlty18                              
## Lyp_prp:Ly_                              
## Lyp_prp:D12                              
## Lyp_prp:D18                              
## Lyp_xc:Df12                              
## Lyp_xc:Df18  0.584                       
## Lyp_:L_:D12 -0.953    -0.576             
## Lyp_:L_:D18 -0.552    -0.949     0.594
anova(model_lisas_transfer)
## Type III Analysis of Variance Table with Satterthwaite's method
##                                 Sum Sq  Mean Sq NumDF  DenDF F value Pr(>F)
## Lyap_prep                      0.11453 0.114534     1 816.83  0.6310 0.4272
## Lyap_exec                      0.00002 0.000016     1 817.51  0.0001 0.9926
## Difficulty                     0.34993 0.174963     2 816.49  0.9639 0.3819
## Lyap_prep:Lyap_exec            0.15061 0.150610     1 816.08  0.8297 0.3626
## Lyap_prep:Difficulty           0.43088 0.215442     2 816.10  1.1869 0.3057
## Lyap_exec:Difficulty           0.38583 0.192917     2 816.35  1.0628 0.3460
## Lyap_prep:Lyap_exec:Difficulty 0.62667 0.313337     2 815.95  1.7262 0.1786
emmeans(model_lisas_transfer, ~ Difficulty)
## NOTE: Results may be misleading due to involvement in interactions
##  Difficulty emmean   SE   df lower.CL upper.CL
##  6           0.743 0.07 20.4    0.597    0.889
##  12          0.937 0.07 20.5    0.791    1.083
##  18          1.011 0.07 20.5    0.866    1.157
## 
## Degrees-of-freedom method: kenward-roger 
## Confidence level used: 0.95
lr_lisas_emms <- emmeans(model_lisas_lr, ~ Block * Difficulty)
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'pbkrtest.limit = 3280' (or larger)
## [or, globally, 'set emm_options(pbkrtest.limit = 3280)' or larger];
## but be warned that this may result in large computation time and memory use.
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'lmerTest.limit = 3280' (or larger)
## [or, globally, 'set emm_options(lmerTest.limit = 3280)' or larger];
## but be warned that this may result in large computation time and memory use.
## NOTE: Results may be misleading due to involvement in interactions
lr_lisas_df <- as.data.frame(lr_lisas_emms)

lr_lisas_df$Block <- factor(lr_lisas_df$Block)
lr_lisas_df$Difficulty <- factor(lr_lisas_df$Difficulty)

pd <- position_dodge(0.5)

# 2. Create the combined plot
ggplot(lr_lisas_df, aes(x = Block, y = emmean, group = Difficulty, color = Difficulty)) +
  geom_errorbar(aes(ymin = emmean - SE, ymax = emmean + SE), width = 0.2, position = pd, alpha = 0.7) +
  geom_point(position = pd, size = 3) +
  geom_vline(xintercept = 3.5, linetype = "dashed", color = "gray40") +
  annotate("text", x = 2, y = max(lr_lisas_df$emmean), label = "Learning Phase", fontface = "italic") +
  annotate("text", x = 4.5, y = max(lr_lisas_df$emmean), label = "Testing Phase", fontface = "italic") +
  scale_color_brewer(palette = "Set1") +
  scale_x_discrete(labels = c("1" = "Learning Block 1", "2" = "Learning Block 2", "3" = "Learning Block 3", "4" = "Retention Block")) +
  labs(title = "Motor Performance (LISAS) from Learning to Retention",
       #subtitle = "Comparison of performance efficiency across the Learning Blocks to the Retention Block",
       x = "Block",
       y = "Mean LISAS (lower is better)") +
       # caption = "Error bars represent ±1 Standard Error. Learning Blocks 1-3: Constant Difficulty; Retention Block: Mixed Difficulty.") +
  theme_classic() +
  theme(text = element_text(size = 14), legend.position = "top")
## Warning: Removed 6 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 1 row containing missing values or values outside the scale range
## (`geom_text()`).
## Removed 1 row containing missing values or values outside the scale range
## (`geom_text()`).

transfer_lisas_emms <- emmeans(model_lisas_transfer, ~ Difficulty)
## NOTE: Results may be misleading due to involvement in interactions
transfer_lisas_df <- as.data.frame(transfer_lisas_emms)
transfer_lisas_df$Difficulty <- factor(transfer_lisas_df$Difficulty)
  
ggplot(transfer_lisas_df, aes(x = Difficulty, y = emmean, color = Difficulty), group = 1) +
  geom_line(size = 1, color = "darkblue") +
  geom_point(size = 4, color = "darkblue") +
  geom_errorbar(aes(ymin = lower.CL, ymax = upper.CL), width = 0.1, size = 1, color = "black") +
  #scale_x_discrete(labels = c("1" = "Learning Block 1", "2" = "Learning Block 2", "3" = "Learning Block 3", "4" = "Retention")) +
  labs(title = "Motor Performance (LISAS) During the Transfer Block",
       #subtitle = "Comparison of performance efficiency across the Transfer Block",
       x = "Sequence Length (Difficulty)",
       y = "Mean LISAS (lower is better)") +
       # caption = "Error bars represent ±1 Standard Error. Learning Blocks 1-3: Constant Difficulty; Retention Block: Mixed Difficulty.") +
  theme_classic() +
  theme(text = element_text(size = 14), legend.position = "top")
## Warning in fortify(data, ...): Arguments in `...` must be used.
## ✖ Problematic argument:
## • group = 1
## ℹ Did you misspell an argument name?
## `geom_line()`: Each group consists of only one observation.
## ℹ Do you need to adjust the group aesthetic?

sd_p <- sd(data_all_lr$Lyap_prep, na.rm = TRUE)
sd_e <- sd(data_all_lr$Lyap_exec, na.rm = TRUE)

emm_prep <- emmeans(model_lisas_lr, ~ Block + Difficulty, at = list(Lyap_prep = mean(data_all_lr$Lyap_prep) + sd_p))
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'pbkrtest.limit = 3280' (or larger)
## [or, globally, 'set emm_options(pbkrtest.limit = 3280)' or larger];
## but be warned that this may result in large computation time and memory use.
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'lmerTest.limit = 3280' (or larger)
## [or, globally, 'set emm_options(lmerTest.limit = 3280)' or larger];
## but be warned that this may result in large computation time and memory use.
## NOTE: Results may be misleading due to involvement in interactions
emm_exec <- emmeans(model_lisas_lr, ~ Block + Difficulty, at = list(Lyap_exec = mean(data_all_lr$Lyap_exec) + sd_e))
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'pbkrtest.limit = 3280' (or larger)
## [or, globally, 'set emm_options(pbkrtest.limit = 3280)' or larger];
## but be warned that this may result in large computation time and memory use.
## Note: D.f. calculations have been disabled because the number of observations exceeds 3000.
## To enable adjustments, add the argument 'lmerTest.limit = 3280' (or larger)
## [or, globally, 'set emm_options(lmerTest.limit = 3280)' or larger];
## but be warned that this may result in large computation time and memory use.
## NOTE: Results may be misleading due to involvement in interactions
df_prep <- as.data.frame(emm_prep) %>% mutate(Stability_Type = "Prep sLyE")
df_exec <- as.data.frame(emm_exec) %>% mutate(Stability_Type = "Exec sLyE")
plot_df <- bind_rows(df_prep, df_exec)

ggplot(plot_df, aes(x = Block, y = emmean, group = Stability_Type, color = Stability_Type)) +
  geom_errorbar(aes(ymin = emmean - SE, ymax = emmean + SE), width = 0.2, position = position_dodge(0.4)) +
  geom_point(position = position_dodge(0.4), size = 3) +
  geom_vline(xintercept = 3.5, linetype = "dashed", color = "gray40") +
  facet_wrap(~Difficulty, labeller = labeller(Difficulty = c("6" = "6-Step Difficulty", "12" = "12-Step Difficulty", "18" = "18-Step Difficulty"))) +
  scale_color_manual(values = c("darkred", "darkgreen")) + 
  scale_x_discrete(labels = c("1" = "B1", "2" = "B2", "3" = "B3", "4" = "Ret")) +
  labs(title = "Interaction of sLyE and Difficulty on LISAS Across Learning and Retention Blocks",
       #subtitle = "Comparing how planning vs. execution instability impacts efficiency",
       x = "Block",
       y = "Predicted LISAS",
       color = "Lyapunov Exponent") +
  theme_classic() +
  theme(legend.position = "top", text = element_text(size = 12))
## Warning: Removed 12 rows containing missing values or values outside the scale range
## (`geom_point()`).

sd_p_transfer <- sd(data_all_transfer$Lyap_prep, na.rm = TRUE)
sd_e_transfer <- sd(data_all_transfer$Lyap_exec, na.rm = TRUE)

emm_prep_transfer <- emmeans(model_lisas_transfer, ~ Difficulty, at = list(Lyap_prep = mean(data_all_transfer$Lyap_prep) + sd_p_transfer))
## NOTE: Results may be misleading due to involvement in interactions
emm_exec_transfer <- emmeans(model_lisas_transfer, ~ Difficulty, at = list(Lyap_exec = mean(data_all_transfer$Lyap_exec) + sd_e_transfer))
## NOTE: Results may be misleading due to involvement in interactions
df_prep_transfer <- as.data.frame(emm_prep_transfer) %>% mutate(Stability_Type = "Prep sLyE")
df_exec_transfer <- as.data.frame(emm_exec_transfer) %>% mutate(Stability_Type = "Exec sLyE")
plot_df_transfer <- bind_rows(df_prep_transfer, df_exec_transfer)

ggplot(plot_df_transfer, aes(x = Difficulty, y = emmean, group = Stability_Type, color = Stability_Type)) +
  geom_errorbar(aes(ymin = emmean - SE, ymax = emmean + SE), width = 0.2, position = position_dodge(0.4)) +
  geom_point(position = position_dodge(0.4), size = 3) +
  scale_color_manual(values = c("darkred", "darkgreen")) + 
  labs(title = "Interaction of sLyE and Difficulty on LISAS Across the Transfer Block",
       x = "Sequence Length (Difficulty)",
       y = "Predicted LISAS",
       color = "Lyapunov Exponent") +
  theme_classic() +
  theme(legend.position = "top", text = element_text(size = 12))

Steady states

# 1. Prepare the scaled data
data_for_k <- data_all_combined %>%
  select(Lyap_exec, Lyap_prep, LISAS) %>%
  na.omit() %>%
  scale()

# 2. The Elbow Method (Total Within-Cluster Sum of Squares)
# This looks for the "elbow" where adding more clusters doesn't significantly reduce variance
plot_elbow <- fviz_nbclust(data_for_k, kmeans, method = "wss") +
  labs(title = "Elbow Method: Optimal k for Performance-Stability States",
       subtitle = "Look for the point where the drop flattens out")

# 3. The Silhouette Method (Cluster Quality)
# This measures how similar an object is to its own cluster compared to other clusters
plot_silhouette <- fviz_nbclust(data_for_k, kmeans, method = "silhouette") +
  labs(title = "Silhouette Method: Cluster Consistency",
       subtitle = "Higher values indicate better-defined clusters")

print(plot_elbow) 

print(plot_silhouette)

CLusters

# 1. Define Parameters 
k_optimal <- 4      # Number of steady states (attractors)
set.seed(42)          # For reproducibility

# 2. Prepare Data & Perform K-means Clustering
data_clustering <- data_all_lr %>%
  select(Lyap_exec, Lyap_prep, LISAS) %>%
  na.omit()

# Scale the data (ensures zero variance issues)
data_scaled <- scale(data_clustering)
km_result <- kmeans(data_scaled, centers = k_optimal, nstart = 25) 

# Add cluster assignment back to the data frame
data_clustering$State_ID <- as.factor(km_result$cluster)

# 3. Characterize the Attractors
# This allows us to see which State corresponds to "Best Performance"
attractor_summary <- data_clustering %>%
  group_by(State_ID) %>%
  summarise(
    N = n(),
    mean_Lyap_exec = mean(Lyap_exec),
    mean_Lyap_prep = mean(Lyap_prep),
    mean_LISAS = mean(LISAS)
  ) %>%
  ungroup() %>%
  arrange(State_ID)

print("Learning: Attractor Characterization (k=4) - Sorted by Performance (LISAS)")
## [1] "Learning: Attractor Characterization (k=4) - Sorted by Performance (LISAS)"
print(attractor_summary)
## # A tibble: 4 × 5
##   State_ID     N mean_Lyap_exec mean_Lyap_prep mean_LISAS
##   <fct>    <int>          <dbl>          <dbl>      <dbl>
## 1 1         1162         0.0454         0.0356      0.486
## 2 2          752         0.0731         0.0425      0.596
## 3 3          552         0.0501         0.0457      1.63 
## 4 4          814         0.0523         0.0625      0.541
# 4. Visualization of the Performance-Stability Phase Space
# Mapping LISAS to the size or shape helps visualize how efficiency lives in the stability space
plot_attractor <- ggplot(data_clustering, aes(x = Lyap_exec, y = Lyap_prep, color = State_ID)) + 
  geom_point(alpha = 0.3) +
  # Centroids marked as X
  geom_point(data = as.data.frame(km_result$centers) %>% 
               mutate(State_ID = as.factor(1:k_optimal)), 
             aes(x = Lyap_exec, y = Lyap_prep),
             color = "black", size = 6, shape = 4, stroke = 2) +
  labs(
    title = "Performance-Stability Attractors",
    subtitle = "Clusters defined by Execution Stability, Prep Stability, and LISAS Efficiency",
    x = "Execution Lyapunov Exponent",
    y = "Preparation Lyapunov Exponent"
  ) +
  scale_color_brewer(palette = "Dark2") +
  theme_minimal() +
  theme(plot.title = element_text(face = "bold"))

print(plot_attractor)

# Create the 3D scatter plot
fig_lr <- plot_ly(data_clustering, 
               x = ~Lyap_exec, 
               y = ~Lyap_prep, 
               z = ~LISAS, 
               color = ~State_ID, 
               colors = "Dark2",
               type = 'scatter3d', 
               mode = 'markers',
               marker = list(size = 3, opacity = 0.5)) %>%
  layout(title = "State-Space: Learning & Retention Phase",
         scene = list(xaxis = list(title = 'Exec Stability (sLyE)'),
                      yaxis = list(title = 'Prep Stability (sLyE)'),
                      zaxis = list(title = 'LISAS (Efficiency)')))

fig_lr