Demo of Gait Trajectory Approach with >2 Propulsors

Kara L. Feilich 2017

Note: This is for demonstration purposes only. It does not use real data.

Import Useful Libraries, define palettes, etc.

In [8]:
library(ggplot2)
library(plyr)
library(grid)
library(gridExtra)
library(cowplot)
#library(rgl)
library(scatterplot3d)
library(ggbiplot)

# The palette with grey:
cbPalette <- c("#999999", "#E69F00", "#56B4E9", "#009E73", "#F0E442", "#0072B2", "#D55E00", "#CC79A7")
sem<-function(x) sd(x)/sqrt(length(x))

Read in Sample Data

In [9]:
demo_data<-read.csv(file="UndulationEffort.csv", header = TRUE) 
avg_demo<-ddply(demo_data,c("Species", "Speed..m.s."), summarise, N=length(UndEff..mm.s.), 
                UndEff_av=mean(UndEff..mm.s.), UndEff_se=sem(UndEff..mm.s.),CaudEff_av=mean(CaudalEff..mm.s.),
                CaudEff_se=sem(CaudalEff..mm.s.), PecEff_av=mean(PecEff),  PecEff_se=sem(PecEff), AnalEff_av=mean(AnalEff), 
                AnalEff_se=sem(AnalEff), DorsalEff_av=mean(DorsalEff), DorsalEff_se=sem(DorsalEff))
head(avg_demo)
SpeciesSpeed..m.s.NUndEff_avUndEff_seCaudEff_avCaudEff_sePecEff_avPecEff_seAnalEff_avAnalEff_seDorsalEff_avDorsalEff_se
Balistid-like0.0535 10 0.022773 0.009845586 3.1497 0.9335436 9.3000 1.4477122 51.4811 1.5818479 50.6468 1.1530061
Balistid-like0.1177 10 1.005766 0.063211379 5.4572 1.0493448 29.7982 1.4525676 60.8358 1.3196784 61.7109 1.5746199
Balistid-like0.1605 10 1.019320 0.146913944 3.7694 1.1095414 18.8217 0.9679484 79.1806 1.4030651 77.7078 1.3647156
Balistid-like0.2247 10 2.384813 0.159182542 5.6722 1.6368832 7.2827 0.7626403 89.9542 0.7717766 86.9005 1.8857859
Balistid-like0.2675 10 2.201174 0.129744429 6.0035 1.5070023 2.9996 0.8450075 100.6987 2.2378424 104.5226 1.8234019
Cichla-like 0.0535 10 0.000000 0.000000000 24.9313 0.5959414 31.3978 0.7459178 0.5496 0.1491636 0.9947 0.1916898

Plot 2D relationships between propulsors and speed

In [10]:
# Body Undulation Effort
p1<-ggplot(avg_demo, aes(x=Speed..m.s.,y=UndEff_av,color=Species))+
geom_errorbar(aes(ymin=UndEff_av-UndEff_se, ymax=UndEff_av+UndEff_se),width=0.01)+
geom_line()+
geom_point()+
scale_color_manual(values=cbPalette)+
labs(x="Speed (m/s)",y="Body Effort (mm/s)")+
theme_bw()+theme(legend.position="none")

# Caudal Effort
p2<-ggplot(avg_demo, aes(x=Speed..m.s.,y=CaudEff_av,color=Species))+
geom_errorbar(aes(ymin=CaudEff_av-CaudEff_se, ymax=CaudEff_av+CaudEff_se),width=0.01)+
geom_line()+
geom_point()+
scale_color_manual(values=cbPalette)+
labs(x="Speed (m/s)",y="Caudal Effort (mm/s)")+
theme_bw()+theme(legend.position="none")

# Pectoral Effort
p3<-ggplot(avg_demo, aes(x=Speed..m.s.,y=PecEff_av,color=Species))+
geom_errorbar(aes(ymin=PecEff_av-PecEff_se, ymax=PecEff_av+PecEff_se),width=0.01)+
geom_line()+
geom_point()+
scale_color_manual(values=cbPalette)+
labs(x="Speed (m/s)",y="Pectoral Effort (mm/s)")+
theme_bw()+theme(legend.position="none")

# Dorsal Effort
p4<-ggplot(avg_demo, aes(x=Speed..m.s.,y=DorsalEff_av,color=Species))+
geom_errorbar(aes(ymin=DorsalEff_av-DorsalEff_se, ymax=DorsalEff_av+DorsalEff_se),width=0.01)+
geom_line()+
geom_point()+
scale_color_manual(values=cbPalette)+
labs(x="Speed (m/s)",y="Dorsal Effort (mm/s)")+
theme_bw()+theme(legend.position="none")

# Anal Effort
p5<-ggplot(avg_demo, aes(x=Speed..m.s.,y=AnalEff_av,color=Species))+
geom_errorbar(aes(ymin=AnalEff_av-AnalEff_se, ymax=AnalEff_av+AnalEff_se),width=0.01)+
geom_line()+
geom_point()+
scale_color_manual(values=cbPalette)+
labs(x="Speed (m/s)",y="Anal Effort (mm/s)")+
theme_bw()

p6<-get_legend(p5)
p5<-p5+theme(legend.position="none")

grid.arrange(p1,p2,p3,p4,p5,p6, ncol=3, nrow=2)

Note: For dorsal and anal fin effort, the eel-like and crenicichla-like data overlap (in this fake data set)

Plot Multiple Redundant 3D Gait Spaces

