---
title: ""
format:
html:
theme: cosmo
css: styles.css
toc: true
toc-location: left
toc-title: "Table of contents"
toc-depth: 4
toc-expand: 4
page-layout: full
code-fold: true
code-tools: true
code-copy: true
highlight-style: github
execute:
echo: false
warning: false
message: false
---
::: paper-title
Temporal Dynamics of NREM EEG Microstates across <br> the Night
:::
::: paper-author
Lorena R.R. Gianotti, André Minder, Mirjam Studler, Daria Knoch
:::
::: paper-affiliation
Department of Social Neuroscience and Social Psychology,<br> Institute of Psychology, University of Bern, Switzerland
:::
::: paper-date
Last edited: `r Sys.Date()`
:::
------------------------------------------------------------------------
# Preparation
```{r}
#| echo: true
#| code-fold: true
# Load packages
library(janitor)
library(ggthemes)
library(readxl)
library(lmerTest)
library(kableExtra)
library(emmeans)
library(hms)
library(sjPlot)
library(lme4)
library(nlme)
library(tidyverse)
library(gridExtra)
library(ggplot2)
# Define parameters
size_big <- 14
size_small <- 12
# Load microstates data
data_ms <- readr::read_csv("data/cycles/TemporalParameters_5 classes_GrandGrandMeanTemplate.csv",
show_col_types = FALSE)
data_ms_clean <- data_ms |>
janitor::clean_names() |>
mutate(subject = parse_number(dataset),
.before = subject,
.keep = "unused") |>
rename(ID = subject)
# Pivot to long format
## duration
data_long_duration <- data_ms_clean |>
select(ID, group, condition, contains("mean_duration"), -contains("all")) |>
pivot_longer(
cols = -c("ID", "group", "condition"),
names_to = "class",
values_to = "duration"
) |>
mutate(condition = stringr::str_sub(condition, 6, -1)) |>
rename(cycle = condition,
stage = group) |>
mutate(
class = stringr::str_sub(class, -1, -1) |> toupper(),
cycle = as.factor(cycle),
class = as.factor(class),
stage = as.factor(stage),
ID = as.factor(ID),
duration = duration * 1000,
stage = forcats::fct_relevel(stage, c("N1", "N2", "N3")),
class = forcats::fct_relevel(class, c("A", "B", "C", "D", "E"))
)
## occurrence
data_long_occurrence <- data_ms_clean |>
select(ID, group, condition, contains("mean_occurrence"), -contains("all")) |>
pivot_longer(
cols = -c("ID", "group", "condition"),
names_to = "class",
values_to = "occurrence"
) |>
mutate(condition = stringr::str_sub(condition, 6, -1)) |>
rename(cycle = condition,
stage = group) |>
mutate(
class = stringr::str_sub(class, -1, -1) |> toupper(),
cycle = as.factor(cycle),
class = as.factor(class),
stage = as.factor(stage),
ID = as.factor(ID),
stage = forcats::fct_relevel(stage, c("N1", "N2", "N3")),
class = forcats::fct_relevel(class, c("A", "B", "C", "D", "E"))
)
## coverage
data_long_coverage <- data_ms_clean |>
select(ID, group, condition, contains("coverage")) |>
pivot_longer(
cols = -c("ID", "group", "condition"),
names_to = "class",
values_to = "coverage"
) |>
mutate(condition = stringr::str_sub(condition, 6, -1)) |>
rename(cycle = condition,
stage = group) |>
mutate(
class = stringr::str_sub(class, -1, -1) |> toupper(),
cycle = as.factor(cycle),
class = as.factor(class),
stage = as.factor(stage),
ID = as.factor(ID),
stage = forcats::fct_relevel(stage, c("N1", "N2", "N3")),
class = forcats::fct_relevel(class, c("A", "B", "C", "D", "E"))
)
```
# Descriptive Statistics
## Time segments analysed for each of the 12 combinations of sleep stages and sleep cycles
```{r}
#| echo: true
#| code-fold: true
#| results: asis
# count
tab_n <- data_ms_clean |>
count(group, condition, name = "n")
# compute mean and SD (seconds) + round
tab_time <- data_ms_clean |>
group_by(group, condition) |>
summarise(
mean_total_time = mean(total_time, na.rm = TRUE),
sd_total_time = sd(total_time, na.rm = TRUE),
.groups = "drop"
) |>
mutate(
mean_total_time = round(mean_total_time, 0),
sd_total_time = round(sd_total_time, 0),
time_summary = paste0(mean_total_time, " (± ", sd_total_time, ")")
) |>
select(group, condition, time_summary)
# merge
table_final <- tab_n |>
left_join(tab_time, by = c("group", "condition")) |>
arrange(group, condition)
# create table
table_final |>
knitr::kable(
format = "html",
booktabs = TRUE,
caption = NULL,
col.names = c("Sleep stage", "Sleep cycle", "n",
"Time segments (mean ± SD) in seconds"),
align = c("l","l","c","c"),
escape = TRUE
) |>
kableExtra::kable_styling(
full_width = FALSE,
position = "left",
bootstrap_options = c(),
htmltable_class = "apa-table"
)
```
# Inference Statistics of the Microstate Temporal Characteristics
## Duration
### Model
```{r}
#| echo: true
#| code-fold: true
duration_model <- lmer(
duration ~ cycle * stage * class +
(1|ID) + (1|cycle:ID) + (1|stage:ID) + (1|class:ID),
data = data_long_duration, REML = TRUE
)
sjPlot::tab_model(duration_model)
```
### Type III Test
```{r}
#| echo: true
#| code-fold: true
anova_duration <- anova(duration_model) # lmerTest gives Type III by default in many setups; see note below
knitr::kable(anova_duration, digits = 2, caption = "F-Tests for Duration Model") |>
kableExtra::kable_classic(full_width = FALSE)
```
### Post-hoc Tests
```{r}
#| echo: true
#| code-fold: true
emm_duration <- emmeans(duration_model, pairwise ~ cycle * stage | class)
emm_duration
duration_model_emm <- as.data.frame(emm_duration$emmeans)
```
### Plot
```{r}
#| echo: true
#| code-fold: true
#| fig-width: 12
#| fig-height: 7
#| fig-align: "center"
#| out-width: "100%"
#| fig-cap: ""
duration_emm_plot <- duration_model_emm |>
select(class, cycle, stage, emmean, lower.CL, upper.CL) |>
slice(1:60) |>
ggplot(aes(group = stage, color = stage, y = emmean, x = cycle)) +
geom_line(fill = cycle, alpha = 1) +
geom_point(stat="identity", size = 3, alpha = 1) +
geom_errorbar(aes(ymin=lower.CL, ymax=upper.CL), width=.2, alpha = 1) +
ggtitle("Microstate Classes") +
facet_wrap( ~ class, ncol = 5) +
theme_bw() +
theme(
plot.title = element_text(size = size_big, hjust= 0.5),
axis.text = element_text(size = size_small, family = "sans"),
axis.title = element_text(size = size_big, family = "sans"),
strip.text.x = element_text(size = size_big, family = "sans"),
strip.background = element_blank(),
legend.title = element_blank(),
legend.text = element_text(size = size_small),
legend.position="right",
) +
labs(color = "Sleep Stages") +
scale_y_continuous(name = "Duration (ms)", limits = c(0,150), expand = c(0,0)) +
scale_x_discrete(name= "Sleep Cycles") +
scale_color_manual(values = c("#1b9e77","#d95f02","#7570b3")) #color-blind friendly colors
duration_emm_plot
ggsave("duration_plot.png",
plot = duration_emm_plot,
width = 9,
height = 7,
dpi = 1200,
bg = "transparent",
path = "R:/MicrostateAnalysis/sleepData/MS_SleepMarkers/scripts/graphs/sleep/cycles")
```
## Occurence
### Model
```{r}
#| echo: true
#| code-fold: true
occurrence_model <- lmer(
occurrence ~ cycle * stage * class +
(1|ID) + (1|cycle:ID) + (1|stage:ID) + (1|class:ID),
data = data_long_occurrence, REML = TRUE
)
sjPlot::tab_model(occurrence_model)
```
### Type III Test
```{r}
#| echo: true
#| code-fold: true
anova_occurrence <- anova(occurrence_model)
knitr::kable(anova_occurrence, digits = 3, caption = "F-Tests for the Occurrence Model") |>
kableExtra::kable_classic(full_width = FALSE)
```
### Post-hoc Tests
```{r}
#| echo: true
#| code-fold: true
emm_occurrence <- emmeans(occurrence_model, pairwise ~ cycle * stage | class)
emm_occurrence
est_means_occurrence <- as.data.frame(emm_occurrence$emmeans)
```
### Plot
```{r}
#| echo: true
#| code-fold: true
#| fig-width: 12
#| fig-height: 7
#| fig-align: "center"
#| out-width: "100%"
#| fig-cap: ""
est_means_occurrence_plot <- est_means_occurrence |>
select(class, cycle, stage, emmean, lower.CL, upper.CL) |>
slice(1:60) |>
ggplot(aes(group = stage, color = stage, y = emmean, x = cycle)) +
geom_line(fill = cycle, alpha = 1) +
geom_point(stat="identity", size = 3, alpha = 1) +
geom_errorbar(aes(ymin=lower.CL, ymax=upper.CL), width=.2, alpha = 1) +
ggtitle("Microstate Classes") +
facet_wrap( ~ class, ncol = 5) +
theme_bw() +
theme(
plot.title = element_text(size = size_big, hjust= 0.5),
axis.text = element_text(size = size_small, family = "sans"),
axis.title = element_text(size = size_big, family = "sans"),
strip.text.x = element_text(size = size_big, family = "sans"),
strip.background = element_blank(),
legend.title = element_blank(),
legend.text = element_text(size = size_small),
legend.position="right",
) +
labs(color = "Sleep Stages") +
scale_y_continuous(name = "Occurence (per second)", limits = c(0,6), expand = c(0,0)) +
scale_x_discrete(name= "Sleep Cycles") +
scale_color_manual(values = c("#1b9e77","#d95f02","#7570b3")) #color-blind friendly colors
est_means_occurrence_plot
ggsave("occurrence_plot.png",
plot = est_means_occurrence_plot,
width = 9,
height = 7,
dpi = 1200,
bg = "transparent",
path = "R:/MicrostateAnalysis/sleepData/MS_SleepMarkers/scripts/graphs/sleep/cycles")
```
## Coverage
### Model
```{r}
#| echo: true
#| code-fold: true
coverage_model <- lmer(
coverage ~ cycle * stage * class +
(1|ID) + (1|cycle:ID) + (1|stage:ID) + (1|class:ID),
data = data_long_coverage, REML = TRUE
)
sjPlot::tab_model(coverage_model)
```
### Type III Test
```{r}
#| echo: true
#| code-fold: true
anova_coverage <- anova(coverage_model)
knitr::kable(anova_coverage, digits = 2, caption = "F-Tests for Coverage Model") |>
kableExtra::kable_classic(full_width = FALSE)
```
### Post-hoc Tests
```{r}
#| echo: true
#| code-fold: true
emm_coverage <- emmeans(coverage_model, pairwise ~ cycle * stage | class)
emm_coverage
est_means_coverage <- as.data.frame(emm_coverage$emmeans)
```
### Plot
```{r}
#| echo: true
#| code-fold: true
#| fig-width: 12
#| fig-height: 7
#| fig-align: "center"
#| out-width: "100%"
#| fig-cap: ""
est_means_coverage_plot <- est_means_coverage |>
select(class, cycle, stage, emmean, lower.CL, upper.CL) |>
slice(1:60) |>
ggplot(aes(group = stage, color = stage, y = emmean, x = cycle)) +
geom_line(fill = cycle, alpha = 1) +
geom_point(stat="identity", size = 3, alpha = 1) +
geom_errorbar(aes(ymin=lower.CL, ymax=upper.CL), width=.2, alpha = 1) +
ggtitle("Microstate Classes") +
facet_wrap(~ class, ncol = 5) +
theme_bw() +
theme(
plot.title = element_text(size = size_big, hjust= 0.5),
axis.text = element_text(size = size_small, family = "sans"),
axis.title = element_text(size = size_big, family = "sans"),
strip.text.x = element_text(size = size_big, family = "sans"),
strip.background = element_blank(),
legend.title = element_blank(),
legend.text = element_text(size = size_small),
legend.position="right",
) +
labs(color = "Sleep Stages") +
scale_y_continuous(name = "Coverage (%)", limits = c(0,35), expand = c(0,0)) +
scale_x_discrete(name= "Sleep Cycles") +
scale_color_manual(values = c("#1b9e77","#d95f02","#7570b3")) #color-blind friendly colors
est_means_coverage_plot
ggsave("coverage_plot.png",
plot = est_means_coverage_plot,
width = 9,
height = 7,
dpi = 1200,
bg = "transparent",
path = "R:/MicrostateAnalysis/sleepData/MS_SleepMarkers/scripts/graphs/sleep/cycles")
```