Individualized mental fatigue does not impact neuromuscular function and exercise performance
Contents
- Introduction
- Cognitive tasks
- Subjective data
- Performance
- Knee extensors evaluation
- Transcranial Magnetic Stimulation (TMS)
- Brain Oxygenation
- Conclusions
1. Introduction
This is an R Markdown report of “Individualized mental fatigue does not impact neuromuscular function and exercise performance” dedicated especially to the participants of the study, but if you are interested in the topic, want to replicate the results or “basics” R codes, it is open to everyone.
This document is a mix of a report without excessive scientific argon and R codes (there is a button to show or hide it).
For each variable we measured, there is a part with the median/average values and distribution of the data, and a part with your individual data. To check your individual data, please Contact me and I send you your assigned ID. Probably, some of the code steps are redundant and not necessary, but I am also learning, improving and doing this mostly for “fun” and because I think we must be more transparent and “sharing is caring”. You do not need previous experience with R to follow this. In any case, if you want to reproduce the code, it is always nicely commented in most cases.
The corresponding material to reproduce the document is also available in OSF, but this document is self-sufficient.
Having said that, a brief reminder of what you did in the study:
We need a bunch of packages to reproduce this projects, like tidyverse, readxl, ggplot, etc. They are uploaded here automatically. Probably, some of them you do not really need it, but I have been playing around with many alternatives 😄
invisible({capture.output({
require(tidyverse)
library(tibble)
library(plotly)
require(readxl)
library(ggeasy)
library(cowplot)
library(report)
library(easystats)
library(writexl)
require(rstatix)
require(gridExtra)
require(gifski)
require(ggpubr)
library(smplot2)
library(gtsummary)
library(gt)
library(webshot2)
library(magick)
library(directlabels)
library(Rmisc)
library(PupillometryR)
library(emo)
library(osfr)
library("httr")
require(purrr)
library(zoo)
library(details)
})})First, we need to load all data sets available in OSF:
# Loading directly all data available in OSF
# The NIRS data is loaded later, not possible to do it by OSF as i did the processing steps
# (Maybe possible with Google drive package...need to check)
invisible({capture.output({
# EMG-FORCE
url <- 'https://osf.io/y8kpq//?action=download'
filename <- 'IMF22_Force_EMG.xlsx'
GET(url, write_disk(filename, overwrite = TRUE))
EMG <- readxl::read_xlsx(filename, sheet= "EMG")
force <- readxl::read_xlsx(filename, sheet= "Force")
# Performance-RPE-VAS
url <- 'https://osf.io/6gyc2//?action=download'
filename <- 'IMF22_Performance_RPE_VAS_Long.xlsx'
GET(url, write_disk(filename, overwrite = TRUE))
data<- readxl::read_xlsx(filename)
# TMS
url <- 'https://osf.io/qhw7c//?action=download'
filename <- 'IMF22_TMS.xlsx'
GET(url, write_disk(filename, overwrite = TRUE))
TMS<- readxl::read_xlsx(filename)
# Cognitive tasks
url <- 'https://osf.io/jg5m9//?action=download'
filename <- 'IMF22_Task.xlsx'
GET(url, write_disk(filename, overwrite = TRUE))
IMF<- readxl::read_xlsx(filename)
})})2. Cognitive tasks
In this experiment, you completed two different tasks. The control (easy task) condition was a 0-back, where you only had to press the space bar every time you see the letter “X”. In the mental fatigue condition (high cognitive load), you completed the TloadDback task. In this task, a sequence of letter and number appeared in the screen, and you had to respond to odd/even number and if the current letter was the same as the previous one. The inter stimuli duration (i.e., the time between each number and letter) was adapted individually in the first visit.
2.1 Pre-processing the data.
We have a look at the data set of the cognitive tasks
knitr::kable(head(IMF[, 1:10]), "pipe", caption = "Data for both cognitive task in wide format")| Participant | t1_LCL | t2_LCL | t3_LCL | t4_LCL | t5_LCL | t6_LCL | t7_LCL | t8_LCL | t1_HCL |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 0.9375000 | 1.0000000 | 1.0000000 | 1.0000000 | 1.0000000 | 1.0000000 | 1.0000000 | 0.9642857 | 0.9207778 |
| 2 | 1.0000000 | 0.9761905 | 0.9545455 | 0.9767442 | 0.9756098 | 1.0000000 | 1.0000000 | 0.9777778 | 0.7900729 |
| 3 | 1.0000000 | 1.0000000 | 1.0000000 | 1.0000000 | 0.9791667 | 1.0000000 | 0.9787234 | 1.0000000 | 0.8367833 |
| 4 | 0.9800000 | 1.0000000 | 1.0000000 | 0.9803922 | 0.9800000 | 1.0000000 | 1.0000000 | 0.9433962 | 0.8174000 |
| 5 | 0.9782609 | 1.0000000 | 1.0000000 | 0.9782609 | 0.9782609 | 0.9787234 | 1.0000000 | 1.0000000 | 0.8345938 |
| 6 | 1.0000000 | 1.0000000 | 1.0000000 | 0.9534884 | 1.0000000 | 1.0000000 | 0.9772727 | 1.0000000 | 0.8672917 |
Here, we have the data for both task, but in wide format. However, for most of the functions in R, we (normally) need to transform it in long format.
# Change to long format. We merge col 2 to 17 (separated by_) and we keep only 4 cols. Participant, Time, Condition and the variable with the performance.
IMF_long<- pivot_longer(IMF, cols =2:17, names_to = c("Time", "Condition"),
names_sep = "_", values_to = "Performance", values_drop_na = TRUE)
# Rename the name of the conditions for illustrative purpose
IMF_long<-IMF_long %>% mutate(Condition= recode(Condition, LCL ="Control", HCL= "Mental fatigue"))
knitr::kable(head(IMF_long[, 1:4]), "pipe", caption = "Data for both cognitive task in long format")| Participant | Time | Condition | Performance |
|---|---|---|---|
| 1 | t1 | Control | 0.9375 |
| 1 | t2 | Control | 1.0000 |
| 1 | t3 | Control | 1.0000 |
| 1 | t4 | Control | 1.0000 |
| 1 | t5 | Control | 1.0000 |
| 1 | t6 | Control | 1.0000 |
Compared to the previous table, now Condition and Time are distributed in two columns across participants. The task is divided in 8 blocks of approximately 4min.
2.2 Global performance
We calculated the global performance of each task, that to say, percentage of correct responses.
#First step is to calculate the average.
# Calculate the average across participants for each time and condition for the global performance data.
IMF_longavg <- IMF_long %>%
group_by(Condition, Time) %>%
summarise_at(vars(Performance),
list(average = mean))
# Standardize size of the text across all figures. We will use this for all figures.
size = theme(
title = element_text(size = 12),
axis.text.x = element_text(size = 12),
axis.title.y = element_text(size = 12),
axis.title.x = element_text(size = 12))
# Create the plot with global performance for each task
IMF.plot <- ggplot(IMF_longavg) +
aes(x = Time, y = average, colour = Condition, group = Condition) +
geom_smooth(method = "lm")+
scale_color_brewer(palette = "Set2", direction = 1) +
sm_minimal() +
guides(fill = "none") +
labs( y = "Correct answers (%)",
caption = "n = 22",
title ="Performance of the individualized and control task") +
sizeThe figure:
## `geom_smooth()` using formula = 'y ~ x'
This is the performance (percentage of correct responses) in both cognitive tasks and across time. The individualized cognitive effort task was actually more difficult than the control task. Performance in the control task was close to 100% across time, but in the mental fatigue condition is lower and tends to descend across time. In other words, the task was more demanding and it is what we expected. Furthermore, this is corroborated with the subjective data (as we will see later).
2.3 Individual performance
That was the average performance, but now, we will visualize the individual data for each of you for the high cognitive load. We will see that everyone does not perform equally in the task or across time.
# Filter the data set for getting mental fatigue condition
HCL <- filter(IMF_long, Condition == "Mental fatigue")
HCL.plot <- ggplot(HCL, aes(x = Time, y = Performance, color = Participant, group = Participant)) +
geom_line(linetype = 1,
linewidth = 1.2) +
guides(color = guide_legend(title = "ID"))+
scale_color_identity(labels = paste("ID", 1:22))+
sm_minimal() +
guides(fill = "yes") +
labs( y = "Performance (%)",
# caption = "n = 22",
title ="Individual performance across the task") +
geom_dl(aes(label = Participant), method = list(dl.combine("first.points", "last.points")), cex = 0.3, alpha = 0.5) +
size
HCL.plotHowever, a static graph is not clear since lines are overlapped. Thus, you can check your individual performance in the following interactive plot if you place the mouse over your ID line and Time. Never compare with others… what others do is not your business 😉
# Pass the ggplot to a ggplotly
ggplotly(HCL.plot)Maybe, one limitation of the task is that after we established your threshold in the familiarization, you did not perform the task at that given speed/intensity. Hence, something to consider for future studies.
3. Subjective data
We refer subjective data to the visual analog scales (in the excel) that you used to indicate your subjective level of mental fatigue and activation.
3.1 Global values
This part is what we call manipulation check, i.e., to prove that our intervention (mental fatigue) was really effective.
FatigueRain <- ggplot(data = data, mapping = aes(x = Condition, y = VAS_FAT_NOR)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_boxplot(aes(x = Condition, y = VAS_FAT_NOR, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
sm_minimal() +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
geom_point(aes(fill = Condition, group=ID), size=2,shape=21)+
geom_line(aes(group=ID), linewidth=0.3, color='gray', alpha=0.6) +
guides(fill = "none") +
labs( y = "Normalize score (AU)", x = element_blank(),
title ="Subjective level of mental fatigue",
caption = "n = 21")+
size
ActivationRain <- ggplot(data = data, mapping = aes(x = Condition, y = VAS_ARO_NOR)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_boxplot(aes(x = Condition, y = VAS_ARO_NOR, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
sm_minimal() +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
geom_point(aes(fill = Condition, group=ID), size=2,shape=21)+
geom_line(aes(group=ID), linewidth=0.3, color='gray', alpha=0.6) +
guides(fill = "none") +
labs( y = "Normalize score (AU)", x = element_blank(),
title ="Subjective level of arousal",
# subtitle = "BF10 = 0.487; Anecdotal evidence in favour of the null hypothesis
# (i.e., activation is similar for bot tasks) ",
caption = "n = 21" ) +
size
# Arrange the 2 figures in 2 cols and 1 row. Put a common legend on the right side (if desired)
VASplots <- ggarrange(FatigueRain, ActivationRain,
labels = c("A", "B"),
ncol = 2, nrow = 1,
# common.legend = T,
# legend = "right",
align = "none"
)
VASplots# Alternatively, we could this to place 2 figures in 2 columns (only for a Rm document)
# `{r out.width=c('50%', '50%'), fig.show='hold'}
# FatigueRain
# ActivationRainPanel A) and B) depict a Rain Cloud plot for the VAS questions. The raincloud plot shows the cloud of points (i.e., individual raw data) connected by lines between each condition, a box plot and a one-sided violin plot (showing the probability density of the data at different values). A) Subjective level of mental fatigue. The shape of distribution indicates that in both conditions the observed values were located around the median (everyone follow a similar patron), but the subjective level of mental fatigue was ~ twice higher after the high cognitive load task compared to the control condition. Furthermore, individual data shows that most of the you were more mentally fatigued after completing the mental fatigue task. B) Subjective level of activation In contrast, subjective arousal level was similar across conditions, which shows that performing a task with low cognitive load (control task) did not reduce the activation level. This data shows that the manipulation was indeed effective to induce the mental fatigue state, but activation did not change. If we had not achieved this, we would have had a problem of experimental design 😌.
3.2 Individual values
However, how does it vary individually? The values are arbitrary units, so they do not represent anything, but a change in a score, i.e, more or less mental fatigue. You can again check you individual data. Place the mouse over the points or box.
# interactive graph
ggplotly(FatigueRain, width = 600, height= 900)4.Perfomance and perception of effort
Finally, we can contrast if 🚲 performance and your perception of effort (RPE) was actually affected by the mental fatigue state and the long cognitive effort that you had to do.
4.1 Global performance
# Rain cloud plot
PerformanceRPlot <- ggplot(data = data, mapping = aes(x = Condition, y = Performance)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_boxplot(aes(x = Condition, y = Performance, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
sm_minimal() +
geom_point(aes(fill = Condition, group=ID), size=2,shape=21)+
geom_line(aes(group=ID), linewidth=0.3, color='gray', alpha=0.6) +
guides(fill = "none") +
labs( y = "Time to exhaustion (s)", x = element_blank(),
title ="Performance",
caption = "n = 22")+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.background = element_rect(colour = NA)) +
size
RPERPlot <- ggplot(data = data, mapping = aes(x = Condition, y = RPE)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_boxplot(aes(x = Condition, y = RPE, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
sm_minimal() +
geom_point(aes(fill = Condition, group=ID), size=2,shape=21)+
geom_line(aes(group=ID), linewidth=0.3, color='gray', alpha=0.6) +
guides(fill = "none") +
labs( y = "Borg scale 1-10 (AU)", x = element_blank(),
title ="RPE",
caption = "n = 22")+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.background = element_rect(colour = NA)) +
size
# Arrange the plots together
PerRPE <- ggarrange(PerformanceRPlot, RPERPlot,
labels = c("A", "B"),
ncol = 2,
common.legend = T,
legend = "right",
align = "h"
)
PerRPEThe Rain Cloud plot for (A) physical performance in the cycling time-to-exhaustion test at 80% of peak power output and (B) average rate of perceived exertion during the time-to-exhaustion test. The shape of distribution indicates that in both conditions values were located around the median, but there were no differences between conditions. Individual data shows that 12 out 22 performed better in the mental fatigue condition, 9 performed better in the control condition and 1 performed equally. Similarly, the distribution of the RPE values were around the median and there were no differences between both conditions.
The classical “hypothesis” is that mental fatigue would impair your performance (i.e., less time completed) and increase your RPE, but this was not the case in this study.
4.2 Individual Performance
# Cleveland plot
# adapt y axis
brks <- c(seq(-900, 900, by = 60))
# Configure labels for the graph
lbls = c(seq(900, 0, -60), seq(60, 900, 60))
# Generate Plot
PerfoIND <- data %>% # Cast the users table as a number
mutate(Performance = as.numeric(Performance)) %>%
# Pipe into ggplot
ggplot(aes(x = reorder(ID,(Performance)), y = Performance, fill = Condition)) +
# Plot the point. Alpha to increase transparency of the points and avoid overlapping
geom_point(aes(color = Condition, alpha =0.5))+
# join the point (they disappear in the interactive plot)
geom_line(aes(group = ID), linewidth = 0.1) +
# Shift the y axis
scale_y_continuous(breaks = brks, labels = lbls) +
# Flip the coordinates
coord_flip() +
# Add a theme
sm_classic() +
# Add a title
labs(title="Individual Performance",
y = "Time to exhaustion (s)", x = "ID",
caption = "n = 22") +
# Add more theming options
theme(plot.title = element_text(hjust = .5),
axis.ticks = element_blank())+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
size
ggplotly(PerfoIND)👏 👏 👏 👏
5. Knee extensor evaluation
In this part, we measured different parameters to assess if the mental fatigue state affected your development of force and if there were any effect at peripheral (muscle) level. Then, whether this will eventually explain the “lower performance” (if there had been). These are the data related to the chair with the electrical stimulation that many of you liked 😄
5.1 Pre-processing the data and global performance
Let’s start checking the data already loaded:
knitr::kable(head(force[, 1:5]), "pipe", caption = "Knee extensor evaluation variables")| ID | Condition | Time | Variable | Value |
|---|---|---|---|---|
| 1 | Control | Pre | MVC | 447.92000 |
| 1 | Control | Pre | Superimposed doublet | 4.90000 |
| 1 | Control | Pre | Doublet100Hz | 135.30000 |
| 1 | Control | Pre | Doublet10Hz | 123.12000 |
| 1 | Control | Pre | Secousse | 95.54000 |
| 1 | Control | Pre | VAL | 96.37842 |
There are several variables in the data frame, thus we need to filter each variable we measured.
In addition, we need to do a bit of processing to keep the order of the time (Pre should be before Post) and defined as factors.
# We specify the order that should appear in the graph the time.
# By default they are ordered alphabetically
# If we do not specify Post would come first than Pre (alphabetically)
force$Time <- factor(force$Time, levels=c("Pre", "Post Task", "Post TTE"))
force$Condition <- factor(force$Condition, levels=c("Control", "Mental Fatigue"))We can now process to the results:
For example, for the the maximal voluntary contraction (MVC):
# filter a data.frame with only the variable of interest
MVC <- filter(force, Variable == "MVC")
#We calculate some data to add to the graph.
sumrepdatMVC <- summarySE(MVC, measurevar = "Value",
groupvars=c("Condition", "Time"))
MVCrain <- ggplot(MVC, aes(x = Time, y = Value, fill = Condition)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_point(aes(x = as.numeric(Time)-.15, y = Value, colour = Condition),position = position_jitter(width = .05), size = .25, shape = 20)+
geom_boxplot(aes(x = Time, y = Value, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
geom_line(data = sumrepdatMVC, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), linetype = 3)+
geom_point(data = sumrepdatMVC, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), shape = 18) +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
labs( y = "MVC Force (N)", x = element_blank(),
title ="Maximal Voluntary Contraction",
caption = "n = 21")+
size
MVCrainThe points and the dashed lines which join each plot represents the average. We see that on average, the capacity to produce force is reduced across time, in particular after the cycling exercise. However, this did not vary between the conditions. So, we can certainly firm that subjective mental fatigue do not affect maximal force development.
We will do the same for the other variables:
# VAL rain
VAL <- filter(force, Variable == "VAL")
sumrepdatVAL <- summarySE(VAL, measurevar = "Value",
groupvars=c("Condition", "Time"))
VALrain <- ggplot(VAL, aes(x = Time, y = Value, fill = Condition)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_point(aes(x = as.numeric(Time)-.15, y = Value, colour = Condition),position = position_jitter(width = .05), size = .25, shape = 20)+
geom_boxplot(aes(x = Time, y = Value, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
geom_line(data = sumrepdatVAL, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), linetype = 3)+
geom_point(data = sumrepdatVAL, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), shape = 18) +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
labs( y = "Voluntary activation (%)", x = element_blank(),
title ="Voluntary Activation Level",
caption = "n = 21")+
size
VALrainDuring the MVC, we send you an electrical stimuli superimposed at the level of the peripheral nerve by stimulating the motor axons of the contracting muscle. When the force output is increased by these superimposed electrical stimuli, the person’s voluntary activation (the “completeness” of skeletal muscle activation during voluntary contraction) is considered to be sub-maximal. Therefore, in a idilyc scenario your voluntary activation level (VAL) should be around 100%. We see that after the cognitive task, on average, the VAL increased, but it might be normal due to de carry-over effect of the first MVC and warm-up. Then, after the cycling exercise, it is normal that your VAL is reduced due to the fatigue. Nonetheless, the VAL did not change between the two conditions.
# Doublet rain
Doublet <- filter(force, Variable == "Doublet100Hz")
# Drop a missing value
Doublet = drop_na(Doublet)
sumrepdatDoub <- summarySE(Doublet, measurevar = "Value",
groupvars=c("Condition", "Time"))
Doubletrain <- ggplot(Doublet, aes(x = Time, y = Value, fill = Condition)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_point(aes(x = as.numeric(Time)-.15, y = Value, colour = Condition),position = position_jitter(width = .05), size = .25, shape = 20)+
geom_boxplot(aes(x = Time, y = Value, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
geom_line(data = sumrepdatDoub, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), linetype = 3)+
geom_point(data = sumrepdatDoub, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), shape = 18) +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
labs( y = "100 Hz paired stimulation (N)", x = element_blank(),
title ="Potentiated doublet amplitude (100Hz)",
caption = "n = 20")+
size
DoubletrainThe potentiated doublet amplitude (100Hz) is considered the gold standard to assess peripheral fatigue of the muscle. The amplitude of the force was specially reduced after the cycling exercise (which is logical), but there were not difference between conditions at any point.
# Ratio rain
Ratio <- filter(force, Variable == "Ratio 10Hz/100Hz")
# Drop a missing value
Ratio = drop_na(Ratio)
sumrepdatRatio <- summarySE(Ratio, measurevar = "Value",
groupvars=c("Condition", "Time"))
Ratiorain <- ggplot(Ratio, aes(x = Time, y = Value, fill = Condition)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_point(aes(x = as.numeric(Time)-.15, y = Value, colour = Condition),position = position_jitter(width = .05), size = .25, shape = 20)+
geom_boxplot(aes(x = Time, y = Value, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
geom_line(data = sumrepdatRatio, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), linetype = 3)+
geom_point(data = sumrepdatRatio, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), shape = 18) +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
labs( y = "Ratio 10Hz/100Hz (%)", x = element_blank(),
title ="Ratio 10 Hz / 100 Hz",
caption = "n = 21")+
size
RatiorainAnd finally, the Ratio 10 Hz / 100 Hz, another indicator of fatigue. It showed similar tendency as the potentiated doublet
5.2 Individual data
Now you can easily check your individual values.
# Individual Plot MVC
MVCIND<-ggplot(MVC, aes(x = Time, y = Value))
MVCIND <- MVCIND + geom_line(aes(color = Condition, group = ID)) + geom_point()
# Divide panels for conditions (rows) and participants (columns)
MVCIND <- MVCIND + facet_grid(Condition ~ ID)
MVCIND <- MVCIND +
labs (y= "MVC Force (N)",
x= element_blank(),
title = "MVC for each participant",
caption = "n = 21") +
theme(
strip.background = element_blank(),
legend.title = element_blank(),
strip.text.x = element_blank())+
sm_minimal()+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.title = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 90, hjust = 1, size = 7))+
easy_remove_legend()
ggplotly(MVCIND, width = 800, height = 800)# Individual Plot VAL
VALIND<-ggplot(VAL, aes(x = Time, y = Value))
VALIND <- VALIND + geom_line(aes(color = Condition, group = ID)) + geom_point()
# Divide panels for conditions (rows) and participants (columns)
VALIND <- VALIND + facet_grid(Condition ~ ID)
VALIND <- VALIND +
labs (y= "Voluntary Activation (%)",
x= element_blank(),
title = "VAL for each participant"
) +
theme(
strip.background = element_blank(),
legend.title = element_blank(),
strip.text.x = element_blank())+
sm_minimal()+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.title = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 90, hjust = 1, size = 7))+
easy_remove_legend()
ggplotly(VALIND, width = 800, height = 800)# Individual Plot Doublet
DoubletIND<-ggplot(Doublet, aes(x = Time, y = Value))
DoubletIND <- DoubletIND + geom_line(aes(color = Condition, group = ID)) + geom_point()
# Divide panels for conditions (rows) and participants (columns)
DoubletIND <- DoubletIND + facet_grid(Condition ~ ID)
DoubletIND <- DoubletIND +
labs (y= "100 Hz paired stimulation (N)",
x= element_blank(),
title = "Potentiated Doublet amplitude (100 Hz) for each participant"
) +
theme(
strip.background = element_blank(),
legend.title = element_blank(),
strip.text.x = element_blank())+
sm_minimal()+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.title = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 90, hjust = 1, size = 7))+
easy_remove_legend()
ggplotly(DoubletIND, width = 800, height = 800)# Individual Plot Ratio
RatioIND<-ggplot(Ratio, aes(x = Time, y = Value))
RatioIND <- RatioIND + geom_line(aes(color = Condition, group = ID)) + geom_point()
# Divide panels for conditions (rows) and participants (columns)
RatioIND <- RatioIND + facet_grid(Condition ~ ID)
RatioIND <- RatioIND +
labs (y= "Ratio 10 Hz / 100 Hz (%)",
x= element_blank(),
title = "Ratio 10 Hz / 100 Hz for each participant"
) +
theme(
strip.background = element_blank(),
legend.title = element_blank(),
strip.text.x = element_blank())+
sm_minimal()+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.title = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 90, hjust = 1, size = 7))+
easy_remove_legend()
ggplotly(RatioIND, width = 800, height = 800)6. Transcranial magnetic stimulation
Transcranial magnetic stimulation was equally used to establish a potential link between corticospinal excitability and mental fatigue, as an underlying mechanism by which mental fatigue might reduce exercise performance.
# Reorganizing a messy data set. My bad, my bad...
TMS<-TMS %>%
select(ID,
FAT_PRE_AV20,FAT_PRE_AVG10,FAT_PRE_RATIO, FAT_POS_AV20,FAT_POS_AVG10,FAT_POS_RATIO,
CON_PRE_AV20,CON_PRE_AVG10,CON_PRE_RATIO, CON_POS_AV20,CON_POS_AVG10,CON_POS_RATIO,
)
# Chose the variables, create the col Condition, time, and the variable, put the data into the col. Value
# and drop NA values. Condition are separated for _
TMS_long<- pivot_longer(TMS, cols =2:13, names_to = c("Condition", "Time", "Variable"),
names_sep = "_", values_to = "Value", values_drop_na = TRUE)
# Rename variables names
TMS_long <- TMS_long %>%
mutate(Condition= recode (Condition, FAT = "Mental Fatigue", CON = "Control")) %>%
mutate(Time= recode(Time, PRE ="Pre", POS= "Post"))%>%
mutate(Variable= recode(Variable, AV20= "AVG20"))
# Keep the order
TMS_long$Time <- factor(TMS_long$Time, levels=c("Pre", "Post"))6.1 Global values
We stimulated the left motor cortex 20 times to obtain the motor evoked potentials (MEPs) measured in your hand before and after the cognitive tasks.
MEP might serve as an index of motor cortex excitability. In our study we were interested in knowing if mental fatigue reduced the excitability of the motor cortex and then, this could explain the possible reduction in the exercise performance.
We we calculated the average of these 20 stimulation and the result is:
# take only the variable avg 20 of the data set.
AVG20<- filter(TMS_long, Variable =="AVG20") %>% convert_as_factor(ID, Condition,Time)
# Exclude participants with excessive noise in the signal
AVG20 <- AVG20 %>% filter(!ID %in% c("8", "18"))
sumrepdatAVG20 <- summarySE(AVG20, measurevar = "Value",
groupvars=c("Condition", "Time"))
TMSrain <- ggplot(AVG20, aes(x = Time, y = Value, fill = Condition)) +
geom_flat_violin(aes(fill = Condition),position = position_nudge(x = .1, y = 0), adjust = 1.5, trim = FALSE, alpha = .5, colour = NA)+
geom_point(aes(x = as.numeric(Time)-.15, y = Value, colour = Condition),position = position_jitter(width = .05), size = .25, shape = 20)+
geom_boxplot(aes(x = Time, y = Value, fill = Condition),outlier.shape = NA, alpha = .5, width = .1, colour = "black")+
geom_line(data = sumrepdatAVG20, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), linetype = 3)+
geom_point(data = sumrepdatAVG20, aes(x = as.numeric(Time)+.1, y = Value, group = Condition, colour = Condition), shape = 18) +
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
labs( y = "MEP amplitude (mV)", x = element_blank(),
title ="Average 20 MEPs",
caption = "n = 20")
TMSrainOnce again, corticospinal excitability was neither affected by the high cognitive load of the task.
6.2 Individual values
# Plot for individual data for Motor Evoked potentials
AVG20plot<-ggplot(AVG20, aes(x = Time, y = Value ))
AVG20plot <- AVG20plot + geom_line(aes(color = Condition, group = ID)) + geom_point()
# Divide panels for conditions (rows) and participants (columns)
AVG20plot <- AVG20plot + facet_grid(Condition ~ ID)
AVG20plot <- AVG20plot +
labs (y= "MEP amplitude (mV)",
x= element_blank(),
title = "Average 20 MEPs pre-post task for each participant",
caption = "n = 20") +
theme(
strip.background = element_blank(),
legend.title = element_blank(),
strip.text.x = element_blank())+
sm_minimal()+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
theme(plot.title = element_text(hjust = 0.5),
axis.text.x = element_text(angle = 90, hjust = 1, size = 8))+
easy_remove_legend()
ggplotly(AVG20plot)We can see that the response is variable and there is not a patron in this sample. Thus, we cannot say that motor cortex excitability was affected. FYI, having a higher or lower amplitude do not indicate anything in particular about you, thus do not worry about these values.
7. Brain Oxygenation
Since individual differences can also be reflected at the brain level, we measured cerebral oxygenation via near-infrared spectroscopy (NIRS) to study the adjustments of individual cerebral activation that occur during mentally fatiguing tasks and in order to assess whether brain oxygenation could be used as an objective biomarker of mental fatigue. Some recent research showed that brain oxygenation increases in frontal areas during mental effort tasks, thus we were interesting in monitoring this parameter.
7.1 Pre-processing
Here, we had to do many steps to process the data, since there were multiples files that we needed to merge in a single file, but it can be done in a few seconds.
- Define the list of files:
# Define the list of files with the desired pattern i.e., excel files
# you will need to download the data from OSF and put it in a folder and set that dir.
my_files <- list.files(pattern = "*.xlsx")
my_files- Create a loop to combine these files:
invisible({capture.output({
# Loop for combining the excel files.
# Choose the values for each participant from time 0 (row 0) to max time 1800s (the task lasted around 30min)
# I did some cleaning in the original file before, like e.g., removing the first 50 rows (descriptive data)...
# and change the time scale from 0 to 1800sec as original files did not begin at the same numerical time...probably could be done here (see later)...but i found easier it for the number of files i had to handle :)
nirs <- lapply(my_files, function(i){
x=read_excel(i, sheet = 1)
x=x [c(0:1800), c(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)] # 2nd argument is to select the columns variables. There are 15 col with data
x$file = i
x
})
})})- Now, all files are merged in one list with multiple data frames. However, they still need to be processed because we need to merge it in only one data.frame, there are some missing values, labels are not correct, etc.
# Bind multiple data frames by row and column
nirs <- nirs %>%
dplyr::bind_rows(nirs)
# Separate column to create participant and condition
nirs=separate(nirs, file, sep="_", into = c("ID", "Condition"))
# Change label of participants
nirs <- nirs %>%
mutate(Condition= recode(Condition, A.xlsx ="Control", B.xlsx ="Mental Fatigue"))
# change 0 values to NA
nirs[nirs == 0] <- NA
# Drop all NA values
nirs <- na.omit(nirs)
# Change column names()
nirs <- setNames(nirs, (c("Time", "Tx1,Tx2,Tx3 TSI%", "Tx1,Tx2,Tx3 TSI Fit",
"Tx1-O2Hb", "Tx1-HHb", "Tx1-tHb", "Tx1-HbDiff",
"Tx2-O2Hb", "Tx2-HHb", "Tx2-tHb", "Tx2-HbDiff",
"Tx3-O2Hb", "Tx3-HHb", "Tx3-tHb", "Tx3-HbDiff",
"ID", "Condition"
)))
# Reorder the columns. Just for aesthetics purpose
nirs <- nirs %>%
select(ID, Time, Condition, everything())
# Calculate the average for the 3 Nirs "lengths" and add to the data.frame
nirs$O2Hbtotal<- ((nirs$`Tx1-O2Hb` + nirs$`Tx2-O2Hb` + nirs$`Tx3-O2Hb`)/3)
nirs$HHbtotal <- ((nirs$`Tx1-HHb` + nirs$`Tx2-HHb` + nirs$`Tx3-HHb`)/3)
nirs$HbDiff <- ((nirs$`Tx1-HbDiff` + nirs$`Tx2-HbDiff` + nirs$`Tx3-HbDiff`)/3)
nirs$tHb <- (nirs$O2Hbtotal + nirs$HHbtotal)- It is almost done, but we were interested in the time on task effect, i.e., how brain oxygenation varied across the performance of the cognitive task. Therefore, we need to create periods (bin) to divide the 1800s (we divided in 8 periods). This is how to do it:
# Create bins of of time (8 blocks of 4 min) (with this, one could easily avoid to adapt the time of each individual file, but i realized late...it's learning by doing and it s-works)
# create the variable to cut the times
time <- nirs$Time
# create 8 bins of equal length
nirs$Period <- cut(time, 8, labels = c("t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8"))- There is a bit more of pre-processing…
#change to long formata
nirs_long <- pivot_longer(nirs, cols = 4:21, names_to = "Variable", values_to = "Values")
# convert long format with the average of each period and variable for each participant
nirs_stat <- nirs_long %>%
group_by(ID, Condition, Period, Variable) %>%
summarise_at(vars(Values), # Specify column
list(average = mean))
# Select only the variable of (possible) interest
target <- c("O2Hbtotal", "HHbtotal", "HHbtotal", "HbDiff", "tHb", "Tx1,Tx2,Tx3 TSI%")
# include these variables in the data frame
nirs_stat <- filter(nirs_stat, Variable %in% target)Here, we can finally see the result of the analysis:
# Filter the variables of interest for the figures
O2 <- filter(nirs_stat, Variable == "O2Hbtotal") %>%
group_by(Period, Condition) %>% summarise_at(vars(average),
list(average = mean))
HHB <- filter(nirs_stat, Variable == "HHbtotal") %>%
group_by(Period, Condition) %>% summarise_at(vars(average),
list(average = mean))
O2Plot <- ggplot(na.omit(O2), aes(x = Period, y = average, colour = Condition, group = Condition) ) +
geom_point() +
geom_line()+
scale_y_continuous(limits = c(-5, 2))+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
easy_remove_x_axis(what = "text")+
geom_hline(yintercept = 0, linetype='dotted', col = 'gray')+
labs( y = "Δ oxy-HB (μm)", x = element_blank(),
title =" Oxyhaemoglobin",
subtitle = " ",
caption = "")+
size
HHBPlot <- ggplot(na.omit(HHB), aes(x = Period, y = average, colour = Condition, group = Condition) ) +
geom_point() +
geom_line()+
scale_y_continuous(limits = c(-6, 2))+
scale_colour_brewer(palette = "Set2")+
scale_fill_brewer(palette = "Set2")+
sm_classic() +
easy_remove_x_axis(what = "text")+
geom_hline(yintercept = 0, linetype='dotted', col = 'gray')+
labs( y = "Δ deoxy-HB (μm)", x = element_blank(),
title =" Deoxyhemoglobin",
subtitle = " ",
caption = "")+
size
NIRSplot <- ggarrange(O2Plot, HHBPlot,
labels = c("A", "B"),
ncol = 1, nrow = 2,
common.legend = T,
legend = "right",
align = "h"
)
NIRSplotSome studies have pointed out that brain oxygenation (Oxyhaemoglobin) increases in frontal areas throughout the course of mental effort tasks. One hypothesis is that we have to allocate more “cognitive resources” to perform task involving the pre-frontal cortex (i.e., the TloadDback). Nonetheless, our results did not support this hypothesis in this experiment. There were not differences between the two conditions or across time. It is also true that these studies used fNIRS, thus they had better accuracy. We also compared the De-Oxyhaemoglobin and it is similar.
I’m not including individual values, because they don’t represent anything particularly interesting to you.
8. Conclusions
It is a complicated and complex topic, and we do not have a definitive answer. Mental fatigue induced “artificially” in a lab with a cognitive task with high demands does not seem to have negative effect in this study (and some others). Nonetheless, we should keep in mind that this is only one study and we should look at the cumulative evidence. In others words, if the topic of mental fatigue and exercise is a movie, this study is only a photogram (but in 4K 😄 !) Finally, either when you see a study showing a positive or a negative results, take it with a pinch of salt! Because there is too much hype in medias, and others things related to academia…
You can read the full article here and statistical analysis are in JASP format in OSF, more user friendly.
Additionally, for other perspective about this topic, you might have a look a this article
If you still have any doubts, feel free to Contact me
PS. Important to know and check on which system and version of R the report was made if you want to replicate it in the future. It might not work in other circumstances
sessioninfo::session_info()%>%
details::details(
summary = 'Current session info',
open = TRUE
)Current session info
─ Session info ───────────────────────────────────────────────────────────────
setting value
version R version 4.2.2 (2022-10-31)
os macOS Ventura 13.6
system aarch64, darwin20
ui X11
language (EN)
collate fr_CH.UTF-8
ctype fr_CH.UTF-8
tz Europe/Zurich
date 2023-09-30
pandoc 2.19.2 @ /Applications/RStudio.app/Contents/MacOS/quarto/bin/tools/ (via rmarkdown)
─ Packages ───────────────────────────────────────────────────────────────────
package * version date (UTC) lib source
abind 1.4-5 2016-07-21 [1] CRAN (R 4.2.0)
assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.2.0)
backports 1.4.1 2021-12-13 [1] CRAN (R 4.2.0)
base64enc 0.1-3 2015-07-28 [1] CRAN (R 4.2.0)
bayestestR * 0.13.0 2022-09-18 [1] CRAN (R 4.2.0)
bookdown 0.32 2023-01-17 [1] CRAN (R 4.2.0)
broom 1.0.3 2023-01-25 [1] CRAN (R 4.2.0)
broom.helpers 1.9.0 2022-09-23 [1] CRAN (R 4.2.0)
bslib 0.4.2 2022-12-16 [1] CRAN (R 4.2.0)
cachem 1.0.6 2021-08-19 [1] CRAN (R 4.2.0)
car 3.1-1 2022-10-19 [1] CRAN (R 4.2.0)
carData 3.0-5 2022-01-06 [1] CRAN (R 4.2.0)
cellranger 1.1.0 2016-07-27 [1] CRAN (R 4.2.0)
checkmate 2.1.0 2022-04-21 [1] CRAN (R 4.2.0)
chromote 0.1.1 2022-09-07 [1] CRAN (R 4.2.0)
cli 3.6.0 2023-01-09 [1] CRAN (R 4.2.0)
clipr 0.8.0 2022-02-22 [1] CRAN (R 4.2.0)
cluster 2.1.4 2022-08-22 [1] CRAN (R 4.2.2)
coda 0.19-4 2020-09-30 [1] CRAN (R 4.2.0)
codetools 0.2-18 2020-11-04 [1] CRAN (R 4.2.2)
colorspace 2.1-0 2023-01-23 [1] CRAN (R 4.2.0)
correlation * 0.8.3 2022-10-09 [1] CRAN (R 4.2.0)
cowplot * 1.1.1 2020-12-30 [1] CRAN (R 4.2.0)
crayon 1.5.2 2022-09-29 [1] CRAN (R 4.2.0)
crosstalk 1.2.0 2021-11-04 [1] CRAN (R 4.2.0)
crul 1.3 2022-09-03 [1] CRAN (R 4.2.0)
curl 5.0.0 2023-01-12 [1] CRAN (R 4.2.0)
data.table 1.14.6 2022-11-16 [1] CRAN (R 4.2.0)
datawizard * 0.6.4 2022-11-19 [1] CRAN (R 4.2.2)
DBI 1.1.3 2022-06-18 [1] CRAN (R 4.2.0)
dbplyr 2.2.1 2022-06-27 [1] CRAN (R 4.2.0)
deldir 1.0-6 2021-10-23 [1] CRAN (R 4.2.0)
desc 1.4.2 2022-09-08 [1] CRAN (R 4.2.0)
details * 0.3.0 2022-03-27 [1] CRAN (R 4.2.0)
digest 0.6.31 2022-12-11 [1] CRAN (R 4.2.0)
directlabels * 2021.1.13 2021-01-16 [1] CRAN (R 4.2.0)
dplyr * 1.1.0 2023-01-29 [1] CRAN (R 4.2.0)
easystats * 0.5.2 2022-08-30 [1] CRAN (R 4.2.0)
effectsize * 0.8.2 2022-10-31 [1] CRAN (R 4.2.0)
ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.2.0)
emmeans 1.8.4-1 2023-01-17 [1] CRAN (R 4.2.0)
emo * 0.0.0.9000 2023-02-04 [1] Github (hadley/emo@3f03b11)
estimability 1.4.1 2022-08-05 [1] CRAN (R 4.2.0)
evaluate 0.20 2023-01-17 [1] CRAN (R 4.2.0)
fansi 1.0.4 2023-01-22 [1] CRAN (R 4.2.0)
farver 2.1.1 2022-07-06 [1] CRAN (R 4.2.0)
fastmap 1.1.0 2021-01-25 [1] CRAN (R 4.2.0)
forcats * 0.5.2 2022-08-19 [1] CRAN (R 4.2.0)
foreign 0.8-83 2022-09-28 [1] CRAN (R 4.2.2)
Formula 1.2-4 2020-10-16 [1] CRAN (R 4.2.0)
fs 1.6.0 2023-01-23 [1] CRAN (R 4.2.0)
gargle 1.2.1 2022-09-08 [1] CRAN (R 4.2.0)
generics 0.1.3 2022-07-05 [1] CRAN (R 4.2.0)
ggeasy * 0.1.3 2022-11-20 [1] Github (jonocarroll/ggeasy@b4b7269)
gghalves 0.1.3 2022-05-30 [1] CRAN (R 4.2.0)
ggplot2 * 3.4.0 2022-11-04 [1] CRAN (R 4.2.0)
ggpubr * 0.5.0 2022-11-16 [1] CRAN (R 4.2.2)
ggsignif 0.6.4 2022-10-13 [1] CRAN (R 4.2.0)
gifski * 1.6.6-1 2022-04-05 [1] CRAN (R 4.2.0)
glue 1.6.2 2022-02-24 [1] CRAN (R 4.2.0)
googledrive 2.0.0 2021-07-08 [1] CRAN (R 4.2.0)
googlesheets4 1.0.1 2022-08-13 [1] CRAN (R 4.2.0)
gridExtra * 2.3 2017-09-09 [1] CRAN (R 4.2.0)
gt * 0.8.0 2022-11-16 [1] CRAN (R 4.2.2)
gtable 0.3.1 2022-09-01 [1] CRAN (R 4.2.0)
gtsummary * 1.6.2 2022-09-30 [1] CRAN (R 4.2.0)
haven 2.5.1 2022-08-22 [1] CRAN (R 4.2.0)
highr 0.10 2022-12-22 [1] CRAN (R 4.2.0)
Hmisc 4.7-1 2022-08-15 [1] CRAN (R 4.2.0)
hms 1.1.2 2022-08-19 [1] CRAN (R 4.2.0)
htmlTable 2.4.1 2022-07-07 [1] CRAN (R 4.2.0)
htmltools 0.5.4 2022-12-07 [1] CRAN (R 4.2.0)
htmlwidgets 1.6.1 2023-01-07 [1] CRAN (R 4.2.0)
httpcode 0.3.0 2020-04-10 [1] CRAN (R 4.2.0)
httr * 1.4.4 2022-08-17 [1] CRAN (R 4.2.0)
insight * 0.18.7 2022-11-18 [1] CRAN (R 4.2.2)
interp 1.1-3 2022-07-13 [1] CRAN (R 4.2.0)
jpeg 0.1-10 2022-11-29 [1] CRAN (R 4.2.0)
jquerylib 0.1.4 2021-04-26 [1] CRAN (R 4.2.0)
jsonlite 1.8.4 2022-12-06 [1] CRAN (R 4.2.0)
knitr 1.42 2023-01-25 [1] CRAN (R 4.2.0)
labeling 0.4.2 2020-10-20 [1] CRAN (R 4.2.0)
later 1.3.0 2021-08-18 [1] CRAN (R 4.2.0)
lattice * 0.20-45 2021-09-22 [1] CRAN (R 4.2.2)
latticeExtra 0.6-30 2022-07-04 [1] CRAN (R 4.2.0)
lazyeval 0.2.2 2019-03-15 [1] CRAN (R 4.2.0)
lifecycle 1.0.3 2022-10-07 [1] CRAN (R 4.2.0)
lubridate 1.9.0 2022-11-06 [1] CRAN (R 4.2.0)
magick * 2.7.3 2021-08-18 [1] CRAN (R 4.2.0)
magrittr 2.0.3 2022-03-30 [1] CRAN (R 4.2.0)
MASS 7.3-58.1 2022-08-03 [1] CRAN (R 4.2.2)
Matrix 1.5-1 2022-09-13 [1] CRAN (R 4.2.2)
memoise 2.0.1 2021-11-26 [1] CRAN (R 4.2.0)
mgcv 1.8-41 2022-10-21 [1] CRAN (R 4.2.2)
modelbased * 0.8.5 2022-08-18 [1] CRAN (R 4.2.0)
modelr 0.1.10 2022-11-11 [1] CRAN (R 4.2.0)
multcomp 1.4-20 2022-08-07 [1] CRAN (R 4.2.0)
munsell 0.5.0 2018-06-12 [1] CRAN (R 4.2.0)
mvtnorm 1.1-3 2021-10-08 [1] CRAN (R 4.2.0)
nlme 3.1-160 2022-10-10 [1] CRAN (R 4.2.2)
nnet 7.3-18 2022-09-28 [1] CRAN (R 4.2.2)
osfr * 0.2.9 2022-09-25 [1] CRAN (R 4.2.0)
parameters * 0.19.0 2022-10-05 [1] CRAN (R 4.2.0)
performance * 0.10.0 2022-10-03 [1] CRAN (R 4.2.0)
pillar 1.8.1 2022-08-19 [1] CRAN (R 4.2.0)
pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.2.0)
plotly * 4.10.1 2022-11-07 [1] CRAN (R 4.2.0)
plyr * 1.8.8 2022-11-11 [1] CRAN (R 4.2.0)
png 0.1-8 2022-11-29 [1] CRAN (R 4.2.0)
processx 3.8.0 2022-10-26 [1] CRAN (R 4.2.0)
promises 1.2.0.1 2021-02-11 [1] CRAN (R 4.2.0)
ps 1.7.2 2022-10-26 [1] CRAN (R 4.2.0)
PupillometryR * 0.0.4 2021-09-19 [1] CRAN (R 4.2.0)
purrr * 1.0.1 2023-01-10 [1] CRAN (R 4.2.0)
pwr 1.3-0 2020-03-17 [1] CRAN (R 4.2.0)
quadprog 1.5-8 2019-11-20 [1] CRAN (R 4.2.0)
R6 2.5.1 2021-08-19 [1] CRAN (R 4.2.0)
RColorBrewer 1.1-3 2022-04-03 [1] CRAN (R 4.2.0)
Rcpp 1.0.10 2023-01-22 [1] CRAN (R 4.2.0)
readr * 2.1.3 2022-10-01 [1] CRAN (R 4.2.0)
readxl * 1.4.1 2022-08-17 [1] CRAN (R 4.2.0)
report * 0.5.5 2022-08-22 [1] CRAN (R 4.2.0)
reprex 2.0.2 2022-08-17 [1] CRAN (R 4.2.0)
rlang * 1.0.6 2022-09-24 [1] CRAN (R 4.2.0)
rmarkdown 2.20 2023-01-19 [1] CRAN (R 4.2.0)
rmdformats 1.0.4.9000 2023-02-05 [1] Github (juba/rmdformats@6d5b252)
Rmisc * 1.5.1 2022-05-02 [1] CRAN (R 4.2.0)
rpart 4.1.19 2022-10-21 [1] CRAN (R 4.2.2)
rprojroot 2.0.3 2022-04-02 [1] CRAN (R 4.2.0)
rstatix * 0.7.1 2022-11-09 [1] CRAN (R 4.2.0)
rstudioapi 0.14 2022-08-22 [1] CRAN (R 4.2.0)
rvest 1.0.3 2022-08-19 [1] CRAN (R 4.2.0)
sandwich 3.0-2 2022-06-15 [1] CRAN (R 4.2.0)
sass 0.4.5 2023-01-24 [1] CRAN (R 4.2.0)
scales 1.2.1 2022-08-20 [1] CRAN (R 4.2.0)
sdamr 0.2.0 2022-11-16 [1] CRAN (R 4.2.2)
see * 0.7.3 2022-09-20 [1] CRAN (R 4.2.0)
sessioninfo 1.2.2 2021-12-06 [1] CRAN (R 4.2.0)
smplot2 * 0.1.0 2022-11-20 [1] Github (smin95/smplot2@87f8331)
stringi 1.7.12 2023-01-11 [1] CRAN (R 4.2.0)
stringr * 1.5.0 2022-12-02 [1] CRAN (R 4.2.0)
survival 3.4-0 2022-08-09 [1] CRAN (R 4.2.2)
TH.data 1.1-1 2022-04-26 [1] CRAN (R 4.2.0)
tibble * 3.1.8 2022-07-22 [1] CRAN (R 4.2.0)
tidyr * 1.3.0 2023-01-24 [1] CRAN (R 4.2.0)
tidyselect 1.2.0 2022-10-10 [1] CRAN (R 4.2.0)
tidyverse * 1.3.2 2022-07-18 [1] CRAN (R 4.2.0)
timechange 0.1.1 2022-11-04 [1] CRAN (R 4.2.0)
tzdb 0.3.0 2022-03-28 [1] CRAN (R 4.2.0)
utf8 1.2.3 2023-01-31 [1] CRAN (R 4.2.0)
vctrs 0.5.2 2023-01-23 [1] CRAN (R 4.2.0)
viridisLite 0.4.1 2022-08-22 [1] CRAN (R 4.2.0)
webshot2 * 0.1.0 2022-05-18 [1] CRAN (R 4.2.0)
websocket 1.4.1 2021-08-18 [1] CRAN (R 4.2.0)
withr 2.5.0 2022-03-03 [1] CRAN (R 4.2.0)
writexl * 1.4.1 2022-10-18 [1] CRAN (R 4.2.0)
xfun 0.37 2023-01-31 [1] CRAN (R 4.2.0)
xml2 1.3.3 2021-11-30 [1] CRAN (R 4.2.0)
xtable 1.8-4 2019-04-21 [1] CRAN (R 4.2.0)
yaml 2.3.7 2023-01-23 [1] CRAN (R 4.2.0)
zoo * 1.8-11 2022-09-17 [1] CRAN (R 4.2.0)
[1] /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/library
──────────────────────────────────────────────────────────────────────────────