In the following plots, swimming speed in m/s is represented by the size of the point (larger = faster)

Note: For reasons I don't understand, RGL crashes when run from a Jupyter notebook... but this is the line of code you would use.

In [11]:
#with(avg_demo,plot3d(UndEff_av,CaudEff_av,PecEff_av, type="s",col=as.numeric(Species)))

This is making the equivalent static plots using a different package, scatterplot3d. To do this, you need to subset the data by species

In [12]:
# Making subsets for things
cichlalike <- subset(avg_demo, Species=="Cichla-like") 
crenicichlalike <- subset(avg_demo, Species=="Crenicichla-like") 
symphysodonlike <- subset(avg_demo, Species=="Symphysodon-like") 
balistidlike <- subset(avg_demo, Species=="Balistid-like") 
eellike <- subset(avg_demo, Species=="Eel-like")

Body Undulation, Caudal Fins, Pectoral Fins

In [13]:
s3d<-scatterplot3d(x=avg_demo$UndEff_av, y=avg_demo$CaudEff_av, z=avg_demo$PecEff_av,
                             color=cbPalette[as.numeric(avg_demo$Species)], 
                             pch=16, cex.symbols=(avg_demo$Speed..m.s.*10), type='p', xlab='Body Effort(mm/s)',
              ylab='Caudal Effort (mm/s)', zlab='Pectoral Effort (mm/s)')
s3d$points3d(x=balistidlike$UndEff_av, y=balistidlike$CaudEff_av, z=balistidlike$PecEff_av,type="l",col=cbPalette[1])
s3d$points3d(x=cichlalike$UndEff_av, y=cichlalike$CaudEff_av, z=cichlalike$PecEff_av,type="l",col=cbPalette[2])
s3d$points3d(x=crenicichlalike$UndEff_av, y=crenicichlalike$CaudEff_av, z=crenicichlalike$PecEff_av,type="l",col=cbPalette[3])
s3d$points3d(x=eellike$UndEff_av, y=eellike$CaudEff_av, z=eellike$PecEff_av,type="l",col=cbPalette[4])
s3d$points3d(x=symphysodonlike$UndEff_av, y=symphysodonlike$CaudEff_av, z=symphysodonlike$PecEff_av,type="l",col=cbPalette[5])

Body Undulation, Dorsal Fin, Anal Fin

In [14]:
s3d<-scatterplot3d(x=avg_demo$UndEff_av, y=avg_demo$DorsalEff_av, z=avg_demo$AnalEff_av,
                             color=cbPalette[as.numeric(avg_demo$Species)], 
                             pch=16, cex.symbols=(avg_demo$Speed..m.s.*10), type='p', xlab='Body Effort(mm/s)',
              ylab='Dorsal Effort (mm/s)', zlab='Anal Effort (mm/s)')
s3d$points3d(x=balistidlike$UndEff_av, y=balistidlike$DorsalEff_av, z=balistidlike$AnalEff_av,type="l",col=cbPalette[1])
s3d$points3d(x=cichlalike$UndEff_av, y=cichlalike$DorsalEff_av, z=cichlalike$AnalEff_av,type="l",col=cbPalette[2])
s3d$points3d(x=crenicichlalike$UndEff_av, y=crenicichlalike$DorsalEff_av, z=crenicichlalike$AnalEff_av,type="l",col=cbPalette[3])
s3d$points3d(x=eellike$UndEff_av, y=eellike$DorsalEff_av, z=eellike$AnalEff_av,type="l",col=cbPalette[4])
s3d$points3d(x=symphysodonlike$UndEff_av, y=symphysodonlike$DorsalEff_av, z=symphysodonlike$AnalEff_av,type="l",col=cbPalette[5])

Use PCA for dimension reduction

In [15]:
# Isolate gait parameters

gait_params<-c("Species", "Speed..m.s.", "UndEff_av", "CaudEff_av", "PecEff_av","DorsalEff_av", "AnalEff_av")
gait_data<-avg_demo[gait_params]
gait_PCA<-prcomp(gait_data[,3:7], scale=TRUE, center=TRUE)
print(gait_PCA)
summary(gait_PCA)
Standard deviations:
[1] 1.63987416 1.21788048 0.79221030 0.44643359 0.02607191

Rotation:
                    PC1         PC2        PC3         PC4          PC5
UndEff_av     0.2585816  0.69793975 -0.1432174 -0.65230556  0.001368594
CaudEff_av    0.4725635  0.14063771 -0.7155175  0.49490742  0.002479270
PecEff_av     0.2209786 -0.69265383 -0.3839049 -0.56921819  0.002607622
DorsalEff_av -0.5744377  0.08143695 -0.4029012 -0.05360136 -0.705823520
AnalEff_av   -0.5753338  0.08185246 -0.3972546 -0.05178464  0.708377258
Importance of components:
                          PC1    PC2    PC3     PC4     PC5
Standard deviation     1.6399 1.2179 0.7922 0.44643 0.02607
Proportion of Variance 0.5378 0.2967 0.1255 0.03986 0.00014
Cumulative Proportion  0.5378 0.8345 0.9600 0.99986 1.00000
In [16]:
g <- ggbiplot(gait_PCA, obs.scale = 1, var.scale = 1, 
              groups = factor(gait_data$Species), ellipse = TRUE, 
              circle = TRUE)
g <- g + scale_color_manual(values=cbPalette)
g <- g + theme(legend.direction = 'vertical', 
               legend.position = 'right')
print(g)
Loading required package: scales
In [ ]: