This code analyzes data from male and female Endler guppies exposed to cues of risk (predator cue + alarm cue) in the presence or absence of social groups. Individuals assigned to the “Alone” treatment were placed in a tank next to an empty treatment tank. Individuals assigned to the “Social” treatment were placed in a tank next to a treatment tank with 3 unfamilar same-sex conspecifics. Individuals were recored for 10 minutes before risk cues were elicited, with minutes 5-10 being considered “baseline” and further recorded for an additional 35 minutes (encompassing Acute-Trial30 stages, 0-2100 seconds) after receipt of cues of risk (0.75 mL of fresh predator cue, 0.75 mL of alarm cue).
This code specifically analyzes cortisol release rate collected from water. Cortisol was collected two hours before pre receipt of risk cue before the experiment began and 35 minutes post receipt of risk cues.
##Clear enviroment
rm(list=ls())
#Load necessary libraries
#load necessary libraries
library(librarian)
shelf(tidyverse, magrittr, lmerTest, ggpubr, MuMIn, emmeans, rstatix, sjPlot, lsr,car,patchwork)
##
## The 'cran_repo' argument in shelf() was not set, so it will use
## cran_repo = 'https://cran.r-project.org' by default.
##
## To avoid this message, set the 'cran_repo' argument to a CRAN
## mirror URL (see https://cran.r-project.org/mirrors.html) or set
## 'quiet = TRUE'.
#Reading in data file
cortData <- read.csv("CortisolMasterSheetSB.csv")
#Checking structure and turning characters into factors as necessary for factor analysis
str(cortData)
## 'data.frame': 122 obs. of 12 variables:
## $ FishID : int 1 1 2 2 3 3 4 4 5 5 ...
## $ SampleID : int 63 132 60 125 102 114 19 133 43 123 ...
## $ Sex : chr "F" "F" "F" "F" ...
## $ Treatment : chr "Social" "Social" "Control" "Control" ...
## $ Stage : chr "Post" "Pre" "Post" "Pre" ...
## $ Dilution : int 50 50 50 50 50 50 50 50 50 50 ...
## $ GroupID : int 1 1 1 1 1 1 1 1 10 10 ...
## $ Cortisol_Elisa: num 190 747 146 943 341 ...
## $ Plate : int 19 6 11 10 12 15 19 13 18 12 ...
## $ Weight : num 0.29 0.23 0.13 0.17 0.14 0.15 0.17 0.21 0.09 0.07 ...
## $ Length : num 3.4 3.4 2.5 2.5 2.1 2.1 2.2 2.2 NA NA ...
## $ Depth : num 0.5 0.5 0.3 0.3 0.3 0.3 0.3 0.3 NA NA ...
#Converting all characters to factors
cortData %<>%
mutate(across(where(is_character), as_factor)) -> cortData ##looks for columns that are seen as characters and turning them into factors
str(cortData)
## 'data.frame': 122 obs. of 12 variables:
## $ FishID : int 1 1 2 2 3 3 4 4 5 5 ...
## $ SampleID : int 63 132 60 125 102 114 19 133 43 123 ...
## $ Sex : Factor w/ 2 levels "F","M": 1 1 1 1 1 1 1 1 2 2 ...
## $ Treatment : Factor w/ 2 levels "Social","Control": 1 1 2 2 2 2 1 1 2 2 ...
## $ Stage : Factor w/ 2 levels "Post","Pre": 1 2 1 2 1 2 1 2 1 2 ...
## $ Dilution : int 50 50 50 50 50 50 50 50 50 50 ...
## $ GroupID : int 1 1 1 1 1 1 1 1 10 10 ...
## $ Cortisol_Elisa: num 190 747 146 943 341 ...
## $ Plate : int 19 6 11 10 12 15 19 13 18 12 ...
## $ Weight : num 0.29 0.23 0.13 0.17 0.14 0.15 0.17 0.21 0.09 0.07 ...
## $ Length : num 3.4 3.4 2.5 2.5 2.1 2.1 2.2 2.2 NA NA ...
## $ Depth : num 0.5 0.5 0.3 0.3 0.3 0.3 0.3 0.3 NA NA ...
#Turing specific numerical/integers into factors
#We also want FishID, GroupID, and Plate to be factors
cortData %>%
mutate(FishID = as.factor(FishID)) -> cortData
cortData %>%
mutate(GroupID = as.factor(GroupID)) -> cortData
cortData %>%
mutate(Plate = as.factor(Plate)) -> cortData
str(cortData)
## 'data.frame': 122 obs. of 12 variables:
## $ FishID : Factor w/ 62 levels "1","2","3","4",..: 1 1 2 2 3 3 4 4 5 5 ...
## $ SampleID : int 63 132 60 125 102 114 19 133 43 123 ...
## $ Sex : Factor w/ 2 levels "F","M": 1 1 1 1 1 1 1 1 2 2 ...
## $ Treatment : Factor w/ 2 levels "Social","Control": 1 1 2 2 2 2 1 1 2 2 ...
## $ Stage : Factor w/ 2 levels "Post","Pre": 1 2 1 2 1 2 1 2 1 2 ...
## $ Dilution : int 50 50 50 50 50 50 50 50 50 50 ...
## $ GroupID : Factor w/ 18 levels "1","3","4","5",..: 1 1 1 1 1 1 1 1 9 9 ...
## $ Cortisol_Elisa: num 190 747 146 943 341 ...
## $ Plate : Factor w/ 17 levels "2","3","4","5",..: 17 5 9 8 10 13 17 11 16 10 ...
## $ Weight : num 0.29 0.23 0.13 0.17 0.14 0.15 0.17 0.21 0.09 0.07 ...
## $ Length : num 3.4 3.4 2.5 2.5 2.1 2.1 2.2 2.2 NA NA ...
## $ Depth : num 0.5 0.5 0.3 0.3 0.3 0.3 0.3 0.3 NA NA ...
#Measurment Transformation
#Transforming the cortisol measurement from pg/mL to ng/dl
cortData %>%
mutate(cortNG = (Cortisol_Elisa/1000)) -> cortData
#Creating the column to report cortisol by weight
cortData %>%
mutate(cortWeight = (cortNG/Weight)) -> cortData
#Creating the column to report cortisol by weight by minute
cortData %>%
mutate(cortFinal = (cortWeight/30)) -> cortData
#Putting all factors in the order we want and renaming if necessary
levels(cortData$Treatment) <- list(Alone = "Control", Social = "Social")
levels(cortData$Sex) <- list(female = "F", male = "M")
#levels(cortData$Stage) <- list(Pre = "Pre", Post = "Post")
str(cortData)
## 'data.frame': 122 obs. of 15 variables:
## $ FishID : Factor w/ 62 levels "1","2","3","4",..: 1 1 2 2 3 3 4 4 5 5 ...
## $ SampleID : int 63 132 60 125 102 114 19 133 43 123 ...
## $ Sex : Factor w/ 2 levels "female","male": 1 1 1 1 1 1 1 1 2 2 ...
## $ Treatment : Factor w/ 2 levels "Alone","Social": 2 2 1 1 1 1 2 2 1 1 ...
## $ Stage : Factor w/ 2 levels "Post","Pre": 1 2 1 2 1 2 1 2 1 2 ...
## $ Dilution : int 50 50 50 50 50 50 50 50 50 50 ...
## $ GroupID : Factor w/ 18 levels "1","3","4","5",..: 1 1 1 1 1 1 1 1 9 9 ...
## $ Cortisol_Elisa: num 190 747 146 943 341 ...
## $ Plate : Factor w/ 17 levels "2","3","4","5",..: 17 5 9 8 10 13 17 11 16 10 ...
## $ Weight : num 0.29 0.23 0.13 0.17 0.14 0.15 0.17 0.21 0.09 0.07 ...
## $ Length : num 3.4 3.4 2.5 2.5 2.1 2.1 2.2 2.2 NA NA ...
## $ Depth : num 0.5 0.5 0.3 0.3 0.3 0.3 0.3 0.3 NA NA ...
## $ cortNG : num 0.19 0.747 0.146 0.943 0.341 ...
## $ cortWeight : num 0.655 3.248 1.127 5.549 2.433 ...
## $ cortFinal : num 0.0218 0.1083 0.0376 0.185 0.0811 ...
#Standard Error Formual Input and obtain sample sizes
#Standard error formula:
se <- function(x) sd(x, na.rm=T)/sqrt(length(x))
#Sample sizes
tapply(cortData$FishID, list(cortData$Treatment, cortData$Stage, cortData$Sex), length)
## , , female
##
## Post Pre
## Alone 15 16
## Social 16 16
##
## , , male
##
## Post Pre
## Alone 15 15
## Social 15 14
#Filter out single high cort data male
dim(cortData)
## [1] 122 15
cortData %>%
filter(cortFinal < 1) -> cortData
dim(cortData)
## [1] 121 15
#First check for outliers
#Create column with difference of after cue - before cue to control for individual starting cortisol
cortData %>%
pivot_wider(id_cols=c(Treatment, Sex, FishID, GroupID, Plate),
names_from = Stage,
values_from = cortFinal) -> cortDatNew
cortData %>%
pivot_wider(id_cols=c(Treatment, Sex, FishID, GroupID),
names_from = Stage,
values_from = cortFinal) %>%
mutate(difference =(Post - Pre)) -> cortDatDiff
#cortData %>%
# mutate(cortFinal = (cortWeight/30)) -> cortData
#before cue
#after cue
#cortFinal
list_quantiles <- tapply(cortDatDiff$difference, cortDatDiff$Sex, quantile, na.rm = TRUE)
dim(cortDatDiff)
## [1] 62 7
Q1s <- sapply(1:2, function(i) list_quantiles[[i]][2])
Q3s <- sapply(1:2, function(i) list_quantiles[[i]][4])
IQRs <- tapply(cortDatDiff$difference, cortDatDiff$Sex, IQR, na.rm = TRUE)
Lowers <- Q1s - 1.5*IQRs
Uppers <- Q3s + 1.5*IQRs
datas <- split(cortDatDiff, cortDatDiff$Sex)
data_no_outlierCort <- NULL
for (i in 1:2){
out <- subset(datas[[i]], datas[[i]]$difference > Lowers[i] & datas[[i]]$difference < Uppers[i])
data_no_outlierCort <- rbind(data_no_outlierCort, out)
}
dim(data_no_outlierCort) #six outliers removed
## [1] 56 7
cort.lmm <- lmer(Pre~Sex*Treatment +
+ (1|GroupID) + (1|Plate), data = cortDatNew)
## boundary (singular) fit: see help('isSingular')
#Check residuals for normality
resid(cort.lmm) -> cortResids
hist(cortResids)
ggdensity(cortResids,
main="Density plot of residuals",
xlab="Residuals")
ggqqplot(cortResids)
shapiro.test(cortResids)
##
## Shapiro-Wilk normality test
##
## data: cortResids
## W = 0.9274, p-value = 0.001392
#Fits our criteria, let's check effects
anova(cort.lmm)
## Type III Analysis of Variance Table with Satterthwaite's method
## Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
## Sex 0.144001 0.144001 1 57 10.3829 0.002104 **
## Treatment 0.005283 0.005283 1 57 0.3809 0.539575
## Sex:Treatment 0.011494 0.011494 1 57 0.8288 0.366463
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
ranova(cort.lmm)
## boundary (singular) fit: see help('isSingular')
## boundary (singular) fit: see help('isSingular')
## ANOVA-like table for random-effects: Single term deletions
##
## Model:
## Pre ~ Sex + Treatment + (1 | GroupID) + (1 | Plate) + Sex:Treatment
## npar logLik AIC LRT Df Pr(>Chisq)
## <none> 7 35.6 -57.2
## (1 | GroupID) 6 35.6 -59.2 0 1 1
## (1 | Plate) 6 35.6 -59.2 0 1 1
#Pulling out R2
r.squaredGLMM(cort.lmm)
## R2m R2c
## [1,] 0.1593917 0.1593917
## Warning: The `size` argument of `element_rect()` is deprecated as of ggplot2 3.4.0.
## ℹ Please use the `linewidth` argument instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
##Analysis of post-cue cortisol release rate between sexes regardless of treatment with group ID as a random effect
cort.lmm <- lmer(Post~Sex*Treatment + (1|GroupID) + (1|Plate), data = cortDatNew)
#Check residuals for normality
resid(cort.lmm) -> cortResids
hist(cortResids)
ggdensity(cortResids,
main="Density plot of residuals",
xlab="Residuals")
ggqqplot(cortResids)
shapiro.test(cortResids)
##
## Shapiro-Wilk normality test
##
## data: cortResids
## W = 0.93512, p-value = 0.003296
#Fits our criteria, let's check effects
anova(cort.lmm)
## Type III Analysis of Variance Table with Satterthwaite's method
## Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
## Sex 0.093862 0.093862 1 10.203 8.2752 0.01616 *
## Treatment 0.001137 0.001137 1 27.755 0.1002 0.75394
## Sex:Treatment 0.033163 0.033163 1 25.174 2.9238 0.09958 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
#Means and se
tapply(cortData$cortFinal, list(cortData$Sex, cortData$Stage), mean)
## before cue after cue
## female 0.1108598 0.1040713
## male 0.2073859 0.1852387
tapply(cortData$cortFinal, list(cortData$Sex, cortData$Stage), se)
## before cue after cue
## female 0.01497993 0.02175837
## male 0.02681746 0.02623432
ranova(cort.lmm)
## boundary (singular) fit: see help('isSingular')
## ANOVA-like table for random-effects: Single term deletions
##
## Model:
## Post ~ Sex + Treatment + (1 | GroupID) + (1 | Plate) + Sex:Treatment
## npar logLik AIC LRT Df Pr(>Chisq)
## <none> 7 29.416 -44.831
## (1 | GroupID) 6 29.412 -46.825 0.00610 1 0.9377
## (1 | Plate) 6 29.114 -46.228 0.60247 1 0.4376
#Pulling out R2
r.squaredGLMM(cort.lmm)
## R2m R2c
## [1,] 0.09818171 0.5569277
##Panel graphs
# panel <- (cortgraph2|cortgraph3)
# # plot_annotation(tag_levels = 'A') #add figure labels
# panel
cortNO.lmm <- lmer(difference~Treatment*Sex + (1|GroupID), data =cortDatDiff)
## boundary (singular) fit: see help('isSingular')
#Check residuals for normality
resid(cortNO.lmm) -> cortResidsNO
hist(cortResidsNO)
ggdensity(cortResidsNO,
main="Density plot of residuals",
xlab="Residuals")
ggqqplot(cortResidsNO)
shapiro.test(cortResidsNO)
##
## Shapiro-Wilk normality test
##
## data: cortResidsNO
## W = 0.94252, p-value = 0.007665
#Fits criteria
anova(cortNO.lmm)
## Type III Analysis of Variance Table with Satterthwaite's method
## Sum Sq Mean Sq NumDF DenDF F value Pr(>F)
## Treatment 0.042809 0.042809 1 55 1.9290 0.17047
## Sex 0.003065 0.003065 1 55 0.1381 0.71158
## Treatment:Sex 0.071569 0.071569 1 55 3.2249 0.07802 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
ranova(cortNO.lmm)
## ANOVA-like table for random-effects: Single term deletions
##
## Model:
## difference ~ Treatment + Sex + (1 | GroupID) + Treatment:Sex
## npar logLik AIC LRT Df Pr(>Chisq)
## <none> 6 21.302 -30.604
## (1 | GroupID) 5 21.302 -32.604 7.1054e-15 1 1
r.squaredGLMM(cortNO.lmm)
## R2m R2c
## [1,] 0.07898577 0.07898577
#Boxplot graphing Difference in cortisol release rate after receipt of risk cues by Treatment and Sex #Fulldataset
#Boxplot graphing Difference in cortisol release rate after receipt of risk cues by Treatment and Sex with outliers taken out
## 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.
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Warning: Removed 3 rows containing non-finite outside the scale range
## (`stat_boxplot()`).
## Warning: Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).
## Removed 3 rows containing missing values or values outside the scale range
## (`geom_point()`).