## Snapshots of human anatomy, locomotion, and behavior from Late Pleistocene footprints at Engare Sero, Tanzania
##
## Code and annotations written by Kevin G. Hatala (kevin.g.hatala@gmail.com) and Adam D. Gordon (adam.d.gordon@gmail.com)


## Load all required libraries
library(caret)
library(circular)
library(dplyr)
library(ggplot2)
library(Hmisc)
library(nlme)
library(reshape2)
library(ROCR)

## Analyses follow sequence of Methods section in published manuscript

##
##
## Estimating speeds of travel
##
##

## Load experimental data set (these data are not original to the current study; see reference 36 for details regarding this data set)
expStridesAndSpeedsRAW <- read.csv(file.choose())
## Convert raw stride length measurements to relative stride lengths for experimental data set
expStridesAndSpeeds <- mutate(expStridesAndSpeedsRAW, relStrideLength = (strideLength*100)/footprintLength)

## Load fossil footprint data set (these data are provided in Supplementary Data S1)
engareSeroPrintDimensions <- read.csv(file.choose())
## Extract median footprint dimensions for each Engare Sero trackway
trackwayMedianDimensions <- as.data.frame(engareSeroPrintDimensions %>%
                                            select(Trackway, heelToDigit3, heelToHallux, forefootBreadth, heelBreadth) %>%
                                            group_by(Trackway) %>%
                                            summarise_all(~median(.,na.rm=TRUE)))

## Load fossil trackway data set (these data are provided in Supplementary Data S2)
engareSeroStrideLengths <- read.csv(file.choose())
## Append trackway median dimensions
engareSeroMedStridesAndTracks <- full_join(engareSeroStrideLengths, trackwayMedianDimensions)
## Add a variable for relative stride lengths (median stride length divided by median track length)
engareSeroRelativeStrideData <- as.data.frame(engareSeroMedStridesAndTracks %>%
                                    mutate(relStrideLength = medStrideLength/(heelToHallux/10)))

## Try an inclusive predictive model, blending all walking and running data
velocityPredictionData <- expStridesAndSpeeds %>%
  select(1, 2, 5, 6, 10)
velocityPredictionData <- velocityPredictionData[complete.cases(velocityPredictionData),]
set.seed(123)
inTrain <- createDataPartition(y = velocityPredictionData$Velocity, p = 0.7, list = FALSE)
train <- velocityPredictionData[inTrain,]
test <- velocityPredictionData[-inTrain,]
inclusiveVelocityModel <- lm(Velocity~relStrideLength, data=train)
summary(inclusiveVelocityModel)
anova(inclusiveVelocityModel)
velocityPreds <- predict(inclusiveVelocityModel, newdata = test)
velocityRMSE <- sqrt(mean((test$Velocity-velocityPreds)^2))
velocityRMSE
## RMSE is equal to 0.452 m/s

## Precede linear regression with logistic regression model to predict gait type (to potentially reduce variance/error by conducting speed predictions within gait types)
## Code walk trials as 1, run trials as 0
velocityPredictionData$Gait <- ifelse(velocityPredictionData$Gait == "Walk", 1, 0)
## Divide into new training and test sets
set.seed(234)
inTrain2 <- createDataPartition(y = velocityPredictionData$Velocity, p = 0.7, list = FALSE)
train2 <- velocityPredictionData[inTrain,]
test2 <- velocityPredictionData[-inTrain,]
gaitModel <- glm(Gait~relStrideLength, family = binomial(link = 'logit'), data = train2)
summary(gaitModel)
anova(gaitModel, test = "Chisq")
fitted.results <- predict(gaitModel, newdata = test2, type = 'response')
fitted.results <- ifelse(fitted.results > 0.5, 1, 0)
misclassificationError <- mean(fitted.results != test2$Gait)
numberMisclassified <- sum(fitted.results != test2$Gait)
numberMisclassified
print(paste('Accuracy', (1-misclassificationError)*100))
## Accuracy = 97.79%
p <- predict(gaitModel, newdata = test2, type = "response")
pr <- prediction(p, test2$Gait)
prf <- performance(pr, measure = "tpr", x.measure = "fpr")
plot(prf)
auc <- performance(pr, measure = "auc")
auc <- auc@y.values[[1]]
auc
## AUC = 0.996

## Walk-only regression model
walkTrainData <- train2 %>%
  filter(Gait == 1)
plot(x = walkTrainData$relStrideLength, y = walkTrainData$Velocity)
## Divide into new training and test sets
walkVelocityModel <- lm(Velocity~relStrideLength, data = walkTrainData)
summary(walkVelocityModel)
anova(walkVelocityModel)
walkTestData <- test2 %>%
  mutate(Gait = fitted.results) %>%
  filter(Gait == 1)
walkVelocityPreds <- predict(walkVelocityModel, newdata = walkTestData)
walkVelocityRMSE <- sqrt(mean((walkTestData$Velocity-walkVelocityPreds)^2))
walkVelocityRMSE
## RMSE is equal to 0.252 m/s for test trials (compared with 0.452 m/s for inclusive model)

## Run-only regression model
runTrainData <- train2 %>%
  filter(Gait == 0)
plot(x = runTrainData$relStrideLength, y = runTrainData$Velocity)
## Divide into new training and test sets
runVelocityModel <- lm(Velocity~relStrideLength, data = runTrainData)
summary(runVelocityModel)
anova(runVelocityModel)
runTestData <- test2 %>%
  mutate(Gait = fitted.results) %>%
  filter(Gait == 0)
runVelocityPreds <- predict(runVelocityModel, newdata = runTestData)
runVelocityRMSE <- sqrt(mean((runTestData$Velocity-runVelocityPreds)^2))
runVelocityRMSE
## RMSE is equal to 0.610 m/s for test trials (compared with 0.452 m/s for inclusive model)
## Summary: Dividing by gait leads to lower RMSE on walking predictions but higher RMSE on running predictions
## Difference is likely due to greater between-subject variation in running mechanics (discussed in main text of manuscript)

## Walk model comparison to see if random subject effect might result in greater accuracy of predictive model
walkModelA <- gls(Velocity~relStrideLength, data = walkTrainData)
walkModelB <- lme(Velocity~relStrideLength, data = walkTrainData, random = ~1|Subject)
walkModelC <- lme(Velocity~relStrideLength, data = walkTrainData, random = ~1 + relStrideLength|Subject)
AIC(walkModelA, walkModelB, walkModelC)
summary(walkModelC)
anova(walkModelC)
plot(walkModelC, select = c(1))
normResWalk<-resid(walkModelC, type = "normalized")
boxplot(normResWalk~Subject, data = walkTrainData)
plot(x = walkTrainData$relStrideLength, y = normResWalk)
plot(walkModelC, Velocity~fitted(.))
qqnorm(walkModelC, ~resid(.)|Subject)
## Population predictions derived from walkModelC
meeWalkVelocityPreds <- predict(walkModelC, newdata = walkTestData, level = 0)
meeWalkVelocityRMSE2 <- sqrt(mean((walkTestData$Velocity-meeWalkVelocityPreds)^2))
meeWalkVelocityRMSE2
## RMSE = 0.238 m/s

## Model comparison to see if random subject effect might result in greater accuracy of predictive model
runModelA <- gls(Velocity~relStrideLength, data = runTrainData)
runModelB <- lme(Velocity~relStrideLength, data = runTrainData, random = ~1|Subject)
runModelC <- lme(Velocity~relStrideLength, data = runTrainData, random = ~1 + relStrideLength|Subject)
AIC(runModelA, runModelB, runModelC)
summary(runModelC)
anova(runModelC)
plot(runModelC, select=c(1))
normResRun<-resid(runModelC, type = "normalized")
boxplot(normResRun~Subject, data = runTrainData)
plot(x = runTrainData$relStrideLength, y = normResRun)
plot(runModelC, Velocity~fitted(.))
qqnorm(runModelC, ~resid(.)|Subject)
## Fixed effects coefficients extracted from walkModelC
meeRunVelocityPreds <- predict(runModelC, newdata = runTestData, level = 0)
meeRunVelocityRMSE2 <- sqrt(mean((runTestData$Velocity-meeRunVelocityPreds)^2))
meeRunVelocityRMSE2
## RMSE = 0.599 m/s
## Slight improvements in RMSE when predicting with population parameters derived from mixed effects model

## Generate gait type predictions for Engare Sero trackways
engareSeroGaitPreds <- predict(gaitModel, newdata = engareSeroRelativeStrideData, type = "response")
engareSeroGaitPreds <- ifelse(engareSeroGaitPreds > 0.5, 1, 0)
engareSeroGaitTypes <- mutate(engareSeroRelativeStrideData, Gait = engareSeroGaitPreds)
## Separate Engare Sero walking and running trackways 
engareSeroWalkData <- filter(engareSeroGaitTypes, Gait == 1)
engareSeroRunData <- filter(engareSeroGaitTypes, Gait == 0)

## Generate Engare Sero velocity predictions
engareSeroWalkVelocities <- predict(walkModelC, newdata = engareSeroWalkData, level = 0)
engareSeroWalkPredictions <- as.data.frame(cbind(as.character(engareSeroWalkData$Trackway), engareSeroWalkData$relStrideLength, engareSeroWalkVelocities))
colnames(engareSeroWalkPredictions) <- c("Trackway", "relStrideLength", "predVelocity")
engareSeroWalkPredictions
engareSeroRunVelocities <- predict(runModelC, newdata = engareSeroRunData, level = 0)
engareSeroRunPredictions <-as.data.frame(cbind(as.character(engareSeroRunData$Trackway), engareSeroRunData$relStrideLength, engareSeroRunVelocities))
colnames(engareSeroRunPredictions) <- c("Trackway", "relStrideLength", "predVelocity")
engareSeroRunPredictions

## Plot velocity predictions (Figure 4)
engareSeroRunPredictions$predVelocity <- as.numeric(levels(engareSeroRunPredictions$predVelocity))[engareSeroRunPredictions$predVelocity]
engareSeroRunPredictions2 <- as.data.frame(engareSeroRunPredictions %>%
                                             mutate(LL = predVelocity - runVelocityRMSE) %>%
                                             mutate(UL = predVelocity + runVelocityRMSE))
engareSeroWalkPredictions$predVelocity <- as.numeric(levels(engareSeroWalkPredictions$predVelocity))[engareSeroWalkPredictions$predVelocity]
engareSeroWalkPredictions2 <- as.data.frame(engareSeroWalkPredictions %>%
                                              mutate(LL = predVelocity - walkVelocityRMSE) %>%
                                              mutate(UL = predVelocity + walkVelocityRMSE))
allSpeedPredictions <- rbind(engareSeroRunPredictions2, engareSeroWalkPredictions2)
speedPredictionPlot <- ggplot(allSpeedPredictions, aes(x = Trackway, y = predVelocity)) +
  geom_errorbar(aes(ymin = LL, ymax = UL), width = .1) +
  geom_point() +
  labs(y = "Predicted velocity (m/s)", x = "Trackway") +
  theme(axis.title.x = element_text(size=12,colour="black"), axis.text.x = element_text(size = 10,angle = 45, colour = "black", vjust = 1, hjust = 1),
        axis.title.y = element_text(size=12,colour="black"), axis.text.y = element_text(size = 10,colour="black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
speedPredictionPlot
ggsave(filename = "speedPredictionPlot.jpg", scale = 1, width = 6.5, height = 3.25, dpi = 300)

## Output Engare Sero velocity predictions to .csv file (Table 1)
engareSeroVelocities <- full_join(engareSeroWalkPredictions, engareSeroRunPredictions)
write.csv(engareSeroVelocities, "engareSeroVelocities.csv")


##
##
## Analyzing trackway orientations
##
##

## Load data on trackway orientations (these are available in Supplementary Data S2)
trackwayOrientations <- read.csv(file.choose())
## Convert orientation data to circular object
trackCirc <- as.circular(trackwayOrientations[,2], type = "directions", units = "degrees", zero = pi/2, rotation = "clock")
## Plot rose diagram to visualize distribution of trackway orientations
rose <- ggplot(mapping = aes(x = trackCirc)) +
  stat_bin(breaks = (0:8 - 0.5)/8 * 360) +
  scale_x_continuous(
    breaks = 0:7/8*360, 
    labels = c("N", "NE", "E", "SE", "S", "SW", "W", "NW")
  ) +
  coord_polar(start = -pi/8) +
  theme(axis.title.x = element_blank())
rose
## Rayleigh's test of uniformity for trackway orientations
rTest<- rayleigh.test(trackCirc)
rTest
## P-value = 0.0096 (suggests directionality)
## Bimodal distribution of the data set is obvious (one NE group, one SW group)
## Analyze NE only
neTrackways <- trackwayOrientations[1:6, 2]
neTrackCirc <- as.circular(neTrackways, type = "angles", units = "degrees", zero = pi/2, rotation = "clock")
rTestNE<- rayleigh.test(neTrackCirc)
rTestNE
## P-value = 0 (suggests directionality)
## Calculate bootstrapped 95% CI
set.seed(4652)
mle.vonmises.bootstrap.ci(neTrackCirc)

## Analyze SW only
swTrackways <- trackwayOrientations[7:22, 2]
swTrackCirc <- as.circular(swTrackways, type = "angles", units = "degrees", zero = pi/2, rotation = "clock")
rTestSW <- rayleigh.test(swTrackCirc)
rTestSW
## P-value = 0 (suggests directionality)
## Calculate bootstrapped 95% CI
set.seed(5643)
mle.vonmises.bootstrap.ci(swTrackCirc)


##
##
## Estimating body size
##
##

## Load experimental data set (these data are not original to the current study; see reference 36 for details regarding this data set)
expPrintAndBodySizesRAW <- read.csv(file.choose())

## Constructing models for stature predictions - walking speeds
plot(x = expPrintAndBodySizesRAW$heelToHallux, y = expPrintAndBodySizesRAW$Stature)
plot(x = expPrintAndBodySizesRAW$forefootBreadth, y = expPrintAndBodySizesRAW$Stature)
plot(x = expPrintAndBodySizesRAW$heelBreadth, y = expPrintAndBodySizesRAW$Stature)
staturePredictionDataWalk <- as.data.frame(expPrintAndBodySizesRAW %>%
  filter(Gait == "Walk") %>%
  select(1, 2, 4, 6, 8, 9) %>%
  group_by(Subject) %>%
  summarise_all(~median(., na.rm = TRUE)) %>%
  select(Subject, Stature, heelToHallux, forefootBreadth, heelBreadth))
set.seed(345)
inTrain <- createDataPartition(y = staturePredictionDataWalk$Stature, p = 0.7, list = FALSE)
train <- staturePredictionDataWalk[inTrain,]
test <- staturePredictionDataWalk[-inTrain,]
statureModelWalkA <- lm(Stature~heelToHallux+forefootBreadth+heelBreadth, data = train)
summary(statureModelWalkA)
statureModelWalkB <- lm(Stature~heelToHallux+forefootBreadth, data = train)
summary(statureModelWalkB)
statureModelWalkC <- lm(Stature~heelToHallux, data = train)
summary(statureModelWalkC)
AIC(statureModelWalkA, statureModelWalkB, statureModelWalkC)
testPredictionsWalkA <- predict(statureModelWalkA, newdata = test)
statureRMSEWalkA <- sqrt(mean((test$Stature-testPredictionsWalkA)^2))
statureRMSEWalkA
## RMSE of 7.68 cm
testPredictionsWalkB <- predict(statureModelWalkB, newdata = test)
statureRMSEWalkB <- sqrt(mean((test$Stature-testPredictionsWalkB)^2))
statureRMSEWalkB
## RMSE of 7.66 cm
testPredictionsWalkC <- predict(statureModelWalkC, newdata = test)
statureRMSEWalkC <- sqrt(mean((test$Stature-testPredictionsWalkC)^2))
statureRMSEWalkC
## RMSE of 6.27 cm - lowest prediction error from model that predicts stature from just footprint length (heel to hallux)

## Stature prediction from Engare Sero trackways that reflect walking data
head(trackwayMedianDimensions)
engareSeroStaturePredictionDataWalk <- select(trackwayMedianDimensions, c(1,3))[-2,]
engareSeroStaturePredictionDataWalk <- engareSeroStaturePredictionDataWalk %>%
  mutate(heelToHallux = heelToHallux/10)
engareSeroStaturePredictionsWalk <- predict(statureModelWalkC, newdata = engareSeroStaturePredictionDataWalk)
engareSeroStaturePredictionsWalk
## Merge trackway labels and stature predictions (converted to meters) into one table
engareSeroStaturesWalk <-as.data.frame(cbind(as.character(engareSeroStaturePredictionDataWalk$Trackway), engareSeroStaturePredictionsWalk/100))
colnames(engareSeroStaturesWalk) <- c("Trackway", "predStature")
engareSeroStaturesWalk

## Constructing models for stature predictions - running speeds
staturePredictionDataRun <- as.data.frame(expPrintAndBodySizesRAW %>%
                                         filter(Gait == "Run") %>%
                                         select(1, 2, 4, 6, 8, 9) %>%
                                         group_by(Subject) %>%
                                         summarise_all(~median(., na.rm = TRUE)) %>%
                                         select(Subject, Stature, heelToHallux, forefootBreadth, heelBreadth))
set.seed(456)
inTrain <- createDataPartition(y = staturePredictionDataRun$Stature, p = 0.7, list = FALSE)
train <- staturePredictionDataRun[inTrain,]
test <- staturePredictionDataRun[-inTrain,]
statureModelRunA <- lm(Stature~heelToHallux + forefootBreadth + heelBreadth, data = train)
summary(statureModelRunA)
statureModelRunB <- lm(Stature~heelToHallux + forefootBreadth, data = train)
summary(statureModelRunB)
statureModelRunC <- lm(Stature~heelToHallux, data = train)
summary(statureModelRunC)
AIC(statureModelRunA, statureModelRunB, statureModelRunC)
testPredictionsRunA <- predict(statureModelRunA, newdata = test)
statureRMSERunA <- sqrt(mean((test$Stature - testPredictionsRunA)^2))
statureRMSERunA
## RMSE of 8.47 cm
testPredictionsRunB <- predict(statureModelRunB, newdata = test)
statureRMSERunB <- sqrt(mean((test$Stature - testPredictionsRunB)^2))
statureRMSERunB
## RMSE of 8.23 cm
testPredictionsRunC <- predict(statureModelRunC, newdata = test)
statureRMSERunC <- sqrt(mean((test$Stature - testPredictionsRunC)^2))
statureRMSERunC
## RMSE of 7.82 cm - lowest prediction error from model that predicts stature from just footprint length (heel to hallux)

## Regression equations from statureModelWalkC and statureModelRunC were copied into Table S1

## Stature prediction from Engare Sero trackways that reflect running data
engareSeroStaturePredictionDataRun <- select(trackwayMedianDimensions, c(1, 3))[2,]
engareSeroStaturePredictionDataRun <- engareSeroStaturePredictionDataRun %>%
  mutate(heelToHallux = heelToHallux/10)
engareSeroStaturePredictionsRun <- predict(statureModelRunC, newdata = engareSeroStaturePredictionDataRun)
engareSeroStaturesRun <-as.data.frame(cbind(as.character(engareSeroStaturePredictionDataRun$Trackway), engareSeroStaturePredictionsRun/100))
colnames(engareSeroStaturesRun) <- c("Trackway", "predStature")
engareSeroStaturesRun

## Output Engare Sero stature predictions to .csv file (Table 2)
engareSeroStatures <- rbind(engareSeroStaturesWalk, engareSeroStaturesRun)
write.csv(engareSeroStatures,"engareSeroStatures.csv")


##
##
## Estimating group structure
##
##

## Load experimental data set (these data are not original to the current study; see reference 36 for details regarding this data set)
experimentalFootprints <- read.csv(file.choose())
footVars <- c("Footprint.Length.B", "Foot.Length.B")
experimentalFootprints <- experimentalFootprints[complete.cases(experimentalFootprints[,footVars]),]

## Plot footprint - foot lengths as histograms (Figure S1)
experimentalFootprints.v2<-experimentalFootprints %>%
  mutate(footprintError = Footprint.Length.B - Foot.Length.B) %>%
  mutate(footprintProportionalError = footprintError/Foot.Length.B)
footToPrintError<-ggplot(experimentalFootprints.v2, aes(x = footprintProportionalError)) +
  geom_histogram(bins=20) +
  scale_x_continuous(breaks = c(-0.15, -0.10, -0.05, 0, 0.05, 0.10, 0.15), labels = c(-0.15, -0.10, -0.05, 0, 0.05, 0.10, 0.15)) +
  xlab("(Footprint length - Foot length)/Foot length") +
  ylab("Frequency") +
  geom_vline(xintercept = mean(experimentalFootprints.v2$footprintProportionalError), linetype = "dashed") +
  theme(axis.title.x = element_text(size = 12, colour = "black"), axis.text.x = element_text(size = 10, colour = "black", vjust = 1, hjust = 1),
        axis.title.y = element_text(size = 12, colour = "black"), axis.text.y = element_text(size = 10, colour = "black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
footToPrintError
ggsave(filename = "footToPrintError.jpg", device = "jpeg", scale = 1, width = 6.5, height = 3.25, units = "in", dpi = 300)

## Compare the above plots with length variability among the fossil trackways
## Build summary table of fossil trackways
colLabels <- c("heelToHallux.n", "heelToHallux.mean", "heelToHallux.median", "heelToHallux.sd", "heelToHallux.CV",
                "heelToDigit3.n", "heelToDigit3.mean", "heelToDigit3.median", "heelToDigit3.sd", "heelToDigit3.CV",
                "forefootBreadth.n", "forefootBreadth.mean", "forefootBreadth.median", "forefootBreadth.sd", "forefootBreadth.CV",
                "heelBreadth.n", "heelBreadth.mean", "heelBreadth.median", "heelBreadth.sd", "heelBreadth.CV")
trackSummary <- data.frame(matrix(NaN, nlevels(engareSeroPrintDimensions$Trackway), length(colLabels)))
colnames(trackSummary) <- colLabels
rownames(trackSummary) <- levels(engareSeroPrintDimensions$Trackway)
for (i in 1:nlevels(engareSeroPrintDimensions$Trackway)) {
  temp.data <- engareSeroPrintDimensions[engareSeroPrintDimensions$Trackway == levels(engareSeroPrintDimensions$Trackway)[i],]
  temp.data.heelToHallux <- sort(temp.data$heelToHallux)
  temp.data.heelToDigit3 <- sort(temp.data$heelToDigit3)
  temp.data.forefootBreadth <- sort(temp.data$forefootBreadth)
  temp.data.heelBreadth <- sort(temp.data$heelBreadth)
  trackSummary$heelToHallux.n[i] <- length(temp.data.heelToHallux)
  trackSummary$heelToHallux.mean[i] <- mean(temp.data.heelToHallux, na.rm = TRUE)
  trackSummary$heelToHallux.median[i] <- median(temp.data.heelToHallux, na.rm = TRUE)
  if (trackSummary$heelToHallux.n[i] > 1) {
    trackSummary$heelToHallux.sd[i] <- sd(temp.data.heelToHallux, na.rm = TRUE)
    trackSummary$heelToHallux.CV[i] <- sd(temp.data.heelToHallux, na.rm = TRUE)/trackSummary$heelToHallux.mean[i]
  }
  trackSummary$heelToDigit3.n[i] <- length(temp.data.heelToDigit3)
  trackSummary$heelToDigit3.mean[i] <- mean(temp.data.heelToDigit3, na.rm = TRUE)
  trackSummary$heelToDigit3.median[i] <- median(temp.data.heelToDigit3, na.rm = TRUE)
  if (trackSummary$heelToDigit3.n[i] > 1) {
    trackSummary$heelToDigit3.sd[i] <- sd(temp.data.heelToDigit3, na.rm = TRUE)
    trackSummary$heelToDigit3.CV[i] <- sd(temp.data.heelToDigit3, na.rm = TRUE)/trackSummary$heelToDigit3.mean[i]
  }
  trackSummary$forefootBreadth.n[i] <- length(temp.data.forefootBreadth)
  trackSummary$forefootBreadth.mean[i] <- mean(temp.data.forefootBreadth, na.rm = TRUE)
  trackSummary$forefootBreadth.median[i] <- median(temp.data.forefootBreadth, na.rm = TRUE)
  if (trackSummary$forefootBreadth.n[i] > 1) {
    trackSummary$forefootBreadth.sd[i] <- sd(temp.data.forefootBreadth, na.rm = TRUE)
    trackSummary$forefootBreadth.CV[i] <- sd(temp.data.forefootBreadth, na.rm = TRUE)/trackSummary$forefootBreadth.mean[i]
  }
  trackSummary$heelBreadth.n[i] <- length(temp.data.heelBreadth)
  trackSummary$heelBreadth.mean[i] <- mean(temp.data.heelBreadth, na.rm = TRUE)
  trackSummary$heelBreadth.median[i] <- median(temp.data.heelBreadth, na.rm = TRUE)
  if (trackSummary$heelBreadth.n[i] > 1) {
    trackSummary$heelBreadth.sd[i] <- sd(temp.data.heelBreadth, na.rm = TRUE)
    trackSummary$heelBreadth.CV[i] <- sd(temp.data.heelBreadth, na.rm = TRUE)/trackSummary$heelBreadth.mean[i]
  }
}

## Plot histograms showing how individual track lengths differ proportionately from the median track length within a trackway (Figure S2)
png(filename = "Engare Sero proportional length differences.png", width = 1350, height = 900)
par(mfrow = c(5, 5))
for (i in 1:length(trackSummary[,1])) {
  temp.data <- engareSeroPrintDimensions[engareSeroPrintDimensions$Trackway == levels(engareSeroPrintDimensions$Trackway)[i],]
  temp.data.heelToHallux <- sort(temp.data$heelToHallux)
  temp.data.heelToDigit3 <- sort(temp.data$heelToDigit3)
  temp.data.forefootBreadth <- sort(temp.data$forefootBreadth)
  temp.data.heelBreadth <- sort(temp.data$heelBreadth)
  if (length(temp.data.heelToHallux) > 0) hist((temp.data.heelToHallux - median(temp.data.heelToHallux))/median(temp.data.heelToHallux),
                                                 main = paste0(levels(engareSeroPrintDimensions$Trackway)[i], " (n=", length(temp.data.heelToHallux), ")"),
                                                 xlab = "Proportional difference", breaks = 10, col = "gray")
}
dev.off()

## Load sample of modern human foot sizes from anthropometric studies (these data are not original to the current study; see references 48 and 49 for details regarding this data set)
anthropometricFeet <- read.csv(file.choose())

## Initial data inspection for ages at which growth seems to cede in both sexes
plot(anthropometricFeet$age, anthropometricFeet$foot.length.mm, col = "white",
     main = "Contemporary sample of foot lengths", xlab = "Age (years)", ylab = "Foot length (mm)")
points(anthropometricFeet$age[anthropometricFeet$sex == "M"], anthropometricFeet$foot.length.mm[anthropometricFeet$sex == "M"], pch = 4, col = "blue")
points(anthropometricFeet$age[anthropometricFeet$sex == "F"], anthropometricFeet$foot.length.mm[anthropometricFeet$sex == "F"], pch = 4, col = "red")
## Growth clearly stops/slows below age 24 in both sexes - further constrain plot
constrainedAge <- filter(anthropometricFeet, age < 24)
plot(constrainedAge$age, constrainedAge$foot.length.mm, col = "white",
     main = "Contemporary sample of foot lengths", xlab = "Age (years)", ylab = "Foot length (mm)")
points(constrainedAge$age[constrainedAge$sex == "M"], constrainedAge$foot.length.mm[constrainedAge$sex == "M"], pch = 4, col = "blue")
points(constrainedAge$age[constrainedAge$sex == "F"], constrainedAge$foot.length.mm[constrainedAge$sex == "F"], pch = 4, col = "red")
axis(1, at = seq(0,24,0.2))
## Visual inspection of data suggest cessations of growth in foot length at approximately the ages below:
cutoff.male <- 17.8
cutoff.female <- 14
## Plot color-coded growth curve (Figure S3)
anthropometricFeet.v2 <- anthropometricFeet %>%
  mutate(ageClass = case_when(sex == "M" & age >= cutoff.male ~ "adultM",
                              sex == "M" & age < cutoff.male ~ "juvM",
                              sex == "F" & age >= cutoff.female ~ "adultF",
                              sex == "F" & age < cutoff.female ~ "juvF",
                              TRUE~as.character(NA)))
footLengthCurve<-ggplot(anthropometricFeet.v2, aes(x = age, y = foot.length.mm, colour = ageClass)) +
  geom_point() +
  geom_vline(xintercept = 17.8, colour = "#0072B2", linetype = "dashed") +
  geom_vline(xintercept = 14, colour = "#D55E00", linetype = "dashed") +
  xlab("Age (years)") +
  ylab("Foot length (mm)") +
  scale_color_manual(limits = c("adultM", "juvM", "adultF","juvF"),
                     values = c("#0072B2","#56B4E9","#D55E00","#E69F00")) +
  theme(axis.title.x = element_text(size = 12, colour = "black"), axis.text.x = element_text(size = 10, colour = "black", vjust = 1, hjust = 1),
        axis.title.y = element_text(size = 12, colour = "black"), axis.text.y = element_text(size = 10, colour = "black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
footLengthCurve
ggsave(filename = "footLengthCurve.jpg", device = "jpeg", scale = 1, width = 3.25, height = 3.25, units = "in", dpi = 300)

## Preliminary steps for iterative resampling procedure
positive.error <- 0.05
negative.error <- 0.05
n.resample <- 10000
CI <- 0.95
n.steps.cutoff <- 50
fossilPrints <- cbind(engareSeroPrintDimensions[,1:2], "Lengths" = engareSeroPrintDimensions$heelToHallux)
fossilPrints <- fossilPrints[order(fossilPrints$Lengths, na.last = NA),]
fossilPrints <- fossilPrints[order(fossilPrints$Trackway, na.last = NA),]
fossilPrints$Trackway <- factor(fossilPrints$Trackway)
colLabels <- c("Length.n", "Length.median", "Length.min", "Length.max", "Length.min.error", "Length.max.error", "Length.min.to.use", "Length.max.to.use")
fossilTrackSummary <- data.frame(matrix(NaN, nlevels(fossilPrints$Trackway), length(colLabels)))
colnames(fossilTrackSummary) <- colLabels
rownames(fossilTrackSummary) <- levels(fossilPrints$Trackway)
for (i in 1:nlevels(fossilPrints$Trackway)) {
  temp.data <- fossilPrints[fossilPrints$Trackway == levels(fossilPrints$Trackway)[i],]
  fossilTrackSummary$Length.n[i] <- length(temp.data$Lengths)
  fossilTrackSummary$Length.median[i] <- median(temp.data$Lengths)
  fossilTrackSummary$Length.min[i] <- min(temp.data$Lengths)
  fossilTrackSummary$Length.max[i] <- max(temp.data$Lengths)
  fossilTrackSummary$Length.min.error[i] <- median(temp.data$Lengths) - median(temp.data$Lengths) * negative.error
  fossilTrackSummary$Length.max.error[i]  <- median(temp.data$Lengths) + median(temp.data$Lengths) * positive.error
  fossilTrackSummary$Length.min.to.use[i] <- min(temp.data$Lengths)
  fossilTrackSummary$Length.max.to.use[i] <- max(temp.data$Lengths)
  if (fossilTrackSummary$Length.n[i] < n.steps.cutoff) {
    fossilTrackSummary$Length.min.to.use[i] <- fossilTrackSummary$Length.min.error[i]
    fossilTrackSummary$Length.max.to.use[i] <- fossilTrackSummary$Length.max.error[i]
  }
}
## Reorder fossil track summary so that the first track is the track with the longest foot
fossilTrackSummary <- fossilTrackSummary[order(fossilTrackSummary$Length.median, decreasing = TRUE),]
longestFoot <- fossilTrackSummary$Length.median[1]
fossilTrackSummary[,-1] <- fossilTrackSummary[,-1]/longestFoot
## Use one standard deviation greater than the mean for adult males in the comparative sample as the cutoff for the largest foot
meanMaleComparativeLength <- mean(anthropometricFeet$foot.length.mm[anthropometricFeet$sex == "M" & anthropometricFeet$age >= cutoff.male])
sdMaleComparativeLength <- sd(anthropometricFeet$foot.length.mm[anthropometricFeet$sex == "M" & anthropometricFeet$age >= cutoff.male])
largestCutoff <- meanMaleComparativeLength + sdMaleComparativeLength

## Plot original comparative sample to look for likely age bias (Figure S4)
agePyramid <- ggplot(anthropometricFeet, aes(x = age, fill = sex)) +
  geom_histogram(data = subset(anthropometricFeet, sex == "M"), bins = 26) +
  geom_histogram(data = subset(anthropometricFeet, sex == "F"), bins = 26, aes(y = ..count..*(-1))) +
  scale_y_continuous(breaks = seq(-400, 400, 50), labels = abs(seq(-400, 400, 50))) +
  scale_x_continuous(breaks = seq(0, 52, 2)) +
  coord_flip() +
  scale_fill_manual(limits = c("M", "F"),
                    values = c("#0072B2", "#D55E00")) +
  xlab("Age (years)") +
  ylab("Count") +
  geom_hline(yintercept = -50, linetype = "dashed") +
  geom_hline(yintercept = 50, linetype = "dashed") +
  theme(axis.title.x = element_text(size = 12, colour = "black"), axis.text.x = element_text(size = 10, colour = "black", vjust = 1, hjust = 1),
        axis.title.y = element_text(size = 12, colour = "black"), axis.text.y = element_text(size = 10, colour = "black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
agePyramid
ggsave(filename = "agePyramid.jpg", device = "jpeg", scale = 1, width = 6.5, height = 3.25, units = "in", dpi = 300)

## BEGIN ITERATIVE PROCEDURE
## Resampled.feet will hold the rowname in the ontogenetic dataset of each resampled foot, so that later one can go back and extract age, sex, length, etc.
n.tracks <- length(fossilTrackSummary[,1])
resampled.feet <- matrix(0, n.resample, n.tracks)
colnames(resampled.feet) <- rownames(fossilTrackSummary)
resampled.agesex <- matrix(NA, n.resample, n.tracks)
colnames(resampled.agesex) <- rownames(fossilTrackSummary)
resampled.dimorphism <- matrix(NA, n.resample)
column.labels <- c("AM", "AF", "JM", "JF")
resampled.agesex.proportions <- matrix(0, n.resample, length(column.labels))
colnames(resampled.agesex.proportions) <- column.labels

youngest <- floor(min(anthropometricFeet$age))
n.intervals <- floor((max(anthropometricFeet$age)-youngest) / 2 + 1) + 1

set.seed(6798)
pb <- winProgressBar(title = "Resampling foot data: 0% done", min = 0, max = n.resample, width = 360)
for (i in 1:n.resample) {
  ##########
  # Procedure to cut full comparative sample down to have roughly equal age categories
  temp.feet <- NA
  for (k in 1:n.intervals) {
    younger <- (k-1)*2 + youngest
    older   <- younger + 2
    males   <- anthropometricFeet[anthropometricFeet$age > younger & anthropometricFeet$age <= older & anthropometricFeet$sex == "M",]
    females <- anthropometricFeet[anthropometricFeet$age > younger & anthropometricFeet$age <= older & anthropometricFeet$sex == "F",]
    if (length(males[,1]) <= 50)   temp.feet <- c(temp.feet, as.integer(row.names(males)))   else temp.feet <- c(temp.feet, as.integer(row.names(males)[sample(length(males[,1]), 50)]))
    if (length(females[,1]) <= 50) temp.feet <- c(temp.feet, as.integer(row.names(females))) else temp.feet <- c(temp.feet, as.integer(row.names(females)[sample(length(females[,1]), 50)]))
  }
  temp.feet <- sort(temp.feet)
  temp.anthropometricFeet <- anthropometricFeet[temp.feet,]
  ##########
  
  resampled.feet[i,1] <- sample(as.integer(rownames(temp.anthropometricFeet[temp.anthropometricFeet$foot.length.mm >= largestCutoff,])), 1)
  temp.largestFoot <- anthropometricFeet$foot.length.mm[resampled.feet[i,1]]
  sex <- as.character(anthropometricFeet$sex[resampled.feet[i,1]])
  if (sex=="M") {
    if (anthropometricFeet$age[resampled.feet[i,1]] >= cutoff.male) age <- "A"
    else age <- "J"
  }
  else if (sex=="F") {
    if (anthropometricFeet$age[resampled.feet[i,1]] >= cutoff.female) age <- "A"
    else age <- "J"
  }
  resampled.agesex[i,1] <- paste(age,sex,sep="")
  for (j in 2:n.tracks) {
    bottom <- temp.largestFoot * fossilTrackSummary$Length.min.to.use[j]
    top    <- temp.largestFoot * fossilTrackSummary$Length.max.to.use[j]
    sampling.pool <- as.integer(rownames(temp.anthropometricFeet[temp.anthropometricFeet$foot.length.mm >= bottom & temp.anthropometricFeet$foot.length.mm <= top,]))
    resampled.feet[i,j] <- sample(sampling.pool, 1)
    sex <- as.character(anthropometricFeet$sex[resampled.feet[i,j]])
    if (sex=="M") {
      if (anthropometricFeet$age[resampled.feet[i,j]] >= cutoff.male) age <- "A"
      else age <- "J"
    }
    else if (sex=="F") {
      if (anthropometricFeet$age[resampled.feet[i,j]] >= cutoff.female) age <- "A"
      else age <- "J"
    }
    resampled.agesex[i,j] <- paste(age,sex,sep="")
  }
  if (sum(resampled.agesex[i,]=="AM") > 0 & sum(resampled.agesex[i,]=="AF") > 0) resampled.dimorphism[i] <-  mean(anthropometricFeet$foot.length.mm[resampled.feet[i,][resampled.agesex[i,]=="AM"]]) / mean(anthropometricFeet$foot.length.mm[resampled.feet[i,][resampled.agesex[i,]=="AF"]])
  resampled.agesex.proportions[i,1] <- sum(resampled.agesex[i,]=="AM") / n.tracks
  resampled.agesex.proportions[i,2] <- sum(resampled.agesex[i,]=="AF") / n.tracks
  resampled.agesex.proportions[i,3] <- sum(resampled.agesex[i,]=="JM") / n.tracks
  resampled.agesex.proportions[i,4] <- sum(resampled.agesex[i,]=="JF") / n.tracks
  setWinProgressBar(pb, i, title=paste("Resampling foot data: ", round(i/n.resample*100, 2), "% done", sep=""))
}
close(pb)

## Plot age pyramid to evaluate the reduction of age bias in the resampling procedure (Figure S5)
agePyramidReduced <- ggplot(temp.anthropometricFeet, aes(x = age, fill = sex)) +
  geom_histogram(data = subset(temp.anthropometricFeet, sex == "M"), bins = 26) +
  geom_histogram(data = subset(temp.anthropometricFeet, sex == "F"), bins = 26, aes(y = ..count..*(-1))) +
  scale_y_continuous(breaks = seq(-60, 60, 10), labels = abs(seq(-60, 60, 10))) +
  scale_x_continuous(breaks = seq(0, 52, 2)) +
  coord_flip() +
  scale_fill_manual(limits = c("M", "F"),
                    values = c("#0072B2", "#D55E00")) +
  xlab("Age (years)") +
  ylab("Count") +
  theme(axis.title.x = element_text(size = 12, colour = "black"), axis.text.x = element_text(size = 10, colour = "black", vjust = 1, hjust = 1),
        axis.title.y = element_text(size = 12, colour = "black"), axis.text.y = element_text(size = 10, colour = "black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
agePyramidReduced
ggsave(filename = "agePyramidReduced.jpg", device = "jpeg", scale = 1, width = 6.5, height = 3.25, units = "in", dpi = 300)

## Compare raw Engare Sero footprint sizes to foot size distribution in comparative sample from anthropometric study (Figure 5)
plotDataPrints <- fossilPrints
plotDataPrints$Trackway <- factor(fossilPrints$Trackway, levels = rownames(fossilTrackSummary), ordered = TRUE)
males <- anthropometricFeet[anthropometricFeet$sex == "M",]
males$adult <- males$age >= cutoff.male
males$category <- "Juv.\nMale"
males$category[males$adult] <- "Adult\nMale"
females <- anthropometricFeet[anthropometricFeet$sex == "F",]
females$adult <- females$age >= cutoff.female
females$category <- "Juv.\nFemale"
females$category[females$adult] <- "Adult\nFemale"
comparative <- rbind(males,females)
comparative$category <- factor(comparative$category, levels = c("Adult\nMale", "Adult\nFemale", "Juv.\nMale", "Juv.\nFemale"), ordered = TRUE)
comparative <- data.frame("Trackway" = comparative$category, "Track.ID" = NA, "Lengths" = comparative$foot.length.mm)
plotDataPrints <- rbind(comparative, plotDataPrints)
## Plot comparative data and fossil data separately, then merge for presentation in paper
plotDataPrints.A <- plotDataPrints %>%
  filter(Trackway == "Adult\nMale" | Trackway == "Adult\nFemale" | Trackway == "Juv.\nMale" | Trackway == "Juv.\nFemale")
footprintLengthPlotA <- ggplot(plotDataPrints.A, aes(x = Trackway, y = Lengths, fill = Trackway)) +
  geom_boxplot() +
  ylim(125, 325) +
  scale_fill_manual(limits = c("Adult\nMale", "Juv.\nMale","Adult\nFemale","Juv.\nFemale"),
                    values = c("#0072B2", "#56B4E9", "#D55E00", "#E69F00")) +
  scale_x_discrete(limits = c("Adult\nMale", "Adult\nFemale", "Juv.\nMale", "Juv.\nFemale"),
                   labels = c("AM", "AF", "JM", "JF")) +
  ylab("Foot/footprint length (mm)") +
  theme(axis.title.x = element_blank(), axis.text.x = element_text(size = 8, angle = 45, hjust = 1, vjust = 1, colour = "black"),
        axis.title.y = element_text(size = 12, colour = "black"), axis.text.y = element_text(size = 10, colour = "black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
footprintLengthPlotA
ggsave(filename = "footprintLengthPlotA.jpg", device = "jpeg", scale = 1, width = 1.25, height = 3.25, units = "in", dpi = 300)
plotDataPrints.B <- plotDataPrints %>%
  filter(Trackway != "Adult\nMale" & Trackway != "Adult\nFemale" & Trackway != "Juv.\nMale" & Trackway != "Juv.\nFemale")
footprintLengthPlotB <-ggplot(plotDataPrints.B, aes(x = Trackway, y = Lengths)) +
  geom_point(shape = 21, fill = "#999999") +
  stat_summary(fun.y = median, fun.ymin = median, fun.ymax = median, geom = "crossbar", width = 0.75) +
  ylim(125, 325) +
  theme(axis.title.x = element_blank(), axis.text.x = element_text(size = 8, angle = 45, hjust = 1, vjust = 1, colour = "black"),
        axis.title.y = element_blank(), axis.text.y = element_blank(), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), 
        axis.line.y = element_blank(), axis.ticks.y = element_blank(), legend.position = "none")
footprintLengthPlotB
ggsave(filename = "footprintLengthPlotB.jpg", device = "jpeg", scale = 1, width = 5.25, height = 3.25, units = "in", dpi = 300)

## Compute proportions of resampled age/sex categories
proportion.AM <- function(x) sum(x=="AM")/length(x)
proportion.AF <- function(x) sum(x=="AF")/length(x)
proportion.JM <- function(x) sum(x=="JM")/length(x)
proportion.JF <- function(x) sum(x=="JF")/length(x)

## Generate table of age/sex resampling results (Table S2) and plot of age/sex proportions (Figure 6)
track.agesex.proportions <- cbind(apply(resampled.agesex, 2, proportion.AM), apply(resampled.agesex, 2, proportion.AF), apply(resampled.agesex, 2, proportion.JM), apply(resampled.agesex, 2, proportion.JF))
track.agesex.proportions <- as.data.frame(track.agesex.proportions)
track.agesex.proportions <- tibble::rownames_to_column(track.agesex.proportions, "Trackway")
track.agesex.proportions$Trackway <- as.factor(track.agesex.proportions$Trackway)
colnames(track.agesex.proportions) <- c("Trackway", "AM", "AF", "JM", "JF")
track.agesex.proportions$Trackway <- reorder(track.agesex.proportions$Trackway, -track.agesex.proportions$AM, desc = TRUE)
track.agesex.proportions
## Write age/sex proportions to .csv file (Table 3)
write.csv(track.agesex.proportions, "trackAgesexProportions.csv")
## Convert to long format for plotting
track.agesex.proportions.v2 <- melt(track.agesex.proportions, id.vars = "Trackway")
colnames(track.agesex.proportions.v2) <- c("Trackway", "AgeSex", "Probability")
trackAgeSexProportionsPlot <- ggplot(track.agesex.proportions.v2, aes(x = Trackway, y = Probability, fill = AgeSex)) +
  geom_bar(stat = "identity", position = position_stack(reverse = TRUE)) +
  scale_fill_manual(limits = c("JF", "JM", "AF", "AM"),
                    values = c("#E69F00", "#56B4E9", "#D55E00", "#0072B2")) +
  scale_y_continuous(expand = c(0,0)) +
  geom_hline(yintercept = 0.50, linetype = "dashed") +
  theme(axis.title.x = element_text(size = 12, colour = "black"), axis.text.x = element_text(size = 10, colour = "black"),
        axis.title.y = element_text(size = 12, colour = "black"), axis.text.y = element_text(size = 10, colour = "black"), legend.title = element_blank(),
        panel.background = element_blank(), panel.grid.major = element_blank(), panel.grid.minor = element_blank(),
        axis.line = element_line(colour = "black"), axis.ticks = element_line(colour = "black"), legend.position = "none")
trackAgeSexProportionsPlot
ggsave(filename = "trackAgeSexProportionsPlot.jpg", device = "jpeg", scale = 1, width = 6.5, height = 3.25, units = "in", dpi = 300)

## Compute 95% confidence intervals for age/sex proportions, adult sex ratio, adult:juvenile ratio, and log footprint dimorphism (Table 3)
LL.index <- ceiling((1 - CI)/2 * (n.resample))
UL.index <- (n.resample) - LL.index + 1
CI.sort <- function(Table.name, index) sort(Table.name)[index]
column.labels <- c("Median.resampled", "CI.LL", "CI.UL")
## Adult sex ratio is number of males divided by number of females
row.labels <- c("AM.proportion", "AF.proportion", "JM.proportion", "JF.proportion",
                "adult.sex.ratio", "adult.juvenile.ratio", "log.adult.dimorphism")
CI.table <- data.frame(matrix(NA, length(row.labels), length(column.labels)))
rownames(CI.table) <- row.labels
colnames(CI.table) <- column.labels
sex.ratio <- resampled.agesex.proportions[,"AM"]/resampled.agesex.proportions[,"AF"]
adult.juv.ratio <- (resampled.agesex.proportions[,"AM"] + resampled.agesex.proportions[,"AF"])/
  (resampled.agesex.proportions[,"JM"] + resampled.agesex.proportions[,"JF"]) 
for (i in 1:n.resample) if (sex.ratio[i] == 0) sex.ratio[i] <- NA
for (i in 1:n.resample) if (adult.juv.ratio[i] == 0) adult.juv.ratio[i] <- NA
CI.table["AM.proportion", "Median.resampled"] <- median(resampled.agesex.proportions[,"AM"])
CI.table["AF.proportion", "Median.resampled"] <- median(resampled.agesex.proportions[,"AF"])
CI.table["JM.proportion", "Median.resampled"] <- median(resampled.agesex.proportions[,"JM"])
CI.table["JF.proportion", "Median.resampled"] <- median(resampled.agesex.proportions[,"JF"])
CI.table["adult.sex.ratio", "Median.resampled"] <- median(sex.ratio, na.rm = TRUE)
CI.table["adult.juvenile.ratio", "Median.resampled"] <- median(adult.juv.ratio, na.rm = TRUE)
CI.table["log.adult.dimorphism", "Median.resampled"] <- median(log(resampled.dimorphism), na.rm=TRUE)
CI.table["AM.proportion", "CI.LL"] <- CI.sort(resampled.agesex.proportions[,"AM"], LL.index)
CI.table["AF.proportion", "CI.LL"] <- CI.sort(resampled.agesex.proportions[,"AF"], LL.index)
CI.table["JM.proportion", "CI.LL"] <- CI.sort(resampled.agesex.proportions[,"JM"], LL.index)
CI.table["JF.proportion", "CI.LL"] <- CI.sort(resampled.agesex.proportions[,"JF"], LL.index)
CI.table["adult.sex.ratio", "CI.LL"] <- CI.sort(sex.ratio, LL.index)
CI.table["adult.juvenile.ratio", "CI.LL"] <- CI.sort(adult.juv.ratio, LL.index)
CI.table["log.adult.dimorphism", "CI.LL"] <- CI.sort(log(resampled.dimorphism), LL.index)
CI.table["AM.proportion", "CI.UL"] <- CI.sort(resampled.agesex.proportions[,"AM"], UL.index)
CI.table["AF.proportion", "CI.UL"] <- CI.sort(resampled.agesex.proportions[,"AF"], UL.index)
CI.table["JM.proportion", "CI.UL"] <- CI.sort(resampled.agesex.proportions[,"JM"], UL.index)
CI.table["JF.proportion", "CI.UL"] <- CI.sort(resampled.agesex.proportions[,"JF"], UL.index)
CI.table["adult.sex.ratio", "CI.UL"] <- CI.sort(sex.ratio, UL.index)
CI.table["adult.juvenile.ratio", "CI.UL"] <- CI.sort(adult.juv.ratio, UL.index)
CI.table["log.adult.dimorphism", "CI.UL"] <- CI.sort(log(resampled.dimorphism), UL.index)
CI.table
## Write confidence table to .csv file (Table 3)
write.csv(CI.table,"ageSexCITable.csv")


## Save workspace
save.image(file=paste0("Footprint analysis ", Sys.Date(), ".RData"))
