Important Note: If the R code (.rmd file) does not work when trying to rerun the analysis, one issue may be that the datasets (the .xlsx and/or .csv files) and additional images (i.e., the .png files) must be in the same working environment (usually the same folder) as the .rmd file. If possible, make sure the supplementary figures are in the same folder as the R Code. In the event that this is not possible, deactivate the chunks that contain references to supplementary figures or delete these lines from the R Code.
1 Loading in data
#Ingesting data
<-readxl::read_excel("Devonian Fish Tale Supplementary File 1 (Data).xlsx")%>%
data_initialfilter(is.na(drop)) %>%
rename(clade=Clade,higher_group="Higher Group",order=Order,family=Family,
extinct=Extinct,shape=Shape,habitat=Habitat,
total_length="Total Length (cm)",precaudal_length="Precaudal Length (cm)",
body_mass="Body Mass (g)",head_length="Head Length (cm)",
snout_length="Snout Length (cm)",OOL="OOL (cm)",
body_width="Mediolateral Body Width (cm)",
body_depth="Dorsoventral Body Height (cm)",
genus=Genus,species=Species, specimen=Specimen,length_as="Length As",
fork_length="Fork Length (cm)",girth="Girth (cm)",
prepectoral_length="Prepectoral Length (cm)",
prepelvic_length="Prepelvic Length (cm)",
mouth_width="Mouth Width (cm)",head_depth="Head Height (cm)",
swimbladder="Presence of Swimbladder",
heterocercal="Presence of Heterocercal Caudal Fin",
ontogeny="Ontogenetic Status",references="Reference",
is_body_mass_estimated="Is Body Mass Estimated")%>%
mutate(taxon = paste0(genus,"_",species),
shape=relevel(factor(shape),"fusiform"),
habitat=relevel(factor(habitat),"demersal"))
#Filtering out known juveniles from the final dataset
<-data_initial%>%
data_finalfilter(ontogeny %in% c("adult","subadult")|is.na(ontogeny)|clade=="Placodermi")
<-quo(clade=="Placodermi"&length_as=="total length"|specimen %in% c("CMNH 7424","CMNH 6090","CMNH 7054","CMNH 5768")) fossil.specimens
1.1 Separating out fossil taxa
<-data_initial%>%
(fossil_taxafilter(clade=="Placodermi")%>%
mutate(specimen2=paste0(genus," ",specimen),
taxon=str_replace(taxon,"_"," "))%>%
column_to_rownames("specimen2")%>%
arrange(head_length)%>%
mutate(taxon=ifelse(genus=="Newspecies","Gen. et sp. nov.",taxon)))
1.2 Calculating species-average model
<-data_final%>%
data_speciesdrop_na(total_length,OOL)%>%
filter(length_as!="estimated t.l.")%>%
mutate(N=ifelse(is.na(N),as.numeric(N),1))%>%
group_by(taxon)%>%
summarise(across(where(is.numeric), weighted.mean, N),
N=sum(N),genus=unique(genus),species=unique(species),
clade=unique(clade),higher_group=unique(higher_group),
order=unique(order),family=unique(family),
shape=unique(shape),habitat=unique(habitat))%>%
select(taxon,N,total_length,OOL,everything())
write.csv(data_species,"data_species.csv",row.names=F)
2 Code book
2.1 Measurements
Measurement | Variable Name | Definition |
---|---|---|
Total length | total_length | Length from anterior tip of rostrum to posterior tip of caudal fin |
Fork length | fork_length | Length from anterior tip of rostrum to notch in caudal fork between upper and lower caudal fin lobes. Coded as NA for taxa without a caudal notch. |
Standard length | precaudal_length | Length from anterior tip of rostrum to posterior tip of caudal peduncle |
Head length | head_length | Length from anterior tip of rostrum to posterior margin of branchial cavity For sharks: from snout to opening of terminal gill arch For osteichthyans: from snout to posterior end of operculum For arthrodires: from snout to cranio-thoracic joint |
Snout length | snout_length | Length from anterior tip of rostrum to anterior margin of orbit |
Orbit-opercle length (OOL) | OOL | Length from anterior margin of the orbit to posterior margin of the branchial cavity (see head_length for more details). Equivalent to head length minus snout length |
Head depth | head_depth | Height of head from dorsal tip of supraoccipital to ventral margin of branchials.1 |
Body height | body_depth | Greatest dorsoventral height of the body |
Body width | body_width | Greatest mediolateral width of the body |
Girth | girth | greatest circumference of the body in transverse view |
Pre-pectoral length | prepectoral_length | Length from tip of snout to origin of pectoral fin along anteroposterior axis |
Pre-pelvic length | prepelvic_length | Length from tip of snout to origin of pelvic fin along anteroposterior axis |
Bill length | bill_length | Length that the bill protrudes anterior to the mouth in Istiophoriformes and Hemirhamphidae. This value was subtracted from total length and all other measurements that measured from the tip of the snout before the start of the study. |
1 - Note that when possible head_depth
in chondrichthyans was measured at the posterior margin of the chondrocranium to allow for more direct comparisons with other fishes, but most prior authors follow Compagno (1984) in taking this measurement as the depth at the origin of the pectoral fin.
2.2 Definitions for habitus
Term | Definition |
---|---|
Benthic | Spend large amounts of time on the bottom of bodies of water and are often poor or infrequent swimmers |
Demersal | Active swimmers, but typically live close to the sea floor. Often live in and around complex environments like underwater vegetation, coral reefs, or rock crevices |
Neritic | Active swimmers in the water column, but live in shallower waters closer to the shore . When associated with complex habitats like reefs, rock outcrops, or seaweed beds are typically found above the structure rather than living within it |
Pelagic | Inhabits open waters far from any shoreline, such as the open ocean or the open waters of large rivers or lakes. Often highly migratory or oceanodromus |
Notably, these states are an attempt to categorize a very broad ecological spectrum that goes from benthic ↔︎ demersal ↔︎ neritic ↔︎ pelagic, and there are many species that could be argued to straddle some of these boundaries either within a single life stage (e.g., Sphyraena could be considered neritic/pelagic) or at different parts of their lifecycle (e.g., diadromous fishes like salmon). Additionally, many fishes are described as “benthopelagic”, which essentially provides almost no useful information as to their habits. “Benthopelagic” fishes could be considered as analogous to demeral but in practice seems to encompass demersal and clearly neritic fishes (e.g., many carangids like Seriola). Adding to this confusion, studies of freshwater fishes that are active in the water column consider them all to be “pelagic”, whereas researchers on marine fishes with analogous habits will often describe the same species as “benthopelagic” and treat them as equivalent to demersal species (e.g., this is a common issue when browsing the species profiles on FishBase). This makes it exceedingly hard to make comparisons of habits between freshwater and marine fishes.
As a result, in this study habitat
was determined based on which of the above categories fishes most closely conformed to based on their natural history. However, the author wishes to note here how some of these habitat designations may need to be revised, due to the general confusion regarding life habit classifications in fishes.
2.3 Definitions for shape
Measurement | Definition | Example |
---|---|---|
fusiform | Generalized fish body plan with a “torpedo-like” body shape | rainbow trout (Oncorhynchus mykiss) |
elongate | Trunk is anteroposteriorly elongate but not snake-like or truly anguilliform | barracuda (Sphyraena spp.) |
anguilliform | Extremely elongate, snake-like body, often with reduced fins | American eel (Anguilla rostrata) |
compressiform | Body is anteroposteriorly short and deep relative to its length, often discoid | bluegill (Lepomis macrochirus) |
macruriform | Precaudal portion is normal but has a long, straight “whip-like” or “lizard-like” tail, in contrast to a heterocercal or homocercal caudal fin. Alopias and Stegostoma are treated as macruriform here because of similarities in body construction (specifically, a long, whip-like caudal fin that results in OOL dramatically underestimating body length). | chimaeras (Chimaeridae) |
Defining the elongate
category for sharks was a bit difficult. There are some sharks that very clearly exhibit elongated body plans (e.g., Isistius, Scyliorhinidae, Hemiscyllidae, Etmopterus), but a number of other shark groups exhibit an ambiguous condition (Mustelus, Hemigaleus spp.). This makes it difficult to code body shape, especially because sharks in general exhibit a “stretched out” body plan compared to other fishes (see manuscript). However, comparisons to ray-finned fishes (in terms of body depth
/precaudal length
and the residuals of the OOL model) suggest that at least some of these shark lineages do exhibit trunk proportions similar to elongate
ray-finned fishes, and treating them as fusiform
is statistically inappropriate. Therefore, a shark was considered to be elongate
in body shape if it appeared to have a much more elongate trunk than is typical for an average shark-like body shape (e.g., Carcharhinus, Squalus)
2.4 Taxonomic distribution of observations
%>%
data_finaldrop_na(OOL,total_length)%>%
filter(length_as!="estimated t.l.")%>%
group_by(clade)%>%
summarise(N=n(),Taxa=n_distinct(taxon))%>%
add_row(clade="All Species",
N=data_final%>%drop_na(OOL,total_length)%>%
filter(length_as!="estimated t.l.")%>%
summarise(N=n())%>%pull(),
Taxa=data_final%>%drop_na(OOL,total_length)%>%
filter(length_as!="estimated t.l.")%>%
summarise(Taxa=n_distinct(taxon))%>%pull())%>%
kable(col.names=c("Clade","# Occurences","# Taxa"),
align=c("l","c","c"),
caption="Taxonomic distribution of observations made in this study")%>%
row_spec(6, bold = T)%>%
kable_styling()
Clade | # Occurences | # Taxa |
---|---|---|
Actinopterygii | 2210 | 769 |
Chondrichthyes | 568 | 181 |
Petromyzontiformes | 358 | 8 |
Placodermi | 17 | 10 |
Sarcopterygii | 16 | 3 |
All Species | 3169 | 971 |
2.5 Final cleaned dataset
%>%
data_finalarrange(clade,higher_group,order,family,genus,species)
2.6 Saving cleaned dataset
write.csv(data_final,file="ool_data_cleaned.csv")
3 Correlation of head and body proportions
grid.arrange(ncol=2,
ggplot(data_final%>%filter(!is.na(head_depth),length_as=="total length"),
aes(x=body_depth/total_length,y=head_depth/head_length))+
geom_point(aes(color=clade,shape=clade))+
geom_smooth(formula=y~x,method="lm")+
scale_x_continuous(labels=scales::label_percent(accuracy = 1))+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
ggtitle("A")+
theme(legend.position="none"),
ggplot(data_final%>%filter(!is.na(head_depth),length_as=="total length"),
aes(x=body_depth/total_length,y=body_depth/head_length))+
geom_point(aes(color=clade,shape=clade))+
geom_smooth(formula=y~x,method="lm")+
scale_x_continuous(labels=scales::label_percent(accuracy = 1))+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
ggtitle("B")+
theme(legend.position="none"),
ggplot(data_final%>%filter(!is.na(head_depth),length_as=="total length"),
aes(x=body_depth/precaudal_length,y=head_depth/head_length))+
geom_point(aes(color=clade,shape=clade))+
geom_smooth(formula=y~x,method="lm")+
scale_x_continuous(labels=scales::label_percent(accuracy = 1))+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
ggtitle("C")+
theme(legend.position="none"),
ggplot(data_final%>%filter(!is.na(head_depth),
!family %in% c("Balistidae","Monacanthidae"),
!order %in% c("Acanthuriformes"),
!="Selene",
genus=="total length"),
length_asaes(x=body_depth/total_length,y=head_depth/OOL))+
geom_point(aes(color=clade,shape=clade))+
ggtitle("D")+
geom_smooth(formula=y~x,method="lm")+
scale_x_continuous(labels=scales::label_percent(accuracy = 1))+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
theme(legend.position=c(0.8,0.2))+
labs(color="Clade",shape="Clade")
)
Figure 3.1: Plot of relative head and body proportions in fishes, showing how the length-height ratio of the head and body are closely correlated with one another. This is the case regardless of whether (A) the proportion between head length and height is compared to the proportion between total length and body height, (B) head length and total length are scaled to greatest body height, or (C) head length and height are compared to the proportion between precaudal/standard length and body depth rather than total length. (D) shows this correlated remains even when considering OOL as a proxy for head length, with the exception of Acanthuriformes, Balistoidei, and Selene vomer (omitted for clarity in D).
Note that the values measured on the axes in these graphs are showing the correlation between the proportional measurements between the aspect ratio of the head and body of a fish, not their absolute values. Thus, as fishes’ bodies get longer, their heads also get longer.
rbind(
"head height/head length and body depth/total length "=summary(lm(I(body_depth/total_length)~I(head_depth/head_length),data_final))$r.squared,
"body depth/head length and body depth/total length"=summary(lm(I(body_depth/total_length)~I(head_depth/total_length),data_final))$r.squared,
"height height/head length and body depth/precaudal length"=summary(lm(I(body_depth/precaudal_length)~I(head_depth/head_length),data_final))$r.squared,
"height height/OOL and body depth/total length"=summary(lm(I(body_depth/total_length)~I(head_depth/OOL),data_final))$r.squared
%>%
)kable(digits=3,col.names="R2",caption="R<sup>2</sup> values for the correlation between relative proportions of head and body, using different criteria to define this proportion")%>%
kable_styling()
R2 | |
---|---|
head height/head length and body depth/total length | 0.798 |
body depth/head length and body depth/total length | 0.882 |
height height/head length and body depth/precaudal length | 0.696 |
height height/OOL and body depth/total length | 0.672 |
Based on this, it seems very clear that the proportions of the head and body in fishes are strongly correlated, with elongation of the head closely correlating to elongation of the body whether head elongation is defined relative to head height or body height, and whether body length is defined as precaudal length or total length.
4 Crude total length estimate using head length in Dunkleosteus terrelli
<-
head_length_distribution%>%filter(!is.na(total_length))%>%
data_finalfilter(!genus %in% c("Plesiobatis","Apletodon"),
=="total length")%>%
length_asdrop_na(head_length)%>%
group_by(taxon)%>%
summarise(head_length=mean(head_length),total_length=mean(total_length))%>%
mutate(percent_head_length=head_length/total_length)
<-mean(head_length_distribution$percent_head_length)
mean_head_length<-mean(head_length_distribution$percent_head_length)-(2*sd(head_length_distribution$percent_head_length))
lower_head_length<-mean(head_length_distribution$percent_head_length)+(2*sd(head_length_distribution$percent_head_length))
upper_head_lengthdata.frame("Mean"=mean_head_length*100,
"Lower C.I."=lower_head_length*100,
"Upper C.I."=upper_head_length*100)%>%
kable(digits=2,caption="Mean percent head length for all fishes, as well as 95% prediction interval for this proportion",
col.names=c("Mean","Lower 95% P.I.","Lower 95% P.I."))%>%
kable_styling()
Mean | Lower 95% P.I. | Lower 95% P.I. |
---|---|---|
22.69 | 14.06 | 31.33 |
ggplot(head_length_distribution,aes(percent_head_length))+
geom_histogram(col="black",fill="gray",bins=30)+
geom_vline(xintercept=mean_head_length,
linetype="dashed")+
geom_vline(xintercept=lower_head_length,
linetype="dotted",alpha=0.5)+
geom_vline(xintercept=upper_head_length,
linetype="dotted",alpha=0.5)+
labs(x="Percent Head Length",y="Number of Species")+
scale_x_continuous(labels=scales::label_percent(accuracy = 1))+
theme_classic()
Figure 4.1: Histogram of percent head length in fishes, using species averages of adult and subadult individuals in the present dataset. Dashed line represents mean percent head length and dotted lines represent percent head lengths at +/- two standard deviations of the mean value.
From this it is possible to determine that in fishes the total head length is, on average, about 22.7% of the total length of the organism.
%>%
fossil_taxafilter(specimen %in% c("CMNH 7424","CMNH 6090","CMNH 7054","CMNH 5768"))%>%
mutate(crude_total_length=head_length/mean_head_length,
crude_total_length_lower=head_length/upper_head_length,
crude_total_length_upper=head_length/lower_head_length)%>%
# The two are reversed here because a smaller % head length results in a longer body
arrange(head_length)%>%
rownames_to_column()%>%
select(specimen,head_length,crude_total_length,
%>%
crude_total_length_lower,crude_total_length_upper)kable(digits=1,align=c("l","c","c","c"),
col.names = c("Specimen","Head Length","Est. Length","Lower","Upper"),
caption="Estimate of total length in <i>Dunkleosteus terrelli</i> using head length")%>%
kable_styling()
Specimen | Head Length | Est. Length | Lower | Upper |
---|---|---|---|---|
CMNH 7424 | 34.0 | 149.8 | 108.5 | 241.9 |
CMNH 6090 | 51.0 | 224.8 | 162.8 | 362.8 |
CMNH 7054 | 53.6 | 236.3 | 171.1 | 381.4 |
CMNH 5768 | 61.3 | 270.2 | 195.7 | 436.1 |
From this, it is possible to produce a very crude estimate suggesting that adult individuals of D. terrelli (i.e., CMNH 5768) have an estimated length of 2.7 m, which based on the proportions seen in extant fishes suggest a potential range of body length from 1.96-4.36 m.
%>%
fossil_taxafilter(length_as!="estimated t.l.",clade=="Placodermi")%>%
mutate(crude_total_length=head_length/mean_head_length,
crude_total_length_lower=head_length/upper_head_length,
crude_total_length_upper=head_length/lower_head_length,
PE=(((crude_total_length-total_length)/crude_total_length))*100,
taxon=str_replace(taxon,"_"," "))%>%
rownames_to_column()%>%
# The two are reversed here because a smaller % head length results in a longer body
arrange(head_length)%>%
select(taxon,specimen,head_length,crude_total_length,
%>%
crude_total_length_lower,crude_total_length_upper,total_length,PE)kable(digits=1,align=c("l","c","c","c","c","c","c","c"),
caption="Estimate of total length in specimens of complete placoderms using head length",
col.names = c("Taxon","Specimen","Head Length","Est. Length","Lower","Upper","Actual Length","%PE"))%>%
column_spec(1, italic = T)%>%
column_spec(c(4,7), bold = T)%>%
kable_styling()
Taxon | Specimen | Head Length | Est. Length | Lower | Upper | Actual Length | %PE |
---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 2.3 | 10.3 | 7.5 | 16.6 | 13.7 | -33.0 |
Millerosteus minor | Composite Millerosteus | 3.0 | 13.0 | 9.4 | 21.1 | 14.9 | -14.6 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 4.6 | 20.2 | 14.6 | 32.6 | 23.0 | -13.9 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 5.7 | 25.3 | 18.3 | 40.8 | 30.3 | -19.7 |
Coccosteus cuspidatus | NMS 1893.107.27 | 6.2 | 27.5 | 19.9 | 44.4 | 29.6 | -7.7 |
Coccosteus cuspidatus | NMS 1897.55.6 | 6.5 | 28.5 | 20.7 | 46.0 | 32.3 | -13.2 |
Coccosteus cuspidatus | FMNH PF 1673 | 6.8 | 29.7 | 21.5 | 48.0 | 37.1 | -24.8 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 7.1 | 31.2 | 22.6 | 50.4 | 39.4 | -26.3 |
Coccosteus cuspidatus | NMS 1900.12.12 | 7.1 | 31.4 | 22.7 | 50.7 | 34.4 | -9.6 |
Coccosteus cuspidatus | ROM VP 52664 | 7.7 | 34.0 | 24.6 | 54.9 | 37.5 | -10.3 |
Plourdosteus canadensis | MNHM 2-177 | 8.7 | 38.4 | 27.8 | 62.0 | 37.5 | 2.3 |
Dickosteus threiplandi | NMS 1987.7.118 | 9.2 | 40.6 | 29.4 | 65.6 | 43.7 | -7.5 |
Holonema westolli | Recon. (Miles 1971) | 9.6 | 42.5 | 30.8 | 68.6 | 60.6 | -42.7 |
Watsonosteus fletti | NMS G.1995.4.2 | 11.5 | 50.7 | 36.7 | 81.9 | 56.6 | -11.6 |
Gen. et sp. nov. | CMNH 50233 | 12.4 | 54.5 | 39.5 | 88.0 | 63.0 | -15.6 |
Dickosteus threiplandi | NHMUK PV P 49663 | 12.7 | 55.7 | 40.4 | 90.0 | 52.3 | 6.2 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 13.6 | 59.8 | 43.4 | 96.6 | 89.7 | -49.9 |
However, in complete specimens of arthrodires, using head length to estimate total length produces systematic underestimates of body length, which are quite substantial in some cases.
The 95% prediction interval for head length cited in Table 4.1 completely excludes the larger body sizes for Dunkleosteus typically cited in previous studies, which are almost invariable greater than 5 m in length for adult individuals like CMNH 5768. Even though head length produces underestimates of body size in arthrodires, there is essentially no way to produce sizes larger than 5 m even assuming head-body proportions comparable to Amazichthys (which produces an estimated length of 4.05 m for CMNH 5768).
Notably, the above results make absolutely no additional assumptions as to any other biological features of the taxa being considered, such as the shorter snouts of arthrodires compared to other fishes, the fact that the most extreme head proportions in this dataset are seen in strongly anguilliform or compressed body shapes that are not likely to be present in Dunkleosteus, etc. Thus, these estimates can be further refined, as seen below…
5 All taxon model
5.1 Graph of OOL against total length
<-lm(log(total_length)~log(OOL),
fit.OOL%>% filter(length_as!="estimated t.l."))
data_final <-ggplot(
(dunk_length_specimens%>%
data_finalfilter(length_as=="total length")%>%
drop_na(OOL,total_length)%>%
augment(fit.OOL,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF))%>%
arrange(clade),
aes(y=total_length,x=OOL))+
geom_smooth(aes(color=clade),se=F,method="lm",formula=y~x)+
geom_star(aes(fill=clade,starshape=clade),size=2)+
geom_smooth(method="lm",formula=y~x)+
geom_line(aes(y=.lower), color = "blue", linetype = "dashed")+
geom_line(aes(y=.upper), color = "blue", linetype = "dashed")+
geom_smooth(data=.%>%filter(clade=="Chondrichthyes"),
method="lm",col="green",formula=y~x)+
geom_star(aes(fill=clade,starshape=clade),color="white",starstroke=0.33,
%>%filter(clade=="Placodermi"),size=3,show.legend=F)+
.scale_starshape_manual(values=c(15,13,11,1,28))+
scale_fill_manual(values=c(hue_pal()(4)[1:3],"black",hue_pal()(4)[4]),na.value=NA)+
scale_color_manual(values=c(hue_pal()(4)[1:2],NA,NA,"NA"),na.value=NA)+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)",
color="Clade",starshape="Clade",fill="Clade")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
geom_text(aes(x = 0.18, y = 1900, label = lm_eqn.all(fit.OOL)),
hjust=0, parse = TRUE,data.frame())+
theme_classic()+
theme(legend.position=c(0.85,0.2)))
Figure 5.1: Plot of orbit-opercular length against total length in fishes (using a log10 scale), using individual specimen values.
ggsave("Figure 7 (OOL Regression).tiff",dunk_length_specimens,device="tiff",
width=170,height=127.5,dpi=600,units="mm",compression="lzw")
5.2 Results of model
<-data_final%>%
OOL_residualsfilter(!is.na(OOL),!is.na(total_length),length_as!="estimated t.l.")%>%
mutate(residuals=(residuals(lm(log(total_length)~log(OOL)))))
summary(fit.OOL)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.61436 -0.14237 0.00201 0.13581 1.55312
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.900761 0.009076 209.4 <2e-16 ***
## log(OOL) 0.996190 0.004175 238.6 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2248 on 3167 degrees of freedom
## (14 observations deleted due to missingness)
## Multiple R-squared: 0.9473, Adjusted R-squared: 0.9473
## F-statistic: 5.693e+04 on 1 and 3167 DF, p-value: < 2.2e-16
regression.stats(fit.OOL)
5.3 Diagnostic plots for model
par(mfrow=c(2,2))
plot(fit.OOL)
Figure 5.2: Diagnostic plots for model regressing total length against orbit-opercular length
5.4 Comparing to untransformed model
5.4.1 Model summary
lm(total_length~OOL,data_final) %>%
summary()
##
## Call:
## lm(formula = total_length ~ OOL, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -198.50 -9.41 -4.55 4.54 362.53
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.90954 0.53010 16.81 <2e-16 ***
## OOL 5.86007 0.02866 204.48 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 23.64 on 3167 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9296, Adjusted R-squared: 0.9296
## F-statistic: 4.181e+04 on 1 and 3167 DF, p-value: < 2.2e-16
5.4.2 Graph of untransformed OOL versus total length
ggplot(
%>%
data_finalfilter(length_as=="total length")%>%
drop_na(OOL,total_length)%>%
augment(lm(total_length~OOL,data_final),newdata=.,interval="prediction")%>%
arrange(clade),
aes(y=total_length,x=OOL))+
geom_smooth(aes(color=clade),se=F,method="lm",formula=y~x)+
geom_star(aes(fill=clade,starshape=clade),size=2)+
geom_smooth(method="lm",formula=y~x)+
geom_line(aes(y=.lower), color = "blue", linetype = "dashed")+
geom_line(aes(y=.upper), color = "blue", linetype = "dashed")+
geom_smooth(data=.%>%filter(clade=="Chondrichthyes"),
method="lm",col="green",formula=y~x)+
geom_star(aes(fill=clade,starshape=clade),color="white",starstroke=0.33,
%>%filter(clade=="Placodermi"),size=3,show.legend=F)+
.scale_starshape_manual(values=c(15,13,11,1,28))+
scale_fill_manual(values=c(hue_pal()(4)[1:3],"black",hue_pal()(4)[4]),na.value=NA)+
scale_color_manual(values=c(hue_pal()(4)[1:2],NA,NA,"NA"),na.value=NA)+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)",
color="Clade",starshape="Clade",fill="Clade")+
geom_text(aes(x = 0.18, y = 950,
label = lm_eqn.all(lm(total_length~OOL,data_final))),
hjust=0, parse = TRUE,data.frame())+
theme_classic()+
coord_cartesian(y=c(-50,1000))+
theme(legend.position=c(0.85,0.2))
Figure 5.3: Plot of OOL versus total length using untransformed data. Note that the regression line is calculated on the data without log-transformation, this is not the regression line of the log-transformed data back-transformed to arithmetic units.
5.4.3 Diagnostic plots
par(mfrow=c(2,2))
plot(lm(total_length~OOL,data_final))
Figure 5.4: Diagnostic plots for untransformed model
5.4.4 Histogram of residuals
grid.arrange(ncol=2,
ggplot(data_final%>%filter(!is.na(OOL))%>%
filter(!is.na(total_length)),
aes(x=residuals(lm(total_length~OOL))))+
geom_histogram(col="black",fill="gray",bins=30)+
stat_function(fun = function(x) dnorm(x,
mean=mean(residuals(lm(total_length~OOL,data_final),na.rm=TRUE)),
sd=sd(residuals(lm(total_length~OOL,data_final),na.rm=TRUE)))*
nrow(data.frame(residuals(lm(total_length~OOL,data_final),na.rm=TRUE)))*
max(residuals(lm(total_length~OOL,
((+
data_final)))abs(min(residuals(lm(total_length~OOL,
/
data_final)))))30),
color = "red", size = 0.5)+
ggtitle("Untransformed Model")+
labs(y="Count",x="Residuals")+theme_classic(),
ggplot(data_final%>%filter(!is.na(OOL))%>%
filter(!is.na(total_length)),
aes(x=residuals(lm(log(total_length)~log(OOL)))))+
geom_histogram(col="black",fill="gray",bins=30)+
stat_function(fun = function(x) dnorm(x,
mean=mean(residuals(lm(log(total_length)~log(OOL),data_final),na.rm=TRUE)),
sd=sd(residuals(lm(log(total_length)~log(OOL),data_final),na.rm=TRUE)))*
nrow(data.frame(residuals(lm(log(total_length)~log(OOL),data_final),na.rm=TRUE)))*
max(residuals(lm(log(total_length)~
((log(OOL),
+
data_final)))abs(min(residuals(lm(log(total_length)~
log(OOL),
/
data_final)))))30),
color = "red", size = 0.5)+
ggtitle("Log-Transformed Model")+
labs(y="Count",x="Residuals")+theme_classic()
)
Figure 5.5: Histogram of residuals in untransformed and natural log transformed model
Based on the heterosketasticity in the scale-location plot, increased leverage of certain highly influential points (mostly large taxa), and the strongly leptokurtic distribution of the residuals of the untransformed model, a model in which the data is log-transformed before analysis is preferred here.
5.4.5 Examination of kurtosis
rbind("Untransformed Model"=data_final%$%
lm(total_length~OOL)%>%
residuals()%>%
kurtosis(),
"Log-Transformed Model"=fit.OOL%>%
residuals()%>%
kurtosis(),
"Back-Transformed Residuals"=fit.OOL%>%
residuals()%>%
exp()%>%
kurtosis()
%>%data.frame()%>%
)add_column(skewness=c(skewness(residuals(lm(total_length~OOL,data_final))),
skewness(residuals(fit.OOL)),
skewness(exp(residuals(fit.OOL)))))%>%
kable(digits=2,align="c",col.names=c("Excess Kurtosis","Skewness"),
caption="Kurtosis and skewness for the regression model between OOL with and without log-transformation, as well as the residuals from a log-transformed model back-transformed to an arithmetic scale.")%>%
kable_styling()
Excess Kurtosis | Skewness | |
---|---|---|
Untransformed Model | 37.81 | 2.77 |
Log-Transformed Model | 2.20 | 0.44 |
Back-Transformed Residuals | 32.73 | 3.18 |
Based on this, the log-transformed model shows minor excess kurtosis (kurtosus < 3), and little skewness. However, when back-transformed into an arithmetic scale, the residuals of the model show extreme kurtosis (> 30). This means that while log-transformation normalizes the distribution of data and makes it possible to accurately fit a regression model, when back-transformed into arithmetic terms it fails to accurately project prediction intervals for new data, since the prediction intervals are based in part on the standard error of the model (and hence the residuals).
Or, to put it in less statistically minded terms, de-transforming a log-log model results outliers being exaggerated, because error goes from being calculated on a log-scale to an unlogged one. This results in outliers having a disproportionate effect on the model. Detransformation will transform almost any study’s distribution of residuals from a nearly-normal distribution to a leptokurtic one, unless the model itself is almost perfectly normal (which it never is). Calculating prediction intervals on leptokurtic models is known to drastically inflate error bounds (Miller, 1986), however there are few suggestions to how to apply this to log-transformed regression equations, such as those of most biological data.
5.4.6 Estimates of placoderms using an untransformed model
%>%
fossil_taxafilter(!!fossil.specimens)%>%
augment(lm(total_length~OOL,data_final),newdata=.,interval="predict")%>%
select(taxon,specimen,total_length,.fitted,.lower,.upper)%>%
kable(digits=1,align=c("l","c","c","c","c","c"),
col.names = c("Taxon","Specimen","Actual Length","Est.","Lower 95% P.I.","Upper 95% P.I."),
caption="Length estimates for placoderms known from complete body fossils using a non-log transformed model.")%>%
column_spec(1,italic=T)%>%
add_header_above(c(" "=3,"Estimated Length"=3))%>%
column_spec(4,bold=T)%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | Lower 95% P.I. | Upper 95% P.I. |
---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 20.9 | -25.5 | 67.2 |
Millerosteus minor | Composite Millerosteus | 14.9 | 22.7 | -23.6 | 69.1 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 30.0 | -16.3 | 76.4 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 36.2 | -10.1 | 82.6 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 39.3 | -7.1 | 85.6 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 40.1 | -6.3 | 86.4 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 40.5 | -5.9 | 86.9 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 46.9 | 0.6 | 93.3 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 46.2 | -0.1 | 92.6 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 45.7 | -0.6 | 92.1 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 53.4 | 7.1 | 99.8 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 57.5 | 11.2 | 103.9 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 53.2 | 6.9 | 99.6 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 65.5 | 19.2 | 111.9 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 68.3 | 21.9 | 114.7 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 69.2 | 22.8 | 115.5 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 76.6 | 30.2 | 123.0 |
Dunkleosteus terrelli | CMNH 7424 | NA | 178.9 | 132.5 | 225.2 |
Dunkleosteus terrelli | CMNH 6090 | NA | 264.4 | 218.0 | 310.8 |
Dunkleosteus terrelli | CMNH 7054 | NA | 275.5 | 229.1 | 321.9 |
Dunkleosteus terrelli | CMNH 5768 | NA | 316.6 | 270.1 | 363.0 |
Note how for the very smallest placoderm taxa (e.g., Millerosteus, Coccosteus) the 95% prediction intervals for the model where the data is not log-transformed before regressing are negative. This is likely a result of heteroskedasticity in the model (i.e., larger fishes are measured with more error), which means that an untransformed model is unsuitable for estimating length in Dunkleosteus.
5.5 Distribution of residuals
ggplot(OOL_residuals%>%filter(length_as!="estimated t.l."),
aes(y=residuals,x=clade))+
geom_violin(aes(fill=clade),scale="width")+
geom_hline(yintercept=0,linetype="dashed")+
geom_hline(data=.%>%filter(clade=="Placodermi"),
aes(yintercept=mean(residuals)),color="#00B0F6",linetype="dashed")+
geom_boxplot(width=0.3)+
scale_y_continuous(breaks=seq(-1.5,1.5,0.2))+
labs(y="Residuals",x="Clade")+
theme(legend.position="none")
Figure 5.6: Box-and-whisker plot of distribution of residuals in OOL model separated by clade.
As can be seen, arthrodire placoderms show slightly negative residuals (i.e., a slight overestimate of body length), but overall their residuals are well within the range of variation of other fishes.
5.6 Species-average model
<-lm(log(total_length)~log(OOL),
fit.species_average%>%
data_speciescolumn_to_rownames("taxon"))
<-lm(log(total_length)~log(OOL),
fit.species_average2%>%
data_speciesfilter(!shape %in%
c("macruriform","compressiform","anguiliform")%>%
replace_na(TRUE),
!family %in% c("Balistidae","Monacanthidae",
"Serranidae","Holocentridae"),
!genus %in% c("Rhinochimaera"))%>%
column_to_rownames("taxon"))
<-data_species%>%ungroup()%>%
data_speciesmutate(fit=exp(predict(fit.species_average,data_species,interval="prediction"))[,1],
lwr=exp(predict(fit.species_average,data_species,interval="prediction"))[,2],
upr=exp(predict(fit.species_average,data_species,interval="prediction"))[,3],
residuals=residuals(fit.species_average2)[match(data_species$taxon,names(fit.species_average2$residuals))])
ggplot(
%>%
data_speciesdrop_na(OOL,total_length)%>%
augment(fit.species_average,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.species_average)$CF))%>%
arrange(clade),
aes(y=total_length,x=OOL))+
geom_smooth(aes(color=clade),se=F,method="lm",formula=y~x)+
geom_star(aes(fill=clade,starshape=clade),size=2)+
geom_smooth(method="lm",formula=y~x)+
geom_line(aes(y=.lower), color = "blue", linetype = "dashed")+
geom_line(aes(y=.upper), color = "blue", linetype = "dashed")+
geom_smooth(data=.%>%filter(clade=="Chondrichthyes"),
method="lm",col="green",formula=y~x)+
geom_star(aes(fill=clade,starshape=clade),color="white",starstroke=0.33,
%>%filter(clade=="Placodermi"),size=3,show.legend=F)+
.scale_starshape_manual(values=c(15,13,11,1,28))+
scale_fill_manual(values=c(hue_pal()(4)[1:3],"black",hue_pal()(4)[4]),na.value=NA)+
scale_color_manual(values=c(hue_pal()(4)[1:2],NA,NA,"NA"),na.value=NA)+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)",
color="Clade",starshape="Clade",fill="Clade")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
geom_text(aes(x = 0.18, y = 1900, label = lm_eqn.all(fit.species_average)),
hjust=0, parse = TRUE,data.frame())+
theme_classic()+
theme(legend.position=c(0.85,0.2))
Figure 5.7: Plot of orbit-opercular length against total length in fishes (on a log10 scale), using the average value for adults of each species.
write.csv(data_species%>%select(taxon,clade,N,OOL,total_length,everything()),
file="ool_data_cleaned_speciesaverages.csv")
summary(fit.species_average)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_species %>%
## column_to_rownames("taxon"))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.56385 -0.13633 -0.01091 0.11679 1.58038
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.911462 0.016657 114.8 <2e-16 ***
## log(OOL) 0.982030 0.008339 117.8 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2334 on 965 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.9349, Adjusted R-squared: 0.9349
## F-statistic: 1.387e+04 on 1 and 965 DF, p-value: < 2.2e-16
regression.stats(fit.species_average)
5.6.1 Species averages, excluding anguilliform, compressiform, and macruriform taxa
summary(fit.species_average2)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_species %>%
## filter(!shape %in% c("macruriform", "compressiform", "anguiliform") %>%
## replace_na(TRUE), !family %in% c("Balistidae", "Monacanthidae",
## "Serranidae", "Holocentridae"), !genus %in% c("Rhinochimaera")) %>%
## column_to_rownames("taxon"))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.50908 -0.11894 -0.01996 0.09556 1.55340
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.951446 0.015773 123.7 <2e-16 ***
## log(OOL) 0.977179 0.007704 126.8 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2034 on 775 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.954, Adjusted R-squared: 0.954
## F-statistic: 1.609e+04 on 1 and 775 DF, p-value: < 2.2e-16
regression.stats(fit.species_average2)
5.7 Percent of taxa that have estimates falling withing X percent of their actual length
rbind(data_final%>%
mutate(fit=exp(predict(fit.OOL,.))*regression.stats(fit.OOL)$CF,
PE=(fit-total_length)/fit)%>%
mutate(onethird=ifelse(PE<0.333&PE>(-0.333),1,0),
onefifth=ifelse(PE<0.2&PE>(-0.2),1,0))%>%
drop_na(onethird,onefifth)%>%
select(onethird,onefifth)%>%
summarise(across(onethird:onefifth,~mean(.))),
%>%
data_speciesmutate(fit=exp(predict(fit.species_average,.))*regression.stats(fit.species_average)$CF,
PE=(fit-total_length)/fit)%>%
mutate(onethird=ifelse(PE<0.333&PE>(-0.333),1,0),
onefifth=ifelse(PE<0.2&PE>(-0.2),1,0))%>%
drop_na(onethird,onefifth)%>%
select(onethird,onefifth)%>%
summarise(across(onethird:onefifth,~mean(.)))
%>%
)mutate(across(everything(),~.*100),
rowname=c("Individual Specimens","Species Averages"))%>%
column_to_rownames("rowname")%>%
kable(digits=2,align=c("l","c","c"),
col.names = c("+/- 33%","+/- 20%"))%>%
add_header_above(c(" "=1,"Percent of observations within X percent of actual value"=2))%>%
kable_styling()
+/- 33% | +/- 20% | |
---|---|---|
Individual Specimens | 88.29 | 67.31 |
Species Averages | 87.80 | 68.56 |
Based on this, estimated lengths for the majority of taxa fall within +/- 20% of the actual value, and nearly all taxa fall within +/- 33% of the actual value. The taxa that do not tend to be those with extreme body plans (e.g., hyper-anguilliform, hyper-compressiform, extremely posteriorly shifted orbit), which suggests that the returned 95% prediction intervals for the model (which tend to be +/- 50% or more estimated length) are not accurate and using +/- %PE is a more accurate way of expressing uncertainty in length estimates for arthrodires.
5.8 Distribution of head proportions across clades
grid.arrange(
ggplot(data_final%>%filter(length_as!="estimated t.l.",!is.na(total_length),!is.na(head_length))%>%
group_by(taxon)%>%
summarise(total_length=mean(total_length),head_length=mean(head_length),clade=unique(clade)),
aes(y=head_length/total_length,x=clade))+
geom_hline(aes(yintercept=mean(head_length/total_length)))+
geom_hline(data=.%>%filter(clade=="Placodermi"),color=hue_pal()(5)[4],
aes(yintercept=mean(head_length/total_length)))+
geom_violin(aes(fill=clade),scale="width")+
geom_boxplot(width=0.3)+
labs(x="Clade",y="Percent of Total Length")+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
ggtitle("Head Length as Percent of Total Length")+
theme(legend.position="none"),
ggplot(data_final%>%filter(length_as!="estimated t.l.",!is.na(total_length),!is.na(OOL))%>%
group_by(taxon)%>%
summarise(snout_length=mean(snout_length),total_length=mean(total_length),OOL=mean(OOL),clade=unique(clade)),
aes(y=OOL/total_length,x=clade))+
geom_hline(aes(yintercept=mean(OOL/total_length)))+
geom_hline(data=.%>%filter(clade=="Placodermi"),color=hue_pal()(5)[4],
aes(yintercept=mean(OOL/total_length)))+
geom_violin(aes(fill=clade),scale="width")+
geom_boxplot(width=0.3)+
labs(x="Clade",y="Percent of Total Length")+
ggtitle("OOL as Percent of Total Length")+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
theme(legend.position="none"),
ggplot(data_final%>%filter(length_as!="estimated t.l.",!is.na(total_length),!is.na(OOL),!is.na(snout_length))%>%
group_by(taxon)%>%
summarise(snout_length=mean(snout_length),total_length=mean(total_length),OOL=mean(OOL),clade=unique(clade)),
aes(y=OOL/(total_length-snout_length),x=clade))+
geom_hline(aes(yintercept=mean(OOL/(total_length-snout_length))))+
geom_hline(data=.%>%filter(clade=="Placodermi"),color=hue_pal()(5)[4],
aes(yintercept=mean(OOL/(total_length-snout_length))))+
geom_violin(aes(fill=clade),scale="width")+
geom_boxplot(width=0.3)+
labs(x="Clade",y="Percent of Total Length")+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
ggtitle("OOL as Percent of Total Length minus Snout Length")+
theme(legend.position="none"))
Figure 5.8: Distributions of head length as a percent of total length (top), OOL as a percent of total length (middle), and OOL as a percent of total length minus snout length (bottom) in fishes examined in this study. Data points for these box-and-whisker plots are species-averages.
Overall, placoderms seem to show heads that are comparable in relative length to other fishes. OOL as percent total length is slightly high (though still within the range of variation), but this appears to be due to the unusually short snout of arthrodires relative to other gnathostomes.
5.9 Testing to see if different clades have different regression lines
summary(lm(log(total_length)~log(OOL)+clade,
data_final))
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + clade, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.59829 -0.12924 -0.00425 0.10517 1.57293
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.884758 0.009115 206.778 <2e-16 ***
## log(OOL) 0.994769 0.004481 221.997 <2e-16 ***
## cladeChondrichthyes 0.015222 0.011311 1.346 0.178
## cladePetromyzontiformes 0.146521 0.012561 11.665 <2e-16 ***
## cladePlacodermi -0.061216 0.053592 -1.142 0.253
## cladeSarcopterygii -0.034912 0.055525 -0.629 0.530
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2201 on 3163 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9495, Adjusted R-squared: 0.9495
## F-statistic: 1.19e+04 on 5 and 3163 DF, p-value: < 2.2e-16
options(width=1000)
summary(lm(log(total_length)~log(OOL)*clade,
data_final))
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * clade, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.59791 -0.11815 -0.00554 0.10533 1.55427
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.846948 0.009576 192.866 <2e-16 ***
## log(OOL) 1.016435 0.004818 210.975 <2e-16 ***
## cladeChondrichthyes 0.377939 0.033054 11.434 <2e-16 ***
## cladePetromyzontiformes -0.003554 0.086416 -0.041 0.9672
## cladePlacodermi 0.047962 0.203902 0.235 0.8141
## cladeSarcopterygii 1.296739 1.057700 1.226 0.2203
## log(OOL):cladeChondrichthyes -0.139344 0.011991 -11.621 <2e-16 ***
## log(OOL):cladePetromyzontiformes 0.076935 0.044931 1.712 0.0869 .
## log(OOL):cladePlacodermi -0.061467 0.109895 -0.559 0.5760
## log(OOL):cladeSarcopterygii -0.449506 0.349320 -1.287 0.1983
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2155 on 3159 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9517, Adjusted R-squared: 0.9516
## F-statistic: 6916 on 9 and 3159 DF, p-value: < 2.2e-16
Comparing regression lines with both shape and clade
options(width=1000)
summary(lm(log(total_length)~log(OOL)*clade+shape,
data_final))
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * clade + shape, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.63004 -0.09248 0.00986 0.09829 1.20185
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.851146 0.008399 220.404 < 2e-16 ***
## log(OOL) 0.988477 0.004177 236.629 < 2e-16 ***
## cladeChondrichthyes 0.146592 0.028976 5.059 4.46e-07 ***
## cladePetromyzontiformes -0.474570 0.075036 -6.325 2.90e-10 ***
## cladePlacodermi 0.102825 0.171002 0.601 0.54768
## cladeSarcopterygii 1.292541 0.886844 1.457 0.14509
## shapeanguilliform 0.466817 0.020294 23.003 < 2e-16 ***
## shapecompressiform -0.096815 0.011969 -8.089 8.51e-16 ***
## shapeelongate 0.240656 0.009920 24.261 < 2e-16 ***
## shapeflattened 0.073593 0.036068 2.040 0.04140 *
## shapemacruriform 0.422009 0.029736 14.192 < 2e-16 ***
## log(OOL):cladeChondrichthyes -0.055296 0.010514 -5.259 1.54e-07 ***
## log(OOL):cladePetromyzontiformes 0.104893 0.037688 2.783 0.00542 **
## log(OOL):cladePlacodermi -0.074344 0.092147 -0.807 0.41984
## log(OOL):cladeSarcopterygii -0.421548 0.292893 -1.439 0.15018
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1807 on 3154 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9661, Adjusted R-squared: 0.9659
## F-statistic: 6420 on 14 and 3154 DF, p-value: < 2.2e-16
anova(lm(log(total_length)~log(OOL)*clade+shape,
data_final))
Comparing regression lines with both shape and clade, using species averages
options(width=1000)
%>%
data_species lm(log(total_length)~log(OOL)*clade+shape,.)%>%
summary()
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * clade + shape, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.59859 -0.11207 0.00263 0.09726 1.15804
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.900713 0.016195 117.365 < 2e-16 ***
## log(OOL) 0.960253 0.008935 107.467 < 2e-16 ***
## cladeChondrichthyes 0.099869 0.062688 1.593 0.111465
## cladePetromyzontiformes -0.626886 0.219484 -2.856 0.004381 **
## cladePlacodermi 0.027436 0.243927 0.112 0.910469
## cladeSarcopterygii 2.186985 2.236617 0.978 0.328417
## shapeanguilliform 0.491471 0.036919 13.312 < 2e-16 ***
## shapecompressiform -0.070926 0.020863 -3.400 0.000703 ***
## shapeelongate 0.199297 0.020550 9.698 < 2e-16 ***
## shapeflattened 0.085480 0.055041 1.553 0.120751
## shapemacruriform 0.401588 0.049930 8.043 2.59e-15 ***
## log(OOL):cladeChondrichthyes -0.023399 0.023541 -0.994 0.320490
## log(OOL):cladePetromyzontiformes 0.159576 0.154635 1.032 0.302356
## log(OOL):cladePlacodermi -0.020417 0.126127 -0.162 0.871438
## log(OOL):cladeSarcopterygii -0.704677 0.763649 -0.923 0.356358
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1989 on 952 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.9534, Adjusted R-squared: 0.9527
## F-statistic: 1390 on 14 and 952 DF, p-value: < 2.2e-16
If examining based on species averages sharks and other fish groups do not have significant differences in slope between clades.
%>%
data_finalaugment(fit.OOL,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF))%>%
drop_na(total_length,OOL)%>%
ggplot(.,
aes(y=total_length,x=OOL))+
geom_point(aes(shape=clade),color="dark grey",fill="light grey",show.legend=F)+
geom_smooth(method="lm",formula=y~x,alpha=0.25,se=F)+
geom_point(data=.%>%filter(clade=="Chondrichthyes")%>%
drop_na(shape)%>%
mutate(shape=factor(ifelse(family %in%
c("Lamnidae","Megachasmatidae","Echinorhinidae"),
"Lam./Megac./Echin.",
as.character(shape))),
shape=relevel(factor(shape),"fusiform")),
aes(shape=clade,fill=shape))+
geom_smooth(data=.%>%filter(clade=="Chondrichthyes"),color="black",
method="lm",formula=y~x,alpha=0.25)+
geom_line(aes(y=.lower), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_line(aes(y=.upper), color = "#3366FF", linetype = "dashed",alpha=0.5)+
scale_shape_manual(values=c(21,24,22,23,25),guide="none")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)",fill="Body Shape")+
theme_classic()+
theme(legend.position=c(0.7,0.25))+
guides(fill=guide_legend(override.aes = list(shape = 24)))
Figure 5.9: Plot of OOL against total length in fishes on a log10 scale, focusing on sharks, showing the non-random distribution of sharks with respect to size and body shape. The very smallest sharks (e.g., Scyliorhinidae) all have elongate bodies, whereas the very largest sharks tend to be Lamniformes (Lamnidae, Megachasmatidae) or Echinorhiniformes with very short trunk proportions (abbreviated as “Lam./Megac./Echin.” in the legend). Thus, although chondrichthyans show a different regresson linefrom other taxa, this is not due to a different allometric relationship between OOL and total length but rather due to non-random differences in ecology that are mirrored in other fishes (i.e., tunas also show shorter bodies than other fishes). Black line represents regression for chondrichthyans whereas blue line represents regression for all fishes.
5.10 Effects of ontogeny on model error
5.10.1 Effects of ontogeny with for smaller actinopterygians
Note: these data use the initial data set that does not filter out the confirmed juvenile individuals prior to the analysis.
%>%
data_initialdrop_na(OOL,total_length)%>%
filter(references!="Slagle pers. comm.")%>%
#Removed this one because I could only measure it from a photo at an angle, not personally, and it is much bigger than all other specimens, so I am not 100% sure if it is reliable
augment(fit.OOL,newdata=.)%>%
filter(taxon %in% c("Hiodon_tergisus",
"Amblopites_rupestris",
"Alosa_pseudoharengus",
"Neogobius_melanostomus",
"Etheostoma_caeruleum",
"Micropterus_dolomieu"))%>%
ggplot(aes(total_length,.resid))+
geom_point(aes(fill=genus),shape=21)+
geom_smooth(aes(color=genus),formula=y~x,method="lm")+
labs(x="Total Length (cm)",y="Residuals",fill="Species",shape="Species",color="Species")+
theme(legend.text = element_text(face = "italic"))
Figure 5.10: Plot of residuals versus total length for smaller fishes that could be measured directly
5.10.2 Effects of ontogeny with for Geotria
%>%
data_initialfilter(taxon=="Geotria_macrostoma") %>%
augment(fit.OOL,newdata=.)%>%
ggplot(.,aes(total_length,.resid))+
geom_point(fill="gray",shape=21)+
geom_smooth(method="lm",formula=y~x)+
labs(x="Total Length (cm)",y="Residuals")
Figure 5.11: Plot of residuals versus total length in the lamprey Geotria macrostoma using data from Baker et al. (2021).
There is a slightly positive allometry in the residuals for lampreys, though not as strong as for actinopterygians.
5.10.4 Effects of ontogeny with for Eusthenopteron from Schultze (1984)
<-data.frame(
eusthenopteronsnout_length=c(1.5,1.2,NA,NA,2.0,2.8,2.8,2.7,2.7,2.6,NA,2.4,2.7,2.9,2.9,NA,NA,NA,NA,NA,4.4,3.3,
3.3,3.6,NA,NA,NA,NA,NA,3.4,NA,NA,NA,NA,NA,11.1,NA,NA,NA,NA,NA,NA,NA,12,14.5,13.8,
NA,NA,19.8,32,0),
head_length=c(7.5,7.2,8.2,8.2,11.1,11.7,11.7,11.7,11.7,13.3,NA,12.6,14,14.2,14.6,
16.2,19.6,16.7,20.9,20.1,19.5,NA,NA,22.1,25.3,26.1,NA,26.3,25.4,27.2,
30.8,32.8,31.9,39.9,39.2,56.3,51.4,51.2,45.2,45.2,NA,53.3,54.9,64.6,
72,76.5,63.9,81.1,87.5,135.5,191),
precaudal_length=c(27.2,27.2,28.9,28.3,NA,44.3,44.3,50.8,50.8,45,45,53.7,NA,NA,
58.3,62.7,64,67.7,78.3,78.4,78.4,93.1,93.1,NA,100.4,115.6,NA,NA,
120.9,NA,NA,NA,133.7,168.3,168.3,200.4,200.8,210.3,218.9,218.9,
NA,248.2,252.6,262.1,317.3,342.3,371.9,376.4,NA,NA,793.9),
total_length=c(28,28,31.8,32.2,NA,48,48,51.5,51.5,49.2,NA,58,NA,NA,NA,70.4,67.2,
NA,86.4,84.3,83.1,96.5,96.5,NA,113.7,129.6,120.9,NA,NA,NA,NA,NA,
NA,NA,NA,215.9,NA,NA,227,227,NA,NA,NA,NA,331.9,345.9,NA,NA,NA,NA,808.5)
%>%
)mutate(OOL=head_length-snout_length) %>%
augment(lm(total_length~precaudal_length,.),newdata=.)%>%
mutate(est_length=ifelse(!is.na(total_length),total_length,.fitted))
%>%
eusthenopteronlm(log(est_length)~log(OOL),.)%>%summary()
##
## Call:
## lm(formula = log(est_length) ~ log(OOL), data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.15257 -0.09672 0.02296 0.08062 0.13145
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.70976 0.07725 22.13 1.05e-11 ***
## log(OOL) 0.97824 0.02516 38.88 7.72e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.09955 on 13 degrees of freedom
## (36 observations deleted due to missingness)
## Multiple R-squared: 0.9915, Adjusted R-squared: 0.9908
## F-statistic: 1512 on 1 and 13 DF, p-value: 7.72e-15
OOL
is also recovered as isometric with total_length
for Eusthenopteron based on the data for Schultze (1984), though that study includes very few individuals between 40-80 cm.
6 Effect of phylogenetic position on regression model
6.1 Examining if residuals are consistent across major clades of fishes
<-data_final%>%
OOL_residualsfilter(!is.na(OOL))%>%
filter(!is.na(total_length))%>%
mutate(residuals=(residuals(lm(log(total_length)~log(OOL)))))
Mutating factor for more inclusive fish clades
<-OOL_residuals%>%
residuals2filter(!is.na(residuals),length_as!="estimated t.l.",
!(extinct==T&clade=="Chondrichthyes"))%>%
group_by(taxon)%>%
summarize(residuals=mean(residuals),order=unique(order),
family=unique(family),shape=unique(shape),higher_group=unique(higher_group))%>%
mutate(higher_group=factor(higher_group,levels=c("Petromyzontiformes","Arthrodira","Chondrichthyes","Sarcopterygii","Basal Actinopterygii","Basal Teleostei","Ostariophysi","Stem Euteleostei","Acanthopterygii")))%>%
arrange(higher_group,order,taxon)
<- residuals2 %>%
level_info arrange(higher_group, order) %>%
pull(order) %>%
unique()
<-residuals2%>%
residuals2mutate(order=factor(order,levels=rev(level_info)))
Note, some of the clades used here (i.e., “Basal Actinopterygii”, “Stem Euteleostei”) are paraphyletic, but this was done in order to examine the major trends in the evolution of OOL proportions across fishes.
ggplot(residuals2,
aes(residuals,y=order))+
geom_vline(xintercept=0,linetype="dashed")+
geom_violin(aes(fill=higher_group),scale="width")+
labs(y="Higher Clade",x="Residuals",fill="Higher Clade",color="Higher Clade")+
geom_boxplot()+
theme(legend.position=c(0.8,0.3))
Figure 6.1: Box and whisker plot of the species-average residuals (excluding known juveniles) of the OOL ~ total length regression model grouped by order, sorted and color-coded by major fish clade.
ggplot(residuals2,aes(y=residuals,x=higher_group))+
geom_hline(yintercept=0,linetype="dashed")+
geom_violin(aes(fill=higher_group),scale="width")+
geom_boxplot(width=0.3)+
labs(x="Higher Clade",y="Residuals")+
theme(legend.position="none",axis.text.x = element_text(angle = 45, vjust = 1, hjust=1))
Figure 6.2: Box and whisker plot of the species-average residuals (excluding known juveniles) of the OOL ~ total length regression model, grouped by major fish clade.
6.2 Testing if Acanthoptergyii have statistically larger heads than other fishes
6.2.1 Testing residuals of OOL versus total length vary significantly between acanthopterygians and other fishes.
%>%
residuals2mutate(higher_group=relevel(higher_group,"Chondrichthyes"))%$%
lm(residuals~higher_group,.)%>%
summary()
##
## Call:
## lm(formula = residuals ~ higher_group, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.70861 -0.14209 -0.01925 0.10385 1.46668
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.019697 0.016728 1.178 0.23928
## higher_groupPetromyzontiformes 0.009651 0.081306 0.119 0.90554
## higher_groupArthrodira -0.077369 0.073106 -1.058 0.29018
## higher_groupSarcopterygii 0.002772 0.131004 0.021 0.98312
## higher_groupBasal Actinopterygii 0.181811 0.058696 3.097 0.00201 **
## higher_groupBasal Teleostei 0.108875 0.042598 2.556 0.01074 *
## higher_groupOstariophysi 0.020555 0.023689 0.868 0.38578
## higher_groupStem Euteleostei 0.066738 0.036537 1.827 0.06807 .
## higher_groupAcanthopterygii -0.091342 0.019564 -4.669 3.46e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.225 on 962 degrees of freedom
## Multiple R-squared: 0.0812, Adjusted R-squared: 0.07356
## F-statistic: 10.63 on 8 and 962 DF, p-value: 2.196e-14
Basal actinopterygians and acanthopterygians were found to have statistically detectable residuals from the base level of Chondrichthyes. With basal actinopterygians, this is likely due to the large number of gars (Lepisosteidae) and elongate-bodied sturgeons (i.e., Pseudoscaphirhynchus) considered relative to the diversity of the clade. However, for Acanthopterygii this is harder to explain because a wide diversity of acanthopterygians were sampled.
%>%
residuals2mutate(shape=relevel(as.factor(shape),"fusiform"),
higher_group=relevel(higher_group,"Chondrichthyes"))%$%
lm(residuals~higher_group+shape,.)%>%
summary()
##
## Call:
## lm(formula = residuals ~ higher_group + shape, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.57877 -0.11309 -0.00095 0.10697 1.19325
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.06016 0.01617 -3.719 0.000211 ***
## higher_groupPetromyzontiformes -0.41144 0.08181 -5.029 5.88e-07 ***
## higher_groupArthrodira -0.01853 0.06405 -0.289 0.772446
## higher_groupSarcopterygii 0.08263 0.11454 0.721 0.470846
## higher_groupBasal Actinopterygii 0.13033 0.05199 2.507 0.012349 *
## higher_groupBasal Teleostei -0.06444 0.04167 -1.546 0.122337
## higher_groupOstariophysi 0.08719 0.02169 4.020 6.28e-05 ***
## higher_groupStem Euteleostei 0.01243 0.03258 0.382 0.702859
## higher_groupAcanthopterygii -0.03227 0.01815 -1.778 0.075703 .
## shapeanguilliform 0.50095 0.04094 12.236 < 2e-16 ***
## shapecompressiform -0.05127 0.02071 -2.476 0.013454 *
## shapeelongate 0.21014 0.02007 10.473 < 2e-16 ***
## shapeflattened 0.08950 0.05434 1.647 0.099911 .
## shapemacruriform 0.40665 0.04922 8.262 4.74e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1964 on 957 degrees of freedom
## Multiple R-squared: 0.3039, Adjusted R-squared: 0.2944
## F-statistic: 32.13 on 13 and 957 DF, p-value: < 2.2e-16
6.2.1.1 Same analysis, examining head length
Considering residuals of head length and total length by themselves
%>%
data_finaldrop_na(head_length,total_length)%>%
group_by(taxon)%>%
summarise(higher_group=unique(higher_group),shape=unique(shape),
head_length=mean(head_length),total_length=mean(total_length))%>%
augment(lm(log(total_length)~log(head_length),.),newdata=.)%>%
mutate(higher_group=relevel(as.factor(higher_group),"Chondrichthyes"))%$%
lm(.resid~higher_group,.)%>%
summary()
##
## Call:
## lm(formula = .resid ~ higher_group, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.46077 -0.11452 -0.01988 0.09829 1.53835
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.063497 0.013666 4.646 3.85e-06 ***
## higher_groupAcanthopterygii -0.139962 0.015984 -8.757 < 2e-16 ***
## higher_groupArthrodira 0.077506 0.059727 1.298 0.1947
## higher_groupBasal Actinopterygii -0.028837 0.047954 -0.601 0.5478
## higher_groupBasal Teleostei 0.190382 0.034802 5.470 5.72e-08 ***
## higher_groupOstariophysi -0.008899 0.019354 -0.460 0.6458
## higher_groupPetromyzontiformes -0.072814 0.066426 -1.096 0.2733
## higher_groupSarcopterygii 0.045563 0.107029 0.426 0.6704
## higher_groupStem Euteleostei 0.055367 0.029850 1.855 0.0639 .
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1839 on 962 degrees of freedom
## Multiple R-squared: 0.1813, Adjusted R-squared: 0.1745
## F-statistic: 26.63 on 8 and 962 DF, p-value: < 2.2e-16
Adding in shape as an additional categorical variable
%>%
data_finaldrop_na(head_length,total_length)%>%
group_by(taxon)%>%
summarise(higher_group=unique(higher_group),shape=unique(shape),
head_length=mean(head_length),total_length=mean(total_length))%>%
augment(lm(log(total_length)~log(head_length)+shape,.),newdata=.)%>%
mutate(higher_group=relevel(as.factor(higher_group),"Chondrichthyes"))%$%
lm(.resid~higher_group,.)%>%
summary()
##
## Call:
## lm(formula = .resid ~ higher_group, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.65484 -0.10061 -0.00623 0.09422 1.21323
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.057397 0.012272 4.677 3.33e-06 ***
## higher_groupAcanthopterygii -0.111475 0.014353 -7.767 2.06e-14 ***
## higher_groupArthrodira 0.095077 0.053633 1.773 0.0766 .
## higher_groupBasal Actinopterygii -0.052799 0.043061 -1.226 0.2204
## higher_groupBasal Teleostei 0.022120 0.031251 0.708 0.4792
## higher_groupOstariophysi 0.007456 0.017379 0.429 0.6680
## higher_groupPetromyzontiformes -0.461448 0.059649 -7.736 2.58e-14 ***
## higher_groupSarcopterygii 0.087313 0.096109 0.908 0.3639
## higher_groupStem Euteleostei 0.007610 0.026805 0.284 0.7765
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1651 on 962 degrees of freedom
## Multiple R-squared: 0.1549, Adjusted R-squared: 0.1478
## F-statistic: 22.04 on 8 and 962 DF, p-value: < 2.2e-16
However, in the case of head length acanthopterygians still stand out as having larger than expected heads even after adding in shape as an additional explanatory variable. This could be due to phylogenetic signal, and is worth testing with phylogenetic comparative methods in a future analysis, but in the context of the present study makes it worth testing if acanthopterygian fishes have an undue influence on length regressions for Dunkleosteus.
Notably, Petromyzontiformes also have heads that are larger than expected for anguilliform fishes. This may be because Petromyzontiformes are not anguilliform because of specializations for axial elongation, but because they diverged from other vertebrates prior to the evolution of limb girdles. Thus, lampreys may not be truly anguilliform but “fusiform fishes without fins”.
Also, note that in these analyses arthrodires are recovered as, on average, not having significantly different head-body proportions from elasmobranchs and other non-acanthopterygian fishes.
6.3 Absolute residuals of the model by family
ggplot(residuals2%>%
mutate(abs_residuals=abs(residuals)),
aes(x=abs_residuals,y=reorder(family,desc(abs_residuals))))+
geom_vline(xintercept=0,linetype="dashed")+
geom_violin(aes(fill=higher_group),scale="width")+
geom_boxplot(width=0.3)+
labs(y="Family",x="Absolute Residuals")+
theme(legend.position="none",axis.text.x = element_text(angle = 45, vjust = 1, hjust=1))+
coord_cartesian(xlim=c(0,0.6))
Figure 6.3: Box-and-whisker plot of the absolute residuals of the model sorted by family, showing how the taxa with the lowest error rates tend to be those with generalized, fusiform body plans.
7 Effect of body shape on regression model
7.1 Graph of OOL versus total length color-coded by shape
%>%
data_finaldrop_na(shape)%>%
ggplot(aes(y=total_length,x=OOL))+
geom_star(aes(fill=shape,starshape=clade))+
scale_starshape_manual(values=c(15,13,11,1,28),guide="none")+
geom_smooth(formula=y~x,method="lm")+
geom_smooth(formula=y~x,method="lm")+
labs(fill="Body Shape",starshape="Clade",
x="Orbit-Opercular Length (cm)",y="Total Length (cm)")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
theme_classic()+
theme(legend.position=c(0.85,0.25))+
guides(fill = guide_legend(override.aes = list(starshape = 15)))
Figure 7.1: Graph of OOL versus total length (plotted on a log10 scale) color-coded by body shape
7.2 Testing to see if different body shapes have different regression lines
7.2.1 Testing for differences in intercept
options(width=1000)
#Testing for differences in intercept between body shape groups
summary(lm(log(total_length)~log(OOL)+shape,
data_final))
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + shape, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64817 -0.09960 -0.00015 0.10395 1.38686
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.864814 0.008083 230.721 < 2e-16 ***
## log(OOL) 0.979538 0.003532 277.362 < 2e-16 ***
## shapeanguilliform 0.246846 0.009810 25.163 < 2e-16 ***
## shapecompressiform -0.097574 0.012227 -7.980 2.03e-15 ***
## shapeelongate 0.254968 0.009766 26.109 < 2e-16 ***
## shapeflattened 0.079619 0.036772 2.165 0.0304 *
## shapemacruriform 0.435956 0.030099 14.484 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1859 on 3162 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.964, Adjusted R-squared: 0.9639
## F-statistic: 1.412e+04 on 6 and 3162 DF, p-value: < 2.2e-16
7.2.2 Testing for differences in slope between groups
#Testing for differences in slope between body shape groups
summary(lm(log(total_length)~log(OOL)*shape,
data_final))
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * shape, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.62517 -0.09867 -0.00170 0.10336 1.39119
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.877576 0.008716 215.406 < 2e-16 ***
## log(OOL) 0.973000 0.003911 248.802 < 2e-16 ***
## shapeanguilliform 0.244345 0.041452 5.895 4.15e-09 ***
## shapecompressiform -0.109844 0.028747 -3.821 0.000135 ***
## shapeelongate 0.134659 0.026878 5.010 5.74e-07 ***
## shapeflattened -0.048682 0.236282 -0.206 0.836779
## shapemacruriform 0.381928 0.096882 3.942 8.25e-05 ***
## log(OOL):shapeanguilliform 0.001095 0.021337 0.051 0.959057
## log(OOL):shapecompressiform 0.006197 0.017716 0.350 0.726504
## log(OOL):shapeelongate 0.054360 0.011317 4.803 1.63e-06 ***
## log(OOL):shapeflattened 0.051227 0.090326 0.567 0.570662
## log(OOL):shapemacruriform 0.024145 0.039368 0.613 0.539715
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1854 on 3157 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9643, Adjusted R-squared: 0.9642
## F-statistic: 7747 on 11 and 3157 DF, p-value: < 2.2e-16
7.2.3 ANOVA of residuals versus body shape
%>%
data_final::augment(fit.OOL,newdata=.)%>%
broomlm(.resid~shape,.)%>%
anova()
%>%
data_final::augment(fit.OOL,newdata=.)%>%
broomlm(.resid~shape,.)%>% summary()
##
## Call:
## lm(formula = .resid ~ shape, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.62907 -0.09982 -0.00154 0.10634 1.37362
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.068454 0.004233 -16.172 < 2e-16 ***
## shapeanguilliform 0.247953 0.009840 25.199 < 2e-16 ***
## shapecompressiform -0.089115 0.012136 -7.343 2.64e-13 ***
## shapeelongate 0.250026 0.009742 25.665 < 2e-16 ***
## shapeflattened 0.069075 0.036827 1.876 0.0608 .
## shapemacruriform 0.429435 0.030168 14.235 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1865 on 3163 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.3123, Adjusted R-squared: 0.3112
## F-statistic: 287.2 on 5 and 3163 DF, p-value: < 2.2e-16
7.3 Box-and-whisker plot of residuals by body shape
ggplot(OOL_residuals%>%
mutate(shape=factor(shape,levels=c("macruriform","flattened","anguilliform",
"elongate","fusiform","compressiform"))) %>%
filter(ontogeny %in% c("adult","subadult")|is.na(ontogeny)) %>%
group_by(taxon) %>%
summarise(residuals=mean(residuals),shape=unique(shape)),
aes(x=shape,y=residuals))+
geom_hline(yintercept=0,linetype="dashed")+
geom_violin(aes(fill=shape),scale="width")+
geom_boxplot(width=0.3)+
labs(x="Shape",y="Residuals")+
theme(legend.position="none")
Figure 7.2: Box and whisker plot of residuals in the dataset categorized by body shape, showing how fishes with elongate or anguilliform bodies are characterized by more negative residuals and fishes with shorter (compressiform) bodies are characterized by more positive residuals. Data points are average residuals for each species with known juveniles removed.
%>%
OOL_residualsfilter(shape=="fusiform",!family %in% c("Acanthuridae","Monacanthidae","Balistidae"))%>%
mutate(shape2=factor(case_when(family=="Holocentridae"~"Holocentridae",
=="Serranidae"~"Serranidae",
familyTRUE ~ "Other Fusiform Fishes"),
ordered=T,levels=c("Holocentridae","Serranidae","Other Fusiform Fishes")))%>%
group_by(shape2)%>%
summarise(mean=mean(residuals),
max=max(residuals),
min=min(residuals),
lwr=mean-2*sd(residuals),
upr=mean+2*sd(residuals))%>%
mutate(CI=paste0("(",round(lwr,3),"-",round(upr,3),")"),
range=paste0("(",round(min,3),"-",round(max,3),")"))%>%
select(shape2,mean,CI,range)%>%
kable(digits=3,
caption="Mean, 95% confidence interval, and range of residuals in fusiform fishes, showing how in general fusiform fishes (i.e., non-grouper fishes) have residuals that span 0.",
col.names=c("Group","Mean","95% C.I.","Range"))%>%
kable_styling()
Group | Mean | 95% C.I. | Range |
---|---|---|---|
Holocentridae | -0.291 | (-0.426–0.155) | (-0.374–0.166) |
Serranidae | -0.351 | (-0.619–0.082) | (-0.589-0.149) |
Other Fusiform Fishes | -0.037 | (-0.351-0.276) | (-0.518-0.804) |
7.4 Comparing regression lines for different body proportions
The primary purpose of this was to see if complete arthrodires can reliably be described as fusiform
in body shape, given a known length and width.
7.4.1 Comparing regression lines for total length and body depth
%>%
data_finaldrop_na(body_depth)%>%
ggplot(aes(total_length,body_depth))+
geom_star(aes(color=shape,starshape=clade))+
geom_star(aes(fill=shape,starshape=clade))+
scale_starshape_manual(values=c(15,13,28,1,11))+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
geom_smooth(aes(color=shape),method="lm",formula=y~x,se=F)+
geom_smooth(method="lm",formula=y~x)+
labs(y="Body Depth (cm)",x="Total Length (cm)",
color="Body Shape",starshape="Clade",fill="Body Shape")+
geom_star(data=.%>%filter(clade=="Placodermi"),
aes(starshape=clade),color="white",starstroke=0.33,size=3,fill="black",show.legend=F)+
guides(fill=guide_legend(override.aes = list(shape = 15)),
color=guide_legend(override.aes = list(shape = 15)))
Figure 7.3: Plotting regression lines for different levels of body shape
7.4.2 Comparing regression lines for total length and proportional body depth
%>%
data_finaldrop_na(body_depth,total_length)%>%
ggplot(aes(x=total_length,y=body_depth/total_length))+
geom_star(aes(color=shape,starshape=clade))+
geom_star(aes(fill=shape,starshape=clade))+
geom_star(data=data_final%>%filter(clade=="Placodermi"),
aes(starshape=clade),color="white",starstroke=0.33,size=3,fill="black",show.legend=F)+
scale_x_continuous(trans="log10")+
scale_starshape_manual(values=c(15,13,11,1,28))+
labs(y="Body Depth (as % of total length)",x="Total Length (cm)",
starshape="Clade",color="Body Shape",fill="Body Shape")+
geom_smooth(aes(color=shape),method="lm",formula=y~x,se=F)+
geom_smooth(method="lm",formula=y~x)+
guides(fill=guide_legend(override.aes = list(shape = 15)),
color=guide_legend(override.aes = list(shape = 15)))
7.4.3 Comparing total length against body width
%>%
data_finalfilter(clade %in% c("Actinopterygii","Chondrichthyes","Placodermi","Sarcopterygii")) %>%
drop_na(body_width)%>%
ggplot(aes(x=total_length,y=body_width))+
labs(y="Body Width (cm)",x="Total Length (cm)",
color="Shape",fill="Shape",starshape="Clade")+
geom_point(aes(color=shape),shape=21)+
geom_star(aes(fill=shape,starshape=clade))+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
scale_starshape_manual(values=c(15,13,1,28))+
geom_smooth(aes(color=shape),method="lm",formula=y~x,se=F)+
geom_smooth(method="lm",formula=y~x)+
geom_star(data=data_final%>%filter(clade=="Placodermi"),size=3,fill="white")+
theme_classic()+
guides(fill=guide_legend(override.aes = list(shape = 15)))
Based on this, it appears that arthrodires known from complete remains show a shape similar enough to fusiform fishes to categorize them as such (with the possible exception of Amazichthys). However, among fusiform fishes arthrodires show aspects of body shape that significantly differentiate them from both actinopterygians and elasmobranchs (see next section).
7.5 Body shape diversity in fishes
7.5.1 Body height versus body width
For this section, total length for arthrodires for which incomplete remains are known was estimated using the model including body shape as a covariate and allowing slope to vary between Chondrichthyans and all other fishes, which is considered the best-fitting equation here, in order to highlight differences in overall body shape between arthrodires and all other fishes.
ggplot(data_final %>%
drop_na(body_depth,body_width)%>%
filter(clade %in%
c("Actinopterygii","Chondrichthyes","Placodermi","Sarcopterygii")),
aes(body_depth,body_width))+
geom_star(aes(fill=clade,starshape=clade),size=1.5)+
geom_star(data=.%>%filter(clade=="Placodermi"),aes(fill=clade,starshape=clade),size=3,
show.legend=F)+
scale_starshape_manual(values=c(15,13,1,28))+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
geom_abline(slope=1,linetype="dashed")+
labs(x="Body Height (cm)",y="Body Width (cm)",color="Clade",fill="Clade",starshape="Clade")+
theme(legend.position=c(0.8,0.2))
Figure 7.4: Dotted line represents a line with slope of 1 (i.e., representing fishes with a body equal in height and width), showing how arthrodires and chondrichthyans generally have bodies that are subcircular in cross-section, whereas actinopterygians generally have bodies that are much deeper than wide
As can be seen from this graph, chondrichthyans, arthrodires, and what few sarcopterygians could be considered in this analysis generally have a body that is subcircular in cross-section (width and height near equal), whereas most actinopterygians have a body that is much deeper relative to its width.
7.5.2 Boxplot of body_depth
/body_width
across fishes
%>%
data_finaldrop_na(body_width,body_depth)%>%
mutate(clade2=case_when(genus %in% c("Dunkleosteus","Paramylostoma",
"Bungartius","Heintzichthys") ~ "Cleveland Shale Arthrodira",
=="Placodermi"~"Other Arthrodira",
clade%in% c("Thunnus","Katsuwonus","Allothunnus",
genus "Auxis","Euthynnus","Sarda","Cybiosarda","Gymnosarda",
"Orcynopsis") ~ "Thunnini and Sardini",
=="Siluriformes" ~ "Siluriformes",
order=="Basal Actinopterygii"~"Basal Actinopterygii",
higher_group=="Actinopterygii" ~ "Other Teleostei",
clade=="Chondrichthyes" ~ "Chondrichthyes",
clade== "Sarcopterygii" ~ "Sarcopterygii")) %>%
clade mutate(body_ratio=body_depth/body_width,
clade2=factor(clade2,ordered=T,
levels=c("Cleveland Shale Arthrodira",
"Other Arthrodira",
"Chondrichthyes",
"Basal Actinopterygii",
"Siluriformes",
"Thunnini and Sardini",
"Other Teleostei",
"Sarcopterygii"))) %>%
ggplot(aes(clade2,body_ratio))+
geom_hline(yintercept=1,linetype="dashed")+
geom_violin(aes(fill=clade2),scale="width",show.legend=F)+
geom_boxplot(width=0.3)+
scale_fill_manual(values=c(hue_pal()(7)))+
scale_x_discrete(labels = wrap_format(16))+
labs(y="Body Depth/Body Width",x="Clade")+
coord_cartesian(ylim=c(0,4))+
theme(axis.text.x = element_text(angle = 45,vjust = 1, hjust=1))
Figure 7.5: Box plot of body depth/body width ratio in fishes examined in this study
The outlier point among “Other Arthrodira” is Eastmanosteus calliaspis, a pachyosteomorph arthrodire that shows a mediolaterally narrower body than other taxa. The Cleveland Shale arthrodire that represents an outlier is CMNH 7424, a juvenile specimen of D. terrelli with a much more circular body cross-section, more similar to coccosteomorphs. Note that all of the “Other Arthrodires” considered here are non-pachyosteomorph taxa. Amazichthys trinajsticae could not be included as its body_width
is unclear.
7.5.3 Body height versus total length in fusiform fishes
<-lm(log(total_length)~log(OOL)*(clade=="Chondrichthyes")+
fit.shape_clade3+(family=="Serranidae")+(family=="Holocentridae"),
shape
data_final)
%>%
data_final filter(!is.na(body_depth),shape=="fusiform"|clade=="Placodermi")%>%
mutate(total_length=ifelse(is.na(total_length),
exp(predict(fit.shape_clade3,.))*
regression.stats(fit.shape_clade3)$CF,
%>%
total_length))arrange(clade)%>%
ggplot(aes(total_length,body_depth))+
geom_star(aes(fill=clade,starshape=clade),size=1.5)+
scale_starshape_manual(values=c(15,13,1,28))+
geom_smooth(method="lm",formula=y~x,aes(color=clade),se=F)+
geom_star(data=.%>%filter(clade=="Placodermi"),aes(fill=clade,starshape=clade),size=3,
show.legend=F)+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
labs(x="Total Length (cm)",y="Body Depth (cm)",color="Clade",
fill="Clade",starshape="Clade")+
theme(legend.position=c(0.8,0.2))
Figure 7.6: Plot of body depth versus total length in fusiform fishes. Note how arthrodires and sarcopterygians have deeper bodies than chondrichthyans despite lacking the very mediolaterally narrow bodies seen in actinopterygians, and indeed actinopterygians often have deeper bodies than similar-sized arthrodires except in the very deep-bodied Dunkleosteus
However, arthrodires have much deeper bodies than sharks at similar body lengths, more comparable to actinopterygian and sarcopterygian fishes. This includes the otherwise very shark-like Amazichthys trinajsticae. There are only two taxa which do not. The first is Gymnotrachelus hydei, which has a very unusual armor shape (narrow body, anteroposteriorly short armor relative to the head) that suggests it may eventually be found out to pertain to a highly elongate-bodied or anguilliform taxon. The other is the reconstruction of Titanichthys clarki in Boyle and Ryan (2017). However, the value for this taxon may be an underestimate because…
- The reconstructed specimen is a subadult, and body depth increases through ontogeny in Dunkleosteus terrelli
- The reconstruction is missing its ventral shield (body height here is an approximation), and thus the addition of the ventral armor may make the body deeper.
- The reconstructed height of the torso may be an underestimate, as the mediodorsal seems to be too low to allow the head-raising musculature to easily attach to it and also maintain a streamlined body shape.
7.5.4 Body width versus total length in fusiform/elongate fishes
ggplot(data_final %>% filter(!is.na(body_width),
%in% c("elongate","fusiform"))%>%
shape mutate(total_length=ifelse(is.na(total_length),
exp(predict(fit.shape_clade3,.))*
regression.stats(fit.shape_clade3)$CF,
total_length),clade=ifelse(order %in% c("Siluriformes"),
"Actinopterygii (Siluriformes)",clade),
clade=ifelse(family %in% c("Scombridae"),
"Actinopterygii (Scombridae)",clade))%>%
arrange(clade),
aes(total_length,body_width))+
geom_smooth(method="lm",formula=y~x,aes(color=clade),se=F)+
geom_star(aes(color=clade,starshape=clade),
%>%filter(clade=="Sarcopterygii"),size=1.5)+
.geom_star(aes(fill=clade,starshape=clade),size=1.5)+
scale_starshape_manual(values=c(15,15,15,13,1,28))+
scale_color_manual(values=c(hue_pal()(3)[1],"#c4342a","#fbb2ad",
hue_pal()(3)[2],"black",hue_pal()(3)[3]))+
scale_fill_manual(values=c(hue_pal()(3)[1],"#c4342a","#fbb2ad",
hue_pal()(3)[2],"black",hue_pal()(3)[3]))+
geom_smooth(method="lm",formula=y~x,aes(color=clade),se=F,show.legend=F)+
geom_star(data=.%>%filter(clade=="Placodermi"),aes(fill=clade,starshape=clade),
color="white",starstroke=0.33,size=3,show.legend=F)+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
labs(x="Total Length (cm)",y="Body Width (cm)",color="Clade",
fill="Clade",starshape="Clade",alpha="Clade")+
theme(legend.position=c(0.8,0.2))
Figure 7.7: Plot of body width versus total length in fusiform and elongate-bodied fishes. Total length is estimated for arthrodires for which complete remains are unknown.
Based on this, it is clear that arthrodires have much wider bodies than most chondrichthyans or typical actinopterygians. The only fishes that have similar body proportions to arthrodires in this regard are catfishes (Siluriformes), tuna-like scombrids (i.e., taxa like Thunnus or Sarda), and sarcopterygians (not shown in figure due to low number of data points).
7.6 Correlation between aspect ratio and percent head length
grid.arrange(
ggplot(data_final %>%
drop_na(precaudal_length,head_length,body_depth,shape) %>%
filter(length_as=="total length")%>%
group_by(taxon)%>% summarise(across(c(head_length,precaudal_length,body_depth),
mean),shape=unique(shape),clade=unique(clade),genus=unique(genus),family=unique(family)),
aes(y=body_depth/precaudal_length,x=head_length/precaudal_length))+
geom_star(aes(fill=shape,starshape=clade))+
geom_star(data=.%>%filter(family %in% c("Balistidae","Monacanthidae","Acanthuridae")),
aes(starshape=clade),fill="white")+
geom_star(data=.%>%filter(family=="Serranidae"),
aes(starshape=clade),fill="black")+
scale_starshape_manual(values=c(15,13,12,1,12))+
labs(x="Percent Head Length",y="Aspect Ratio of Body")+
geom_vline(aes(xintercept=mean(head_length/precaudal_length)),linetype="dashed")+
theme_classic()+
theme(legend.position = "none"),
ggplot(data_final %>%
drop_na(precaudal_length,OOL,body_depth,shape) %>%
filter(length_as=="total length")%>%
group_by(taxon)%>% summarise(across(c(OOL,precaudal_length,body_depth),
mean),shape=unique(shape),clade=unique(clade),genus=unique(genus),family=unique(family)),
aes(y=body_depth/precaudal_length,x=OOL/precaudal_length))+
geom_star(aes(fill=shape,starshape=clade))+
geom_star(data=.%>%filter(family %in% c("Balistidae","Monacanthidae","Acanthuridae")),
aes(starshape=clade),fill="white")+
geom_star(data=.%>%filter(family=="Serranidae"),
aes(starshape=clade),fill="black")+
scale_starshape_manual(values=c(15,13,28,1,11))+
labs(x="Percent Orbit-Opercular Length",y="Aspect Ratio of Body",
starshape="Clade",fill="Shape")+
geom_vline(aes(xintercept=mean(OOL/precaudal_length)),linetype="dashed")+
theme_classic()+
theme(legend.position = "bottom")+
guides(fill=guide_legend(ncol=2),
starshape=guide_legend(ncol=2)),
heights=c(2,2.2)
)
Figure 7.8: Plot of (A) percent head length versus body aspect ratio (body depth
/precaudal length
) and (B) plot of percent OOL versus body aspect ratio, showing how for the most part head proportions are consistent in fishes of different body shapes but there is a slight effect of axial elongation. Black circles are groupers (Serranidae) and white circles are taxa with posteriorly shifted orbits (e.g., Balistidae).
As can be seen by this graph, there is a slight correlation between percent head length and axial elongation, particularly in more-elongate bodied taxa, but the correlation is not strong and it is not one that can be easily approximated by a linear model (i.e., its effect is much more pronounced on elongate taxa than it is in compressiform ones). In general, head-body proportions remain fairly consistent across fishes of diverse body shapes
7.7 Esting accuracy in species with a posteriorly shifted orbit using Balistes virescens
rbind(data_final%>%
filter(references=="Afrisal et al. 2019"),
%>%
data_finalfilter(references=="Afrisal et al. 2019")%>%
mutate(OOL=7.1))%>%
data.frame()%>%
mutate(fit=exp(predict(fit.OOL,.))*regression.stats(fit.OOL)$CF,
PE=(fit-total_length)/fit,
anterior_landmark=c("Anterior margin of orbit",
"Anterior margin of gill chamber"),
taxon=str_replace(taxon,"_"," "))%>%
select(taxon,anterior_landmark,OOL,total_length,fit,PE)%>%
kable(digits=c(1,1,1,1,1,3),
align=c("l","c","c","c","c","c"),
col.names=c("Taxon","Anterior Landmark for OOL","OOL","Total Length","Estimated Length","PE"),
caption="Comparison of error rates for OOL in species with a posteriorly shifted orbit using a representative skeletonized specimen of <i>Balistes virescens</i> from Afrisal et al. (2019)")%>%
column_spec(1, italic = T)%>%
kable_styling()
Taxon | Anterior Landmark for OOL | OOL | Total Length | Estimated Length | PE |
---|---|---|---|---|---|
Balistoides virescens | Anterior margin of orbit | 4.6 | 46 | 31.3 | -0.469 |
Balistoides virescens | Anterior margin of gill chamber | 7.1 | 46 | 48.0 | 0.043 |
Based on this, it looks like the reason for the high errors in taxa such as Balistoidei and many Acanthuriformes has nothing to do with the ventrally shifted gill opening. Instead, it appears to be due to a posterior shift in the orbit relative to the overall length of the skull in these taxa.
Thus, this means that in arthrodires (in which the gills are more ventral to the head than posterior like in other fishes) this shift in the branchial skeleton should not result in systematic errors in OOL. Indeed, it somewhat supports the shorter lengths for Dunkleosteus terrelli reported here, as such a shift typically only occurs in fishes with shorter bodies.
8 Comparing total lengths in placoderms with known total length
8.1 Predicting total length in complete Arthrodira
<-fossil_taxa%>%
complete_arthrodire_length_estimatesfilter(!!fossil.specimens,genus!="Dunkleosteus")%>%
augment(fit.OOL,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.species_average,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.species_average)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(across(.cols=c(total_length,
fit1.fitted,fit1.lower,fit1.upper,2),
fit2.fitted,fit2.lower,fit2.upper),round,fit1.range=paste0("(",sprintf("%.1f",round(fit1.lower,1)),"–",
sprintf("%.1f",round(fit1.upper,1)),")"),
fit2.range=paste0("(",fit2.lower,"–",
sprintf("%.1f",round(fit2.upper,1)),")"),
fit1.PE=paste0("(",sprintf("%.1f",round(fit1.fitted*(1-
regression.stats(fit.OOL)$adjPE/100),1)),
"–",sprintf("%.1f",round(fit1.fitted*(1+
regression.stats(fit.OOL)$adjPE/100),1)),")"),
fit2.PE=paste0("(",sprintf("%.1f",round(fit2.fitted*(1-
regression.stats(fit.species_average)$adjPE/100),1)),
"–",sprintf("%.1f",round(fit2.fitted*(1+
regression.stats(fit.species_average)$adjPE/100),1)),")"),
PE=((fit1.fitted-total_length)/fit1.fitted)%>%round(4),
PE2=((fit2.fitted-total_length)/fit2.fitted)%>%round(4))
%>%
complete_arthrodire_length_estimatesrownames_to_column()%>%
select(taxon,specimen,total_length,
fit1.fitted,fit1.PE,fit1.range,PE,%>%
fit2.fitted,fit2.PE,fit2.range,PE2)kable(digits=c(1,1,1,1,1,1,3,1,1,1,3),
col.names=c("Taxon","Specimen","Actual","Est.","+/- PE","95% P.I.","%PE",
"Est.","+/- PE","95% C.I.","%PE"),
align=c("l","c","c","c","c","c","c","c","c","c","c"),
caption="Estimated lengths in specimens of arthrodires known from whole-body remains and in which total length is either measurable or can be approximated.")%>%
column_spec(1, italic = T)%>%
column_spec(c(4,8), bold = T)%>%
add_header_above(c(" "=3,"Individual Data"=4,"Species Averages"=4))%>%
kable_styling()
Taxon | Specimen | Actual | Est. | +/- PE | 95% P.I. | %PE | Est. | +/- PE | 95% C.I. | %PE |
---|---|---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.9 | (11.4–16.3) | (8.9–21.6) | 0.011 | 14.0 | (11.5–16.5) | (8.83–22.1) | 0.017 |
Millerosteus minor | Composite Millerosteus | 14.9 | 16.0 | (13.2–18.9) | (10.3–24.9) | 0.068 | 16.1 | (13.2–19.0) | (10.18–25.5) | 0.072 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 24.4 | (20.2–28.7) | (15.7–38.0) | 0.059 | 24.4 | (20.1–28.8) | (15.44–38.6) | 0.058 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 31.6 | (26.1–37.2) | (20.4–49.1) | 0.043 | 31.5 | (25.8–37.1) | (19.89–49.7) | 0.038 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 35.1 | (28.9–41.3) | (22.6–54.5) | 0.156 | 34.9 | (28.6–41.1) | (22.05–55.1) | 0.150 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 36.0 | (29.7–42.4) | (23.2–56.0) | 0.105 | 35.8 | (29.4–42.2) | (22.63–56.6) | 0.098 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 36.5 | (30.1–42.9) | (23.5–56.7) | -0.017 | 36.2 | (29.8–42.7) | (22.92–57.3) | -0.024 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 43.9 | (36.2–51.7) | (28.3–68.3) | 0.103 | 43.5 | (35.7–51.3) | (27.51–68.8) | 0.094 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 43.1 | (35.6–50.7) | (27.8–67.0) | 0.203 | 42.7 | (35.1–50.3) | (27.01–67.5) | 0.195 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 42.5 | (35.1–50.0) | (27.4–66.1) | 0.118 | 42.1 | (34.6–49.6) | (26.64–66.6) | 0.109 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 51.4 | (42.4–60.4) | (33.1–79.9) | 0.270 | 50.8 | (41.7–59.8) | (32.11–80.3) | 0.261 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 56.1 | (46.3–66.0) | (36.1–87.2) | 0.222 | 55.4 | (45.5–65.3) | (35.02–87.6) | 0.211 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 51.2 | (42.2–60.2) | (32.9–79.5) | -0.185 | 50.6 | (41.5–59.6) | (31.98–80.0) | -0.199 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 65.3 | (53.8–76.8) | (42.0–101.5) | 0.133 | 64.3 | (52.8–75.8) | (40.65–101.7) | 0.119 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 68.5 | (56.5–80.5) | (44.1–106.4) | 0.080 | 67.4 | (55.4–79.4) | (42.61–106.6) | 0.065 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 69.5 | (57.3–81.7) | (44.7–108.0) | 0.247 | 68.3 | (56.1–80.5) | (43.21–108.1) | 0.234 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 78.0 | (64.3–91.7) | (50.2–121.2) | -0.150 | 76.6 | (62.9–90.3) | (48.45–121.2) | -0.171 |
%>%
complete_arthrodire_length_estimatesfilter(specimen %in% c("Composite Millerosteus","Gess and Trinajstic 2017",
"Recon. (Trinajstic 2013)","NMS 1893.107.27",
"FMNH PF 1089","ROM VP 52664","FMNH PF 1673",
"Recon. (M & W 1968)","NMS 1987.7.118","Recon. (Miles 1971)",
"MNHM 2-177","NMS G.1995.4.2","AA.MEM.DS.8"))%>%
select(taxon,specimen,total_length,fit1.fitted,fit1.PE,fit1.range,PE,
%>%
fit2.fitted,fit2.PE,fit2.range,PE2)rename(Taxon=taxon,
Specimen=specimen,
"Actual Length"=total_length,
"Estimated Length"=fit1.fitted,
"+/- PE"=fit1.PE,
"95% P.I."=fit1.range,
Error=PE,
"Estimated Length (Species Averages)"=fit2.fitted,
"+/- PE (Species Averages)"=fit2.PE,
"95% P.I. (Species Averages)"=fit2.range,
"Error (Species Averages)"=PE2)%>%
write.xlsx(file="Devonian Fish Tale Table 2 (Complete Arthrodire Estimates).xlsx")
Note: I am a little skeptical for the results of NHMUK PV P 49663. This specimen is very mangled and the skull and thoracic armor are a mangled mess of plates. It is very hard to see where the head ends and the body begins, as well as the margins of the orbit. Hence, the estimated length may be in error because it was hard to figure out where OOL was.
rbind("Mean Percent Error for Estimates Using Individual Data Points" = complete_arthrodire_length_estimates%>%pull(PE)%>%abs()%>%mean(),
"Mean Percent Error for Species Average Data" = complete_arthrodire_length_estimates%>%pull(PE2)%>%abs()%>%mean())%>%
kable(digits=4,col.names="PE",align="c",
caption="Mean error for arthrodires in which total length is known estimated via OOL",
table.attr = "style='width:70%;'")%>%
kable_styling()
PE | |
---|---|
Mean Percent Error for Estimates Using Individual Data Points | 0.1275 |
Mean Percent Error for Species Average Data | 0.1245 |
From this it can be seen that, without any other additional qualifiers, OOL estimates body length in arthrodires with an accuracy of about +/- 13.5%
8.2 Allometry of OOL in Arthrodira
8.2.1 Allometry of OOL in Coccosteomorpha
%>%
fossil_taxafilter(clade=="Placodermi",
=="total length",
length_as!genus %in% c("Holonema","Amazichthys","Africanaspis","Newspecies"))%$%
lm(log(OOL)~log(total_length),.)%>%
summary()
##
## Call:
## lm(formula = log(OOL) ~ log(total_length), data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.17454 -0.05620 -0.01565 0.07205 0.15702
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -2.24512 0.22556 -9.954 7.74e-07 ***
## log(total_length) 1.13551 0.06411 17.712 1.96e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.09245 on 11 degrees of freedom
## Multiple R-squared: 0.9661, Adjusted R-squared: 0.963
## F-statistic: 313.7 on 1 and 11 DF, p-value: 1.959e-09
8.2.2 Allometry of OOL in all complete Arthrodira
%>%
fossil_taxafilter(clade=="Placodermi",
=="total length")%$%
length_aslm(log(OOL)~log(total_length),.)%>%
summary()
##
## Call:
## lm(formula = log(OOL) ~ log(total_length), data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.252590 -0.061796 0.007598 0.064107 0.217741
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -1.70844 0.25591 -6.676 7.41e-06 ***
## log(total_length) 0.97069 0.07034 13.799 6.27e-10 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1369 on 15 degrees of freedom
## Multiple R-squared: 0.927, Adjusted R-squared: 0.9221
## F-statistic: 190.4 on 1 and 15 DF, p-value: 6.267e-10
9 Predicting body length in Dunkleosteus terrelli
%>%
fossil_taxafilter(!!fossil.specimens,genus=="Dunkleosteus")%>%
augment(fit.OOL,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
mutate(across(fit1.fitted:fit1.upper,~exp(.)*regression.stats(fit.OOL)$CF),
fit1.PE.lower=fit1.fitted*
100-regression.stats(fit.OOL)$adjPE)/100),
((fit1.PE.upper=fit1.fitted*
100+regression.stats(fit.OOL)$adjPE)/100),
((fit1.PE=paste0("(",round(fit1.PE.lower,1),"–",round(fit1.PE.upper,1),")"),
fit1.range=paste0("(",round(fit1.lower,1),"–",round(fit1.upper,1),")"))%>%
augment(fit.species_average,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(across(fit2.fitted:fit2.upper,~exp(.)*regression.stats(fit.species_average)$CF),
fit2.PE.lower=fit2.fitted*((100-regression.stats(fit.species_average)$adjPE)/100),
fit2.PE.upper=fit2.fitted*((100+regression.stats(fit.species_average)$adjPE)/100),
fit2.PE=paste0("(",round(fit2.PE.lower,1),"–",round(fit2.PE.upper,1),")"),
fit2.range=paste0("(",round(fit2.lower,1),"–",round(fit2.upper,1),")"))%>%
select(specimen,fit1.fitted,fit1.PE,fit1.range,fit2.fitted,fit2.PE,fit2.range)%>%
kable(digits=1,
align=c("l","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using an all-species model, without any additional modifications or excluding specimens",
col.names = c("Specimen","Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
add_header_above(c(" "=1,"Individual Specimens"=3,"Species Averages"=3))%>%
column_spec(c(2,5), bold = T)%>%
kable_styling()
Specimen | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|
CMNH 7424 | 195.2 | (160.9–229.5) | (125.6–303.4) | 189.2 | (155.4–223) | (119.6–299.4) |
CMNH 6090 | 293.0 | (241.6–344.5) | (188.5–455.5) | 282.4 | (232–332.8) | (178.4–447.1) |
CMNH 7054 | 305.7 | (252.1–359.4) | (196.7–475.2) | 294.5 | (241.9–347.1) | (186–466.2) |
CMNH 5768 | 352.6 | (290.7–414.5) | (226.8–548.1) | 338.9 | (278.4–399.4) | (214–536.7) |
9.1 Predicting total length excluding taxa with extreme body shapes
Note: “extreme body shapes” as defined here, includes anguiliform, compressiform, and macruriform taxa, as well as taxa with posteriorly shifted orbits like Balistoidei.
It seems highly unlikely that Dunkleosteus had an anguilliform, macruriform, or truly compressiform body plan (though a semi-compressiform lamnid-like body plan is possible). Similarly, Dunkleosteus clearly does not demonstrate the cranial features that cause some other taxa to exhibit high error rates, such as the posteriorly shifted orbits of Balistoidei or the elongate rostrum of Rhinochimaera or Mitsukurina. Ruling out the enlarged heads of groupers is more difficult (as one might expect Dunkleosteus to have a large head), but it seems like an unlikely inference given that other arthrodires show head-body proportions within the range of variation of “typical” (i.e., non-grouper) fishes. Thus, all of these taxa can be safely excluded from the regression model. However, it is not possible to fully rule out an elongate body plan as seen in Coryphaena or some Istiophoriformes, though there is no evidence from the preserved remains of Dunkleosteus to suggest that this taxon had this type of body plan.
Thus, a model was fit comprised solely of fusiform and elongate-bodied taxa, excluding those other taxa which exhibited discernable specializations that could be ruled out or were highly unlikely in Dunkleosteus.
<-lm(log(total_length)~log(OOL),
fit.no_extreme_shapes%>%filter(!shape %in%
data_finalc("anguiliform","compressiform","macruriform"),
!family %in% c("Balistidae", "Monacanthidae", "Serranidae","Holocentridae")))
summary(fit.no_extreme_shapes)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(!shape %in% c("anguiliform", "compressiform", "macruriform"),
## !family %in% c("Balistidae", "Monacanthidae", "Serranidae",
## "Holocentridae")))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.53960 -0.12634 -0.00626 0.11267 1.52559
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.962169 0.008480 231.4 <2e-16 ***
## log(OOL) 0.983551 0.003791 259.4 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1943 on 2658 degrees of freedom
## (51 observations deleted due to missingness)
## Multiple R-squared: 0.962, Adjusted R-squared: 0.962
## F-statistic: 6.73e+04 on 1 and 2658 DF, p-value: < 2.2e-16
regression.stats(fit.no_extreme_shapes)
%>%
fossil_taxafilter(!!fossil.specimens,genus=="Dunkleosteus")%>%
augment(fit.no_extreme_shapes,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
mutate(across(fit1.fitted:fit1.upper,~exp(.)*regression.stats(fit.no_extreme_shapes)$CF),
fit1.PE.lower=fit1.fitted*((100-regression.stats(fit.no_extreme_shapes)$adjPE)/100),
fit1.PE.upper=fit1.fitted*((100+regression.stats(fit.no_extreme_shapes)$adjPE)/100),
fit1.PE=paste0("(",round(fit1.PE.lower,1),"–",round(fit1.PE.upper,1),")"),
fit1.range=paste0("(",round(fit1.lower,1),"–",round(fit1.upper,1),")"))%>%
augment(fit.species_average2,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(across(fit2.fitted:fit2.upper,~exp(.)*regression.stats(fit.no_extreme_shapes)$CF),
fit2.PE.lower=fit2.fitted*((100-regression.stats(fit.no_extreme_shapes)$adjPE)/100),
fit2.PE.upper=fit2.fitted*((100+regression.stats(fit.no_extreme_shapes)$adjPE)/100),
fit2.PE=paste0("(",round(fit2.PE.lower,1),"–",round(fit2.PE.upper,1),")"),
fit2.range=paste0("(",round(fit2.lower,1),"–",round(fit2.upper,1),")"))%>%
select(specimen,fit1.fitted,fit1.PE,fit1.range,fit2.fitted,fit2.PE,fit2.range)%>%
kable(digits=1,
align=c("l","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model excluding anguilliform, short-bodied, and macruriform taxa",
col.names = c("Specimen","Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
add_header_above(c(" "=1,"Individual Specimens"=3,"Species Averages"=3))%>%
column_spec(c(2,5), bold = T)%>%
kable_styling()
Specimen | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|
CMNH 7424 | 197.4 | (167.2–227.5) | (134.8–288.9) | 191.1 | (161.9–220.3) | (128.1–285.1) |
CMNH 6090 | 294.7 | (249.8–339.7) | (201.3–431.5) | 284.7 | (241.2–328.1) | (190.7–424.9) |
CMNH 7054 | 307.4 | (260.5–354.3) | (209.9–450) | 296.8 | (251.5–342.1) | (198.8–443) |
CMNH 5768 | 353.8 | (299.8–407.8) | (241.7–518) | 341.3 | (289.2–393.4) | (228.6–509.6) |
9.2 Plot of estimated lengths for Dunkleosteus using orbit-opercular length
<-ggplot(data_final%>%
(dunkleosteus_lengthcbind(exp(predict(lm(log(total_length)~log(OOL),
%>%
data_finalfilter(!shape %in% c("compressiform","anguiliform","macruriform"))%>%
filter(clade!="Placodermi")),
interval="prediction")))%>%
data_final,filter(!clade %in% c("Petromyzontiformes")),
aes(y=total_length,x=OOL))+
geom_point(aes(shape=clade),color="dark grey",fill="light grey")+
geom_smooth(method="lm",alpha=0.25,se=F)+
geom_line(aes(y=lwr), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_line(aes(y=upr), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_errorbar(data=.%>%filter(specimen %in% c("CMNH 5768", "CMNH 7054", "CMNH 6090", "CMNH 7424")),
aes(ymin=lwr,ymax=upr),width=0.1)+
geom_point(data=.%>%filter(specimen %in% c("CMNH 5768", "CMNH 7054", "CMNH 6090", "CMNH 7424")),
aes(shape=clade,y=fit),fill="black",size=2)+
scale_shape_manual(values=c(21,24,22,23),guide="none")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)")+
theme_classic()+
theme(legend.position=c(0.8,0.25)))
## `geom_smooth()` using formula = 'y ~ x'
9.3 Data plotted on a detransformed scale
ggplot(data_final%>%
drop_na(OOL)%>%
filter(clade %in% c("Actinopterygii","Sarcopterygii","Chondrichthyes","Placodermi","Petromyzontiformes"))%>%
augment(fit.OOL,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF)),
aes(y=total_length,x=OOL))+
coord_cartesian(y=c(0,600),x=c(0,90))+
geom_polygon(data=data.frame(OOL=c(0,71.75,85),total_length=c(0,750,750)),
alpha=0.5,fill="yellow")+
geom_hline(yintercept = 460,linetype="dotted",color="red")+
geom_segment(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(y=.lower,yend=.lower,x=-20,xend=OOL),
linetype="dashed",alpha=0.75)+
geom_segment(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(y=.upper,yend=.upper,x=-20,xend=OOL),
linetype="dashed",alpha=0.75)+
scale_shape_manual(values=c(15,13,11,1,28),guide="none")+
geom_point(aes(starshape=clade),color="dark grey",fill="light grey")+
geom_line(aes(y=.fitted), color = "#3366FF",size=1)+
geom_line(aes(y=.lower), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_line(aes(y=.upper), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_errorbar(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(ymin=.lower,ymax=.upper),width=3)+
geom_point(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(starshape=clade,y=.fitted),fill="black",size=2)+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)")+
theme_classic()+
theme(legend.position=c(0.8,0.25))+
geom_label(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(y=ifelse(specimen=="CMNH 6090",.upper-4,
ifelse(specimen=="CMNH 7054",.upper+2,.upper)),
x=0,label=round(.upper,1)),size=3)+
geom_label(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(y=ifelse(specimen=="CMNH 6090",.lower-8,
ifelse(specimen=="CMNH 7054",.lower+8,.lower)),
x=0,label=round(.lower,1)),size=3)+
annotate("text",x=90,y=475,label="4.6 m",color="red")+
geom_text(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(label=specimen,
x=ifelse(specimen=="CMNH 7054",OOL+1,OOL),
y=ifelse(specimen=="CMNH 6090",.lower-18,.lower)),hjust=0,nudge_y=-13)
Figure 9.1: Length estimates for Dunkleosteus terrelli plotted on a non-log transformed scale.
Note that in order to produce lengths of greater than 5 m for large, adult individuals of Dunkleosteus terrelli (i.e., the very uppermost part of the prediction interval in this graph) requires Dunkleosteus to plot in a region of the graph where there are few fishes in general. Most of the fishes that are in this region of the graph are either anguilliform taxa or ones with highly elongate caudal fins such as Alopias. Indeed, most of the large fishes in the upper region of this graph tend to be those with highly elongate bodies such as Tetrapturus.
10 Estimating total length in Dunkleosteus terrelli under different models
For this section, length estimates will primarily focus on four specimens: CMNH 7424, CMNH 6090, CMNH 7054, and CMNH 5768. OOL is measurable in a number of other specimens of Dunkleosteus terrelli, but the four specimens listed here are known from complete, mounted heads that pertain to a single individual, and thus are the most useful as a reality check to test the effects of different models on the size of D. terrelli.
10.1 Predicting using fusiform taxa only
Note, for this model the families Serranidae, Monacanthidae, and Balistidae were excluded, due to these groups showing apomorphic specializations in skull morphology (either an enlarged head in Serranidae or a posteriorly shifted orbit in Balistoidei) which suggests they violate the assumptions of consistent head-body proportions seen in all other fusiform fishes.
<-lm(log(total_length)~log(OOL),
fit.fusiform%>%
data_finalfilter(shape %in% c("fusiform"),length_as!="estimated t.l.",
!family %in% c("Serranidae","Holocentridae",
"Monacanthidae","Balistidae","")))
summary(fit.fusiform)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(shape %in% c("fusiform"), length_as != "estimated t.l.",
## !family %in% c("Serranidae", "Holocentridae", "Monacanthidae",
## "Balistidae", "")))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.47860 -0.09612 0.00455 0.09063 0.78554
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.912061 0.007449 256.7 <2e-16 ***
## log(OOL) 0.971318 0.003296 294.7 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1543 on 1739 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.9804, Adjusted R-squared: 0.9804
## F-statistic: 8.687e+04 on 1 and 1739 DF, p-value: < 2.2e-16
regression.stats(fit.fusiform)
<-fossil_taxa%>%
predict.fusiformdrop_na(OOL)%>%
filter(!!fossil.specimens)%>%
augment(fit.fusiform,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.fusiform)$CF),
PE=(.fitted-total_length)/.fitted,
.PE=paste0("(",round(.fitted*(1-
regression.stats(fit.fusiform)$adjPE/100),1),
"–",round(.fitted*(1+
regression.stats(fit.fusiform)$adjPE/100),1),")"),
.range=paste0("(",round(.lower,1),
"–",round(.upper,1),
")"))%>%
arrange(.fitted)%>%
select(taxon,specimen,total_length,.fitted,.PE,.range,PE)
%>%
predict.fusiformkable(digits=c(1,1,1,1,1,1,3),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model based on only fusiform fishes",
col.names = c("Taxon","Specimen","Actual Length","Est.","+/- %PE","95% P.I.","%PE"))%>%
column_spec(1, italic = T)%>%
column_spec(4, bold = T)%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | +/- %PE | 95% P.I. | %PE |
---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.6 | (12–15.3) | (10.1–18.5) | -0.006 |
Millerosteus minor | Composite Millerosteus | 14.9 | 15.7 | (13.8–17.6) | (11.6–21.3) | 0.048 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 23.7 | (20.9–26.5) | (17.5–32.1) | 0.029 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 30.4 | (26.8–34.1) | (22.5–41.2) | 0.006 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 33.7 | (29.7–37.7) | (24.9–45.6) | 0.121 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 34.6 | (30.5–38.7) | (25.6–46.8) | 0.067 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 35.0 | (30.9–39.2) | (25.9–47.4) | -0.060 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 40.6 | (35.8–45.5) | (30–55) | 0.077 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 41.2 | (36.3–46.1) | (30.4–55.8) | 0.165 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 42.0 | (37–46.9) | (31–56.8) | 0.061 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 48.7 | (42.9–54.5) | (36–65.9) | -0.245 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 48.9 | (43.1–54.7) | (36.1–66.2) | 0.233 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 53.3 | (46.9–59.6) | (39.4–72.1) | 0.180 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 61.7 | (54.4–69.1) | (45.6–83.6) | 0.083 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 64.7 | (57–72.4) | (47.8–87.6) | 0.026 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 65.6 | (57.8–73.4) | (48.5–88.8) | 0.202 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 73.4 | (64.7–82.2) | (54.3–99.4) | -0.221 |
Dunkleosteus terrelli | CMNH 7424 | NA | 179.6 | (158.3–200.9) | (132.7–243.1) | NA |
Dunkleosteus terrelli | CMNH 6090 | NA | 266.9 | (235.2–298.6) | (197.1–361.3) | NA |
Dunkleosteus terrelli | CMNH 7054 | NA | 278.2 | (245.1–311.2) | (205.5–376.6) | NA |
Dunkleosteus terrelli | CMNH 5768 | NA | 319.7 | (281.7–357.6) | (236.1–432.8) | NA |
rbind("%PE (all specimens)"=predict.fusiform%>%
drop_na(total_length)%>%
mutate(PE=((.fitted-total_length)/.fitted)%>%round(4))%>%
pull(PE)%>%abs()%>%mean(),
"%PE (excluding unusual specimens)"=predict.fusiform %>%
drop_na(total_length)%>%
filter(!taxon %in% c("Amazichthys trinajsticae","Holonema westolli"),
!="NHMUK PV P 49663")%>%
specimenmutate(PE=((.fitted-total_length)/.fitted)%>%round(4))%>%
pull(PE)%>%abs()%>%mean())%>%
kable(digits=4,col.names="PE",align="c",
caption="Mean percent error for length estimations of complete arthrodires using OOL and a model based solely on fusiform fishes",
table.attr = "style='width:70%;'")%>%
kable_styling()
PE | |
---|---|
%PE (all specimens) | 0.1077 |
%PE (excluding unusual specimens) | 0.0830 |
“Unusual specimens” in this case refers to Holonema westolli, Amazichthys trinajsticae, and one specimen of Dickosteus threiplandi (NHMUK PV P 49663).
- Although the reconstruction of H. westolli from Trinajstic (1999) is used here because of the limited data, it is not clear if the head-trunk proportions of this specimen are correct. One specimen that preserves a near-complete tail (WAM 96.6.111A) seems to measure approximately 21-23 cm posterior to the armor. However, it is unclear how this specimen scales with the anterior half of the animal, as the only plate preserved is a partial posteroventrolateral. Thus, it is possible this animal had a shorter post-thoracic region, which would bring it more in line with the proportions seen in other arthrodires.
- Amazichthys trinajsticae shows unusual head-body proportions compared to other arthrodires,, and hence it is possible that this specimen is an outlier compared to other members of the group.
- The head region of NMHUK PV P 49963 is poorly preserved and it may be that OOL is mis-measured in this specimen. The rough dimensions of the head can be somewhat defined but many of its features are distorted (e.g., lateral lines ), and it may be that the location of the cranio-thoracic joint is not accurately identified. This is supported by the fact that its head proportions differ greatly from the other specimen of D. threiplandi considered here (NMS 1987.7.118).
10.1.1 Graph of fusiform fishes only
ggplot(data_final%>%
cbind(exp(predict(lm(log(total_length)~log(OOL),
%>%
data_finalfilter(shape == "fusiform",
!="estimated t.l.")),
length_asinterval="prediction")))%>%
data_final,filter(shape=="fusiform",
!="estimated t.l."),
length_asaes(y=total_length,x=OOL))+
geom_point(aes(color=clade,shape=clade))+
geom_point(aes(fill=clade,shape=clade),size=2)+
geom_smooth(method="lm",formula=y~x)+
scale_shape_manual(values=c(21,24,22,23))+
scale_color_manual(values=c("red","green",NA,NA),na.value=NA)+
geom_point(data=data_final%>%filter(family=="Serranidae"),
shape=21,size=2,fill="gray")+
geom_point(data=data_final%>%filter(family %in% c("Monacanthidae","Balistidae")&
=="fusiform"),
shapeshape=21,size=2,fill="white")+
geom_smooth(data=data_final%>%filter(family=="Serranidae"),
formula=y~x,method="lm",color="black")+
geom_line(aes(y=lwr), color = "blue", linetype = "dashed")+
geom_line(aes(y=upr), color = "blue", linetype = "dashed")+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)",
color="Clade",shape="Clade",fill="Clade")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
theme_classic()+
theme(legend.position=c(0.8,0.25))
Figure 10.1: Plot of orbit-opercular length against total length on a log10 scale in fusiform fishes. Groupers (Serranidae), which show a shift in the y-intercept of their regression line due to having disproportionately large heads, are denoted in gray. Balistoidei, which are also excluded because of an apomorphic posterior shift in the orbit, are denoted in white.
ggplot(data_final%>%
cbind(exp(predict(lm(log(total_length)~log(OOL),
data_final%>%
filter(shape == "fusiform",
length_as!="estimated t.l.")),
data_final,interval="prediction")))%>%
filter(shape=="fusiform",
length_as!="estimated t.l."),
aes(y=OOL/total_length,x=total_length))+
geom_point(aes(color=clade,shape=clade))+
geom_point(aes(fill=clade,shape=clade),size=2)+
geom_smooth(method="lm",formula=y~x)+
scale_shape_manual(values=c(21,24,22,23))+
scale_color_manual(values=c("red","green",NA,NA),na.value=NA)+
geom_point(data=data_final%>%filter(family=="Serranidae"),
shape=21,size=2,fill="gray")+
geom_point(data=data_final%>%filter(family %in% c("Monacanthidae","Balistidae")&
shape=="fusiform"),
shape=21,size=2,fill="white")+
geom_smooth(data=data_final%>%filter(family=="Serranidae"),
formula=y~x,method="lm",color="black")+
geom_line(aes(y=lwr), color = "blue", linetype = "dashed")+
geom_line(aes(y=upr), color = "blue", linetype = "dashed")+
labs(x="Total Length (cm)",y="Percent OOL",
color="Clade",shape="Clade",fill="Clade")+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans='log10')+
theme_classic()+
theme(legend.position=c(0.8,0.25))
10.1.2 Effect of groupers (Serranidae)
10.1.2.1 OOL in groupers relative to other fishes
ggplot(data_final%>%
drop_na(OOL,total_length)%>%
filter(shape=="fusiform",
!="estimated t.l.")%>%
length_asmutate(clade=case_when(clade=="Placodermi"~"Placodermi",
=="Sarcopterygii"~"Sarcopterygii",
clade%in% c("Lamnidae","Megachasmatidae")~"Lamnidae + Megachasmatidae",
family =="Chondrichthyes"~"Chondrichthyes",
clade=="Serranidae"~"Serranidae",
family%in% c("Monacanthidae","Balisidae")~"Balistoidei",
family =="Actinopterygii"~"Actinopterygii, Other"))%>%
cladearrange(clade),
aes(y=OOL/total_length,x=total_length))+
geom_star(aes(color=clade,starshape=clade))+
geom_star(aes(fill=clade,starshape=clade),size=2)+
geom_star(aes(fill=clade,starshape=clade),size=3,
data=.%>% filter(clade=="Placodermi"))+
geom_smooth(method="lm",formula=y~x)+
scale_starshape_manual(values=c(15,15,13,13,1,15,15))+
scale_fill_manual(values=c(hue_pal()(5)[1],"white",hue_pal()(5)[-1],"gray"))+
geom_smooth(data=data_final%>%filter(family=="Serranidae"),
formula=y~x,method="lm",color="black")+
labs(x="Total Length (cm)",y="OOL (as percent of total length)",
color="Clade",starshape="Clade",fill="Clade")+
scale_x_continuous(trans='log10')+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
theme_classic()
Figure 10.2: OOL graphed as a percentage of total length in fusiform fishes, showing how groupers (Serranidae), particularly more derived groupers of the Cephalopholis-Epinephelus clade and not more basal grouper like Variola and Plectropomus, have much larger OOL than would be expected for fusiform taxa, and taxa with posteriorly shifted orbits (Balistoidei) have much smaller OOL than expected.
10.1.2.2 Testing if groupers show a significantly different intercept than other fishes
%$%
data_finallm(log(total_length)~log(OOL)+(family=="Serranidae"),.)%>%
summary()
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + (family == "Serranidae"),
## data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64110 -0.13139 -0.00761 0.11900 1.53088
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.927582 0.008375 230.16 <2e-16 ***
## log(OOL) 0.994479 0.003821 260.26 <2e-16 ***
## family == "Serranidae"TRUE -0.373931 0.015065 -24.82 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2057 on 3166 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9559, Adjusted R-squared: 0.9559
## F-statistic: 3.43e+04 on 2 and 3166 DF, p-value: < 2.2e-16
%$%
data_finallm(log(total_length)~log(head_length)+(family=="Serranidae"),.)%>%
summary()
##
## Call:
## lm(formula = log(total_length) ~ log(head_length) + (family ==
## "Serranidae"), data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.51915 -0.10999 -0.00499 0.09563 1.62999
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.592558 0.008167 195.01 <2e-16 ***
## log(head_length) 0.968756 0.003183 304.37 <2e-16 ***
## family == "Serranidae"TRUE -0.268291 0.012970 -20.68 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.177 on 3166 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9674, Adjusted R-squared: 0.9673
## F-statistic: 4.691e+04 on 2 and 3166 DF, p-value: < 2.2e-16
Based on this, groupers have a significantly lower intercept (i.e., larger head/OOL relative to total length) than is typical for fishes.
10.1.2.3 Testing whether groupers have larger OOL than other fishes when body shape is accounted for
%$%
data_finallm(log(total_length)~log(OOL)+shape+(family=="Serranidae"),.)%>%
summary()
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + shape + (family ==
## "Serranidae"), data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64948 -0.09520 -0.00805 0.09211 1.38777
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.897877 0.007540 251.707 <2e-16 ***
## log(OOL) 0.978394 0.003241 301.868 <2e-16 ***
## shapeanguilliform 0.215939 0.009091 23.754 <2e-16 ***
## shapecompressiform -0.122066 0.011265 -10.835 <2e-16 ***
## shapeelongate 0.224477 0.009048 24.809 <2e-16 ***
## shapeflattened 0.049513 0.033767 1.466 0.143
## shapemacruriform 0.405574 0.027649 14.669 <2e-16 ***
## family == "Serranidae"TRUE -0.310218 0.012729 -24.372 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1706 on 3161 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9697, Adjusted R-squared: 0.9696
## F-statistic: 1.445e+04 on 7 and 3161 DF, p-value: < 2.2e-16
Even if accounting for shape, grouper still stand out as a major outlier.
10.1.2.4 Summary of slopes test between groupers and other fusiform fishes
%>%
data_final filter(shape=="fusiform") %$%
lm(log(total_length)~log(OOL)*(family=="Serranidae"),.)%>%
summary()
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * (family == "Serranidae"),
## data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.47883 -0.09856 0.00122 0.08809 0.93848
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.912362 0.007491 255.295 < 2e-16 ***
## log(OOL) 0.971215 0.003319 292.625 < 2e-16 ***
## family == "Serranidae"TRUE -0.320537 0.043750 -7.327 3.45e-13 ***
## log(OOL):family == "Serranidae"TRUE 0.002961 0.022289 0.133 0.894
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1555 on 1938 degrees of freedom
## (44 observations deleted due to missingness)
## Multiple R-squared: 0.9786, Adjusted R-squared: 0.9786
## F-statistic: 2.955e+04 on 3 and 1938 DF, p-value: < 2.2e-16
Based on this, it appears as though despite serranids showing a much significantly lower intercept (i.e., larger head/OOL) than other fusiform fishes, the allometric relationship (slope) between the two is the same.
10.1.2.5 Predicting body lengths in arthrodires using only groupers
<-lm(log(total_length)~log(OOL),
fit.grouper%>%filter(family=="Serranidae"))
data_finalpredict(fit.grouper,
(%>%
fossil_taxafilter(!is.na(OOL),clade=="Placodermi",
=="Dunkleosteus"&specimen%in% c("CMNH 7054","CMNH 6090","CMNH 5768","CMNH 7424")|length_as=="total length"),
genusinterval="prediction")%>%
exp()*regression.stats(fit.grouper)$CF)%>%
data.frame()%>%rownames_to_column()%>%
arrange(fit)%>%
left_join(fossil_taxa%>%rownames_to_column(),by="rowname")%>%
mutate(est_OOL=exp(predict(fit.fusiform,.))*regression.stats(fit.fusiform)$CF,
total_length=ifelse(length_as=="estimated t.l.",NA,total_length))%>%
select(taxon,specimen,total_length,est_OOL,fit,lwr,upr)%>%
kable(digits=1,align=c("l","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model based on only groupers (Serranidae)",
col.names = c("Taxon","Specimen","Actual Length","Estimated Length Using All Fusiform Taxa","Est.","Lwr 95% P.I.","Upr 95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(5, bold = T)%>%
add_header_above(c(" "=4,"Estimated Using Serranidae"=3))%>%
kable_styling()
Taxon | Specimen | Actual Length | Estimated Length Using All Fusiform Taxa | Est. | Lwr 95% P.I. | Upr 95% P.I. |
---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.6 | 9.9 | 7.6 | 12.9 |
Millerosteus minor | Composite Millerosteus | 14.9 | 15.7 | 11.4 | 8.8 | 14.9 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 23.7 | 17.3 | 13.3 | 22.5 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 30.4 | 22.2 | 17.1 | 28.9 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 33.7 | 24.6 | 18.9 | 32.0 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 34.6 | 25.3 | 19.4 | 32.9 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 35.0 | 25.6 | 19.7 | 33.3 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 40.6 | 29.7 | 22.8 | 38.7 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 41.2 | 30.1 | 23.2 | 39.2 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 42.0 | 30.7 | 23.6 | 39.9 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 48.7 | 35.6 | 27.4 | 46.4 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 48.9 | 35.8 | 27.5 | 46.6 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 53.3 | 39.0 | 30.0 | 50.8 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 61.7 | 45.3 | 34.8 | 58.9 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 64.7 | 47.4 | 36.5 | 61.7 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 65.6 | 48.1 | 37.0 | 62.6 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 73.4 | 53.9 | 41.4 | 70.2 |
Dunkleosteus terrelli | CMNH 7424 | NA | 179.6 | 132.6 | 101.4 | 173.5 |
Dunkleosteus terrelli | CMNH 6090 | NA | 266.9 | 197.6 | 150.5 | 259.3 |
Dunkleosteus terrelli | CMNH 7054 | NA | 278.2 | 206.0 | 156.9 | 270.5 |
Dunkleosteus terrelli | CMNH 5768 | NA | 319.7 | 236.9 | 180.2 | 311.5 |
As can be seen by these results, using groupers (Serranidae) results in much shorter lengths for arthrodires, specifically because serranids have disproportionately large heads relative to their body size compared to other fishes. Thus, although groupers have a largely fusiform body plan, it seems reasonable to exclude them from the fusiform fishes-only model because of their unusual proportions.
10.1.3 Plotting estimated lengths for Dunkleosteus using a fusiform-only model
ggplot(data_final%>%
augment(fit.fusiform,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.fusiform)$CF))%>%
filter(shape=="fusiform"),
aes(y=total_length,x=OOL))+
geom_star(aes(starshape=clade),color="dark grey",fill="light grey")+
stat_smooth(geom='line',aes(y=.fitted), color = "#3366FF", method="lm",
alpha=0.95, se=FALSE,size=.75,formula=y~x)+
geom_line(aes(y=.lower), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_line(aes(y=.upper), color = "#3366FF", linetype = "dashed",alpha=0.5)+
geom_errorbar(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(ymin=.lower,ymax=.upper),width=0.1)+
geom_star(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(starshape=clade,y=.fitted),fill="black",size=2)+
scale_starshape_manual(values=c(15,11,13,1,28),guide="none")+
labs(x="Orbit-Opercular Length (cm)",y="Total Length (cm)")+
coord_cartesian(y=c(0,500),x=c(0,75))+
geom_segment(data=.%>%filter(genus=="Dunkleosteus",!!fossil.specimens),
aes(y=.lower,yend=.lower,x=-20,xend=OOL),
linetype="dashed",alpha=0.75)+
geom_segment(data=.%>%filter(genus=="Dunkleosteus",!!fossil.specimens),
aes(y=.upper,yend=.upper,x=-20,xend=OOL),
linetype="dashed",alpha=0.75)+
geom_errorbar(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(ymin=.lower,ymax=.upper),width=3)+
geom_label(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(y=.upper,x=0,label=round(.upper,1)),size=3)+
geom_label(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(y=.lower,x=0,label=round(.lower,1)),size=3)+
geom_text(data=.%>%filter(!!fossil.specimens,genus=="Dunkleosteus"),
aes(label=specimen,x=OOL,
y=ifelse(specimen=="CMNH 6090",.lower-10,.lower)),hjust=0,nudge_y=-13)+
theme_classic()
Figure 10.3: Minimum and maximum estimated length in specimens of Dunkleosteus terrelli considered in this study using orbit-opercular length, using an equation only considering fusiform taxa (i.e., excluding taxa with very elongate body shapes like barracudas). Plot is zoomed in to focus on lengths in Dunkleosteus. Error bars represent 95% prediction intervals.
10.2 Predicting using pelagic taxa
10.2.1 Model only considering pelagic taxa
<-lm(log(total_length)~log(OOL),
fit.pelagic%>%
data_finalfilter(!shape %in% c("macruriform","anguilliform"),
%in% c("pelagic"),
habitat !order %in% c("Rajiformes","Chimaeriformes"),
!="Molidae",
family !genus %in% c("Alopias","Regalecus"),
!="estimated t.l."))
length_as
summary(fit.pelagic)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(!shape %in% c("macruriform", "anguilliform"), habitat %in%
## c("pelagic"), !order %in% c("Rajiformes", "Chimaeriformes"),
## family != "Molidae", !genus %in% c("Alopias", "Regalecus"),
## length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.46661 -0.14354 -0.00813 0.16128 0.71921
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.037299 0.024742 82.34 <2e-16 ***
## log(OOL) 0.967703 0.008509 113.73 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1974 on 636 degrees of freedom
## (9 observations deleted due to missingness)
## Multiple R-squared: 0.9531, Adjusted R-squared: 0.9531
## F-statistic: 1.293e+04 on 1 and 636 DF, p-value: < 2.2e-16
regression.stats(fit.pelagic)
10.2.2 Model using habitat as an additional categorical variable
Note: Regalecus and Alopias were excluded from this model given their highly unusual body shapes compared to typical pelagic fishes.
<-lm(log(total_length)~log(OOL)+habitat+
fit.pelagic_categorical=="Serranidae"),
(family%>%
data_finalfilter(!shape %in% c("macruriform","anguilliform"),
!order %in% c("Rajiformes","Chimaeriformes"),
!genus %in% c("Alopias","Regalecus"),
!="estimated t.l."))
length_assummary(fit.pelagic_categorical)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + habitat + (family ==
## "Serranidae"), data = data_final %>% filter(!shape %in% c("macruriform",
## "anguilliform"), !order %in% c("Rajiformes", "Chimaeriformes"),
## !genus %in% c("Alopias", "Regalecus"), length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64809 -0.12248 -0.00544 0.11633 1.07584
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.890826 0.008688 217.628 < 2e-16 ***
## log(OOL) 0.974702 0.004006 243.290 < 2e-16 ***
## habitatbenthic 0.044706 0.014212 3.146 0.00168 **
## habitatneritic 0.034554 0.010251 3.371 0.00076 ***
## habitatpelagic 0.126054 0.010192 12.368 < 2e-16 ***
## family == "Serranidae"TRUE -0.301080 0.014390 -20.923 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1883 on 2683 degrees of freedom
## (14 observations deleted due to missingness)
## Multiple R-squared: 0.9672, Adjusted R-squared: 0.9671
## F-statistic: 1.58e+04 on 5 and 2683 DF, p-value: < 2.2e-16
regression.stats(fit.pelagic_categorical)
<-
fit.pelagic_categorical_species_averageslm(log(total_length)~log(OOL)+habitat+(family=="Serranidae"),
%>%
data_species filter(!shape %in% c("macruriform","anguilliform"),
!genus %in% c("Alopias","Regalecus"),
!order %in% c("Rajiformes","Chimaeriformes")))
summary(fit.pelagic_categorical_species_averages)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + habitat + (family ==
## "Serranidae"), data = data_species %>% filter(!shape %in%
## c("macruriform", "anguilliform"), !genus %in% c("Alopias",
## "Regalecus"), !order %in% c("Rajiformes", "Chimaeriformes")))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.59491 -0.11176 -0.00376 0.09799 1.06055
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.908923 0.014559 131.114 < 2e-16 ***
## log(OOL) 0.971019 0.007069 137.370 < 2e-16 ***
## habitatbenthic 0.036828 0.022498 1.637 0.101986
## habitatneritic 0.029849 0.016182 1.845 0.065414 .
## habitatpelagic 0.072419 0.019422 3.729 0.000204 ***
## family == "Serranidae"TRUE -0.282089 0.025060 -11.256 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1877 on 905 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.9575, Adjusted R-squared: 0.9573
## F-statistic: 4079 on 5 and 905 DF, p-value: < 2.2e-16
regression.stats(fit.pelagic_categorical_species_averages)
10.2.3 Predictions for Dunkleosteus
<-lm(log(total_length)~log(OOL),data_species%>%
fit.pelagic_averagesfilter(habitat=="pelagic",
!shape %in% c("macruriform","anguilliform"),
!genus %in% c("Alopias","Regalecus"),
!family %in% c("Molidae"),
!order %in% c("Rajiformes","Chimaeriformes")))
%>%
fossil_taxafilter(!!fossil.specimens)%>%drop_na(habitat)%>%
augment(fit.pelagic,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelagic)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.pelagic_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelagic_averages)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
augment(fit.pelagic_categorical,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelagic_categorical)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit3",.)))%>%
augment(fit.pelagic_categorical_species_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelagic_categorical_species_averages)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit4",.)))%>%
mutate(fit1.PE=paste0("(",round(fit1.fitted*(1-
regression.stats(fit.pelagic)$adjPE/100),1),
"–",round(fit1.fitted*(1+
regression.stats(fit.pelagic)$adjPE/100),1),")"),
fit2.PE=paste0("(",round(fit2.fitted*(1-
regression.stats(fit.pelagic_averages)$adjPE/100),1),
"–",round(fit2.fitted*(1+
regression.stats(fit.pelagic_averages)$adjPE/100),1),")"),
fit3.PE=paste0("(",round(fit1.fitted*(1-
regression.stats(fit.pelagic_categorical)$adjPE/100),1),
"–",round(fit1.fitted*(1+
regression.stats(fit.pelagic_categorical)$adjPE/100),1),")"),
fit4.PE=paste0("(",round(fit4.fitted*(1-
regression.stats(fit.pelagic_categorical_species_averages)$adjPE/100),1),
"–",round(fit4.fitted*(1+
regression.stats(fit.pelagic_categorical_species_averages)$adjPE/100),1),")"),
fit1.range=paste0("(",round(fit1.lower,1),"–",round(fit1.upper,1),")"),
fit2.range=paste0("(",round(fit2.lower,1),"–",round(fit2.upper,1),")"),
fit3.range=paste0("(",round(fit3.lower,1),"–",round(fit3.upper,1),")"),
fit4.range=paste0("(",round(fit4.lower,1),"–",round(fit4.upper,1),")"))%>%
select(taxon,specimen,total_length,
fit1.fitted,fit1.PE,fit1.range,
fit2.fitted,fit2.PE,fit2.range,
fit3.fitted,fit3.PE,fit3.range,%>%
fit4.fitted,fit4.PE,fit4.range,)kable(digits=1,
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model considering only pelagic taxa, excluding rays, molids, and anguilliform (e.g., <i>Regalecus</i> and macruriform (e.g., <i>Alopias</i>) taxa",
col.names = c("Taxon","Specimen","Total Length",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(c(4,7,10,13), bold = T)%>%
add_header_above(c(" "=3,"Individual Specimens"=3,"Species Averages"=3,
"Individual Specimens"=3,"Species Averages"=3))%>%
add_header_above(c(" "=3,"Considering Pelagic Taxa Only"=6,
"Treating Life Habits as Additional Categorical Variable"=6))%>%
kable_styling()%>%
scroll_box(width = "100%")
Taxon | Specimen | Total Length | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 15.4 | (12.9–18) | (10.5–22.8) | 15.3 | (12.8–17.7) | (10.3–22.5) | 14.0 | (13.1–17.7) | (9.7–20.3) | 14.2 | (12.1–16.2) | (9.8–20.5) |
Millerosteus minor | Composite Millerosteus | 14.9 | 17.8 | (14.8–20.7) | (12–26.2) | 17.5 | (14.7–20.3) | (11.9–25.9) | 16.2 | (15.1–20.4) | (11.2–23.4) | 16.3 | (14–18.6) | (11.3–23.6) |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 26.8 | (22.3–31.2) | (18.1–39.5) | 26.1 | (22–30.3) | (17.7–38.5) | 23.3 | (22.8–30.7) | (16.1–33.8) | 23.7 | (20.3–27.1) | (16.4–34.3) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 34.4 | (28.7–40) | (23.3–50.7) | 33.4 | (28.1–38.6) | (22.6–49.1) | 30.0 | (29.2–39.5) | (20.8–43.4) | 30.5 | (26.1–34.8) | (21.1–44) |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 38.0 | (31.7–44.3) | (25.8–56.1) | 36.8 | (31–42.7) | (25–54.2) | 33.2 | (32.4–43.7) | (23–48.1) | 33.7 | (28.9–38.5) | (23.3–48.7) |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 39.0 | (32.5–45.5) | (26.5–57.5) | 37.8 | (31.8–43.7) | (25.7–55.6) | 34.1 | (33.2–44.8) | (23.6–49.4) | 34.6 | (29.7–39.5) | (23.9–50) |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 39.5 | (33–46) | (26.8–58.2) | 38.2 | (32.2–44.3) | (26–56.3) | 34.6 | (33.6–45.4) | (23.9–50) | 35.0 | (30.1–40) | (24.2–50.7) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 47.3 | (39.5–55.1) | (32.1–69.7) | 45.6 | (38.4–52.8) | (31–67.1) | 41.4 | (40.3–54.3) | (28.6–59.9) | 42.0 | (36–47.9) | (29–60.7) |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 46.4 | (38.7–54.1) | (31.5–68.5) | 44.8 | (37.7–51.9) | (30.4–65.9) | 40.7 | (39.5–53.3) | (28.1–58.8) | 41.2 | (35.4–47.1) | (28.5–59.6) |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 45.8 | (38.2–53.4) | (31.1–67.5) | 44.2 | (37.2–51.2) | (30–65) | 40.1 | (39–52.6) | (27.7–58) | 40.6 | (34.9–46.4) | (28.1–58.8) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 55.1 | (45.9–64.2) | (37.4–81.2) | 52.9 | (44.5–61.3) | (35.9–77.8) | 48.3 | (46.9–63.2) | (33.4–69.9) | 48.9 | (41.9–55.9) | (33.8–70.7) |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 60.0 | (50–69.9) | (40.7–88.4) | 57.5 | (48.4–66.6) | (39.1–84.6) | 52.6 | (51.1–68.9) | (36.4–76.1) | 53.3 | (45.7–60.9) | (36.9–77) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 54.8 | (45.8–63.9) | (37.2–80.8) | 52.7 | (44.3–61) | (35.8–77.5) | 50.3 | (46.7–63) | (34.7–72.8) | 50.5 | (43.3–57.7) | (34.9–73.2) |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 69.5 | (58–81) | (47.1–102.4) | 66.4 | (55.9–76.9) | (45.1–97.6) | 61.0 | (59.2–79.8) | (42.2–88.3) | 61.8 | (53–70.5) | (42.7–89.3) |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 72.8 | (60.7–84.8) | (49.4–107.3) | 69.4 | (58.4–80.4) | (47.2–102.2) | 72.5 | (62–83.6) | (50.1–105) | 69.6 | (59.7–79.4) | (48.1–100.7) |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 73.8 | (61.6–86) | (50.1–108.8) | 70.4 | (59.2–81.5) | (47.8–103.6) | 64.8 | (62.8–84.7) | (44.8–93.8) | 65.6 | (56.3–74.9) | (45.4–94.9) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 82.6 | (68.9–96.3) | (56–121.7) | 78.6 | (66.1–91) | (53.4–115.6) | 82.4 | (70.3–94.9) | (57–119.2) | 79.0 | (67.7–90.2) | (54.6–114.3) |
Dunkleosteus terrelli | CMNH 7424 | NA | 201.3 | (168–234.6) | (136.6–296.7) | 187.6 | (157.9–217.3) | (127.3–276.6) | 202.1 | (171.4–231.2) | (139.7–292.5) | 193.1 | (165.6–220.5) | (133.3–279.5) |
Dunkleosteus terrelli | CMNH 6090 | NA | 298.7 | (249.2–348.1) | (202.6–440.4) | 275.8 | (232.2–319.5) | (186.8–407.4) | 300.8 | (254.3–343) | (207.9–435.2) | 286.8 | (246.1–327.6) | (198.1–415.4) |
Dunkleosteus terrelli | CMNH 7054 | NA | 311.3 | (259.7–362.8) | (211.1–459) | 287.2 | (241.7–332.7) | (194.4–424.2) | 313.6 | (265–357.5) | (216.7–453.7) | 299.0 | (256.5–341.5) | (206.4–433) |
Dunkleosteus terrelli | CMNH 5768 | NA | 357.5 | (298.3–416.7) | (242.4–527.2) | 328.8 | (276.7–380.9) | (222.4–486.1) | 360.5 | (304.4–410.6) | (249.1–521.6) | 343.5 | (294.7–392.4) | (237.2–497.6) |
10.2.4 Predicting using pelagic and neritic taxa
<-lm(log(total_length)~log(OOL),
fit.pelagic_neritic%>%
data_finalfilter(habitat %in% c("pelagic","neritic"),
!shape %in% c("anguilliform","macruriform"),
!order %in% c("Rajiformes","Chimaeriformes"),
!= "Molidae",
family !="Alopias",
genus!="estimated t.l."))
length_as
<-lm(log(total_length)~log(OOL),
fit.pelagic_neritic_averages%>%
data_speciesfilter(habitat %in% c("pelagic","neritic"),
!shape %in% c("anguilliform","macruriform"),
!order %in% c("Rajiformes","Chimaeriformes"),
!= "Molidae",
family !="Alopias"))
genus
summary(fit.pelagic_neritic)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(habitat %in% c("pelagic", "neritic"), !shape %in%
## c("anguilliform", "macruriform"), !order %in% c("Rajiformes",
## "Chimaeriformes"), family != "Molidae", genus != "Alopias",
## length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.53511 -0.13147 -0.03248 0.13202 0.87878
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.954422 0.014432 135.4 <2e-16 ***
## log(OOL) 0.984589 0.005609 175.5 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1897 on 1108 degrees of freedom
## (10 observations deleted due to missingness)
## Multiple R-squared: 0.9653, Adjusted R-squared: 0.9653
## F-statistic: 3.081e+04 on 1 and 1108 DF, p-value: < 2.2e-16
regression.stats(fit.pelagic_neritic)
%>%
fossil_taxafilter(!!fossil.specimens)%>%
augment(fit.pelagic_neritic_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelagic_neritic)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.pelagic_neritic_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.pelagic_neritic_averages)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(fit1.range=paste0("(",round(fit1.lower,1),"–",round(fit1.upper,1),")"),
fit2.range=paste0("(",round(fit2.lower,1),"–",round(fit2.upper,1),")"),
fit1.PE=paste0("(",round(fit1.fitted*(1-
regression.stats(fit.pelagic_neritic)$adjPE/100),1),
"–",round(fit1.fitted*(1+
regression.stats(fit.pelagic_neritic)$adjPE/100),1),")"),
fit2.PE=paste0("(",round(fit2.fitted*(1-
regression.stats(fit.pelagic_neritic_averages)$adjPE/100),1),
"–",round(fit2.fitted*(1+
regression.stats(fit.pelagic_neritic_averages)$adjPE/100),1),")"))%>%
select(taxon,specimen,fit1.fitted,fit1.PE,fit1.range,fit2.fitted,fit2.PE,fit2.range)%>%
kable(digits=1,
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model considering pelagic and neritic taxa, excluding rays, molids, and anguilliform (e.g., <i>Regalecus</i> and macruriform (e.g., <i>Alopias</i>) taxa",
col.names = c("Taxon","Specimen",
"Est.","+/- PE","95% P.I.",
"Est.","+/- PE","95% P.I."))%>%
add_header_above(c(" "=2,"Individual Specimens"=3,"Species Averages"=3))%>%
column_spec(1, italic = T)%>%
column_spec(c(3,6), bold = T)%>%
kable_styling()
Taxon | Specimen | Est. | +/- PE | 95% P.I. | Est. | +/- PE | 95% P.I. |
---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 14.4 | (12.2–16.7) | (10.1–20.6) | 14.4 | (12.4–16.5) | (10.1–20.6) |
Millerosteus minor | Composite Millerosteus | 16.6 | (14–19.2) | (11.6–23.7) | 16.6 | (14.3–19) | (11.6–23.7) |
Africanaspis dorissa | Gess and Trinajstic 2017 | 24.9 | (21–28.9) | (17.5–35.6) | 24.9 | (21.4–28.5) | (17.5–35.6) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 32.0 | (27–37) | (22.4–45.7) | 32.0 | (27.4–36.5) | (22.4–45.7) |
Coccosteus cuspidatus | NMS 1893.107.27 | 35.4 | (29.8–40.9) | (24.7–50.5) | 35.4 | (30.3–40.4) | (24.7–50.5) |
Coccosteus cuspidatus | NMS 1897.55.6 | 36.3 | (30.6–42) | (25.4–51.8) | 36.3 | (31.1–41.4) | (25.4–51.8) |
Coccosteus cuspidatus | FMNH PF 1673 | 36.7 | (31–42.5) | (25.7–52.5) | 36.7 | (31.5–41.9) | (25.7–52.5) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 43.9 | (37–50.8) | (30.7–62.7) | 43.9 | (37.7–50.1) | (30.7–62.7) |
Coccosteus cuspidatus | NMS 1900.12.12 | 43.1 | (36.4–49.9) | (30.2–61.6) | 43.1 | (37–49.2) | (30.2–61.6) |
Coccosteus cuspidatus | ROM VP 52664 | 42.5 | (35.9–49.2) | (29.8–60.8) | 42.5 | (36.5–48.6) | (29.8–60.8) |
Plourdosteus canadensis | MNHM 2-177 | 51.1 | (43.1–59.1) | (35.8–73) | 51.1 | (43.9–58.3) | (35.8–73) |
Dickosteus threiplandi | NMS 1987.7.118 | 55.6 | (46.9–64.4) | (38.9–79.5) | 55.6 | (47.8–63.5) | (38.9–79.5) |
Holonema westolli | Recon. (Miles 1971) | 50.9 | (42.9–58.9) | (35.6–72.7) | 50.9 | (43.7–58.1) | (35.6–72.7) |
Watsonosteus fletti | NMS G.1995.4.2 | 64.4 | (54.3–74.5) | (45.1–92) | 64.4 | (55.3–73.5) | (45.1–92) |
Gen. et sp. nov. | CMNH 50233 | 67.4 | (56.8–78) | (47.2–96.3) | 67.4 | (57.9–77) | (47.2–96.3) |
Dickosteus threiplandi | NHMUK PV P 49663 | 68.3 | (57.6–79.1) | (47.8–97.6) | 68.3 | (58.7–78) | (47.8–97.6) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 76.4 | (64.4–88.4) | (53.5–109.2) | 76.4 | (65.6–87.3) | (53.5–109.2) |
Dunkleosteus terrelli | CMNH 7424 | 185.2 | (156.2–214.3) | (129.5–265) | 185.2 | (159–211.5) | (129.5–265) |
Dunkleosteus terrelli | CMNH 6090 | 274.2 | (231.1–317.2) | (191.5–392.6) | 274.2 | (235.4–313) | (191.5–392.6) |
Dunkleosteus terrelli | CMNH 7054 | 285.7 | (240.8–330.5) | (199.5–409) | 285.7 | (245.2–326.1) | (199.5–409) |
Dunkleosteus terrelli | CMNH 5768 | 327.8 | (276.3–379.3) | (228.8–469.5) | 327.8 | (281.4–374.2) | (228.8–469.5) |
10.3 Predicting using sharks only
Note: this model calculated excluding Rajiformes, Chimaeriformes, and Alopias
<-lm(log(total_length)~log(OOL),
fit.sharks%>%
data_finalfilter(clade=="Chondrichthyes",
!(order %in% c("Rajiformes","Chimaeriformes")),
!="Alopias",
genus!="estimated t.l."))
length_as
summary(fit.sharks)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(clade == "Chondrichthyes", !(order %in% c("Rajiformes",
## "Chimaeriformes")), genus != "Alopias", length_as !=
## "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.39445 -0.09146 -0.00525 0.09698 0.55179
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.180860 0.021976 99.24 <2e-16 ***
## log(OOL) 0.885207 0.007596 116.54 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1457 on 538 degrees of freedom
## Multiple R-squared: 0.9619, Adjusted R-squared: 0.9618
## F-statistic: 1.358e+04 on 1 and 538 DF, p-value: < 2.2e-16
regression.stats(fit.sharks)
<-(predict(fit.sharks,
predict.shark%>%filter(!is.na(OOL)),
fossil_taxainterval="prediction")%>%
exp()*regression.stats(fit.sharks)$CF)%>%
data.frame()%>%rownames_to_column()%>%
arrange(fit)%>%
left_join(fossil_taxa%>%rownames_to_column(),by="rowname")%>%
filter(!!fossil.specimens)%>%
select(taxon,specimen,total_length,fit,lwr,upr)
%>%
predict.sharkkable(digits=1,
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> and other arthrodires using a model considering only chondrichthyans, excluding rays, chimeras, and <i>Alopias</i>",
col.names = c("Taxon","Specimen","Actual Length","Est.","Lwr 95% P.I.","Upr 95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(4, bold = T)%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | Lwr 95% P.I. | Upr 95% P.I. |
---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 16.8 | 12.6 | 22.5 |
Millerosteus minor | Composite Millerosteus | 14.9 | 19.2 | 14.4 | 25.6 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 27.9 | 20.9 | 37.1 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 35.0 | 26.3 | 46.7 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 38.4 | 28.8 | 51.2 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 39.3 | 29.5 | 52.4 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 39.8 | 29.9 | 53.0 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 45.6 | 34.2 | 60.7 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 46.1 | 34.6 | 61.5 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 46.9 | 35.2 | 62.5 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 53.7 | 40.3 | 71.6 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 53.9 | 40.5 | 71.8 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 58.3 | 43.8 | 77.7 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 66.7 | 50.1 | 88.9 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 69.6 | 52.3 | 92.7 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 70.5 | 52.9 | 93.9 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 78.1 | 58.7 | 104.1 |
Dunkleosteus terrelli | CMNH 7424 | NA | 176.5 | 132.6 | 235.1 |
Dunkleosteus terrelli | CMNH 6090 | NA | 253.3 | 190.1 | 337.4 |
Dunkleosteus terrelli | CMNH 7054 | NA | 263.0 | 197.4 | 350.4 |
Dunkleosteus terrelli | CMNH 5768 | NA | 298.5 | 224.1 | 397.8 |
10.3.1 Model excluding Lamniformes and Echinorhiniformes
Because many of the very largest fishes in this analysis are Lamniformes or Echinorhiniformes. Lamniformes tend to show a distinctly longer OOL relative to their total length (whether this is due to their anteriorposteriorly short trunk, an elongated gill region, or both is unclear at this time). On the other hand, Echinorhinus shows an unusually long head among fishes and appears to display a truncated abdomen (i.e., postpelvic region of the body). Varojean (1972) notes that E. cookei displays an unusual positive allometry of the head and abdomen relative to the trunk, and it is possible this is indicative of some unusual developmental pattern resulting in the strange body proportions of this taxon. Because of these factors, it is worth questioning whether the regression line might be biased in favor of Lamniformes and Echinorhinformes, and thus producing shorter body length estimates in Dunkleosteus.
<-lm(log(total_length)~log(OOL),
fit.lamniformes%>%
data_finalfilter(!order %in% c("Lamniformes","Echinorhiniformes"),
!="estimated t.l."))
length_as<-lm(log(total_length)~log(OOL),
fit.lamniformes2%>%
data_speciesfilter(!order %in% c("Lamniformes","Echinorhiniformes")))
<-lm(log(total_length)~log(OOL)+shape,
fit.lamniformes3%>%
data_finalfilter(!order %in% c("Lamniformes","Echinorhiniformes"),
!="estimated t.l."))
length_as
<-(fossil_taxa%>%
predict.lamniformesdrop_na(OOL)%>%
filter(!!fossil.specimens)%>%
mutate(fit=predict(fit.lamniformes,.,interval="prediction")[,1],
lwr=predict(fit.lamniformes,.,interval="prediction")[,2],
upr=predict(fit.lamniformes,.,interval="prediction")[,3],
fit2=predict(fit.lamniformes2,.,interval="prediction")[,1],
lwr2=predict(fit.lamniformes2,.,interval="prediction")[,2],
upr2=predict(fit.lamniformes2,.,interval="prediction")[,3],
fit3=predict(fit.lamniformes3,.,interval="prediction")[,1],
lwr3=predict(fit.lamniformes3,.,interval="prediction")[,2],
upr3=predict(fit.lamniformes3,.,interval="prediction")[,3],
across(fit:upr,~exp(.)*regression.stats(fit.lamniformes)$CF),
across(fit2:upr2,~exp(.)*regression.stats(fit.lamniformes2)$CF),
across(fit3:upr3,~exp(.)*regression.stats(fit.lamniformes3)$CF))%>%
arrange(fit)%>%
filter(genus %in% c("Coccosteus","Dunkleosteus"))%>%
select(taxon,specimen,fit,lwr,upr,fit2,lwr2,upr2,fit3,lwr3,upr3))
%>%
predict.lamniformesmutate(range=paste0("(",round(lwr,1),"-",round(upr,1),")"),
range2=paste0("(",round(lwr2,1),"-",round(upr2,1),")"),
range3=paste0("(",round(lwr3,1),"-",round(upr3,1),")"))%>%
rownames_to_column()%>%
select(taxon,specimen,fit,range,fit2,range2,fit3,range3)%>%
kable(digits=1,
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model considering all fishes except Lamniformes. This table focuses on results in <i>Dunkleosteus</i> as Lamniformes are expected to bias only the very upper parts of the regression model",
col.names = c("Taxon","Specimen","Est.","95% P.I.","Est.","95% P.I.","Est.","95% P.I."))%>%
add_header_above(c(" "=2,
"Individual Data"=2,
"Species Averages"=2,
"Individual Data, With Shape"=2))%>%
column_spec(1, italic = T)%>%
column_spec(c(3,5,7),bold=T)%>%
kable_styling()
Taxon | Specimen | Est. | 95% P.I. | Est. | 95% P.I. | Est. | 95% P.I. |
---|---|---|---|---|---|---|---|
Coccosteus cuspidatus | NMS 1893.107.27 | 35.3 | (22.8-54.7) | 35.0 | (22.1-55.3) | 33.1 | (22.9-47.7) |
Coccosteus cuspidatus | NMS 1897.55.6 | 36.3 | (23.4-56.2) | 35.9 | (22.7-56.7) | 34.0 | (23.6-48.9) |
Coccosteus cuspidatus | FMNH PF 1673 | 36.8 | (23.7-57) | 36.4 | (23-57.5) | 34.4 | (23.9-49.6) |
Coccosteus cuspidatus | ROM VP 52664 | 42.9 | (27.7-66.5) | 42.3 | (26.8-66.8) | 40.0 | (27.8-57.7) |
Coccosteus cuspidatus | NMS 1900.12.12 | 43.5 | (28.1-67.4) | 42.9 | (27.1-67.8) | 40.6 | (28.2-58.5) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 44.3 | (28.6-68.7) | 43.7 | (27.6-69) | 41.3 | (28.7-59.6) |
Dunkleosteus terrelli | CMNH 7424 | 201.2 | (129.8-311.7) | 191.5 | (121.1-303) | 181.6 | (126-261.7) |
Dunkleosteus terrelli | CMNH 6090 | 303.7 | (196-470.6) | 286.5 | (181-453.4) | 271.7 | (188.5-391.7) |
Dunkleosteus terrelli | CMNH 7054 | 317.1 | (204.6-491.4) | 298.8 | (188.8-472.9) | 283.4 | (196.6-408.6) |
Dunkleosteus terrelli | CMNH 5768 | 366.4 | (236.4-567.8) | 344.1 | (217.4-544.7) | 326.5 | (226.4-470.7) |
Omitting Lamniformes and Echinorhinoformes from the analysis results in a slight inflation of body length relative to other models. However this is mostly in the individual specimen model without any additional assumptions, and mostly due to the heavy sampling of long-bodied Istiophoriformes (e.g., Tetrapturus) in this data set. Using species averages or using a model that also considers shape produces results much closer to those without Lamniformes or Echinorhiniformes.
Additionally, the results of the model excluding Lamniformes are not considered very reliable as they result in the exclusion of taxa that would be expected to be most similar to Dunkleosteus in ecology and body shape (Carr 2010, Ferrón et al. 2017). Although lamnids and other pelagic lamniformes show a distinct underestimate of body length using OOL, Dunkleosteus might be expected to be more likely to show a more similar proportional relationship to lamnids than any other taxon (i.e., having a shorter trunk and longer OOL relative to total length than taxa like Coccosteus) given it has also been interpreted as an active pelagic swimmer (Carr 2010).
10.4 Using OOL to estimate total length minus snout length and then adding snout length on as an integer
Because arthrodires have a proportionally shorter snout than most other fishes, one question is whether this could have a biasing effect on the model because it assumes that arthrodires have rostral proportions similar to other fishes. Thus, a model was fitted seeing how well OOL predicted total length minus snout length, and then adding snout length back on as an integer because this was a known, measurable value in specimens of Dunkleosteus terrelli.
<-lm(log(total_length-snout_length)~log(OOL)+(family=="Serranidae")+(family=="Holocentridae"),data_final)
fit.minus_snout_length1<-lm(log(total_length-snout_length)~log(OOL)+(family=="Serranidae")+(family=="Holocentridae"),data_species)
fit.minus_snout_length2
summary(fit.minus_snout_length1)
##
## Call:
## lm(formula = log(total_length - snout_length) ~ log(OOL) + (family ==
## "Serranidae") + (family == "Holocentridae"), data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.65536 -0.12362 -0.00575 0.11336 1.59565
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.871337 0.008133 230.10 <2e-16 ***
## log(OOL) 0.986866 0.003694 267.17 <2e-16 ***
## family == "Serranidae"TRUE -0.378178 0.014519 -26.05 <2e-16 ***
## family == "Holocentridae"TRUE -0.330185 0.031654 -10.43 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1982 on 3165 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9587, Adjusted R-squared: 0.9586
## F-statistic: 2.446e+04 on 3 and 3165 DF, p-value: < 2.2e-16
rbind("Individual Data"=regression.stats(fit.minus_snout_length1),
"Species Averages"=regression.stats(fit.minus_snout_length2))
Note that the summary statistics presented here are for total length - snout length, not total length. Snout length must then be added back on as an integer to get the true total length.
%>%
fossil_taxafilter(!!fossil.specimens,!is.na(snout_length))%>%
augment(fit.minus_snout_length1,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.minus_snout_length1)$CF+
snout_length),.PE=paste0("(",round(.fitted*(1-
regression.stats(fit.minus_snout_length1)$adjPE/100),1),
"–",round(.fitted*(1+
regression.stats(fit.minus_snout_length1)$adjPE/100),1),")"),
.range=paste0("(",round(.lower,1),
"–",round(.upper,1),
")"))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.minus_snout_length2,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF+
snout_length),.PE=paste0("(",round(.fitted*(1-
regression.stats(fit.minus_snout_length2)$adjPE/100),1),
"–",round(.fitted*(1+
regression.stats(fit.minus_snout_length2)$adjPE/100),1),")"),
.range=paste0("(",round(.lower,1),
"–",round(.upper,1),
")"))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
select(taxon,specimen,total_length,fit1.fitted,fit1.PE,fit1.range,fit2.fitted,fit2.PE,fit2.range)%>%
kable(digits=1,align=c("l","c","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model estimating total length minus snout length using OOL and treating snout length as a known integer",
col.names=c("Taxon","Specimen","Actual Length","Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
add_header_above(c(" "=3,"Individual Data"=3,"Species Averages"=3))%>%
column_spec(1, italic = T)%>%
column_spec(c(4,7), bold = T)%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.6 | (11.5–15.7) | (9.3–19.9) | 13.6 | (11.4–15.7) | (9.1–20.4) |
Millerosteus minor | Composite Millerosteus | 14.9 | 16.0 | (13.5–18.4) | (11–23.3) | 15.9 | (13.4–18.4) | (10.7–23.8) |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 24.3 | (20.6–28) | (16.8–35.4) | 24.1 | (20.3–28) | (16.3–36) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 31.2 | (26.4–36) | (21.5–45.5) | 30.9 | (26–35.8) | (20.8–46.2) |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 34.4 | (29.1–39.7) | (23.7–50.3) | 34.1 | (28.7–39.6) | (22.9–51.1) |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 35.4 | (29.9–40.9) | (24.4–51.7) | 35.1 | (29.5–40.7) | (23.6–52.5) |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 36.1 | (30.5–41.6) | (24.9–52.5) | 35.7 | (30–41.4) | (24.1–53.4) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 42.3 | (35.8–48.8) | (28.8–62.1) | 41.8 | (35.1–48.5) | (27.8–63) |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 41.7 | (35.2–48.1) | (28.5–61.1) | 41.2 | (34.7–47.8) | (27.5–62) |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 41.6 | (35.2–48) | (28.6–60.8) | 41.2 | (34.6–47.8) | (27.6–61.7) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 49.8 | (42.1–57.5) | (34.1–72.9) | 49.2 | (41.4–57.1) | (32.9–73.9) |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 53.8 | (45.5–62.1) | (36.7–79) | 53.1 | (44.7–61.6) | (35.3–80.1) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 50.6 | (42.8–58.3) | (34.9–73.6) | 50.0 | (42–58) | (33.7–74.6) |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 63.4 | (53.7–73.2) | (43.6–92.7) | 62.6 | (52.6–72.6) | (42–93.9) |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 66.9 | (56.6–77.2) | (46.1–97.7) | 66.0 | (55.5–76.6) | (44.4–98.8) |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 68.0 | (57.5–78.5) | (46.9–99.2) | 67.1 | (56.4–77.8) | (45.1–100.3) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 75.6 | (64–87.3) | (51.9–110.6) | 74.6 | (62.7–86.5) | (49.9–111.8) |
Dunkleosteus terrelli | CMNH 7424 | NA | 187.6 | (158.7–216.5) | (128.8–274.4) | 183.7 | (154.4–213) | (123–275.6) |
Dunkleosteus terrelli | CMNH 6090 | NA | 280.5 | (237.2–323.7) | (192.5–410.2) | 273.9 | (230.2–317.6) | (183.3–411.1) |
Dunkleosteus terrelli | CMNH 7054 | NA | 292.9 | (247.8–338.1) | (201.2–428.3) | 286.0 | (240.3–331.6) | (191.5–429.1) |
Dunkleosteus terrelli | CMNH 5768 | NA | 336.8 | (284.9–388.7) | (231.1–492.7) | 328.5 | (276.1–380.9) | (219.8–493.2) |
%>%
data_finalmutate(fit1=exp(predict(fit.OOL,.))*
regression.stats(fit.OOL)$CF,
fit2=exp(predict(fit.minus_snout_length1,.))*
regression.stats(fit.minus_snout_length1)$CF,
fit3=exp(predict(fit.minus_snout_length2,.))*
regression.stats(fit.minus_snout_length2)$CF,
PE1=((fit1-total_length)/fit1)*100,
PE2=(((fit2+snout_length)-total_length)/(fit2+snout_length))*100,
PE3=(((fit3+snout_length)-total_length)/(fit3+snout_length))*100)%>%
drop_na(PE1,PE2,PE3)%>%
summarise(N=n(),PE1=mean(abs(PE1)),PE2=mean(abs(PE2)),PE3=mean(abs(PE3)))%>%
kable(digits=c(1,2,2,2),align=c("l","c","c","c"),
col.names=c("N","Using OOL to estimate total length","Individual data","Species averages"),
caption="Comparison of PE<sub>cf</sub> between models treating snout length as a separate integer and those using OOL to estimate total length by itself. This statistic had to be calculated separately because the regression model for the former is between OOL and 'total length minus snout length', not total length.")%>%
add_header_above(c(" "=2,"Treating snout length as a separate integer"=2))%>%
kable_styling()
N | Using OOL to estimate total length | Individual data | Species averages |
---|---|---|---|
3169 | 17.55 | 14.2 | 14.32 |
10.5 Predicting using a model that includes shape as a covariate
<-lm(log(total_length)~log(OOL)+shape+(family=="Serranidae")+(family=="Holocentridae"),
fit.with_shape%>%filter(!family %in% c("Balistidae","Monacanthidae"),
data_initial!genus %in% c("Regalecus","Rhinochimaera"))%>%
drop_na(shape))
summary(fit.with_shape)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + shape + (family ==
## "Serranidae") + (family == "Holocentridae"), data = data_initial %>%
## filter(!family %in% c("Balistidae", "Monacanthidae"), !genus %in%
## c("Regalecus", "Rhinochimaera")) %>% drop_na(shape))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64490 -0.09053 -0.00330 0.09049 0.80988
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.890335 0.006705 281.935 < 2e-16 ***
## log(OOL) 0.980615 0.002907 337.341 < 2e-16 ***
## shapeanguilliform 0.209191 0.008395 24.918 < 2e-16 ***
## shapecompressiform -0.114682 0.010760 -10.658 < 2e-16 ***
## shapeelongate 0.224995 0.008267 27.218 < 2e-16 ***
## shapeflattened 0.060436 0.030307 1.994 0.0462 *
## shapemacruriform 0.368367 0.026763 13.764 < 2e-16 ***
## family == "Serranidae"TRUE -0.333454 0.010803 -30.866 < 2e-16 ***
## family == "Holocentridae"TRUE -0.200061 0.025517 -7.840 5.97e-15 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1589 on 3389 degrees of freedom
## (52 observations deleted due to missingness)
## Multiple R-squared: 0.9741, Adjusted R-squared: 0.9741
## F-statistic: 1.596e+04 on 8 and 3389 DF, p-value: < 2.2e-16
regression.stats(fit.with_shape)
%>%
fossil_taxafilter(!!fossil.specimens)%>%
augment(fit.with_shape,
newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.with_shape)$CF))%>%
mutate(range1=paste0("(",round(.lower,1),"–",round(.upper,1),")"),
PE1_lower=.fitted*(1-(regression.stats(fit.with_shape)$adjPE)/100),
PE1_lower=.fitted*(1-(regression.stats(fit.with_shape)$adjPE)/100),
PE1_upper=.fitted*(1+(regression.stats(fit.with_shape)$adjPE)/100),
PE_range1=paste0("(",round(PE1_lower,1),"–",round(PE1_upper,1),")"))%>%
select(taxon,specimen,total_length,.fitted,PE_range1,range1)%>%
kable(digits=1,
align=c("l",rep("c",5)),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> and other arthrodires using a model that includes shape as an additional categorical covariate",
col.names = c("Taxon","Specimen","Actual Length","Est.","+/- %PE","95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(4, bold = T)%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.4 | (11.8–15.1) | (9.8–18.4) |
Millerosteus minor | Composite Millerosteus | 14.9 | 15.5 | (13.6–17.4) | (11.4–21.2) |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 23.5 | (20.7–26.3) | (17.2–32.1) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 30.3 | (26.6–33.9) | (22.2–41.3) |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 33.5 | (29.5–37.6) | (24.5–45.8) |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 34.4 | (30.3–38.6) | (25.2–47) |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 34.9 | (30.7–39) | (25.5–47.6) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 41.8 | (36.8–46.8) | (30.6–57.1) |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 41.1 | (36.1–46) | (30.1–56.1) |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 40.5 | (35.6–45.4) | (29.6–55.3) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 48.8 | (42.9–54.7) | (35.7–66.6) |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 53.2 | (46.8–59.6) | (39–72.7) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 48.6 | (42.8–54.4) | (35.6–66.4) |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 61.8 | (54.3–69.2) | (45.2–84.4) |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 64.7 | (56.9–72.5) | (47.4–88.4) |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 65.6 | (57.8–73.5) | (48.1–89.7) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 92.2 | (81.1–103.2) | (67.5–125.9) |
Dunkleosteus terrelli | CMNH 7424 | NA | 181.5 | (159.7–203.3) | (132.9–247.9) |
Dunkleosteus terrelli | CMNH 6090 | NA | 270.7 | (238.2–303.3) | (198.2–369.8) |
Dunkleosteus terrelli | CMNH 7054 | NA | 282.3 | (248.3–316.3) | (206.7–385.6) |
Dunkleosteus terrelli | CMNH 5768 | NA | 324.8 | (285.8–363.9) | (237.8–443.7) |
10.6 Excluding acanthopterygian fishes
Because some of the highest systematic residuals in the model that could not be explained by changes in body shape were in acanthopterygian clades (i.e., Serranidae, Holocentridae, etc.) and acanthopterygians in general often show shortened or compressiform bodies with anteriorly positioned pelvic girdles (and the associated side effects on body shape), it is worth considering if the shorter lengths for Dunkleosteus terrelli predicted here might be biased by the inclusion of acanthopterygian lineages, which are expected to not be very similar to placoderms in body shape.
Because so many non-acanthopterygian actinopterygians have elongate bodies (gars, polypterids, eels, etc.) that are not typical for fishes more generally (especially when compared against the non-acanthopterygian fossil record), it is worth controlling for the effects of body shape on the model by excluding highly elongate taxa. Models were fit doing both below.
<-lm(log(total_length)~log(OOL),
fit.no_acanthopterygii%>%filter(higher_group!="Acanthoptergyii"))
data_final<-lm(log(total_length)~log(OOL),
fit.no_acanthopterygii2%>%filter(higher_group!="Acanthoptergyii",
data_final%in% c("elongate",
shape "fusiform")))
<-lm(log(total_length)~log(OOL),
fit.no_acanthopterygii3%>%filter(higher_group!="Acanthoptergyii",
data_final=="fusiform"))
shapesummary(fit.no_acanthopterygii)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL), data = data_final %>%
## filter(higher_group != "Acanthoptergyii"))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.61436 -0.14237 0.00201 0.13581 1.55312
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.900761 0.009076 209.4 <2e-16 ***
## log(OOL) 0.996190 0.004175 238.6 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2248 on 3167 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9473, Adjusted R-squared: 0.9473
## F-statistic: 5.693e+04 on 1 and 3167 DF, p-value: < 2.2e-16
rbind(
"All Taxa"=regression.stats(fit.no_acanthopterygii),
"Excluding anguilliform and macruriform taxa"=regression.stats(fit.no_acanthopterygii2),
"Fusiform taxa only"=regression.stats(fit.no_acanthopterygii3))
%>%
fossil_taxafilter(length_as=="total length"|specimen %in% c("CMNH 5768","CMNH 7424","CMNH 6090","CMNH 7054"))%>%
augment(fit.no_acanthopterygii,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.no_acanthopterygii2,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
augment(fit.no_acanthopterygii3,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit3",.)))%>%
mutate(across(fit1.fitted:fit1.upper,~exp(.)*regression.stats(fit.no_acanthopterygii)$CF),
across(fit2.fitted:fit2.upper,~exp(.)*regression.stats(fit.no_acanthopterygii2)$CF),
across(fit3.fitted:fit3.upper,~exp(.)*regression.stats(fit.no_acanthopterygii3)$CF))%>%
select(taxon,specimen,total_length,fit1.fitted,fit1.lower,fit1.upper,
fit2.fitted,fit2.lower,fit2.upper,%>%
fit3.fitted,fit3.lower,fit3.upper)arrange(fit1.fitted)%>%
kable(digits=1,align=c("l","c","c","c","c","c","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model that excludes acanthopterygian fishes",
col.names = c("Taxon","Specimen","Actual Length","Est.","Lwr 95% P.I.","Upr 95% P.I.",
"Est.","Lwr 95% P.I.","Upr 95% P.I.",
"Est.","Lwr 95% P.I.","Upr 95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(c(3,4,7,10), bold = T)%>%
add_header_above(c(" "=3,"All non-acanthopterygian fishes"=3,"Excluding anguilliform and macruriform taxa"=3,"Fusiform non-acanthopterygians only"=3))%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | Lwr 95% P.I. | Upr 95% P.I. | Est. | Lwr 95% P.I. | Upr 95% P.I. | Est. | Lwr 95% P.I. | Upr 95% P.I. |
---|---|---|---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.9 | 8.9 | 21.6 | 13.7 | 9.1 | 20.6 | 13.3 | 9.3 | 19.0 |
Millerosteus minor | Composite Millerosteus | 14.9 | 16.0 | 10.3 | 24.9 | 15.8 | 10.5 | 23.8 | 15.3 | 10.7 | 21.9 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 24.4 | 15.7 | 38.0 | 24.0 | 15.9 | 36.2 | 23.1 | 16.2 | 33.0 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 31.6 | 20.3 | 49.1 | 31.0 | 20.5 | 46.7 | 29.7 | 20.8 | 42.4 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 35.1 | 22.6 | 54.5 | 34.4 | 22.8 | 51.8 | 32.9 | 23.0 | 47.0 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 36.0 | 23.2 | 56.0 | 35.3 | 23.4 | 53.2 | 33.7 | 23.6 | 48.2 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 36.5 | 23.5 | 56.7 | 35.7 | 23.7 | 53.9 | 34.2 | 23.9 | 48.8 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 42.5 | 27.4 | 66.1 | 41.6 | 27.6 | 62.7 | 39.7 | 27.8 | 56.6 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 43.1 | 27.8 | 67.0 | 42.2 | 28.0 | 63.6 | 40.2 | 28.1 | 57.4 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 43.9 | 28.3 | 68.3 | 43.0 | 28.5 | 64.8 | 40.9 | 28.7 | 58.5 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 51.2 | 32.9 | 79.5 | 50.0 | 33.2 | 75.4 | 47.5 | 33.3 | 67.9 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 51.4 | 33.1 | 79.9 | 50.2 | 33.3 | 75.7 | 47.7 | 33.4 | 68.2 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 56.1 | 36.1 | 87.2 | 54.8 | 36.3 | 82.6 | 52.0 | 36.4 | 74.3 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 65.3 | 42.0 | 101.5 | 63.7 | 42.2 | 96.1 | 60.3 | 42.2 | 86.1 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 68.5 | 44.1 | 106.4 | 66.8 | 44.3 | 100.7 | 63.2 | 44.2 | 90.2 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 69.5 | 44.7 | 108.0 | 67.7 | 44.9 | 102.2 | 64.1 | 44.8 | 91.5 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 78.0 | 50.2 | 121.2 | 76.0 | 50.4 | 114.7 | 71.7 | 50.2 | 102.5 |
Dunkleosteus terrelli | CMNH 7424 | NA | 195.2 | 125.6 | 303.4 | 189.2 | 125.4 | 285.3 | 175.7 | 123.0 | 251.0 |
Dunkleosteus terrelli | CMNH 6090 | NA | 293.0 | 188.5 | 455.5 | 283.3 | 187.8 | 427.3 | 261.3 | 182.9 | 373.3 |
Dunkleosteus terrelli | CMNH 7054 | NA | 305.7 | 196.7 | 475.2 | 295.5 | 195.9 | 445.8 | 272.4 | 190.6 | 389.2 |
Dunkleosteus terrelli | CMNH 5768 | NA | 352.6 | 226.8 | 548.1 | 340.5 | 225.7 | 513.7 | 313.0 | 219.1 | 447.3 |
However, even when excluding acanthopterygian fishes, estimated lengths for Dunkleosteus were comparable to those of the acanthopterygian-only model. Thus, the short lengths for Dunkleosteus predicted here do not appear to be driven by very short-bodied or large-headed acanthopterygian taxa.
10.7 Considering both clade membership and body shape
One issue with the present model is most of the very largest fishes (3+ m) sampled tend to be pelagic Lamniformes or Echinorhinus spp. that are known to have very long heads relative to body length, whereas some of the most heavily sampled fishes larger than 1 m (i.e., between 1 and 2.5 m) are actinopterygian fishes with elongate trunk proportions (e.g., Tetrapturus, Kajikia, Coryphaena). This could potentially cause biases in estimates of body length for Dunkleosteus, especially given that Lamniformes and Echinorhiniformes tend to bias the correlation between total_length
and OOL
for sharks.
Because of this, a model was fit containing both clade
and shape
, assuming that shape
influences the model as an independent variable (given the residuals due to shape are primarily seen in the intercept) whereas different levels of clade
were allowed to have different slopes (given Lamniformes and Echinorhiniformes drive a different pattern in sharks). This would be expected to estimate length in Dunkleosteus terrelli without it being biased either by fishes with elongate body shapes or by short-bodied lamnids.
<-lm(log(total_length)~log(OOL)*clade+shape+(family=="Serranidae")+(family=="Holocentridae"),
fit.shape_clade
data_final)<-lm(log(total_length)~log(OOL)*clade+shape+(family=="Serranidae")+(family=="Holocentridae"),
fit.shape_clade_species_averages
data_species)<-lm(log(total_length)~log(OOL)*(clade=="Chondrichthyes")+
fit.shape_clade3+(family=="Serranidae")+(family=="Holocentridae"),
shape data_final)
10.7.1 Model including clade and body shape, using individual specimens
summary(fit.shape_clade)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * clade + shape + (family ==
## "Serranidae") + (family == "Holocentridae"), data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64651 -0.08889 0.00184 0.08189 1.17286
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.881731 0.007636 246.444 < 2e-16 ***
## log(OOL) 0.994611 0.003768 263.933 < 2e-16 ***
## cladeChondrichthyes 0.146538 0.026060 5.623 2.04e-08 ***
## cladePetromyzontiformes -0.466907 0.067481 -6.919 5.48e-12 ***
## cladePlacodermi 0.062857 0.153789 0.409 0.6828
## cladeSarcopterygii 1.261956 0.797538 1.582 0.1137
## shapeanguilliform 0.428570 0.018306 23.411 < 2e-16 ***
## shapecompressiform -0.103080 0.011315 -9.110 < 2e-16 ***
## shapeelongate 0.202419 0.009037 22.400 < 2e-16 ***
## shapeflattened 0.058220 0.032441 1.795 0.0728 .
## shapemacruriform 0.404113 0.026750 15.107 < 2e-16 ***
## family == "Serranidae"TRUE -0.325220 0.012314 -26.410 < 2e-16 ***
## family == "Holocentridae"TRUE -0.205108 0.027221 -7.535 6.35e-14 ***
## log(OOL):cladeChondrichthyes -0.069379 0.009473 -7.324 3.04e-13 ***
## log(OOL):cladePetromyzontiformes 0.098758 0.033894 2.914 0.0036 **
## log(OOL):cladePlacodermi -0.073990 0.082868 -0.893 0.3720
## log(OOL):cladeSarcopterygii -0.427682 0.263398 -1.624 0.1045
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1625 on 3152 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9726, Adjusted R-squared: 0.9725
## F-statistic: 6993 on 16 and 3152 DF, p-value: < 2.2e-16
10.7.2 Model including clade and body shape, using species averages
summary(fit.shape_clade_species_averages)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * clade + shape + (family ==
## "Serranidae") + (family == "Holocentridae"), data = data_species)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.61300 -0.09770 -0.00157 0.08416 1.14890
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.913225 0.015082 126.855 < 2e-16 ***
## log(OOL) 0.972992 0.008394 115.912 < 2e-16 ***
## cladeChondrichthyes 0.119128 0.058268 2.044 0.041181 *
## cladePetromyzontiformes -0.601871 0.203911 -2.952 0.003239 **
## cladePlacodermi 0.005422 0.226609 0.024 0.980915
## cladeSarcopterygii 2.174474 2.077767 1.047 0.295576
## shapeanguilliform 0.453944 0.034448 13.178 < 2e-16 ***
## shapecompressiform -0.069246 0.020145 -3.437 0.000613 ***
## shapeelongate 0.170646 0.019247 8.866 < 2e-16 ***
## shapeflattened 0.073032 0.051143 1.428 0.153620
## shapemacruriform 0.381784 0.046415 8.225 6.36e-16 ***
## family == "Serranidae"TRUE -0.285899 0.024694 -11.578 < 2e-16 ***
## family == "Holocentridae"TRUE -0.243648 0.053653 -4.541 6.31e-06 ***
## log(OOL):cladeChondrichthyes -0.044876 0.021958 -2.044 0.041261 *
## log(OOL):cladePetromyzontiformes 0.146836 0.143658 1.022 0.306981
## log(OOL):cladePlacodermi -0.026538 0.117171 -0.226 0.820873
## log(OOL):cladeSarcopterygii -0.717417 0.709414 -1.011 0.312139
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1848 on 950 degrees of freedom
## (4 observations deleted due to missingness)
## Multiple R-squared: 0.9598, Adjusted R-squared: 0.9592
## F-statistic: 1419 on 16 and 950 DF, p-value: < 2.2e-16
10.7.3 Model including clade and body shape, only considering membership in Chondrichthyes as important phylogenetic information
However, one issue with this is the small number of arthrodire taxa for which total length data was available. This means that the coefficient for placoderms has a great degree of uncertainty (=standard error). Examining the results of the model containing different coefficients for major fish clades found that only Chondrichthyes significantly differed from the other fish groups in slope, largely because the largest chondrichthyans are all short-bodied (mostly lamnids or other lamniforms like Megachasma). This suggests it might be better to simply consider a model treating membership in Chondrichthyes as a binary variable, as this would greatly lower uncertainty in the coefficient for clade
and thus improve model accuracy when estimating length in Dunkleosteus and other arthrodires.
summary(fit.shape_clade3)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * (clade == "Chondrichthyes") +
## shape + (family == "Serranidae") + (family == "Holocentridae"),
## data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.64269 -0.09281 -0.00968 0.08598 1.37524
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.881925 0.007824 240.524 < 2e-16 ***
## log(OOL) 0.993271 0.003830 259.341 < 2e-16 ***
## clade == "Chondrichthyes"TRUE 0.147315 0.026872 5.482 4.54e-08 ***
## shapeanguilliform 0.204540 0.009156 22.339 < 2e-16 ***
## shapecompressiform -0.101398 0.011667 -8.691 < 2e-16 ***
## shapeelongate 0.203976 0.009294 21.946 < 2e-16 ***
## shapeflattened 0.056591 0.033489 1.690 0.0912 .
## shapemacruriform 0.402741 0.027612 14.585 < 2e-16 ***
## family == "Serranidae"TRUE -0.322939 0.012690 -25.449 < 2e-16 ***
## family == "Holocentridae"TRUE -0.205049 0.028101 -7.297 3.71e-13 ***
## log(OOL):clade == "Chondrichthyes"TRUE -0.067440 0.009744 -6.921 5.41e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1677 on 3158 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9707, Adjusted R-squared: 0.9707
## F-statistic: 1.048e+04 on 10 and 3158 DF, p-value: < 2.2e-16
10.7.4 Regression statistics
rbind("Individual specimens"=regression.stats(fit.shape_clade),
"Species averages"=regression.stats(fit.shape_clade_species_averages),
"Only considering membership in Chondrichthyes"=regression.stats(fit.shape_clade3))
10.7.5 Predicting length in Dunkleosteus terrelli and other arthrodires
%>%
fossil_taxafilter(!!fossil.specimens)%>%
mutate(IsChondrichthyes=ifelse(clade=="Chondrichthyes",T,F))%>%
augment(fit.shape_clade,newdata=.,interval="predict")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.shape_clade_species_averages,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
augment(fit.shape_clade3,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit3",.)))%>%
mutate(across(fit1.fitted:fit1.upper,~exp(.)*regression.stats(fit.shape_clade)$CF),
across(fit2.fitted:fit2.upper,~exp(.)*regression.stats(fit.shape_clade_species_averages)$CF),
across(fit3.fitted:fit3.upper,~exp(.)*regression.stats(fit.shape_clade3)$CF))%>%
select(taxon,specimen,total_length,fit1.fitted,fit1.lower,fit1.upper,
fit2.fitted,fit2.lower,fit2.upper,%>%
fit3.fitted,fit3.lower,fit3.upper)arrange(fit1.fitted)%>%
kable(digits=1,align=c("l","c","c","c","c","c","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model considering both clade and body shape. 'Chondrichthyan-specific model' refers to model where only group membership considered was whether or not taxon was a member of Chondrichthyes.",
col.names = c("Taxon","Specimen","Actual Length","Est.","Lwr 95% P.I.","Upr 95% P.I.",
"Est.","Lwr 95% P.I.","Upr 95% P.I.",
"Est.","Lwr 95% P.I.","Upr 95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(c(3,4,7,10), bold = T)%>%
add_header_above(c(" "=3,"Individual Specimens"=3,"Species Averages"=3,"Chondrichthyan-Specific Model"=3))%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | Lwr 95% P.I. | Upr 95% P.I. | Est. | Lwr 95% P.I. | Upr 95% P.I. | Est. | Lwr 95% P.I. | Upr 95% P.I. |
---|---|---|---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.7 | 9.4 | 19.8 | 13.6 | 8.6 | 21.6 | 13.5 | 9.7 | 18.8 |
Millerosteus minor | Composite Millerosteus | 14.9 | 15.6 | 10.9 | 22.4 | 15.6 | 10.0 | 24.4 | 15.6 | 11.3 | 21.7 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 23.1 | 16.5 | 32.4 | 23.3 | 15.6 | 34.9 | 23.8 | 17.1 | 33.1 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 29.3 | 21.0 | 40.7 | 29.8 | 20.2 | 43.9 | 30.8 | 22.1 | 42.8 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 32.2 | 23.2 | 44.8 | 32.9 | 22.4 | 48.2 | 34.1 | 24.6 | 47.4 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 33.0 | 23.8 | 45.9 | 33.7 | 23.0 | 49.4 | 35.1 | 25.2 | 48.7 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 33.4 | 24.1 | 46.4 | 34.1 | 23.3 | 50.0 | 35.5 | 25.6 | 49.4 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 38.5 | 27.7 | 53.4 | 39.4 | 27.0 | 57.7 | 41.3 | 29.7 | 57.4 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 39.0 | 28.1 | 54.1 | 40.0 | 27.3 | 58.5 | 41.9 | 30.2 | 58.3 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 39.7 | 28.6 | 55.1 | 40.7 | 27.8 | 59.5 | 42.7 | 30.7 | 59.4 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 45.7 | 32.8 | 63.5 | 47.0 | 32.1 | 68.9 | 49.7 | 35.8 | 69.1 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 45.8 | 33.0 | 63.8 | 47.2 | 32.2 | 69.2 | 49.9 | 35.9 | 69.4 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 49.7 | 35.7 | 69.3 | 51.3 | 34.9 | 75.4 | 54.5 | 39.2 | 75.8 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 57.2 | 40.8 | 80.1 | 59.3 | 40.1 | 87.7 | 63.4 | 45.6 | 88.1 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 59.8 | 42.6 | 83.9 | 62.0 | 41.8 | 92.0 | 66.5 | 47.9 | 92.4 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 60.6 | 43.1 | 85.0 | 62.9 | 42.4 | 93.3 | 67.4 | 48.5 | 93.7 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 82.5 | 58.5 | 116.5 | 83.2 | 55.6 | 124.7 | 92.9 | 66.8 | 129.1 |
Dunkleosteus terrelli | CMNH 7424 | NA | 157.4 | 103.8 | 238.5 | 167.8 | 100.4 | 280.2 | 188.9 | 135.9 | 262.6 |
Dunkleosteus terrelli | CMNH 6090 | NA | 229.0 | 144.7 | 362.6 | 246.8 | 138.2 | 440.6 | 283.3 | 203.8 | 393.8 |
Dunkleosteus terrelli | CMNH 7054 | NA | 238.2 | 149.7 | 378.9 | 256.9 | 142.8 | 462.2 | 295.5 | 212.6 | 410.8 |
Dunkleosteus terrelli | CMNH 5768 | NA | 271.8 | 168.0 | 439.6 | 294.2 | 159.4 | 542.8 | 340.7 | 245.1 | 473.6 |
As an example of what is meant by the small sample size of Arthrodira reducing model precision, compare the prediction intervals for the model including clade
as a categorical variable with the one only using a binary variable considering whether or not a taxon belongs to Chondrichthyes. The prediction intervals of the latter are much smaller, and this is because of the much greater standard error for cladePlacodermi
and the interaction between Placodermi
and log(OOL)
compared to Actinopterygii and Chondrichthyes when each clade is considered by themselves.
11 Allowing relative body depth to influence length estimates
ggplot(data_final%>%
filter(!is.na(OOL),!is.na(total_length),length_as!="estimated t.l.")%>%
mutate(residuals=residuals(fit.OOL),
shape=relevel(
factor(ifelse(family=="Serranidae","Serranidae",as.character(shape))),ref="fusiform"))%>%
filter(!family %in% c("Monacanthidae","Balistidae","Acanthuridae")),
aes(I(body_depth/total_length),residuals))+
geom_star(aes(fill=shape,starshape=clade))+
geom_smooth(data=.%>%filter(!family %in% c("Serranidae", "Balistidae", "Holocentridae", "Acanthuridae", "Monacanthidae"),clade!="Petromyzontiformes"),aes(color="2"),formula=y~x,method="loess")+
geom_smooth(formula=y~x,method="lm",aes(color="1"))+
scale_starshape_manual(values=c(15,11,13,1,28))+
scale_color_manual(labels=c("Lm model of all taxa","Loess fit excluding unusual taxa"),values=c(hue_pal()(2)))+
labs(x="Aspect Ratio of Body (body depth/total length)",y="Residuals of OOL Equation",
starshape="Clade",fill="Shape",colour="Color")+
theme(legend.box = "horizontal",legend.position = c(0.55,0.7))+
guides(fill = guide_legend(override.aes = list(starshape = 15)))
Figure 11.1: Plot between residuals of the all-specimen model (fit.OOL
) and aspect ratio (body_depth
/total_length
). Taxa with posteriorly shifted orbits (Balistoidea and Acanthuridae) omitted to better show patterns in the model. For the loess model, “unusual taxa” refers to members of the clades Petromyzontiformes, Serranidae, Holocenridae, Acanthuridae, Balistidae, and Monacanthidae, which appear to show unusual patterns in residuals separate from the general non-linear correlation between the residuals and body shape.
Note the non-linear relationship between body shape and the residuals of the model, in which there is next to no correlation between the residuals and body shape among compressiform taxa, but there is a pattern of ever-increasing residuals among elongate and anguilliform taxa (especially anguilliform gnathostomes), representing an acceleration in axial elongation relative to the head with increasing aspect ratio.
summary(lm(residuals~I(body_depth/total_length),
%>%
data_finalfilter(!is.na(OOL),!is.na(total_length),length_as!="estimated t.l.")%>%
mutate(residuals=residuals(fit.OOL))))
##
## Call:
## lm(formula = residuals ~ I(body_depth/total_length), data = data_final %>%
## filter(!is.na(OOL), !is.na(total_length), length_as != "estimated t.l.") %>%
## mutate(residuals = residuals(fit.OOL)))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.51018 -0.11320 -0.01116 0.11167 1.41891
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.206770 0.007739 26.72 <2e-16 ***
## I(body_depth/total_length) -1.046554 0.034533 -30.31 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1943 on 2843 degrees of freedom
## (324 observations deleted due to missingness)
## Multiple R-squared: 0.2442, Adjusted R-squared: 0.2439
## F-statistic: 918.5 on 1 and 2843 DF, p-value: < 2.2e-16
As noted by the above report, there is a significant correlation between the residuals of the model and aspect ratio.
11.1 Fitting models including body height as an explanatory variable
11.1.1 Model including body_depth
as additional variable, both as a separate coefficient and considering interaction effects with OOL
<-lm(log(total_length)~
fit.relativedepth1log(OOL)*I(body_depth),
%>% filter(length_as!="estimated t.l."))
data_final summary(fit.relativedepth1)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * I(body_depth), data = data_final %>%
## filter(length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.5986 -0.1372 0.0104 0.1265 1.5669
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.8648663 0.0114444 162.950 <2e-16 ***
## log(OOL) 1.0289687 0.0069719 147.587 <2e-16 ***
## I(body_depth) -0.0033954 0.0016228 -2.092 0.0365 *
## log(OOL):I(body_depth) 0.0004491 0.0003985 1.127 0.2599
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2227 on 2841 degrees of freedom
## (338 observations deleted due to missingness)
## Multiple R-squared: 0.9446, Adjusted R-squared: 0.9445
## F-statistic: 1.614e+04 on 3 and 2841 DF, p-value: < 2.2e-16
11.1.2 Model including interaction between body_depth
and OOL
only
<-lm(log(total_length)~
fit.relativedepth2log(OOL)*log(body_depth)-log(body_depth),
%>% filter(length_as!="estimated t.l."))
data_final summary(fit.relativedepth2)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) * log(body_depth) -
## log(body_depth), data = data_final %>% filter(length_as !=
## "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.60144 -0.13620 0.00993 0.11746 1.56573
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.839404 0.011329 162.36 < 2e-16 ***
## log(OOL) 1.061878 0.009884 107.43 < 2e-16 ***
## log(OOL):log(body_depth) -0.013968 0.002340 -5.97 2.67e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2218 on 2842 degrees of freedom
## (338 observations deleted due to missingness)
## Multiple R-squared: 0.945, Adjusted R-squared: 0.945
## F-statistic: 2.442e+04 on 2 and 2842 DF, p-value: < 2.2e-16
11.1.3 Model including coefficient only
<-lm(log(total_length)~
fit.relativedepth3log(OOL)+log(body_depth),
%>% filter(length_as!="estimated t.l."))
data_final summary(fit.relativedepth3)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + log(body_depth),
## data = data_final %>% filter(length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.60060 -0.13218 0.00929 0.10956 1.59636
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.893312 0.009690 195.381 <2e-16 ***
## log(OOL) 1.073542 0.008044 133.464 <2e-16 ***
## log(body_depth) -0.069984 0.007274 -9.622 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2197 on 2842 degrees of freedom
## (338 observations deleted due to missingness)
## Multiple R-squared: 0.9461, Adjusted R-squared: 0.946
## F-statistic: 2.493e+04 on 2 and 2842 DF, p-value: < 2.2e-16
11.1.4 Model using integer of head length
/body_depth
to model effects of shape on regression
<-lm(log(total_length)~
fit.relativedepth4log(OOL)+I(head_length/body_depth),
%>% filter(length_as!="estimated t.l."))
data_final summary(fit.relativedepth4)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + I(head_length/body_depth),
## data = data_final %>% filter(length_as != "estimated t.l."))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.5752 -0.1218 -0.0119 0.1107 1.6061
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1.796274 0.010154 176.91 <2e-16 ***
## log(OOL) 1.001132 0.004382 228.46 <2e-16 ***
## I(head_length/body_depth) 0.057405 0.003191 17.99 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2115 on 2842 degrees of freedom
## (338 observations deleted due to missingness)
## Multiple R-squared: 0.95, Adjusted R-squared: 0.95
## F-statistic: 2.701e+04 on 2 and 2842 DF, p-value: < 2.2e-16
11.2 Support statistics of models
rbind("With no Shape Information"=regression.stats(fit.OOL),
"With Body Shape as Categorical Variable"=regression.stats(fit.with_shape),
"With Coefficient and Interaction Term from Body Height"=regression.stats(fit.relativedepth1),
"With Interaction Term Only"=regression.stats(fit.relativedepth2),
"With Coefficient Only"=regression.stats(fit.relativedepth3),
"Using Integer of Head Length/Body Height"=regression.stats(fit.relativedepth4))
However, when comparing the model support statistics, while it can be seen that including relative body height as a covariate produces slightly better support in terms of AIC, BIC, and %PE values than a model that does not consider body shape, they perform much more poorly than models that simply brute-forces variation in body shape into a single categorical variable. Thus, it is clear that although covariation between body shape and aspect ratio are affecting length estimates, simply adding in body height as a covarying term does not produce a significant improvement in results in the model here.
11.3 Estimated lengths for Dunkleosteus
%>%
fossil_taxafilter(!!fossil.specimens,!is.na(body_depth),clade=="Placodermi")%>%
augment(fit.relativedepth1,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.relativedepth1)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.relativedepth2,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.relativedepth2)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
augment(fit.relativedepth3,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.relativedepth3)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit3",.)))%>%
augment(fit.relativedepth4,newdata=.,interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.relativedepth4)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit4",.)))%>%
arrange(fit1.fitted)%>%
mutate(range1=paste0("(",round(fit1.lower,1),"-",round(fit1.upper,1),")"),
range2=paste0("(",round(fit2.lower,1),"-",round(fit2.upper,1),")"),
range3=paste0("(",round(fit3.lower,1),"-",round(fit3.upper,1),")"),
range4=paste0("(",round(fit4.lower,1),"-",round(fit4.upper,1),")"),
PE1_lower=fit1.fitted*(1-(regression.stats(fit.relativedepth1)$adjPE)/100),
PE1_upper=fit1.fitted*(1+(regression.stats(fit.relativedepth1)$adjPE)/100),
PE2_lower=fit2.fitted*(1-(regression.stats(fit.relativedepth2)$adjPE)/100),
PE2_upper=fit2.fitted*(1+(regression.stats(fit.relativedepth2)$adjPE)/100),
PE3_lower=fit3.fitted*(1-(regression.stats(fit.relativedepth3)$adjPE)/100),
PE3_upper=fit3.fitted*(1+(regression.stats(fit.relativedepth3)$adjPE)/100),
PE4_lower=fit4.fitted*(1-(regression.stats(fit.relativedepth4)$adjPE)/100),
PE4_upper=fit4.fitted*(1+(regression.stats(fit.relativedepth4)$adjPE)/100),
PE_range1=paste0("(",round(PE1_lower,1),"-",round(PE1_upper,1),")"),
PE_range2=paste0("(",round(PE2_lower,1),"-",round(PE2_upper,1),")"),
PE_range3=paste0("(",round(PE3_lower,1),"-",round(PE3_upper,1),")"),
PE_range4=paste0("(",round(PE4_lower,1),"-",round(PE4_upper,1),")"))%>%
select(taxon,specimen,total_length,
fit1.fitted,PE_range1,range1,
fit2.fitted,PE_range2,range2,
fit3.fitted,PE_range3,range3,%>%
fit4.fitted,PE_range4,range4)kable(digits=1,
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model that incorporates relative body depth. All lengths in cm.",
col.names = c("Taxon","Specimen","Actual Length",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
add_header_above(c(" "=3,"Including coefficient and interaction effect"=3,"Interaction effect with OOL only"=3,"Body depth as coefficient only"=3,
"Integer of head_length/body_depth"=3))%>%
column_spec(1,italic=T)%>%
column_spec(c(4,7,10,13),bold=T)%>%
kable_styling()%>%
scroll_box(width = "100%")
Taxon | Specimen | Actual Length | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Millerosteus minor | Composite Millerosteus | 14.9 | 15.9 | (13.2-18.6) | (10.2-24.5) | 15.9 | (13.2-18.5) | (10.3-24.5) | 15.9 | (13.3-18.5) | (10.3-24.5) | 15.5 | (13-18) | (10.2-23.5) |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 24.5 | (20.3-28.6) | (15.8-37.9) | 24.6 | (20.5-28.8) | (15.9-38) | 24.6 | (20.6-28.7) | (16-37.9) | 24.0 | (20.1-27.9) | (15.8-36.3) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 31.8 | (26.4-37.2) | (20.5-49.2) | 32.0 | (26.6-37.3) | (20.7-49.4) | 31.6 | (26.4-36.8) | (20.5-48.6) | 30.7 | (25.7-35.6) | (20.3-46.4) |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 36.6 | (30.4-42.8) | (23.7-56.7) | 36.8 | (30.6-42.9) | (23.8-56.8) | 35.8 | (29.9-41.7) | (23.2-55) | 34.9 | (29.3-40.6) | (23.1-52.9) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 44.4 | (36.9-52) | (28.7-68.8) | 44.7 | (37.1-52.2) | (28.9-69) | 44.0 | (36.8-51.3) | (28.6-67.7) | 42.4 | (35.5-49.2) | (28-64.2) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 51.2 | (42.5-59.9) | (33.1-79.3) | 51.4 | (42.7-60) | (33.3-79.4) | 49.6 | (41.4-57.8) | (32.2-76.3) | 48.6 | (40.8-56.5) | (32.1-73.7) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 52.0 | (43.2-60.9) | (33.6-80.5) | 52.2 | (43.4-61) | (33.8-80.6) | 51.2 | (42.8-59.6) | (33.3-78.8) | 49.5 | (41.5-57.5) | (32.7-75) |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 65.8 | (54.6-77) | (42.5-101.9) | 65.9 | (54.8-77) | (42.6-101.8) | 64.2 | (53.6-74.8) | (41.7-98.8) | 62.4 | (52.3-72.5) | (41.2-94.5) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 78.3 | (65-91.7) | (50.6-121.3) | 78.4 | (65.2-91.6) | (50.7-121.1) | 76.3 | (63.7-88.8) | (49.6-117.4) | 74.3 | (62.3-86.3) | (49.1-112.5) |
Dunkleosteus terrelli | CMNH 7424 | NA | 196.7 | (163.1-230.2) | (127-304.5) | 194.3 | (161.6-227) | (125.7-300.3) | 195.6 | (163.4-227.8) | (127.1-301) | 188.9 | (158.4-219.4) | (124.7-286.1) |
Dunkleosteus terrelli | CMNH 6090 | NA | 282.7 | (234.5-330.9) | (182.3-438.5) | 283.1 | (235.4-330.7) | (183-437.7) | 288.9 | (241.3-336.5) | (187.7-444.6) | 280.6 | (235.3-326) | (185.3-425.1) |
Dunkleosteus terrelli | CMNH 7054 | NA | 297.4 | (246.7-348.1) | (191.8-461.1) | 296.1 | (246.2-345.9) | (191.5-457.8) | 303.3 | (253.4-353.3) | (197.1-466.8) | 294.0 | (246.4-341.5) | (194.1-445.3) |
Dunkleosteus terrelli | CMNH 5768 | NA | 323.7 | (268.5-378.9) | (207.8-504.3) | 333.3 | (277.2-389.4) | (215.4-515.6) | 342.6 | (286.2-399.1) | (222.6-527.5) | 335.4 | (281.1-389.6) | (221.4-508) |
12 Investigating effect of snout length on regression equation
12.1 Statistics of model including snout length
<-lm(log(total_length)~log(snout_length)+log(OOL),
with_snout_lengthdata=data_final)
summary(with_snout_length)
##
## Call:
## lm(formula = log(total_length) ~ log(snout_length) + log(OOL),
## data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.53993 -0.11835 0.00076 0.10939 1.60679
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.123972 0.010160 209.06 <2e-16 ***
## log(snout_length) 0.230067 0.006753 34.07 <2e-16 ***
## log(OOL) 0.748199 0.008108 92.28 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1923 on 3166 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9614, Adjusted R-squared: 0.9614
## F-statistic: 3.947e+04 on 2 and 3166 DF, p-value: < 2.2e-16
rbind("Without Snout Length"=regression.stats(fit.OOL),
"With Snout Length"=regression.stats(with_snout_length))
From this it is very clear that among the sample of extant fishes, including snout length as an extra explanatory term in the model such that pre-orbital and OOL regions of the skull are allowed to scale independently has a better accuracy in estimating total length than just using OOL by itself.
12.2 Predicting length in arthrodires using snout length
%>%
fossil_taxafilter(!is.na(snout_length),!!fossil.specimens,clade=="Placodermi")%>%
mutate(estimated_length_with_snout=exp(predict(with_snout_length,.))*regression.stats(with_snout_length)$CF,
estimated_length=exp(predict(fit.OOL,.))*regression.stats(fit.OOL)$CF)%>%
mutate(PE_snout=(estimated_length_with_snout-total_length)/estimated_length_with_snout,
PE=(estimated_length-total_length)/estimated_length)%>%
rownames_to_column()%>%
select(taxon,specimen,total_length,estimated_length,PE,estimated_length_with_snout,PE_snout)%>%
kable(digits=c(1,1,1,1,3,1,3),align=c("l","c","c","c","c","c","c"),
col.names = c("Taxon","Specimen","Total Length","Estimated Length","%PE","Estimated Length","%PE"),
caption="Predicting length in whole-body arthrodire specimens with OOL including snout length as an additional variable")%>%
add_header_above(c(" "=3,"Without Snout Length"=2,
"With Snout Length"=2))%>%
column_spec(1,italic=T)%>%
column_spec(c(4,6),bold=T)%>%
kable_styling()
Taxon | Specimen | Total Length | Estimated Length | %PE | Estimated Length | %PE |
---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 13.9 | 0.011 | 11.0 | -0.247 |
Millerosteus minor | Composite Millerosteus | 14.9 | 16.0 | 0.068 | 14.4 | -0.039 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 24.4 | 0.059 | 22.1 | -0.040 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 31.6 | 0.043 | 27.4 | -0.104 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 35.1 | 0.156 | 29.5 | -0.003 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 36.0 | 0.105 | 30.7 | -0.051 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 36.5 | -0.017 | 32.2 | -0.152 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 43.9 | 0.103 | 30.6 | -0.289 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 43.1 | 0.203 | 31.8 | -0.080 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 42.5 | 0.118 | 35.5 | -0.056 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 51.4 | 0.270 | 39.8 | 0.058 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 56.1 | 0.221 | 37.9 | -0.152 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 51.2 | -0.185 | 45.8 | -0.325 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 65.3 | 0.133 | 52.7 | -0.074 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 68.5 | 0.080 | 57.9 | -0.087 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 69.5 | 0.247 | 59.4 | 0.119 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 78.0 | -0.150 | 62.5 | -0.435 |
Dunkleosteus terrelli | CMNH 7424 | NA | 195.2 | NA | 153.2 | NA |
Dunkleosteus terrelli | CMNH 6090 | NA | 293.0 | NA | 227.4 | NA |
Dunkleosteus terrelli | CMNH 7054 | NA | 305.7 | NA | 239.8 | NA |
Dunkleosteus terrelli | CMNH 5768 | NA | 352.6 | NA | 272.0 | NA |
12.3 Relative snout length proportions in fishes
grid.arrange(nrow=1,
ggplot(data_final%>%
drop_na(head_length,snout_length)%>%
filter(clade!="Petromyzontiformes",
!="Blenniiformes"),
orderaes(y=snout_length,x=head_length))+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
geom_star(aes(color=clade,starshape=clade))+
geom_star(aes(fill=clade,starshape=clade))+
geom_smooth(formula=y~x,method="lm")+
geom_smooth(data=.%>%filter(clade=="Placodermi"),aes(color=clade),
formula=y~x,method="lm")+
labs(x="Head Length (mm)",y="Snout Length (mm)")+
scale_starshape_manual(values=c(15,15,1,15))+
scale_color_manual(values=c(NA,NA,hue_pal()(4)[3],NA),na.value=NA)+
geom_star(aes(fill=clade,starshape=clade),
data=.%>%filter(clade=="Placodermi"),size=2)+
ggtitle("Versus Head Length")+
theme(legend.position="none"),
ggplot(data_final%>%
drop_na(total_length,snout_length)%>%
filter(!clade %in% c("Petromyzontiformes"),
!="Blenniiformes"),
orderaes(y=snout_length,x=total_length))+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
geom_star(aes(color=clade,starshape=clade))+
geom_star(aes(fill=clade,starshape=clade))+
geom_smooth(formula=y~x,method="lm")+
scale_starshape_manual(values=c(15,15,1,15))+
geom_smooth(data=.%>%filter(clade=="Placodermi"),formula=y~x,method="lm",
aes(color=clade))+
geom_star(aes(fill=clade,starshape=clade),
data=.%>%filter(clade=="Placodermi"),size=2)+
ggtitle("Versus Total Length")+
scale_color_manual(values=c(NA,NA,hue_pal()(4)[3],NA),na.value=NA)+
labs(x="Total Length (mm)",y="Snout Length (mm)",fill="Clade",
color="Clade",starshape="Clade")+
theme(legend.position=c(0.85,0.2)))
Figure 12.1: Graph of snout length versus head length (left) and total length (right), showing how arthrodire placoderms have significantly shorter snouts than extant fishes. Blenniiformes (in which snout length is near zero) omitted for visualization purposes. All axes here using a log10 scale.
ggplot(data_final%>%
filter(!is.na(total_length) & !is.na(OOL),
!="estimated t.l.")%>%
length_asmutate(residuals=fit.OOL$residuals)%>%
filter(order!="Blenniiformes"),
#Note: Blenniiformes was excluded for clarity because many blennies have eyes that are at the very anterior end of their skull, thus head_length==postorbital length or is very close, and when log-transformed this causes issues with plotting the results.
aes(x=snout_length,y=residuals))+
scale_x_continuous(trans="log10")+
geom_star(aes(fill=clade,starshape=clade))+
geom_star(data=.%>%filter(clade=="Placodermi"),
aes(starshape=clade),fill="white",color="white",size=3,show.legend=F)+
geom_star(data=.%>%filter(clade=="Placodermi"),size=2.5,
aes(fill=clade,starshape=clade),show.legend=F)+
scale_starshape_manual(values=c(15,13,11,1,28))+
geom_smooth(formula=y~x,method="lm")+
labs(x="Snout Length (mm)",y="Residuals of OOL Equation",color="Clade",fill="Clade",starshape="Clade")+
theme(legend.position=c(0.15,0.8))
Figure 12.2: Graph of the residuals of the OOL equation against log-transformed snout length, showing how snout length has a slight allometric correlation with total length in fishes, but that the short snout of arthrodires does not appear to strongly influence their regression results. Note that Blenniiformes was excluded due to the fact that OOL and head length in these taxa are almost equal, which causes problems with log-transforming snout-length (i.e., snout_length
=0).
12.3.1 Scatter plot of percent snout length versus head length
grid.arrange(nrow=1,
ggplot(data_final%>%filter(!is.na(snout_length),!is.na(head_length)),
aes(x=head_length,
y=snout_length/head_length))+
ggtitle("A")+
geom_star(aes(fill=clade),.%>%filter(clade!="Placodermi"),starshape=15)+
geom_smooth(formula=y~x,method="lm",aes(color=clade),alpha=0.25)+
scale_x_continuous(trans="log10")+
geom_star(data=.%>%filter(clade=="Placodermi"),fill="white",color="white",size=3)+
geom_star(data=.%>%filter(clade=="Placodermi"),aes(fill=clade),size=2.5)+
labs(color="Clade",y="Percent Snout Length",x="Head Length (cm)")+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
theme(legend.position="none"),
ggplot(data_final%>%filter(!is.na(snout_length),!is.na(head_length)),
aes(x=clade,
y=snout_length/head_length))+
ggtitle("B")+
geom_hline(aes(yintercept=mean(snout_length/head_length)),linetype="dashed")+
geom_violin(scale="width",aes(fill=clade))+
geom_boxplot(width=0.4)+
labs(fill="Clade",y="Snout Length As % Head Length",x="Clade")+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
theme(legend.position=c(0.8,0.8),
axis.text.x=element_text(angle = 45, vjust = 1, hjust=1)))
Figure 12.3: Scatter plot (A) and box-and-whisker plot (B) of snout length as a percentage of head length in fishes, showing how arthrodire placoderms have significantly shorter snouts than other groups.
12.4 Percent snout length with species-average values
%>%
data_finaldrop_na(snout_length,head_length)%>%
group_by(taxon)%>%
summarise(snout_length=mean(snout_length),
head_length=mean(head_length),
clade=unique(clade))%>%
ggplot(aes(x=head_length,
y=snout_length/head_length))+
geom_star(aes(fill=clade,starshape=clade))+
scale_starshape_manual(values=c(15,15,15,1,15))+
geom_smooth(formula=y~x,method="lm",aes(color=clade),alpha=0.25)+
geom_star(aes(fill=clade,starshape=clade),
%>%filter(clade=="Placodermi"),size=2.5)+
.scale_x_continuous(trans="log10")+
scale_y_continuous(labels=scales::label_percent(accuracy = 1))+
labs(color="Clade",y="Percent Snout Length",x="Head Length (cm)")
12.5 Model including snout length, with variable clade level
%>%
data_finaldrop_na(total_length,snout_length,OOL)%>%
group_by(taxon)%>%
summarise(across(c(total_length,OOL,snout_length),~mean(.)),
clade=unique(clade))%$%
lm(log(total_length)~log(OOL)+log(snout_length)*clade-clade)%>%
summary()
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + log(snout_length) *
## clade - clade)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.49251 -0.12031 -0.01528 0.10390 1.64507
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.14344 0.01918 111.780 < 2e-16 ***
## log(OOL) 0.72853 0.01558 46.771 < 2e-16 ***
## log(snout_length) 0.22709 0.01257 18.072 < 2e-16 ***
## log(snout_length):cladeChondrichthyes 0.03629 0.01008 3.602 0.000332 ***
## log(snout_length):cladePetromyzontiformes 0.02559 0.08246 0.310 0.756392
## log(snout_length):cladePlacodermi 0.21507 0.12085 1.780 0.075457 .
## log(snout_length):cladeSarcopterygii 0.04514 0.05773 0.782 0.434520
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2013 on 964 degrees of freedom
## Multiple R-squared: 0.9517, Adjusted R-squared: 0.9514
## F-statistic: 3163 on 6 and 964 DF, p-value: < 2.2e-16
ANOVA examining if snout proportions (as a percentage of total length) are consistent across fishes
%>%
data_finaldrop_na(total_length,snout_length)%>%
group_by(taxon)%>%
summarise(across(c(total_length,snout_length),~mean(.)),
clade=unique(clade))%>%
mutate(percent_snout=snout_length/total_length)%>%
lm(percent_snout~clade,.) %>% summary()
##
## Call:
## lm(formula = percent_snout ~ clade, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.064330 -0.021019 -0.004309 0.013836 0.225219
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.072032 0.001173 61.403 < 2e-16 ***
## cladeChondrichthyes -0.004917 0.002688 -1.829 0.067652 .
## cladePetromyzontiformes 0.003276 0.011561 0.283 0.776977
## cladePlacodermi -0.039715 0.010354 -3.836 0.000133 ***
## cladeSarcopterygii -0.011592 0.018819 -0.616 0.538056
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03253 on 966 degrees of freedom
## Multiple R-squared: 0.01816, Adjusted R-squared: 0.01409
## F-statistic: 4.467 on 4 and 966 DF, p-value: 0.001399
ANOVA examining if snout proportions (as a percentage of head length) are consistent across fishes
%>%
data_finaldrop_na(head_length,snout_length)%>%
group_by(taxon)%>%
summarise(across(c(head_length,snout_length),~mean(.)),
clade=unique(clade))%>%
mutate(percent_snout=snout_length/head_length)%>%
lm(percent_snout~clade,.) %>% summary()
##
## Call:
## lm(formula = percent_snout ~ clade, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.26808 -0.07084 -0.01686 0.05106 0.53431
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.307864 0.003818 80.631 < 2e-16 ***
## cladeChondrichthyes -0.005443 0.008747 -0.622 0.534
## cladePetromyzontiformes 0.030406 0.037629 0.808 0.419
## cladePlacodermi -0.146713 0.020029 -7.325 4.96e-13 ***
## cladeSarcopterygii -0.020117 0.061249 -0.328 0.743
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1059 on 985 degrees of freedom
## Multiple R-squared: 0.05254, Adjusted R-squared: 0.04869
## F-statistic: 13.66 on 4 and 985 DF, p-value: 7.683e-11
Based on this, it appears that arthrodires, on average, have shorter snouts (preorbital length) than chondrichthyans, actinopterygians, lampreys, and sarcopterygians. Note the magnitude of the interaction coefficient for arthrodire is much greater than all other fish clades.
<-lm(log(total_length)~log(OOL)+log(snout_length)*clade-clade,
fit.snout_with_clade
data_final)<-lm(log(total_length)~log(OOL)+log(snout_length)*clade,
fit.snout_with_clade2
data_final)summary(fit.snout_with_clade)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + log(snout_length) *
## clade - clade, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.51864 -0.11471 -0.00656 0.10149 1.62303
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.114605 0.010755 196.611 < 2e-16 ***
## log(OOL) 0.750201 0.008652 86.708 < 2e-16 ***
## log(snout_length) 0.222808 0.006860 32.481 < 2e-16 ***
## log(snout_length):cladeChondrichthyes 0.014307 0.005065 2.825 0.00476 **
## log(snout_length):cladePetromyzontiformes 0.059586 0.007983 7.464 1.08e-13 ***
## log(snout_length):cladePlacodermi 0.018512 0.084207 0.220 0.82601
## log(snout_length):cladeSarcopterygii -0.002155 0.022507 -0.096 0.92373
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1907 on 3162 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9621, Adjusted R-squared: 0.9621
## F-statistic: 1.339e+04 on 6 and 3162 DF, p-value: < 2.2e-16
rbind("Without Snout Length"=regression.stats(fit.OOL),
"With Snout Length"=regression.stats(with_snout_length),
"With Snout Length and Interaction Effect from Clade"=regression.stats(fit.snout_with_clade),
"With Clade as Both Interaction Factor and Variable"=regression.stats(fit.snout_with_clade2))
The equation here is written as…
\[ \text{lm(log(total_length)~log(OOL)+log(snout_length)*clade-clade} \]
This is necessary because the variable of interest is the interaction between snout length and clade membership. I.e., the equation needs to compensate for the fact that arthrodires have shorter snouts than other fishes. If the term ‘-clade’ is not included, then clade
by itself will be considered as an additional explanatory variable in the analysis.
summary(fit.snout_with_clade2)
##
## Call:
## lm(formula = log(total_length) ~ log(OOL) + log(snout_length) *
## clade, data = data_final)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.51712 -0.10989 -0.00940 0.09613 1.62826
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.106300 0.010745 196.029 < 2e-16 ***
## log(OOL) 0.747107 0.008624 86.636 < 2e-16 ***
## log(snout_length) 0.229552 0.006872 33.405 < 2e-16 ***
## cladeChondrichthyes 0.147970 0.020886 7.085 1.71e-12 ***
## cladePetromyzontiformes 0.122775 0.039255 3.128 0.00178 **
## cladePlacodermi 0.141851 0.047082 3.013 0.00261 **
## cladeSarcopterygii 0.637408 0.555843 1.147 0.25158
## log(snout_length):cladeChondrichthyes -0.051917 0.010709 -4.848 1.31e-06 ***
## log(snout_length):cladePetromyzontiformes -0.023348 0.028515 -0.819 0.41297
## log(snout_length):cladePlacodermi -0.026928 0.084682 -0.318 0.75051
## log(snout_length):cladeSarcopterygii -0.297530 0.259823 -1.145 0.25224
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1888 on 3158 degrees of freedom
## (53 observations deleted due to missingness)
## Multiple R-squared: 0.9629, Adjusted R-squared: 0.9628
## F-statistic: 8206 on 10 and 3158 DF, p-value: < 2.2e-16
As seen here, the interaction between snout length
and clade
is no longer significant, but general clade membership in Placodermi is. This means the model is not accounting for variation driven by the shorter snouts of arthrodires, but is polarized by general residual variation between measured arthrodires and other fishes (except for snout length, since that is represented by the term log(snout_length):cladePlacodermi
). This residual variation may not characterize Dunkleosteus, especially because it is largely driven by pattern in coccosteomorphs.
However, for the sake of transparency, the results of both are presented here.
%>%
fossil_taxafilter(length_as=="total length"|specimen %in% c("CMNH 5768","CMNH 7424","CMNH 6090","CMNH 7054"))%>%
augment(fit.snout_with_clade,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.snout_with_clade2,newdata=.,interval="prediction")%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(across(fit1.fitted:fit1.upper,~exp(.)*regression.stats(fit.snout_with_clade)$CF),
across(fit2.fitted:fit2.upper,~exp(.)*regression.stats(fit.snout_with_clade2)$CF))%>%
mutate(PE1_lower=fit1.fitted*(1-(regression.stats(fit.relativedepth1)$adjPE)/100),
PE1_upper=fit1.fitted*(1+(regression.stats(fit.relativedepth1)$adjPE)/100),
PE2_lower=fit2.fitted*(1-(regression.stats(fit.relativedepth2)$adjPE)/100),
PE2_upper=fit2.fitted*(1+(regression.stats(fit.relativedepth2)$adjPE)/100),
range1=paste0("(",round(fit1.lower,1),"-",round(fit1.upper,1),")"),
range2=paste0("(",round(fit2.lower,1),"-",round(fit2.upper,1),")"),
PE_range1=paste0("(",round(PE1_lower,1),"-",round(PE1_upper,1),")"),
PE_range2=paste0("(",round(PE2_lower,1),"-",round(PE2_upper,1),")"))%>%
select(taxon,specimen,total_length,fit1.fitted,PE_range1,range1,
%>%
fit2.fitted,PE_range2,range2)arrange(fit1.fitted)%>%
kable(digits=1,align=c("l","c","c","c","c","c","c","c","c"),
caption= "Length estimates for specimens of <i>Dunkleosteus terrelli</i> using a model that includes snout length but allows for snout length to vary by clade",
col.names = c("Taxon","Specimen","Actual Length","Est.","+/- %PE.","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
column_spec(1, italic = T)%>%
column_spec(c(3,4,7), bold = T)%>%
add_header_above(c(" "=3,"Model with covarying term for clade only"=3,"Model with extra term for clade"=3))%>%
kable_styling()
Taxon | Specimen | Actual Length | Est. | +/- %PE. | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 10.8 | (8.9-12.6) | (7.1-16.5) | 12.9 | (10.7-15.1) | (8.3-20) |
Millerosteus minor | Composite Millerosteus | 14.9 | 14.2 | (11.8-16.6) | (9.7-20.8) | 16.5 | (13.8-19.3) | (11.2-24.5) |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 22.0 | (18.2-25.7) | (15.1-31.9) | 25.1 | (20.8-29.3) | (17.1-36.7) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 27.3 | (22.6-31.9) | (18.8-39.6) | 31.0 | (25.8-36.2) | (21.2-45.3) |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 29.4 | (24.4-34.4) | (20.2-42.7) | 33.4 | (27.8-39) | (22.8-48.9) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 30.2 | (25.1-35.4) | (20.6-44.4) | 35.1 | (29.2-41) | (23.7-52.1) |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 30.6 | (25.4-35.8) | (21-44.5) | 34.6 | (28.8-40.5) | (23.7-50.7) |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 31.6 | (26.2-36.9) | (21.6-46) | 36.3 | (30.2-42.5) | (24.7-53.5) |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 32.1 | (26.7-37.6) | (22-46.9) | 36.2 | (30.1-42.3) | (24.7-53.1) |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 35.4 | (29.4-41.4) | (24.3-51.6) | 39.9 | (33.2-46.7) | (27.3-58.5) |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 37.6 | (31.2-44) | (25.7-55) | 43.4 | (36.1-50.7) | (29.4-64.1) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 39.6 | (32.9-46.4) | (27.3-57.7) | 44.9 | (37.4-52.5) | (30.7-65.7) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 45.9 | (38.1-53.7) | (31-68) | 50.8 | (42.2-59.3) | (34.2-75.4) |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 52.8 | (43.8-61.8) | (35.9-77.6) | 58.8 | (48.9-68.6) | (39.9-86.6) |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 58.2 | (48.3-68.1) | (39.1-86.5) | 64.1 | (53.3-74.9) | (43-95.5) |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 59.7 | (49.5-69.8) | (40-89) | 65.6 | (54.6-76.7) | (43.9-98) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 62.7 | (52-73.4) | (42.4-92.8) | 69.4 | (57.7-81) | (46.8-102.9) |
Dunkleosteus terrelli | CMNH 7424 | NA | 155.6 | (129-182.1) | (98.3-246.1) | 165.6 | (137.8-193.5) | (105-261.4) |
Dunkleosteus terrelli | CMNH 6090 | NA | 232.2 | (192.6-271.7) | (141-382.4) | 243.2 | (202.3-284.1) | (148.2-399) |
Dunkleosteus terrelli | CMNH 7054 | NA | 245.1 | (203.3-286.8) | (147.3-407.8) | 255.8 | (212.7-298.8) | (154.4-423.8) |
Dunkleosteus terrelli | CMNH 5768 | NA | 278.3 | (230.9-325.7) | (165.7-467.4) | 289.4 | (240.7-338.1) | (173.1-483.8) |
Also note that despite including the extra term, some of the lengths are very far off from their actual values. Another issue is that by adding a term based on allometric relationships within Arthrodira, this is effectively unduly influencing the length estimates in Dunkleosteus by patterns in a small number of much smaller taxa, which may not necessarily be correct (see discussion in Ferrón et al., 2017). This is the entire problem that the use of OOL set out to avoid in the first place. Thus, snout_length
does not appear to be a feasible variable to include in the model at this time.
13 Comparing length estimates across models using Coccosteus cuspidatus and CMNH 5768 (Dunkleosteus terrelli)
Code for fitting same models as above, but for species-averages.
<-(predict(fit.species_average2,fossil_taxa %>%
predict.species_averages2drop_na(OOL,body_width,body_depth),
interval="prediction")%>%
exp()*regression.stats(fit.species_average2)$CF)%>%
data.frame()%>%rownames_to_column()%>%
arrange(fit)%>%
left_join(fossil_taxa%>%rownames_to_column(),by="rowname")%>%
filter(!!fossil.specimens)%>%
select(taxon,specimen,fit,lwr,upr)
<-(predict(fit.species_average,fossil_taxa %>%
predict.species_averagesfilter(!is.na(OOL),!is.na(body_width),!is.na(body_depth)),
interval="prediction")%>%
exp()*regression.stats(fit.species_average)$CF)%>%
data.frame()%>%rownames_to_column()%>%
arrange(fit)%>%
left_join(fossil_taxa%>%rownames_to_column(),by="rowname")%>%
filter(!!fossil.specimens)%>%
select(taxon,specimen,fit,lwr,upr)
# Regression equation for shark-only model using species averages
<-lm(log(total_length)~log(OOL),
fit.sharks_averages%>%
data_speciesfilter(clade=="Chondrichthyes",
!order %in% c("Rajiformes","Chimaeriformes"),
!="Alopias"))
genus
<-(predict(fit.sharks_averages,
predict.sharks_averages%>%
fossil_taxa drop_na(OOL,body_width,body_depth),
interval="prediction")%>%
exp()*regression.stats(fit.sharks_averages)$CF)%>%
data.frame()%>%rownames_to_column()%>%
arrange(fit)%>%
left_join(fossil_taxa%>%rownames_to_column(),by="rowname")%>%
filter(!!fossil.specimens)%>%
select(taxon,specimen,fit,lwr,upr)
# Regression equation for fusiform taxa using species averages
<-lm(log(total_length)~log(OOL),
fit.fusiform_averages%>%
data_speciesfilter(shape %in% c("fusiform"),
!family %in% c("Serranidae", "Monacanthidae",
"Holocentridae",
"Balistidae")))
# Model including shape, using species averages
<-lm(log(total_length)~log(OOL)+shape+(family=="Serranidae")+(family=="Holocentridae"),
fit.with_shape_averages%>%filter(!family %in% c("Balistidae","Monacanthidae"),
data_species!genus %in% c("Regalecus","Rhinochimaera")))
<-(predict(fit.with_shape_averages,fossil_taxa,
predict.with_shape_averagesinterval="prediction")%>%
exp()*regression.stats(fit.with_shape)$CF)%>%
data.frame()%>%
rownames_to_column()%>%
arrange(fit)%>%
left_join(fossil_taxa%>%rownames_to_column(),by="rowname")%>%
filter(!!fossil.specimens)%>%
select(taxon,specimen,fit,lwr,upr)
# Model including shape and variable slope for Chondrichthyes, using species averages
<-lm(log(total_length)~log(OOL)*(clade=="Chondrichthyes")+
fit.shape_clade4+(family=="Serranidae")+(family=="Holocentridae"),
shape
data_species)
# Model including body height as a covariate
<-
fit.relativedepth_averageslm(log(total_length)~log(OOL)+I(log(head_length)/log(body_depth)),
%>%
data_finaldrop_na(total_length,OOL,body_depth,head_length)%>%
group_by(taxon)%>%
summarise(across(c(total_length,head_length,OOL,body_depth),mean),
across(c(clade,habitat,shape),unique))
)
# Elongate and fusiform non-acanthopterygians only, species averages
<-data_species%>%
fit.no_acanthopterygii2_averagesfilter(higher_group!="Acanthopterygii",
%in% c("elongate","fusiform"))%$%
shape lm(log(total_length)~log(OOL),.)
# Using head length, individual data
<-lm(log(total_length)~log(head_length),data_final)
fit.head_length# Using head length, speces_averages
<-lm(log(total_length)~log(head_length),data_species) fit.head_length_averages
Creating table
<-fossil_taxa%>%
CMNH5768_lengthsfilter(specimen %in% c("CMNH 5768","Recon. (M & W 1968)"))%>%
select(genus:length_as)%>%
augment(fit.OOL,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.OOL)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.OOL)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.OOL)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.OOL)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.OOL)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('All Species.individual_data', .)))%>%
augment(fit.species_average,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.species_average)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.species_average)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.species_average)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.species_average)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.species_average)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('All Species.species_averages', .)))%>%
# Excluding unusual body shapes
## Individual data
augment(fit.no_extreme_shapes,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.no_extreme_shapes)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.no_extreme_shapes)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.no_extreme_shapes)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.no_extreme_shapes)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.no_extreme_shapes)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('No Extreme Shapes.individual_data', .)))%>%
## Species averages
augment(fit.species_average2,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.species_average2)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.species_average2)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.species_average2)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.species_average2)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.species_average2)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('No Extreme Shapes.species_averages', .)))%>%
# With shape as a covariate
## Individual data
augment(fit.with_shape,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.with_shape)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.with_shape)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.with_shape)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.with_shape)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.with_shape)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('With Shape as a Covariate.individual_data', .)))%>%
## Species averages
augment(fit.with_shape_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.with_shape_averages)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.with_shape_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.with_shape_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.with_shape_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.with_shape_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('With Shape as a Covariate.species_averages', .)))%>%
# Fusiform taxa only
## Fusiform taxa only, individual data
augment(fit.fusiform,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.fusiform)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.fusiform)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.fusiform)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.fusiform)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.fusiform)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Fusiform Taxa Only.individual_data', .)))%>%
## Fusiform taxa only, species averages
augment(fit.fusiform_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.fusiform_averages)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.fusiform_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.fusiform_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.fusiform_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.fusiform_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Fusiform Taxa Only.species_averages', .)))%>%
# Including body height as a covariate
## Individual data
augment(fit.relativedepth4,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.relativedepth4)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.relativedepth4)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.relativedepth4)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.relativedepth4)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.relativedepth4)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('With Body Height as Covariate.individual_data', .)))%>%
## Species averages
augment(fit.relativedepth_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.relativedepth_averages)$CF+snout_length),
.PE_lower=.fitted*(1-(regression.stats(fit.relativedepth_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.relativedepth_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.relativedepth_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.relativedepth_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('With Body Height as Covariate.species_averages', .)))%>%
# Treating snout length as an integer
## Individual data
augment(fit.minus_snout_length1,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.minus_snout_length1)$CF+snout_length),
.PE_lower=.fitted*(1-(regression.stats(fit.minus_snout_length1)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.minus_snout_length1)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.minus_snout_length1)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.minus_snout_length1)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Treating Snout Length as Separate Integer.individual_data', .)))%>%
## Species averages
augment(fit.minus_snout_length2,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.minus_snout_length2)$CF+snout_length),
.PE_lower=.fitted*(1-(regression.stats(fit.minus_snout_length2)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.minus_snout_length2)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.minus_snout_length2)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.minus_snout_length2)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Treating Snout Length as Separate Integer.species_averages', .)))%>%
# Pelagic taxa only
## Individual data
augment(fit.pelagic,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.pelagic)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.pelagic)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.pelagic)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.pelagic)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.pelagic)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Pelagic Taxa Only.individual_data', .)))%>%
## Species averages
augment(fit.pelagic_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.pelagic_averages)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.pelagic_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.pelagic_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.pelagic_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.pelagic_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Pelagic Taxa Only.species_averages', .)))%>%
# Excluding acanthopterygian taxa only
## Individual data
augment(fit.no_acanthopterygii2,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.no_acanthopterygii2)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.no_acanthopterygii2)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.no_acanthopterygii2)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.no_acanthopterygii2)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.no_acanthopterygii2)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Non-Acanthopterygians Only.individual_data', .)))%>%
## Species averages
augment(fit.no_acanthopterygii2_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.no_acanthopterygii2_averages)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.no_acanthopterygii2_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.no_acanthopterygii2_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.no_acanthopterygii2_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.no_acanthopterygii2_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Non-Acanthopterygians Only.species_averages', .)))%>%
# Shark taxa only
## Individual data
augment(fit.sharks,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.sharks)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.sharks)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.sharks)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.sharks)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.sharks)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Sharks Only.individual_data', .)))%>%
## Species averages
augment(fit.sharks_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.sharks_averages)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.sharks_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.sharks_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.sharks_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.sharks_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Sharks Only.species_averages', .)))%>%
# With shape as a covariate and variable slopes for Chondrichthyes and all other fishes
## Individual data
augment(fit.shape_clade3,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.shape_clade3)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.shape_clade3)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.shape_clade3)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.shape_clade3)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.shape_clade3)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Body Shape and Variable Slope for Chondrichthyes.individual_data', .)))%>%
## Species averages
augment(fit.shape_clade4,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.shape_clade4)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.shape_clade4)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.shape_clade4)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.shape_clade4)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.shape_clade4)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Body Shape and Variable Slope for Chondrichthyes.species_averages', .)))%>%
# Using head length
## Individual data
augment(fit.head_length,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.head_length)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.head_length)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.head_length)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.head_length)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.head_length)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Head Length.individual_data', .)))%>%
## Species averages
augment(fit.head_length_averages,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.head_length_averages)$CF),
.PE_lower=.fitted*(1-(regression.stats(fit.head_length_averages)$adjPE)/100),
.PE_upper=.fitted*(1+(regression.stats(fit.head_length_averages)$adjPE)/100),
.PE=paste0("(",
*(1-(regression.stats(fit.head_length_averages)$adjPE)/100),
.fitted"-",
*(1+(regression.stats(fit.head_length_averages)$adjPE)/100),
.fitted")"))%>%
rename_at(vars(starts_with('.')), funs(paste0('Head Length.species_averages', .)))%>%
select(genus,
"All Species.individual_data.fitted":last_col(),
-ends_with(c("rownames","resid","PE")))%>%
pivot_longer(cols=!genus,
names_to = c("model","type","data_value"),
names_sep = "\\.")%>%
mutate(name=paste0(genus,".",type,".",data_value))%>%
pivot_wider(id_cols="model")%>%
mutate(Coccosteus.individual_data.PE=paste0("(",
sprintf("%.1f",
round(Coccosteus.individual_data.PE_lower,1)),
"–",
sprintf("%.1f",
round(Coccosteus.individual_data.PE_upper,1)),
")"),
Coccosteus.species_averages.PE=paste0("(",
sprintf("%.1f",
round(Coccosteus.species_averages.PE_lower,1)),
"–",
sprintf("%.1f",
round(Coccosteus.species_averages.PE_upper,1)),
")"),
Dunkleosteus.individual_data.PE=paste0("(",
sprintf("%.1f",round(Dunkleosteus.individual_data.PE_lower,1)),
"–",
sprintf("%.1f",round(Dunkleosteus.individual_data.PE_upper,1)),
")"),
Dunkleosteus.species_averages.PE=paste0("(",
sprintf("%.1f",round(Dunkleosteus.species_averages.PE_lower,1)),
"–",
sprintf("%.1f",round(Dunkleosteus.species_averages.PE_upper,1)),
")"),
Coccosteus.individual_data.range=paste0("(",
sprintf("%.1f",round(Coccosteus.individual_data.lower,1)),
"–",
sprintf("%.1f",round(Coccosteus.individual_data.upper,1)),
")"),
Coccosteus.species_averages.range=paste0("(",
sprintf("%.1f",round(Coccosteus.species_averages.lower,1)),
"–",
sprintf("%.1f",round(Coccosteus.species_averages.upper,1)),
")"),
Dunkleosteus.individual_data.range=paste0("(",
sprintf("%.1f",round(Dunkleosteus.individual_data.lower,1)),
"–",
sprintf("%.1f",round(Dunkleosteus.individual_data.upper,1)),
")"),
Dunkleosteus.species_averages.range=paste0("(",
sprintf("%.1f",round(Dunkleosteus.species_averages.lower,1)),
"–",
sprintf("%.1f",round(Dunkleosteus.species_averages.upper,1)),
")"))%>%
select(model,
Dunkleosteus.individual_data.fitted,Dunkleosteus.individual_data.PE,
Dunkleosteus.individual_data.range,
Dunkleosteus.species_averages.fitted,Dunkleosteus.species_averages.PE,
Dunkleosteus.species_averages.range,
Coccosteus.individual_data.fitted,Coccosteus.individual_data.PE,
Coccosteus.individual_data.range,
Coccosteus.species_averages.fitted,Coccosteus.species_averages.PE,
Coccosteus.species_averages.range)# Exporting table for later use
write.xlsx(CMNH5768_lengths,
"Devonian Fish Tale Table 3 (CMNH 5768 Lengths).xlsx",
fileEncoding="UTF-8")
# Creating kable for display
%>%
CMNH5768_lengthskable(digits=1,
caption="Comparison of length estimates in <i>Dunkleosteus terrelli</i> (CMNH 5768) and <i>Coccosteus cuspidatus</i> (using the reconstruction in Miles and Westoll 1968) using a variety of different models",
col.names=c("Model",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I.",
"Est.","+/- %PE","95% P.I."))%>%
column_spec(c(2,5,8,11), bold = T)%>%
add_header_above(c(" "=1,"Individual Data"=3,
"Species Averages"=3,
"Individual Data"=3,
"Species Averages"=3))%>%
add_header_above(c(" "=1,"Dunkleosteus terrelli (CMNH 5768)"=6,
"Coccosteus cuspidatus (M & W 1968)"=6))%>%
kable_styling()
Model | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|---|---|---|---|---|---|
All Species | 352.6 | (290.7–414.5) | (226.8–548.1) | 338.9 | (278.4–399.4) | (214.0–536.7) | 43.9 | (36.2–51.6) | (28.3–68.3) | 43.5 | (35.7–51.3) | (27.5–68.8) |
No Extreme Shapes | 353.8 | (299.8–407.8) | (241.7–518.0) | 343.0 | (289.9–396.1) | (229.7–512.1) | 45.3 | (38.4–52.2) | (30.9–66.3) | 44.5 | (37.6–51.4) | (29.8–66.3) |
With Shape as a Covariate | 324.8 | (285.8–363.9) | (237.8–443.7) | 320.1 | (279.8–360.3) | (229.9–445.6) | 41.8 | (36.8–46.8) | (30.6–57.1) | 42.1 | (36.8–47.4) | (30.3–58.5) |
Fusiform Taxa Only | 319.7 | (281.7–357.6) | (236.1–432.8) | 313.9 | (278.6–349.3) | (234.1–421.1) | 42.0 | (37.0–46.9) | (31.0–56.8) | 41.9 | (37.2–46.6) | (31.3–56.2) |
With Body Height as Covariate | 335.4 | (281.1–389.6) | (221.4–508.0) | 344.1 | (283.6–404.6) | (221.8–536.6) | 42.4 | (35.5–49.2) | (28.0–64.2) | 43.8 | (36.1–51.5) | (28.1–68.5) |
Treating Snout Length as Separate Integer | 336.8 | (284.9–388.7) | (231.1–492.7) | 328.5 | (276.1–380.9) | (219.8–493.2) | 42.3 | (35.8–48.8) | (28.8–62.1) | 41.8 | (35.1–48.5) | (27.8–63.0) |
Pelagic Taxa Only | 357.5 | (298.3–416.7) | (242.4–527.2) | 328.8 | (276.7–380.9) | (222.4–486.1) | 47.3 | (39.5–55.1) | (32.1–69.7) | 45.6 | (38.4–52.8) | (31.0–67.1) |
Non-Acanthopterygians Only | 340.5 | (285.1–395.9) | (225.7–513.7) | 318.5 | (279.3–357.7) | (234.0–433.5) | 43.0 | (36.0–49.9) | (28.5–64.8) | 44.0 | (38.5–49.4) | (32.3–59.7) |
Sharks Only | 298.5 | (264.2–332.9) | (224.1–397.8) | 299.6 | (268.0–331.2) | (227.9–393.9) | 46.9 | (41.5–52.3) | (35.2–62.5) | 46.9 | (41.9–51.8) | (35.7–61.5) |
Body Shape and Variable Slope for Chondrichthyes | 340.7 | (298.4–382.9) | (245.1–473.6) | 328.6 | (284.4–372.9) | (226.9–476.0) | 42.7 | (37.4–48.0) | (30.7–59.4) | 42.6 | (36.9–48.3) | (29.5–61.6) |
Head Length | 266.7 | (228.3–305.0) | (184.2–386.0) | 262.3 | (221.3–303.2) | (176.0–390.9) | 32.7 | (28.0–37.4) | (22.6–47.4) | 32.8 | (27.7–38.0) | (22.0–48.9) |
The reason why some of the estimates using individual data seem to be high (3.7-3.8 m) appears to be directly due to including a very large sample of Kajikia albida (57 specimens, Robins 1974) and Tetrapturus spp. (~11 specimens of T. pfluegeri and ~36 individuals of T. belone; Robins and de Sylva 1963). These fishes all have rather elongate bodies, and the sheer number of individuals being counted results in the estimates being biased upwards when they are considered. This can be seen in the fact that estimates for Coccosteus are very consistent across individual specimen and species-average models, and in earlier iterations of the database prior to the addition of data from Robins (1974) the results between individual data and species-average models were nearly identical for Dunkleosteus terrelli.
14 Estimating length of the largest specimens of Dunkleosteus terrelli (CMNH 5936)
14.1 Examining correlation between biting portion of the inferognathal and orbit-opercular length
# Reading in Dunkleosteus measurement data
<-read.csv("Devonian Fish Tale Supplementary File 2 (Dunkleosteus Measurements).csv",
dunkleosteus_jawsheader=T)%>%
rename("OOL"="OOL")%>%
mutate(clade="Placodermi",higher_group="Arthrodira",order="Arthrodira",
family="Dunkleosteidae",habitat="pelagic",shape="fusiform")%>%
augment(fit.shape_clade3,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.shape_clade3)$CF))%>%
rename(fit=.fitted,lwr=.lower,upr=.upper)%>%
select(specimen,JM1,JM2,JM3,JM4,JM5,inferognathal_length,OOL,head_length,
fit,lwr,upr)
# Printing Dunkleosteus measurement data
%>%
dunkleosteus_jawsremove_rownames()%>%column_to_rownames("specimen")%>%
arrange(JM5)%>%
select(-c(fit,lwr,upr))%>%
kable(digits=1,align="c",
caption="Skeletal measurements of the specimens of <i>Dunkleosteus terrelli</i> considered here. All measurements in cm.",
col.names=c("JM1","JM2","JM3","JM4","JM5","Inferognathal Length","OOL","Head Length"))%>%
kable_styling()
JM1 | JM2 | JM3 | JM4 | JM5 | Inferognathal Length | OOL | Head Length | |
---|---|---|---|---|---|---|---|---|
CMNH 8982 | 5.9 | 2.7 | 4.6 | 5.0 | 8.8 | 18.0 | 23.7 | 28.8 |
CMNH 50322 | 4.8 | 3.3 | 5.6 | 5.8 | 9.5 | 20.2 | 21.5 | 25.8 |
CMNH 6194 (right) | 4.9 | 3.4 | 5.5 | 5.5 | 11.0 | 22.6 | 25.5 | 29.0 |
CMNH 6194 (left) | 6.5 | 3.7 | 5.2 | 5.8 | 11.0 | 23.1 | 25.5 | 29.0 |
CMNH 7424 | 6.4 | 4.1 | 7.0 | 6.9 | 12.2 | 29.9 | 29.0 | 34.0 |
CMNH 5007 | 6.2 | 5.3 | 7.2 | 7.3 | 13.4 | 28.4 | 31.1 | NA |
CMNH OC 1421 | 8.5 | 5.0 | 9.9 | 9.8 | 18.3 | 39.1 | 36.8 | 46.0 |
CMNH 5740 | NA | NA | 11.0 | NA | 20.4 | 40.9 | 41.0 | 48.4 |
CMNH 6090 (left) | 10.7 | 5.7 | 11.8 | 11.5 | 20.4 | 41.3 | 43.6 | 51.0 |
CMNH 6090 (right) | 11.2 | 4.6 | 12.4 | 11.9 | 21.1 | 43.5 | 43.6 | 51.0 |
CMNH 7054 (right) | 9.2 | 7.8 | 13.4 | 14.5 | 22.8 | 47.0 | 45.5 | 53.6 |
CMNH 7054 (left) | 9.7 | 7.6 | 12.9 | 13.9 | 23.7 | 48.4 | 45.5 | 53.6 |
CMNH 8131 | 9.8 | 7.8 | 13.4 | 13.6 | 24.2 | 50.7 | 45.8 | 56.5 |
CMNH 5768 (left) | 13.3 | 9.8 | 15.9 | 13.2 | 26.2 | 54.1 | 52.5 | 61.3 |
CMNH 5768 (right) | 13.2 | 8.5 | 14.8 | 14.5 | 28.1 | 55.5 | 52.5 | 61.3 |
CMNH 5936 | 12.8 | 10.8 | 18.6 | 20.4 | 33.9 | NA | NA | NA |
Note that CMNH 5768 was included twice because there is some taphonomic distortion between the left and right inferognathal, which could potentially bias estimates of CMNH 5936 if not accounted for as CMNH 5768 is the largest complete individual in this study by a large margin.
14.1.1 JM1
summary(lm(OOL~JM1,dunkleosteus_jaws))
##
## Call:
## lm(formula = OOL ~ JM1, data = dunkleosteus_jaws)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.3218 -1.9645 -0.9268 2.2916 6.1508
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.0613 2.9324 2.067 0.061 .
## JM1 3.6281 0.3241 11.195 1.04e-07 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 3.38 on 12 degrees of freedom
## (2 observations deleted due to missingness)
## Multiple R-squared: 0.9126, Adjusted R-squared: 0.9053
## F-statistic: 125.3 on 1 and 12 DF, p-value: 1.045e-07
<-lm(log(JM1)~log(OOL),dunkleosteus_jaws) JM1_allometry
%>%
dunkleosteus_jawsdrop_na(OOL,JM1)%>%
ggplot(aes(y=OOL,x=JM1))+
geom_smooth(method="lm",formula=y~x)+
geom_point(fill="black",color="white",shape=21,size=3)+
labs(x="Length Between Medial and Posterior Cusp (cm)",
y="Orbit-Opercular Length (cm)")+
theme_classic()+
geom_text(aes(label=specimen,
x=ifelse(specimen %in% c("CMNH 5768 (left)","CMNH 7054 (right)"),JM1-0.25,
ifelse(specimen %in% c("CMNH 6090 (right)"),JM1+0.25,JM1)),
y=ifelse(specimen %in% c("CMNH 5768 (left)","CMNH 6090 (right)"),OOL+1.5,
ifelse(specimen %in% c("CMNH 7054 (right)"),OOL-1.5,OOL)),
hjust=ifelse(specimen %in% c("CMNH 5768 (left)","CMNH 7054 (right)",
"CMNH 7054 (left)"),1,
ifelse(specimen %in% c("CMNH 6090 (right)","CMNH 8131"),0,0.5))),
nudge_y=ifelse(residuals(lm(OOL~JM1,dunkleosteus_jaws%>%drop_na(JM1,OOL)))<0,-1,1))
Figure 14.1: Plot of JM1 versus orbit-opercular length in specimens of Dunkleosteus terrelli for which both measurements are known. Length between medial and posterior cusp to JM1 in Ferrón et al. (2017).
14.1.2 JM2
summary(lm(OOL~JM2,dunkleosteus_jaws))
##
## Call:
## lm(formula = OOL ~ JM2, data = dunkleosteus_jaws)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.112 -2.618 -1.183 1.720 11.187
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 12.0435 3.3710 3.573 0.00383 **
## JM2 4.4671 0.5566 8.026 3.64e-06 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 4.531 on 12 degrees of freedom
## (2 observations deleted due to missingness)
## Multiple R-squared: 0.843, Adjusted R-squared: 0.8299
## F-statistic: 64.41 on 1 and 12 DF, p-value: 3.639e-06
<-lm(log(JM2)~log(OOL),dunkleosteus_jaws) JM2_allometry
%>%
dunkleosteus_jawsdrop_na(OOL,JM2)%>%
ggplot(aes(y=OOL,x=JM2))+
geom_smooth(method="lm",formula=y~x)+
geom_point(fill="black",color="white",shape=21,size=3)+
labs(x="Length Between Symphyseal and Accessory Cusp (cm)",
y="Orbit-Opercular Length (cm)")+
theme_classic()+
geom_text(aes(label=specimen,
y=ifelse(specimen %in% c("CMNH 8131","CMNH 7054 (left)","CMNH 6194 (right)"),
+2,OOL),
OOLx=ifelse(specimen %in% c("CMNH 8131","CMNH 7054 (right)"),JM2+0.1,JM2),
hjust=ifelse(specimen %in% c("CMNH 8131","CMNH 7054 (right)","CMNH 6194 (left)"),0,
ifelse(specimen %in% c("CMNH 7054 (left)","CMNH 6194 (right)",
"CMNH 6090 (right)"),1,0.5))),
nudge_y=ifelse(residuals(lm(OOL~JM2,dunkleosteus_jaws%>%drop_na(JM2,OOL)))<0,-1,1))
Figure 14.2: Plot of JM2 versus orbit-opercular length in specimens of Dunkleosteus terrelli for which both measurements are known. Length between symphyseal cusp and accessory cusp is JM2 in Ferrón et al. (2017).
14.1.3 JM3
summary(lm(OOL~JM3,dunkleosteus_jaws))
##
## Call:
## lm(formula = OOL ~ JM3, data = dunkleosteus_jaws)
##
## Residuals:
## Min 1Q Median 3Q Max
## -3.9120 -0.6777 0.0452 1.1049 2.0653
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 10.0211 1.1343 8.834 7.43e-07 ***
## JM3 2.7362 0.1058 25.863 1.45e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.523 on 13 degrees of freedom
## (1 observation deleted due to missingness)
## Multiple R-squared: 0.9809, Adjusted R-squared: 0.9795
## F-statistic: 668.9 on 1 and 13 DF, p-value: 1.451e-12
<-lm(OOL~JM3,dunkleosteus_jaws)
fit.JM3<-lm(log(OOL)~log(JM3),dunkleosteus_jaws) JM3_allometry
%>%
dunkleosteus_jawsfilter(!is.na(OOL))%>%
ggplot(aes(y=OOL,x=JM3))+
geom_smooth(method="lm",formula=y~x)+
geom_point(fill="black",color="white",shape=21,size=3)+
labs(x="Height of Inferognathal at Posterior Cusp (cm)",
y="Orbit-Opercular Length (cm)")+
theme_classic()+
geom_text(aes(x=ifelse(specimen %in% c("CMNH 8131"),JM3+0.5,JM3),
y=ifelse(specimen %in% c("CMNH 8131","CMNH 6194 (right)"),OOL+1,OOL),
label=specimen,
hjust=ifelse(specimen %in% c("CMNH 5768 (left)","CMNH 6194 (right)"),0.5,
ifelse(residuals(lm(OOL~JM3,dunkleosteus_jaws%>%drop_na(JM3,OOL)))<0,0,1))),
nudge_y=ifelse(residuals(lm(OOL~JM3,dunkleosteus_jaws%>%drop_na(JM3,OOL)))<0,-1,1))
Figure 14.3: Plot of JM3 versus orbit-opercular length in specimens of Dunkleosteus terrelli for which both measurements are known. Height of the inferognathal at posterior cusp is JM3 in Ferrón et al. (2017).
14.1.4 JM4
summary(lm(OOL~JM4,dunkleosteus_jaws))
##
## Call:
## lm(formula = OOL ~ JM4, data = dunkleosteus_jaws)
##
## Residuals:
## Min 1Q Median 3Q Max
## -4.6679 -1.4871 0.3709 1.1684 5.9372
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.9464 2.2311 4.01 0.00173 **
## JM4 2.8476 0.2108 13.51 1.28e-08 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.839 on 12 degrees of freedom
## (2 observations deleted due to missingness)
## Multiple R-squared: 0.9383, Adjusted R-squared: 0.9332
## F-statistic: 182.5 on 1 and 12 DF, p-value: 1.278e-08
<-lm(log(JM4)~log(OOL),dunkleosteus_jaws) JM4_allometry
%>%
dunkleosteus_jawsdrop_na(OOL,JM4)%>%
ggplot(aes(y=OOL,x=JM4))+
geom_smooth(method="lm",formula=y~x)+
geom_point(fill="black",color="white",shape=21,size=3)+
labs(x="Height of Inferognathal at Accessory Cusps (cm)",
y="Orbit-Opercular Length (cm)")+
theme_classic()+
geom_text(aes(label=specimen,
x=ifelse(specimen %in% c("CMNH 6090 (left)"),JM4-0.25,JM4),
y=ifelse(specimen %in% c("CMNH 6090 (left)"),OOL-1,
ifelse(specimen %in% c("CMNH 7054 (left)"),OOL+2.5,OOL)),
hjust=ifelse(specimen %in% c("CMNH 6090 (left)",
"CMNH 5768 (left)"),1,0.5)),
nudge_y=ifelse(residuals(lm(OOL~JM4,dunkleosteus_jaws%>%drop_na(JM4,OOL)))<0,-1,1))
Figure 14.4: Plot of JM4 versus orbit-opercular length in specimens of Dunkleosteus terrelli for which both measurements are known. Biting portion of the inferognathal is JM4 in Ferrón et al. (2017).
14.1.5 JM5
<-lm(OOL~JM5,dunkleosteus_jaws)
fit.JM5summary(fit.JM5)
##
## Call:
## lm(formula = OOL ~ JM5, data = dunkleosteus_jaws)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.2666 -1.1650 -0.2614 1.1925 2.3224
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 8.33726 1.13083 7.373 5.40e-06 ***
## JM5 1.61551 0.05907 27.348 7.11e-13 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.442 on 13 degrees of freedom
## (1 observation deleted due to missingness)
## Multiple R-squared: 0.9829, Adjusted R-squared: 0.9816
## F-statistic: 747.9 on 1 and 13 DF, p-value: 7.111e-13
<-lm(log(JM5)~log(OOL),dunkleosteus_jaws) JM5_allometry
%>%
dunkleosteus_jawsfilter(!is.na(OOL))%>%
ggplot(aes(y=OOL,x=JM5))+
geom_smooth(method="lm",formula=y~x)+
geom_point(fill="black",color="white",shape=21,size=3)+
labs(x="Length of Biting Portion of Inferognathal (cm)",
y="Orbit-Opercular Length (cm)")+
theme_classic()+
geom_text(aes(label=specimen,
x=ifelse(specimen %in% c("CMNH 8131","CMNH 6194 (right)"),JM5+0.5,
ifelse(specimen %in% ("CMNH 6090 (left)"),JM5-0.5,JM5)),
y=ifelse(specimen %in% c("CMNH 8131"),OOL+1,
ifelse(specimen %in% c("CMNH 6194 (right)"),OOL+2,
ifelse(specimen %in% c("CMNH 6090 (left)"),OOL-1,OOL))),
hjust=ifelse(specimen %in% c("CMNH 8131","CMNH 7054 (left)","CMNH 6194 (left)"),0,
ifelse(specimen %in% c("CMNH 6090 (left)","CMNH 7054 (right)",
"CMNH 5768 (left)"),1,0.5))
nudge_y=ifelse(residuals(lm(OOL~JM5,dunkleosteus_jaws%>%drop_na(JM5,OOL))) < 0, -1, 1)) ),
Figure 14.5: Plot of JM5 versus orbit-opercular length in specimens of Dunkleosteus terrelli for which both measurements are known. Length of biting portion of the inferognathal is JM5 in Ferrón et al. (2017).
14.1.6 Inferognathal length
<-lm(OOL~inferognathal_length,dunkleosteus_jaws)
inferognathal_lengthsummary(inferognathal_length)
##
## Call:
## lm(formula = OOL ~ inferognathal_length, data = dunkleosteus_jaws)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.5587 -1.4128 0.1857 1.0839 2.9929
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 6.77020 1.42844 4.74 0.000387 ***
## inferognathal_length 0.82009 0.03616 22.68 7.73e-12 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 1.732 on 13 degrees of freedom
## (1 observation deleted due to missingness)
## Multiple R-squared: 0.9753, Adjusted R-squared: 0.9735
## F-statistic: 514.4 on 1 and 13 DF, p-value: 7.729e-12
<-lm(log(inferognathal_length)~log(OOL),dunkleosteus_jaws) inferognathal_length_allometry
%>%
dunkleosteus_jawsfilter(!is.na(OOL))%>%
ggplot(aes(y=OOL,x=inferognathal_length))+
geom_smooth(method="lm",formula=y~x)+
geom_point(fill="black",color="white",shape=21,size=3)+
labs(x="Inferognathal Length (cm)",
y="Orbit-Opercular Length (cm)")+
theme_classic()+
geom_text(aes(x=ifelse(specimen %in% c("CMNH 5768 (left)","CMNH 6090 (left)"),
-0.5,
inferognathal_lengthifelse(specimen %in% c("CMNH 8131"),
+0.5,
inferognathal_length
inferognathal_length)),y=ifelse(specimen %in% c("CMNH 6090 (left)","CMNH 5768 (left)"),OOL-1,
ifelse(specimen %in% c("CMNH 8131"),OOL+1,OOL)),
label=specimen,
hjust=ifelse(specimen %in% c("CMNH 8131","CMNH 7054 (left)","CMNH 6194 (left)"),0,
ifelse(specimen %in% c("CMNH 6090 (left)",
"CMNH 5768 (left)"),1,0.5))),
nudge_y=ifelse(residuals(lm(OOL~inferognathal_length,
%>%drop_na(inferognathal_length,OOL)
dunkleosteus_jaws<0,-1,1)) ))
Figure 14.6: Plot of total inferognathal length versus orbit-opercular length in specimens of Dunkleosteus terrelli for which both measurements are known.
Based on these results, the length of the biting portion of the inferognathal and the height of the posterior cusp of the inferognathal are the best measurements to estimate total length using the correlation between orbit-opercular length and inferognathal dimensions. These are also the dimensions that are most robust to preservational biases and taphonomic distortion (the total length of the inferognathal is often not preserved, as in CMNH 5936), inferognathal wear (JM4 can be variable due to wear), and can be easily identified across taxa (JM1 and JM2 can be hard to identify in worn jaws and are dependent on characters unique to Dunkleosteus, making comparable regression equations difficult to construct for other arthrodires).
14.2 Allometry of inferognathal dimensions in Dunkleosteus terrelli
data.frame("JM1"=c(summary(JM1_allometry)$r.squared,
summary(JM1_allometry)$coefficients[1,],
summary(JM1_allometry)$coefficients[2,]),
"JM2"=c(summary(JM2_allometry)$r.squared,
summary(JM2_allometry)$coefficients[1,],
summary(JM2_allometry)$coefficients[2,]),
"JM3"=c(summary(JM3_allometry)$r.squared,
summary(JM3_allometry)$coefficients[1,],
summary(JM3_allometry)$coefficients[2,]),
"JM4"=c(summary(JM4_allometry)$r.squared,
summary(JM4_allometry)$coefficients[1,],
summary(JM4_allometry)$coefficients[2,]),
"JM5"=c(summary(JM5_allometry)$r.squared,
summary(JM5_allometry)$coefficients[1,],
summary(JM5_allometry)$coefficients[2,]),
"Inferognathal Length"=
c(summary(inferognathal_length_allometry)$r.squared,
summary(inferognathal_length_allometry)$coefficients[1,],
summary(inferognathal_length_allometry)$coefficients[2,]))%>%
t()%>%
data.frame(row.names=c("JM1","JM2","JM3","JM4","JM5","Inferognathal Length"))%>%
select(X1,X6,X7,X8,X9,X2,X3,X4,X5)%>% # Moving slope to be before intercept
kable(digits=3,align="c",
col.names=c("r2","Estimate","Std. Error","T Value","Pr(>|t|)","Estimate","Std. Error","T Value","Pr(>|t|)"),
caption="Examination of allometry of inferognathal dimensions in <i>Dunkleosteus terrelli</i> relative to OOL.")%>%
add_header_above(c(" "=2,"Slope"=4,"Intercept"=4))%>%
column_spec(c(3,7),bold=T)%>%
kable_styling()
r2 | Estimate | Std. Error | T Value | Pr(>|t|) | Estimate | Std. Error | T Value | Pr(>|t|) | |
---|---|---|---|---|---|---|---|---|---|
JM1 | 0.916 | 1.062 | 0.093 | 11.467 | 0 | -1.700 | 0.332 | -5.115 | 0.000 |
JM2 | 0.858 | 1.205 | 0.142 | 8.517 | 0 | -2.652 | 0.508 | -5.225 | 0.000 |
JM3 | 0.968 | 0.702 | 0.036 | 19.726 | 0 | 2.020 | 0.081 | 25.058 | 0.000 |
JM4 | 0.951 | 1.274 | 0.083 | 15.312 | 0 | -2.331 | 0.299 | -7.807 | 0.000 |
JM5 | 0.981 | 1.294 | 0.050 | 25.875 | 0 | -1.814 | 0.180 | -10.083 | 0.000 |
Inferognathal Length | 0.969 | 1.230 | 0.061 | 20.063 | 0 | -0.848 | 0.221 | -3.843 | 0.002 |
The log slope is positive for length variables that span the overall dimensions of the jaw (JM5, inferognathal length), indicating positive allometry of the mouth and jaws relative to OOL.
Because these results are based on the regression between jaw dimensions and OOL, it is possible they could be biased by allometry. Actinopterygians and lampreys show positive ontogenetic allometry of OOL, though sharks and the extinct sarcopterygian Eusthenopteron do not. Because of this it is worth testing these patterns against head length, which is expected to scale closer to isometry in Dunkleosteus terrelli.
data.frame("JM1"=c(summary(lm(log(JM1)~log(head_length),dunkleosteus_jaws))$r.squared,
summary(lm(log(JM1)~log(head_length),dunkleosteus_jaws))$coefficients[1,],
summary(lm(log(JM1)~log(head_length),dunkleosteus_jaws))$coefficients[2,]),
"JM2"=c(summary(lm(log(JM2)~log(head_length),dunkleosteus_jaws))$r.squared,
summary(lm(log(JM2)~log(head_length),dunkleosteus_jaws))$coefficients[1,],
summary(lm(log(JM2)~log(head_length),dunkleosteus_jaws))$coefficients[2,]),
"JM3"=c(summary(lm(log(JM3)~log(head_length),dunkleosteus_jaws))$r.squared,
summary(lm(log(JM3)~log(head_length),dunkleosteus_jaws))$coefficients[1,],
summary(lm(log(JM3)~log(head_length),dunkleosteus_jaws))$coefficients[2,]),
"JM4"=c(summary(lm(log(JM4)~log(head_length),dunkleosteus_jaws))$r.squared,
summary(lm(log(JM4)~log(head_length),dunkleosteus_jaws))$coefficients[1,],
summary(lm(log(JM4)~log(head_length),dunkleosteus_jaws))$coefficients[2,]),
"JM5"=c(summary(lm(log(JM5)~log(head_length),dunkleosteus_jaws))$r.squared,
summary(lm(log(JM5)~log(head_length),dunkleosteus_jaws))$coefficients[1,],
summary(lm(log(JM5)~log(head_length),dunkleosteus_jaws))$coefficients[2,]),
"Inferognathal Length"=
c(summary(lm(log(inferognathal_length)~log(head_length),dunkleosteus_jaws))$r.squared,
summary(lm(log(inferognathal_length)~log(head_length),dunkleosteus_jaws))$coefficients[1,],
summary(lm(log(inferognathal_length)~log(head_length),dunkleosteus_jaws))$coefficients[2,]))%>%
t()%>%
data.frame(row.names=c("JM1","JM2","JM3","JM4","JM5","Inferognathal Length"))%>%
select(X1,X6,X7,X8,X9,X2,X3,X4,X5)%>% # Moving slope to be before intercept
kable(digits=3,align="c",
col.names=c("r2","Estimate","Std. Error","T Value","Pr(>|t|)","Estimate","Std. Error","T Value","Pr(>|t|)"),
caption="Examination of allometry of inferognathal dimensions in <i>Dunkleosteus terrelli</i> relative to head length.")%>%
add_header_above(c(" "=2,"Slope"=4,"Intercept"=4))%>%
column_spec(c(3,7),bold=T)%>%
kable_styling()
r2 | Estimate | Std. Error | T Value | Pr(>|t|) | Estimate | Std. Error | T Value | Pr(>|t|) | |
---|---|---|---|---|---|---|---|---|---|
JM1 | 0.914 | 1.033 | 0.096 | 10.782 | 0 | -1.758 | 0.361 | -4.873 | 0.000 |
JM2 | 0.865 | 1.209 | 0.144 | 8.408 | 0 | -2.883 | 0.542 | -5.322 | 0.000 |
JM3 | 0.971 | 1.364 | 0.068 | 19.915 | 0 | -2.884 | 0.258 | -11.156 | 0.000 |
JM4 | 0.957 | 1.260 | 0.080 | 15.673 | 0 | -2.487 | 0.303 | -8.214 | 0.000 |
JM5 | 0.978 | 1.276 | 0.055 | 23.262 | 0 | -1.959 | 0.207 | -9.460 | 0.000 |
Inferognathal Length | 0.968 | 1.215 | 0.064 | 19.094 | 0 | -0.995 | 0.240 | -4.142 | 0.001 |
Similar to the results with OOL, JM5 and inferognathal length both show positive allometry relative to head length.
14.3 Estimating total length in CMNH 5936
14.3.1 Using JM3
<-dunkleosteus_jaws%>%
JM3_estimatesmutate(OOL=predict(fit.JM3,.),
clade="Placodermi",shape="fusiform",family="Dunkleosteidae")%>%
augment(x=fit.OOL,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF),)%>%
rename_at(vars(starts_with('.')), funs(paste0('fit1', .)))%>%
augment(x=fit.species_average,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.species_average)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit2', .)))%>%
augment(x=fit.fusiform,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.fusiform)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit3', .)))%>%
augment(x=fit.fusiform_averages,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.fusiform_averages)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit4', .)))%>%
augment(x=fit.shape_clade3,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.shape_clade3)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit5', .)))%>%
augment(x=fit.shape_clade_species_averages,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.shape_clade4)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit6', .)))%>%
mutate(specimen=dunkleosteus_jaws$specimen,
fit1.PE=paste0("(",
sprintf("%.1f",
round(fit1.fitted*(1-(regression.stats(fit.OOL)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit1.fitted*(1+(regression.stats(fit.OOL)$adjPE/100)),1)),
")"),
fit2.PE=paste0("(",
sprintf("%.1f",
round(fit2.fitted*(1-(regression.stats(fit.species_average)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit2.fitted*(1+(regression.stats(fit.species_average)$adjPE/100)),1)),
")"),
fit3.PE=paste0("(",
sprintf("%.1f",
round(fit3.fitted*(1-(regression.stats(fit.fusiform)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit3.fitted*(1+(regression.stats(fit.fusiform)$adjPE/100)),1)),
")"),
fit4.PE=paste0("(",
sprintf("%.1f",
round(fit4.fitted*(1-(regression.stats(fit.fusiform_averages)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit4.fitted*(1+(regression.stats(fit.fusiform_averages)$adjPE/100)),1)),
")"),
fit5.PE=paste0("(",
sprintf("%.1f",
round(fit5.fitted*(1-(regression.stats(fit.shape_clade3)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit5.fitted*(1+(regression.stats(fit.shape_clade3)$adjPE/100)),1)),
")"),
fit6.PE=paste0("(",
sprintf("%.1f",
round(fit6.fitted*(1-(regression.stats(fit.shape_clade4)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit6.fitted*(1+(regression.stats(fit.shape_clade4)$adjPE/100)),1)),
")"),
fit1.range=paste0("(",sprintf("%.1f",round(fit1.lower,1)),
"–",sprintf("%.1f",round(fit1.upper,1)),")"),
fit2.range=paste0("(",sprintf("%.1f",round(fit2.lower,1))
"–",sprintf("%.1f",round(fit2.upper,1)),")"),
,fit3.range=paste0("(",sprintf("%.1f",round(fit3.lower,1)),
"–",sprintf("%.1f",round(fit3.upper,1)),")"),
fit4.range=paste0("(",sprintf("%.1f",round(fit4.lower,1)),
"–",sprintf("%.1f",round(fit4.upper,1)),")"),
fit5.range=paste0("(",sprintf("%.1f",round(fit5.lower,1)),
"–",sprintf("%.1f",round(fit5.upper,1)),")"),
fit6.range=paste0("(",sprintf("%.1f",round(fit6.lower,1)),
"–",sprintf("%.1f",round(fit6.upper,1)),")"))%>%
remove_rownames()%>%
column_to_rownames("specimen")%>%
select(fit1.fitted,fit1.PE,fit1.range,
fit2.fitted,fit2.PE,fit2.range,
fit3.fitted,fit3.PE,fit3.range,
fit4.fitted,fit4.PE,fit4.range,
fit5.fitted,fit5.PE,fit5.range,
fit6.fitted,fit6.PE,fit6.range)
%>%
JM3_estimateskable(align="c", digits=1,
col.names=c("Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I."),
caption="Length estimates of the largest known specimen of <i>Dunkleosteus terrelli</i> (CMNH 5936) using JM3 (height of the inferognathal at posterior cusp). Estimates calculated by estimating OOL using the regression between JM3 and OOL, and then inserting that value into the respective equation for total length. All measurements in cm.")%>%
add_header_above(c(" "=1,"All specimens"=3,"Species averages"=3,
"All specimens"=3,"Species averages"=3,
"All specimens"=3,"Species averages"=3))%>%
add_header_above(c(" "=1,"All taxa"=6,"Fusiform fishes"=6,"With variable slopes for Chondrichthyes"=6))%>%
column_spec(c(2,5,8,11,14,17),bold=T)%>%
kable_styling()%>%
scroll_box(width = "100%")
Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CMNH 5936 | 409.4 | (337.6–481.3) | (263.4–636.5) | 392.7 | (322.6–462.8) | (248.0–622.0) | 369.8 | (325.9–413.7) | (273.1–500.7) | 362.7 | (321.9–403.6) | (270.4–486.7) | 395.4 | (346.4–444.5) | (284.4–549.8) | 339.4 | (293.7–385.1) | (179.0–643.6) |
CMNH 5768 (right) | 338.8 | (279.3–398.2) | (217.9–526.6) | 325.8 | (267.7–384.0) | (205.8–515.9) | 307.4 | (270.9–344.0) | (227.1–416.3) | 302.0 | (268.0–336.0) | (225.2–405.1) | 327.4 | (286.8–368.0) | (235.5–455.1) | 283.5 | (245.3–321.7) | (154.8–519.4) |
CMNH 5768 (left) | 360.4 | (297.1–423.6) | (231.8–560.2) | 346.3 | (284.5–408.1) | (218.7–548.4) | 326.5 | (287.7–365.3) | (241.2–442.1) | 320.6 | (284.5–356.7) | (239.0–430.1) | 348.2 | (305.0–391.4) | (250.5–484.1) | 300.7 | (260.2–341.2) | (162.3–557.0) |
CMNH 8131 | 314.0 | (258.9–369.2) | (202.0–488.2) | 302.4 | (248.4–356.4) | (191.0–478.7) | 285.5 | (251.6–319.5) | (210.9–386.6) | 280.7 | (249.1–312.3) | (209.3–376.5) | 303.6 | (265.9–341.2) | (218.4–422.0) | 263.8 | (228.3–299.3) | (146.0–476.8) |
CMNH 7054 (left) | 305.4 | (251.8–359.0) | (196.5–474.8) | 294.2 | (241.7–346.7) | (185.8–465.8) | 277.9 | (244.9–310.9) | (205.3–376.3) | 273.3 | (242.5–304.0) | (203.7–366.5) | 295.3 | (258.6–331.9) | (212.4–410.4) | 256.9 | (222.3–291.5) | (142.9–462.1) |
CMNH 7054 (right) | 313.1 | (258.2–368.1) | (201.4–486.7) | 301.5 | (247.7–355.3) | (190.4–477.4) | 284.7 | (250.9–318.6) | (210.3–385.5) | 279.9 | (248.4–311.4) | (208.7–375.4) | 302.7 | (265.1–340.2) | (217.7–420.8) | 263.1 | (227.6–298.5) | (145.6–475.3) |
CMNH 6090 (left) | 284.4 | (234.5–334.3) | (183.0–442.0) | 274.2 | (225.3–323.1) | (173.2–434.1) | 259.2 | (228.4–290.0) | (191.4–350.9) | 255.0 | (226.3–283.7) | (190.2–342.0) | 275.0 | (240.9–309.0) | (197.8–382.2) | 240.1 | (207.7–272.4) | (135.1–426.5) |
CMNH 6090 (right) | 295.7 | (243.8–347.6) | (190.3–459.7) | 285.0 | (234.1–335.9) | (180.0–451.2) | 269.3 | (237.3–301.3) | (198.9–364.6) | 264.9 | (235.0–294.7) | (197.5–355.2) | 285.9 | (250.4–321.4) | (205.7–397.4) | 249.2 | (215.6–282.7) | (139.3–445.6) |
CMNH 5740 | 269.5 | (222.2–316.8) | (173.4–418.9) | 260.1 | (213.7–306.5) | (164.3–411.7) | 246.0 | (216.8–275.2) | (181.7–333.1) | 242.1 | (214.9–269.4) | (180.6–324.7) | 260.6 | (228.3–293.0) | (187.5–362.3) | 228.2 | (197.4–258.9) | (129.6–401.6) |
CMNH OC 1421 | 249.9 | (206.1–293.8) | (160.8–388.5) | 241.4 | (198.3–284.5) | (152.5–382.1) | 228.5 | (201.4–255.7) | (168.8–309.4) | 225.1 | (199.7–250.4) | (167.9–301.8) | 241.7 | (211.8–271.7) | (173.9–336.0) | 212.4 | (183.7–241.0) | (122.2–369.0) |
CMNH 5007 | 200.8 | (165.5–236.0) | (129.2–312.1) | 194.5 | (159.8–229.3) | (122.9–307.9) | 184.6 | (162.7–206.5) | (136.4–249.9) | 182.1 | (161.6–202.6) | (135.9–244.2) | 194.3 | (170.2–218.4) | (139.8–270.1) | 172.5 | (149.2–195.7) | (102.8–289.3) |
CMNH 7424 | 196.6 | (162.1–231.1) | (126.5–305.5) | 190.5 | (156.5–224.5) | (120.4–301.5) | 180.8 | (159.3–202.3) | (133.6–244.8) | 178.4 | (158.3–198.5) | (133.1–239.2) | 190.3 | (166.7–213.8) | (136.9–264.4) | 169.0 | (146.3–191.8) | (101.1–282.6) |
CMNH 6194 (left) | 163.6 | (134.9–192.3) | (105.3–254.3) | 159.0 | (130.6–187.4) | (100.5–251.6) | 151.2 | (133.3–169.2) | (111.7–204.7) | 149.4 | (132.6–166.3) | (111.5–200.3) | 158.5 | (138.8–178.1) | (114.0–220.2) | 142.0 | (122.9–161.1) | (87.3–231.0) |
CMNH 6194 (right) | 169.7 | (139.9–199.4) | (109.2–263.7) | 164.8 | (135.4–194.2) | (104.1–260.7) | 156.6 | (138.0–175.3) | (115.7–212.1) | 154.8 | (137.3–172.2) | (115.4–207.5) | 164.3 | (143.9–184.7) | (118.2–228.3) | 147.0 | (127.2–166.8) | (89.9–240.3) |
CMNH 50322 | 171.0 | (141.0–201.0) | (110.0–265.8) | 166.1 | (136.4–195.7) | (105.0–262.8) | 157.9 | (139.1–176.6) | (116.6–213.7) | 156.0 | (138.4–173.5) | (116.3–209.1) | 165.6 | (145.1–186.1) | (119.1–230.1) | 148.1 | (128.1–168.0) | (90.5–242.4) |
CMNH 8982 | 153.1 | (126.2–179.9) | (98.5–237.9) | 148.9 | (122.3–175.5) | (94.1–235.5) | 141.7 | (124.8–158.5) | (104.7–191.8) | 140.1 | (124.3–155.9) | (104.5–187.8) | 148.3 | (129.9–166.6) | (106.7–206.0) | 133.3 | (115.3–151.2) | (82.7–214.8) |
14.3.2 Using JM5
<-dunkleosteus_jaws%>%
JM5_estimatesmutate(OOL=predict(fit.JM5,.),
clade="Placodermi",shape="fusiform",family="Dunkleosteidae")%>%
augment(x=fit.OOL,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.OOL)$CF),)%>%
rename_at(vars(starts_with('.')), funs(paste0('fit1', .)))%>%
augment(x=fit.species_average,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.species_average)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit2', .)))%>%
augment(x=fit.fusiform,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.fusiform)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit3', .)))%>%
augment(x=fit.fusiform_averages,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.fusiform_averages)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit4', .)))%>%
augment(x=fit.shape_clade3,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.shape_clade3)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit5', .)))%>%
augment(x=fit.shape_clade_species_averages,newdata=.,interval="prediction") %>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.shape_clade4)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0('fit6', .)))%>%
mutate(specimen=dunkleosteus_jaws$specimen,
fit1.PE=paste0("(",
sprintf("%.1f",
round(fit1.fitted*(1-(regression.stats(fit.OOL)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit1.fitted*(1+(regression.stats(fit.OOL)$adjPE/100)),1)),
")"),
fit2.PE=paste0("(",
sprintf("%.1f",
round(fit2.fitted*(1-(regression.stats(fit.species_average)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit2.fitted*(1+(regression.stats(fit.species_average)$adjPE/100)),1)),
")"),
fit3.PE=paste0("(",
sprintf("%.1f",
round(fit3.fitted*(1-(regression.stats(fit.fusiform)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit3.fitted*(1+(regression.stats(fit.fusiform)$adjPE/100)),1)),
")"),
fit4.PE=paste0("(",
sprintf("%.1f",
round(fit4.fitted*(1-(regression.stats(fit.fusiform_averages)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit4.fitted*(1+(regression.stats(fit.fusiform_averages)$adjPE/100)),1)),
")"),
fit5.PE=paste0("(",
sprintf("%.1f",
round(fit5.fitted*(1-(regression.stats(fit.shape_clade3)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit5.fitted*(1+(regression.stats(fit.shape_clade3)$adjPE/100)),1)),
")"),
fit6.PE=paste0("(",
sprintf("%.1f",
round(fit6.fitted*(1-(regression.stats(fit.shape_clade4)$adjPE/100)),1)),
"–",
sprintf("%.1f",
round(fit6.fitted*(1+(regression.stats(fit.shape_clade4)$adjPE/100)),1)),
")"),
fit1.range=paste0("(",sprintf("%.1f",round(fit1.lower,1)),"–",
sprintf("%.1f",round(fit1.upper,1)),")"),
fit2.range=paste0("(",sprintf("%.1f",round(fit2.lower,1)),"–",
sprintf("%.1f",round(fit2.upper,1)),")"),
fit3.range=paste0("(",sprintf("%.1f",round(fit3.lower,1)),"–",
sprintf("%.1f",round(fit3.upper,1)),")"),
fit4.range=paste0("(",sprintf("%.1f",round(fit4.lower,1)),"–",
sprintf("%.1f",round(fit4.upper,1)),")"),
fit5.range=paste0("(",sprintf("%.1f",round(fit5.lower,1)),"–",
sprintf("%.1f",round(fit5.upper,1)),")"),
fit6.range=paste0("(",sprintf("%.1f",round(fit6.lower,1)),"–",
sprintf("%.1f",round(fit6.upper,1)),")"))%>%
remove_rownames()%>%
column_to_rownames("specimen")%>%
select(fit1.fitted,fit1.PE,fit1.range,
fit2.fitted,fit2.PE,fit2.range,
fit3.fitted,fit3.PE,fit3.range,
fit4.fitted,fit4.PE,fit4.range,
fit5.fitted,fit5.PE,fit5.range,
fit6.fitted,fit6.PE,fit6.range)
%>%
JM5_estimateskable(align="c", digits=1,
col.names=c("Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I.",
"Estimate","+/- %PE","95% C.I."),
caption="Length estimates of the largest known specimen of <i>Dunkleosteus terrelli</i> (CMNH 5936) using JM5 (length of the biting portion of the inferognathal). Estimates calculated by estimating OOL using the regression between JM5 and OOL, and then inserting that value into the respective equation for total length. All measurements in cm.")%>%
add_header_above(c(" "=1,"All specimens"=3,"Species averages"=3,
"All specimens"=3,"Species averages"=3,
"All specimens"=3,"Species averages"=3))%>%
add_header_above(c(" "=1,"All taxa"=6,"Fusiform fishes"=6,"With variable slopes for Chondrichthyes"=6))%>%
column_spec(c(2,5,8,11,14,17),bold=T)%>%
kable_styling()%>%
scroll_box(width = "100%")
Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | Estimate | +/- %PE | 95% C.I. | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
CMNH 5936 | 423.5 | (349.2–497.8) | (272.4–658.4) | 406.0 | (333.6–478.5) | (256.4–643.1) | 382.2 | (336.8–427.6) | (282.3–517.5) | 374.8 | (332.6–417.0) | (279.4–502.9) | 409.0 | (358.3–459.7) | (294.2–568.6) | 350.5 | (303.3–397.7) | (183.7–668.8) |
CMNH 5768 (right) | 360.7 | (297.4–424.0) | (232.1–560.7) | 346.6 | (284.8–408.5) | (218.9–548.9) | 326.8 | (288.0–365.7) | (241.4–442.6) | 321.0 | (284.8–357.1) | (239.3–430.5) | 348.5 | (305.3–391.8) | (250.7–484.5) | 300.9 | (260.4–341.5) | (162.4–557.6) |
CMNH 5768 (left) | 340.6 | (280.8–400.4) | (219.1–529.5) | 327.6 | (269.1–386.1) | (206.9–518.7) | 309.1 | (272.4–345.8) | (228.3–418.5) | 303.6 | (269.5–337.8) | (226.4–407.3) | 329.2 | (288.3–370.0) | (236.8–457.6) | 285.0 | (246.6–323.4) | (155.4–522.6) |
CMNH 8131 | 319.1 | (263.1–375.1) | (205.3–496.0) | 307.2 | (252.3–362.0) | (194.0–486.3) | 290.0 | (255.6–324.5) | (214.2–392.7) | 285.1 | (253.0–317.2) | (212.5–382.3) | 308.4 | (270.2–346.7) | (221.9–428.7) | 267.8 | (231.8–303.9) | (147.8–485.5) |
CMNH 7054 (left) | 313.6 | (258.6–368.6) | (201.7–487.5) | 302.0 | (248.1–355.8) | (190.7–478.1) | 285.1 | (251.3–319.0) | (210.6–386.1) | 280.3 | (248.7–311.9) | (209.0–376.0) | 303.1 | (265.5–340.7) | (218.1–421.4) | 263.5 | (228.0–298.9) | (145.8–476.1) |
CMNH 7054 (right) | 303.6 | (250.4–356.9) | (195.3–472.0) | 292.5 | (240.3–344.7) | (184.8–463.1) | 276.3 | (243.5–309.1) | (204.1–374.1) | 271.7 | (241.1–302.3) | (202.6–364.4) | 293.5 | (257.1–329.9) | (211.2–408.0) | 255.5 | (221.1–289.9) | (142.2–459.1) |
CMNH 6090 (left) | 277.5 | (228.8–326.2) | (178.5–431.3) | 267.6 | (219.9–315.4) | (169.1–423.7) | 253.1 | (223.0–283.1) | (186.9–342.6) | 249.0 | (221.0–277.1) | (185.7–334.0) | 268.3 | (235.0–301.6) | (193.0–373.0) | 234.5 | (202.9–266.1) | (132.6–414.9) |
CMNH 6090 (right) | 285.0 | (235.0–335.1) | (183.4–443.1) | 274.8 | (225.8–323.9) | (173.6–435.1) | 259.8 | (228.9–290.7) | (191.9–351.7) | 255.6 | (226.8–284.4) | (190.6–342.8) | 275.6 | (241.4–309.8) | (198.3–383.1) | 240.6 | (208.2–273.0) | (135.4–427.6) |
CMNH 5740 | 277.4 | (228.7–326.0) | (178.4–431.1) | 267.5 | (219.8–315.3) | (169.0–423.5) | 253.0 | (222.9–283.0) | (186.8–342.5) | 248.9 | (220.9–277.0) | (185.6–333.8) | 268.2 | (234.9–301.5) | (192.9–372.8) | 234.4 | (202.9–266.0) | (132.5–414.7) |
CMNH OC 1421 | 255.0 | (210.3–299.8) | (164.1–396.4) | 246.3 | (202.3–290.3) | (155.6–389.9) | 233.1 | (205.4–260.8) | (172.2–315.6) | 229.5 | (203.7–255.4) | (171.2–307.8) | 246.7 | (216.1–277.3) | (177.5–342.9) | 216.5 | (187.3–245.6) | (124.1–377.5) |
CMNH 5007 | 201.5 | (166.1–236.8) | (129.6–313.2) | 195.2 | (160.4–230.1) | (123.4–308.9) | 185.2 | (163.2–207.2) | (136.8–250.8) | 182.8 | (162.2–203.3) | (136.3–245.0) | 195.0 | (170.8–219.2) | (140.3–271.0) | 173.0 | (149.7–196.4) | (103.1–290.4) |
CMNH 7424 | 188.9 | (155.8–222.1) | (121.6–293.6) | 183.2 | (150.5–215.9) | (115.8–289.9) | 174.0 | (153.3–194.6) | (128.5–235.5) | 171.7 | (152.4–191.1) | (128.1–230.2) | 182.9 | (160.2–205.6) | (131.6–254.2) | 162.8 | (140.9–184.7) | (98.0–270.5) |
CMNH 6194 (left) | 176.2 | (145.3–207.1) | (113.4–273.8) | 171.0 | (140.5–201.6) | (108.1–270.6) | 162.5 | (143.2–181.8) | (120.0–220.0) | 160.5 | (142.4–178.6) | (119.7–215.2) | 170.6 | (149.4–191.7) | (122.7–237.1) | 152.3 | (131.8–172.9) | (92.6–250.5) |
CMNH 6194 (right) | 175.4 | (144.6–206.2) | (112.9–272.6) | 170.3 | (139.9–200.7) | (107.6–269.5) | 161.8 | (142.6–181.0) | (119.5–219.1) | 159.8 | (141.8–177.8) | (119.2–214.3) | 169.8 | (148.8–190.9) | (122.2–236.0) | 151.7 | (131.3–172.1) | (92.3–249.3) |
CMNH 50322 | 160.0 | (131.9–188.0) | (102.9–248.6) | 155.5 | (127.8–183.3) | (98.3–246.0) | 147.9 | (130.3–165.5) | (109.3–200.2) | 146.2 | (129.7–162.7) | (109.1–196.0) | 154.9 | (135.7–174.1) | (111.5–215.3) | 139.0 | (120.3–157.7) | (85.7–225.4) |
CMNH 8982 | 151.4 | (124.8–178.0) | (97.4–235.3) | 147.3 | (121.0–173.6) | (93.1–233.1) | 140.2 | (123.5–156.9) | (103.6–189.8) | 138.6 | (123.0–154.3) | (103.4–185.8) | 146.7 | (128.5–164.9) | (105.5–203.8) | 131.9 | (114.1–149.7) | (82.0–212.3) |
cbind(
%>%
JM3_estimatesslice(1)%>%
mutate(across(where(is.numeric), ~as.character(sprintf("%.1f", round(.,1))))) %>%
rename_at(vars(starts_with('fit1.')), funs(gsub('fit1.','JM3_All specimens_Individual Data_', .)))%>%
rename_at(vars(starts_with('fit2.')), funs(gsub('fit2.','JM3_All specimens_Species Averages_', .)))%>%
rename_at(vars(starts_with('fit3.')), funs(gsub('fit3.','JM3_Fusiform fishes only_Individual Data_', .)))%>%
rename_at(vars(starts_with('fit4.')), funs(gsub('fit4.','JM3_Fusiform fishes only_Species Averages_', .)))%>%
rename_at(vars(starts_with('fit5.')), funs(gsub('fit5.','JM3_Variable slope for chondrichthyans_Individual Data_', .)))%>%
rename_at(vars(starts_with('fit6.')), funs(gsub('fit6.','JM3_Variable slope for chondrichthyans_Species Averages_', .))),
%>%
JM5_estimatesslice(1)%>%
mutate(across(where(is.numeric), ~as.character(sprintf("%.1f", round(.,1))))) %>%
rename_at(vars(starts_with('fit1.')), funs(gsub('fit1.','JM5_All specimens_Individual Data_', .)))%>%
rename_at(vars(starts_with('fit2.')), funs(gsub('fit2.','JM5_All specimens_Species Averages_', .)))%>%
rename_at(vars(starts_with('fit3.')), funs(gsub('fit3.','JM5_Fusiform fishes only_Individual Data_', .)))%>%
rename_at(vars(starts_with('fit4.')), funs(gsub('fit4.','JM5_Fusiform fishes only_Species Averages_', .)))%>%
rename_at(vars(starts_with('fit5.')), funs(gsub('fit5.','JM5_Variable slope for chondrichthyans_Individual Data_', .)))%>%
rename_at(vars(starts_with('fit6.')), funs(gsub('fit6.','JM5_Variable slope for chondrichthyans_Species Averages_', .)))
%>%
)pivot_longer(data=.,
cols=everything(),
names_to = c("measurement","model","type","data_value"),
names_sep = "_")%>%
mutate(total=paste(measurement,model,type,sep="_"),
name=rep(c("Est.","+/- PE","95% P.I."),12))%>%
select(total,value,name)%>%
pivot_wider(id_cols="total",
names_from="name")%>%
separate(col=total,
into=c("Measurement","Model","Type"),
sep="_")%>%
write.xlsx(.,"Devonian Fish Tale Table 4 (CMNH 5936).xlsx")
cbind(
%>% slice(1) %>% rename_with(~str_c("JM3_",.),.cols=everything()),
JM3_estimates %>% slice(1) %>% rename_with(~str_c("JM5_",.),.cols=everything()))%>%
JM5_estimates select(ends_with(".fitted"))%>%
gather()%>%
summarise(mean=mean(value),median=median(value))%>%
kable(digits=1,
col.names=c("Mean","Median"),
caption="Mean and median length estimates for the largest known specimen of <i>Dunkleosteus terrelli</i> (CMNH 5936)",
table.attr = "style='width:70%;'")%>%
kable_styling()
Mean | Median |
---|---|
384.6 | 387.5 |
14.4 Predicted lengths for CMNH 5936 using other jaw measurements
<-dunkleosteus_jaws %>%
CMNH_5936_estimatesfilter(specimen=="CMNH 5936") %>%
select(JM1:JM5)%>%
mutate(shape="fusiform",clade="Placodermi",family="Dunkleosteidae",
inferognathal_length=predict(lm(inferognathal_length~JM5,dunkleosteus_jaws),newdata=.))%>%
augment(lm(OOL~JM1,dunkleosteus_jaws),newdata=.) %>%
rename(JM1.fitted=.fitted)%>%
augment(lm(OOL~JM2,dunkleosteus_jaws),newdata=.) %>%
rename(JM2.fitted=.fitted)%>%
augment(fit.JM3,newdata=.) %>%
rename(JM3.fitted=.fitted)%>%
augment(lm(OOL~JM4,dunkleosteus_jaws),newdata=.) %>%
rename(JM4.fitted=.fitted)%>%
augment(fit.JM5,newdata=.) %>%
rename(JM5.fitted=.fitted)%>%
augment(lm(OOL~inferognathal_length,dunkleosteus_jaws),newdata=.) %>%
rename(inferognathal_length.fitted=.fitted)
<-CMNH_5936_estimates %>%
CMNH_5936_estimatesmutate(length_JM1=exp(predict(fit.shape_clade3,newdata=CMNH_5936_estimates%>%rename(OOL=JM1.fitted)))*regression.stats(fit.shape_clade3)$CF,
length_JM2=exp(predict(fit.shape_clade3,newdata=CMNH_5936_estimates%>%rename(OOL=JM2.fitted)))*regression.stats(fit.shape_clade3)$CF,
length_JM3=exp(predict(fit.shape_clade3,newdata=CMNH_5936_estimates%>%rename(OOL=JM3.fitted)))*regression.stats(fit.shape_clade3)$CF,
length_JM4=exp(predict(fit.shape_clade3,newdata=CMNH_5936_estimates%>%rename(OOL=JM4.fitted)))*regression.stats(fit.shape_clade3)$CF,
length_JM5=exp(predict(fit.shape_clade3,newdata=CMNH_5936_estimates%>%rename(OOL=JM5.fitted)))*regression.stats(fit.shape_clade3)$CF,
length_inf=exp(predict(fit.shape_clade3,newdata=CMNH_5936_estimates%>%rename(OOL=inferognathal_length.fitted)))*regression.stats(fit.shape_clade3)$CF
)
cbind(CMNH_5936_estimates %>% select(JM1:JM5,inferognathal_length) %>% rename ("Inferognathal Length"=inferognathal_length) %>%t(),
%>% select(JM1.fitted:inferognathal_length.fitted) %>% t(),
CMNH_5936_estimates %>% select(length_JM1:length_inf) %>% t()) %>%
CMNH_5936_estimates kable(col.names=c("Inferognathal Measurement","Estimated OOL","Estimated Total Length"),digits=1,
align="c",
caption="Estimated lengths for CMNH 5936 using all jaw measurements considered. Inferognathal length was estimated based on allometric relationship with JM5 in sample of <i>Dunkleosteus terrelli</i>, as the oral region of the inferognathal is consistently around 50% of total inferognathal length in <i>Dunkleosteus</i>. Length estimated from OOL using the equation with shape and a separate allometric line for sharks. All measurements in cm.") %>%
kable_styling()
Inferognathal Measurement | Estimated OOL | Estimated Total Length | |
---|---|---|---|
JM1 | 12.8 | 52.4 | 339.8 |
JM2 | 10.8 | 60.2 | 390.0 |
JM3 | 18.6 | 61.0 | 395.4 |
JM4 | 20.4 | 67.0 | 433.9 |
JM5 | 33.9 | 63.1 | 409.0 |
Inferognathal Length | 68.4 | 62.9 | 407.4 |
Based on this none of the inferognathal measurements appear to produce sizes of 5+ m for the largest individuals of Dunkleosteus terrelli, with most producing estimates around 3.9-4.1 m.
15 Comparing support statistics across models
<-sapply(c("fit.OOL","fit.no_extreme_shapes","fit.with_shape","fit.fusiform",
equations"fit.relativedepth4","with_snout_length","fit.minus_snout_length1",
"fit.pelagic","fit.no_acanthopterygii2","fit.sharks",
"fit.shape_clade","fit.shape_clade3",
"fit.species_average","fit.species_average2","fit.with_shape_averages",
"fit.fusiform_averages","fit.relativedepth_averages","fit.minus_snout_length2",
"fit.pelagic_averages","fit.no_acanthopterygii2_averages","fit.sharks_averages",
"fit.shape_clade_species_averages"), function(x)regression.stats(get(x)))%>%
t()%>%as.data.frame()%>%
rownames_to_column()%>%
mutate(row=1:nrow(.))
%>%
equationsmutate(model = ifelse(row <
%>%filter(rowname=="fit.species_average")%>%pull(row)),
(equations"individual values","species averages"))%>%
select(rowname,model,everything())%>%
select(-row)%>%
kable()%>%
kable_styling()%>%
scroll_box(width = "100%")
rowname | model | N | df | r2 | adjr2 | AIC | BIC | logLik | PE | QMLE | smear | RE | CF | adjPE | SEE |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
fit.OOL | individual values | 3169 | 3167 | 0.9473 | 0.9473 | -463 | -445 | 234 | 17.83 | 1.026 | 1.027 | 1.005 | 1.019 | 17.55 | 25.21 |
fit.no_extreme_shapes | individual values | 2660 | 2658 | 0.962 | 0.962 | -1164 | -1147 | 585 | 15.38 | 1.019 | 1.02 | 0.993 | 1.011 | 15.26 | 21.44 |
fit.with_shape | individual values | 3398 | 3389 | 0.9741 | 0.9741 | -2846 | -2785 | 1433 | 12.1 | 1.013 | 1.013 | 1.003 | 1.009 | 12.03 | 17.23 |
fit.fusiform | individual values | 1741 | 1739 | 0.9804 | 0.9804 | -1562 | -1545 | 784 | 11.98 | 1.012 | 1.012 | 1 | 1.008 | 11.88 | 16.69 |
fit.relativedepth4 | individual values | 2845 | 2842 | 0.95 | 0.95 | -761 | -737 | 384 | 16.26 | 1.023 | 1.024 | 1.023 | 1.023 | 16.17 | 23.56 |
with_snout_length | individual values | 3169 | 3166 | 0.9614 | 0.9614 | -1451 | -1426 | 729 | 14.82 | 1.019 | 1.02 | 1.016 | 1.018 | 14.62 | 21.21 |
fit.minus_snout_length1 | individual values | 3169 | 3165 | 0.9587 | 0.9586 | -1260 | -1230 | 635 | 15.55 | 1.02 | 1.021 | 0.999 | 1.013 | 15.41 | 21.92 |
fit.pelagic | individual values | 638 | 636 | 0.9531 | 0.9531 | -256 | -242 | 131 | 16.65 | 1.02 | 1.02 | 0.989 | 1.009 | 16.56 | 21.83 |
fit.no_acanthopterygii2 | individual values | 2394 | 2392 | 0.9602 | 0.9602 | -687 | -670 | 347 | 16.47 | 1.022 | 1.022 | 1.007 | 1.017 | 16.26 | 23.3 |
fit.sharks | individual values | 540 | 538 | 0.9619 | 0.9618 | -544 | -531 | 275 | 11.57 | 1.011 | 1.011 | 1.014 | 1.012 | 11.51 | 15.69 |
fit.shape_clade | individual values | 3169 | 3152 | 0.9726 | 0.9725 | -2505 | -2396 | 1271 | 11.84 | 1.013 | 1.014 | 1.014 | 1.014 | 11.73 | 17.65 |
fit.shape_clade3 | individual values | 3169 | 3158 | 0.9707 | 0.9707 | -2310 | -2237 | 1167 | 12.45 | 1.014 | 1.015 | 1.016 | 1.015 | 12.4 | 18.27 |
fit.species_average | species averages | 967 | 965 | 0.9349 | 0.9349 | -66 | -51 | 36 | 18.01 | 1.028 | 1.031 | 1.016 | 1.025 | 17.85 | 26.29 |
fit.species_average2 | species averages | 777 | 775 | 0.954 | 0.954 | -266 | -252 | 136 | 15.45 | 1.021 | 1.024 | 1.003 | 1.016 | 15.47 | 22.55 |
fit.with_shape_averages | species averages | 958 | 949 | 0.9663 | 0.966 | -689 | -640 | 354 | 12.69 | 1.014 | 1.014 | 1.004 | 1.011 | 12.57 | 18.29 |
fit.fusiform_averages | species averages | 600 | 598 | 0.9773 | 0.9773 | -579 | -566 | 293 | 11.33 | 1.011 | 1.011 | 0.999 | 1.007 | 11.26 | 16.05 |
fit.relativedepth_averages | species averages | 914 | 911 | 0.9353 | 0.9351 | -86 | -67 | 47 | 17.76 | 1.027 | 1.03 | 1.016 | 1.024 | 17.59 | 25.89 |
fit.minus_snout_length2 | species averages | 967 | 963 | 0.9465 | 0.9463 | -259 | -235 | 134 | 15.93 | 1.023 | 1.025 | 1.011 | 1.019 | 15.96 | 23.49 |
fit.pelagic_averages | species averages | 126 | 124 | 0.9546 | 0.9543 | -51 | -43 | 29 | 15.98 | 1.019 | 1.019 | 0.993 | 1.01 | 15.84 | 21.45 |
fit.no_acanthopterygii2_averages | species averages | 392 | 390 | 0.9773 | 0.9772 | -341 | -329 | 174 | 12.33 | 1.012 | 1.013 | 0.988 | 1.004 | 12.32 | 16.86 |
fit.sharks_averages | species averages | 171 | 169 | 0.9568 | 0.9565 | -191 | -181 | 98 | 10.54 | 1.009 | 1.009 | 1.005 | 1.008 | 10.55 | 14.67 |
fit.shape_clade_species_averages | species averages | 967 | 950 | 0.9598 | 0.9592 | -502 | -415 | 269 | 13.36 | 1.017 | 1.018 | 1.015 | 1.017 | 13.23 | 20.3 |
# Writing model statistics for major models in a single, easily readable table, i.e., Table 1 of the manuscript
<-rbind(
(model_stats%$%
fit.OOLcbind(model="All species",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(OOL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.no_extreme_shapescbind(model="Fusiform and elongate taxa",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(OOL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.with_shapecbind(model="With shape as covariate",
equation=paste0("See Supplementary Information"),
regression.stats(.)),
%$%
fit.fusiformcbind(model="Fusiform species only",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(OOL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.relativedepth4cbind(model="Including body depth as covariate",
equation=paste0("See Supplementary Information"),
regression.stats(.)),
%$%
with_snout_lengthcbind(model="Including snout length as covariate",
equation=paste0("Ln(TL) = ",round(.$coefficients[3],4),
" * Ln(OOL) ",ifelse(.$coefficients[2]>1,"+","-"),
" ",abs(round(.$coefficients[2],4))," * Ln(SNL) ",
ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.pelagiccbind(model="Pelagic species only",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(OOL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.no_acanthopterygii2cbind(model="Excluding Acanthopterygii, fusiform and elongate taxa only",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(OOL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.sharkscbind(model="Sharks only",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(OOL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.)),
%$%
fit.shape_clade3cbind(model="With shape, allowing variable slope for Chondrichthyes",
equation=paste0("See Supplementary Information"),
regression.stats(.)),
lm(log(total_length)~log(head_length),data_final)%$%
cbind(model="Head length",
equation=paste0("Ln(TL) = ",round(.$coefficients[2],4),
" * Ln(HDL) ",ifelse(.$coefficients[1]>1,"+","-"),
" ",abs(round(.$coefficients[1],4))),
regression.stats(.))
%>%
)rownames_to_column()%>%
select(model,N,equation,adjr2,AIC,BIC,PE,CF,adjPE,SEE)%>%
rename(Equation=equation,
"%PE"=PE,
"r2adj"=adjr2,
"%PEcf"=adjPE,
"%SEE"=SEE)%>%
column_to_rownames("model")
%>%
)write.csv("Devonian Fish Tale Table 1 (Model Statistics).csv")
Overall, the models that produce the best support statistics (AIC, %PEcf) are either the model considering only fusiform fishes (fit.fusiform
), the model that includes a crude accounting for shape by including shape
as a categorical variable (fit.with_shape
), or the model that includes shape and allows slope to differentiate between chondrichthyans and all other fishes due to the largest chondricthyans primarily being short-bodied lamnids and the smallest being elongate-bodied carpet sharks (fit.shape_clade3
).
16 Predicting body mass of Dunkleosteus and other arthrodires
16.1 Estimating precaudal and fork length in Dunkleosteus
16.1.1 Estimating fork length using total length of all observations
<-data_final%>%
total_length_to_fork_lengthfilter(length_as=="total length")%>%
filter(!(total_length==fork_length))%>%
filter(!is.na(fork_length))%>%
lm(log(fork_length)~log(total_length)+(clade=="Placodermi"|clade=="Chondrichthyes")+habitat,.)
summary(total_length_to_fork_length)
##
## Call:
## lm(formula = log(fork_length) ~ log(total_length) + (clade ==
## "Placodermi" | clade == "Chondrichthyes") + habitat, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2.39328 -0.02269 0.00416 0.03057 0.23894
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.092653 0.008881 -10.433 < 2e-16 ***
## log(total_length) 1.001728 0.002531 395.773 < 2e-16 ***
## clade == "Placodermi" | clade == "Chondrichthyes"TRUE -0.084416 0.005716 -14.769 < 2e-16 ***
## habitatbenthic 0.036664 0.013179 2.782 0.005462 **
## habitatneritic -0.017093 0.005080 -3.365 0.000783 ***
## habitatpelagic -0.018487 0.005641 -3.277 0.001069 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.07903 on 1694 degrees of freedom
## Multiple R-squared: 0.994, Adjusted R-squared: 0.994
## F-statistic: 5.609e+04 on 5 and 1694 DF, p-value: < 2.2e-16
16.1.2 Estimating precaudal length using total length of all observations
%>%
data_finalfilter(length_as=="total length")%>%
mutate(clade=relevel(factor(clade),"Placodermi"))%>%
filter(!is.na(precaudal_length))%$%
lm(log(precaudal_length)~log(total_length)+clade+habitat,.)%>%
summary()
##
## Call:
## lm(formula = log(precaudal_length) ~ log(total_length) + clade +
## habitat, data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.71852 -0.02860 0.00179 0.03430 0.20519
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.3428725 0.0226302 -15.151 < 2e-16 ***
## log(total_length) 1.0047415 0.0015710 639.562 < 2e-16 ***
## cladeActinopterygii 0.1267135 0.0219543 5.772 8.76e-09 ***
## cladeChondrichthyes 0.0477143 0.0221117 2.158 0.0310 *
## cladePetromyzontiformes 0.0038649 0.0253193 0.153 0.8787
## cladeSarcopterygii 0.0866759 0.0269157 3.220 0.0013 **
## habitatbenthic 0.0277006 0.0047474 5.835 6.03e-09 ***
## habitatneritic 0.0001266 0.0033331 0.038 0.9697
## habitatpelagic 0.0214364 0.0035927 5.967 2.74e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.06194 on 2662 degrees of freedom
## (6 observations deleted due to missingness)
## Multiple R-squared: 0.9963, Adjusted R-squared: 0.9963
## F-statistic: 8.94e+04 on 8 and 2662 DF, p-value: < 2.2e-16
Based on this, setting Placodermi
as the base level for clade
and the limited evidence we have for precaudal/total lengths in arthrodires, chondrichthyans seem like a suitable model to calculate fork and precaudal length in arthrodires, but actinopterygians show a comparatively shorter caudal fin and longer precaudal region than arthrodires.
<-data_final%>%
total_length_to_standard_lengthfilter(length_as=="total length")%>%
filter(!is.na(precaudal_length))%$%
lm(log(precaudal_length)~log(total_length)+(clade=="Placodermi"|clade=="Chondrichthyes")+habitat+shape,.)
summary(total_length_to_standard_length)
##
## Call:
## lm(formula = log(precaudal_length) ~ log(total_length) + (clade ==
## "Placodermi" | clade == "Chondrichthyes") + habitat + shape,
## data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.68971 -0.02900 -0.00119 0.03513 0.26484
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -0.2093917 0.0053967 -38.800 < 2e-16 ***
## log(total_length) 1.0026170 0.0015310 654.879 < 2e-16 ***
## clade == "Placodermi" | clade == "Chondrichthyes"TRUE -0.0742912 0.0035015 -21.217 < 2e-16 ***
## habitatbenthic 0.0133753 0.0050245 2.662 0.00781 **
## habitatneritic 0.0005698 0.0032508 0.175 0.86086
## habitatpelagic 0.0195545 0.0035915 5.445 5.67e-08 ***
## shapeanguilliform -0.0112573 0.0081300 -1.385 0.16627
## shapecompressiform -0.0209863 0.0040400 -5.195 2.21e-07 ***
## shapeelongate 0.0240499 0.0036321 6.621 4.29e-11 ***
## shapeflattened 0.0745609 0.0139088 5.361 9.00e-08 ***
## shapemacruriform -0.1160331 0.0107117 -10.832 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.06052 on 2660 degrees of freedom
## (6 observations deleted due to missingness)
## Multiple R-squared: 0.9965, Adjusted R-squared: 0.9964
## F-statistic: 7.491e+04 on 10 and 2660 DF, p-value: < 2.2e-16
16.1.3 Predicting total length in placoderms in this study assuming fusiform body shape and model with variable slope for clade
<-fossil_taxa%>%
fossil_taxamutate(shape="fusiform")%>%
mutate(total_length=ifelse(is.na(total_length),
exp(predict(fit.shape_clade3,.))*
regression.stats(fit.shape_clade3)$CF,
%>%
total_length))mutate(precaudal_length=ifelse(is.na(precaudal_length),
exp(predict(total_length_to_standard_length,.))*
regression.stats(total_length_to_standard_length)$CF,
precaudal_length),fork_length=ifelse(is.na(fork_length),
exp(predict(total_length_to_fork_length,.))*
regression.stats(total_length_to_fork_length)$CF,
fork_length))
16.2 Estimating body mass in Dunkleosteus using a modified ellipsoid equation
The length-weight equation in this study expands on the methodology of Ault and Luo (2013). Ault and Luo (2013) noted that the body of the fish is best modeled as an ellipsoid, with the equation:
\[ weight = girth^2*length + girth*length + girth^2 + girth + length \]
leaving five coefficients to be solved for experimentally.
To this I add three other parameters. Although a fish’s body is best modeled as an ellipsoid, it is an asymmetrical ellipsoid, with one bulbous half (encompassing the head region) and one thinner, more tapering half (including posterior half of the body tapering to the caudal peduncle). These must be accounted for separately to accurately estimate body mass, especially in an interspecific model, as the proportion of the thicker head region to the thinner abdomen and trunk varies among fishes. E.g., Dunkleosteus has an extremely thick head and likely had a strongly tapering caudal region given its pelagic habits (Carr, 2010), and cannot be modeled as a simple ellipsoid.
Additionally, the caudal fin contributes a small but non-insignificant amount to body mass. This is expected to be greater in taxa with internally heterocercal tails than those in which the tail is supported only by lepidotrichia. As a result, the model was fit with an additional parameter for caudal fins, with a variable level for taxa with internally heterocercal tails (Chondrichthyes, Placodermi, Sarcopterygii, and basal actinopterygian lineages like Polypteriformes, Amiiformes, Lepisosteiformes, and Acipenseriformes) where the spinal cord extends into the caudal fin, and those with internally homocercal tails (Teleostei) where it is truncated.
Taxa that lacked a distinct caudal fin and pre-caudal region (Anguilliformes, Mola) had to be excluded from the model, as their lack of a caudal fin resulted in a significant bias in body mass estimates when applied to fossil taxa.
Another potential source of error in body mass estimates of fishes is the swim bladder. Because the swim bladder is a large, gas-filled organ, this reduces the total density of the fish, and is expected to make fish with swim bladders comparatively lighter at the same volume than those without (Alexander, 1967). Fish without swim bladders include Petromyzontiformes and Chondrichthyans, but also most scombrids (but not istiophoriforms; see McCune and Carlson 2004 for a more comprehensive list of swim bladder loss in fishes). Whether arthrodires had a swim bladder is unknown: the frequently cited presence of lungs in the antiarch Bothriolepis appears to be a paleontological misinterpretation (see Goujet 2011 and Trinajstic et al. 2022) but there is circumstantial evidence based on taphonomy and body shape that Dunkleosteus did not have an enlarged liver similar to extant sharks and instead possessed some form of gas-filled floatation organs (Carr 2010; Engelman pers obs.). For the purposes of this study both were reported here, but the more conservative interpretation of Dunkleosteus without a swimbladder was considered the closer to the actual values.
The list of actinopterygian taxa considered as lacking the swim bladder was taken from McCune and Carlson (2004), Collette and Nauen (1983), and Bone (1972). All extant non-osteichthyan taxa were considered as lacking the swim bladder. The Dipnoi were coded as having swim bladders and the Latimeriidae coded as absent; in coelocanths the ancestral swim-bladder has been converted into a fat-filled organ (Cupello et al. 2015). No attempt was made to account for variation in the size of the swim bladder between fishes.
Girth was not available for all fishes, but body_width
and body_depth
were. There is no easy way to calculate the perimeter of an ellipse, but one commonly used way to do so is Ramanujan’s approximation (Ramanujan 1962; Villarino 2008), which is defined as…
\[ perimeter = π * [(a+b)+\frac{3*(a-b)^2)}{10(a+b)+\sqrt{a^2+14ab+b^2}}] \]
In which \(a\) is the radius of the major (longest) axis of the ellipse and \(b\) is the radius of the minor (i.e., the axis perpendicular to the major axis). In a fish, the major axis of the body in frontal view is almost always the dorsoventral axis, with the mediolateral axis being much narrower (especially in actinopterygians).
Thus, a user-defined formula was written in R to calculate girth based on Ramanujan’s approximation, assuming \(\frac{\text{body_depth}}{2}\) represented the radius of the major axis and \(\frac{\text{body_width}}{2}\) represented the radius of the minor.
#Testing if approximation formula works
%>%
fossil_taxamutate(girth2=ramanujan.approx(body_depth,body_width))%>%
drop_na(girth,girth2)%>%
select(taxon,specimen,girth,girth2)%>%
remove_rownames()%>%
kable(digits=1,col.names=c("Taxon","Specimen","Measured Girth","Estimated Girth Using Ramanujan Approximation"),
caption="Testing Ramanujan's formula for approximating the perimeter of an ellipse on arthrodire specimens for which girth could be directly measured. All measurements in cm.")%>%
column_spec(1, italic = T)%>%
kable_styling()
Taxon | Specimen | Measured Girth | Estimated Girth Using Ramanujan Approximation |
---|---|---|---|
Harrytoombsia elegans | WAM P50914 | 23.1 | 21.4 |
Camuropiscis concinnus | WAM P50976 | 13.0 | 11.4 |
Compagopiscis croucheri | P50942 | 20.8 | 19.3 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 24.8 | 24.1 |
Heintzichthys gouldii | NHMUK PV P 9335 | 77.7 | 74.6 |
Dunkleosteus terrelli | CMNH 7424 | 147.9 | 122.2 |
Dunkleosteus terrelli | CMNH 6090 | 223.0 | 210.1 |
Dunkleosteus terrelli | CMNH 7054 | 215.3 | 207.0 |
Dunkleosteus terrelli | CMNH 5768 | 312.7 | 327.8 |
The actual values of girth
are slightly higher than the approximation. This implies that arthrodires are slightly “blockier” than would be expected if modeled by a perfect ellipse. However, this should prove sufficient for estimating girth in fish specimens for which body_depth
and body_width
is available but girth
was not reported or measurable, most of which are much less blocky than arthrodires.
<-
fit.ellipsoid%>%
data_finalfilter(length_as=="total length",
!=precaudal_length)%>%
total_lengthdrop_na(precaudal_length)%>%
mutate(girth=ifelse(!is.na(girth),girth,
ramanujan.approx(body_depth,body_width)))%$%
lm(log(body_mass)~I(log(girth)^2)*log(precaudal_length)+swimbladder+
log(girth)*log(precaudal_length)+
log(precaudal_length)*log(head_length)-log(head_length)+
:log(total_length-precaudal_length),
heterocercal
.)<-
fit.ellipsoid_no_swimbladder%>%
data_finalfilter(length_as=="total length",
!=precaudal_length)%>%
total_lengthdrop_na(precaudal_length)%>%
mutate(girth=ifelse(!is.na(girth),girth,
ramanujan.approx(body_depth,body_width)))%$%
lm(log(body_mass)~I(log(girth)^2)*log(precaudal_length)+
log(girth)*log(precaudal_length)+
log(precaudal_length)*log(head_length)-log(head_length)+
:log(total_length-precaudal_length),
heterocercal .)
summary(fit.ellipsoid)
##
## Call:
## lm(formula = log(body_mass) ~ I(log(girth)^2) * log(precaudal_length) +
## swimbladder + log(girth) * log(precaudal_length) + log(precaudal_length) *
## log(head_length) - log(head_length) + heterocercal:log(total_length -
## precaudal_length), data = .)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1.7960 -0.1623 -0.0075 0.1562 1.2890
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -3.779040 0.184857 -20.443 < 2e-16 ***
## I(log(girth)^2) 0.335456 0.025047 13.393 < 2e-16 ***
## log(precaudal_length) 2.374638 0.087108 27.261 < 2e-16 ***
## swimbladderTRUE 0.100278 0.045260 2.216 0.0269 *
## log(girth) 0.914463 0.113449 8.061 2.15e-15 ***
## I(log(girth)^2):log(precaudal_length) 0.008503 0.005037 1.688 0.0917 .
## log(precaudal_length):log(girth) -0.529970 0.041916 -12.644 < 2e-16 ***
## log(precaudal_length):log(head_length) 0.116825 0.015195 7.688 3.55e-14 ***
## heterocercalFALSE:log(total_length - precaudal_length) 0.176658 0.032178 5.490 5.09e-08 ***
## heterocercalTRUE:log(total_length - precaudal_length) 0.180682 0.029982 6.026 2.35e-09 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2858 on 1003 degrees of freedom
## (1649 observations deleted due to missingness)
## Multiple R-squared: 0.9915, Adjusted R-squared: 0.9915
## F-statistic: 1.304e+04 on 9 and 1003 DF, p-value: < 2.2e-16
regression.stats(fit.ellipsoid)
The ellipsoid model predicts body mass very well, considering it is an interspecific model based on all fishes and many of the data were estimated based on species-specific length-weight equations. Additionally, the two extra parameters added (ratio of head length to precaudal length, caudal fin size, and presence of swim bladder) explained statistically detectable amounts of variation in the model. There are probably more precise ways to model the body mass of Dunkleosteus (e.g., a volumetric model; Brassey 2016), but for the purposes of this study this seems reliable enough.
rbind(
model1=(lm(log(body_mass)~I(log(girth)^2)*log(precaudal_length)+
log(girth)*log(precaudal_length)+
log(precaudal_length)*log(head_length)-log(head_length)+
!="Actinopterygii"|higher_group=="Basal Actinopterygii"):log(total_length-precaudal_length),
(clade%>%drop_na(girth,body_depth,body_width)%>%
data_finalmutate(precaudal_length=ifelse(is.na(precaudal_length)|
==precaudal_length,
total_length-1,
total_length%>%
precaudal_length))))regression.stats(.),
model2=(lm(log(body_mass)~I(log(girth)^2)*log(precaudal_length)+
log(girth)*log(precaudal_length)+
log(precaudal_length)*log(head_length)-log(head_length)+
!="Actinopterygii"|higher_group=="Basal Actinopterygii"):log(total_length-precaudal_length),
(clade%>%drop_na(girth,body_depth,body_width)%>%
data_finalmutate(precaudal_length=ifelse(is.na(precaudal_length)|
==precaudal_length,
total_length-1,
total_length
precaudal_length),girth=ramanujan.approx(body_depth,body_width))))%>%
regression.stats(.))%>%
`rownames<-`(c("Model Using Directly Measured Girth (when available)",
"Model Using Girth Estimated from Depth and Width"))
A model using the directly-measured value for girth, when it was directly measured in the specimens in question (usually in the collections of the CMNH, FSBC, and OSUM) produced higher errors and worse AIC and BIC values when all other variables are held equal. This is likely to be due to measurement error in measuring girth rather than modelling it based on body_width
and body_depth
.
However, measured girth should still be accurate for arthrodires because the issues with girth
were primarily driven by the difficulties of measuring girth
in fluid-preserved fish, rather than fossilized specimens.
<-fossil_taxa%>%
fossil_taxamutate(girth3=girth,
girth=ifelse(is.na(girth),ramanujan.approx(body_depth,body_width),girth))%>%
augment(fit.ellipsoid,
newdata=.,
interval="predict")%>%
mutate(girth=girth3)%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.ellipsoid)$CF))%>%
mutate(body_mass=.fitted,
mass1.lower=.lower,
mass1.upper=.upper)
<-fossil_taxa%>%
dunk_weightsmutate(swimbladder=T,
girth=ifelse(is.na(girth),ramanujan.approx(body_depth,body_width),girth))%>%
augment(fit.ellipsoid,
newdata=.,
interval="predict")%>%
mutate(swimbladder=F)%>%
rename_at(vars(starts_with('.')), funs(paste0("mass2",.)))%>%
mutate(across(mass2.fitted:mass2.upper,~exp(.)*regression.stats(fit.ellipsoid)$CF))%>%
augment(fit.ellipsoid_no_swimbladder,
newdata=.,
interval="predict")%>%
mutate(girth=girth3)%>%
rename_at(vars(starts_with('.')), funs(paste0("mass3",.)))%>%
mutate(across(mass3.fitted:mass3.upper,~exp(.)*regression.stats(fit.ellipsoid_no_swimbladder)$CF))%>%
drop_na(body_mass)%>%
arrange(body_mass)%>%
mutate(across(c(body_mass,mass1.lower,mass1.upper,mass2.fitted,mass2.lower,mass2.upper,
~./1000),
mass3.lower,mass3.upper,mass3.fitted),mass1.range=paste0("(",round(mass1.lower,3),"–",round(mass1.upper,3),")"),
mass2.range=paste0("(",round(mass2.lower,3),"–",round(mass2.upper,3),")"),
mass3.range=paste0("(",round(mass3.lower,3),"–",round(mass3.upper,3),")"))%>%
select(taxon,specimen,total_length,mass3.fitted,mass3.range,body_mass,mass1.range,mass2.fitted,mass2.range)
%>%
dunk_weightskable(digits=c(1,1,1,3,3,3,3,3,3),align=c("l","c","c","c","c","c","c","c","c"),
col.names=c("Taxon","Specimen","Total Length",
"Est.","95% P.I.",
"Est.","95% P.I.",
"Est.","95% P.I."),
caption="Body masses of arthrodires estimated using a multivariate model. Body masses reported in kg, but with three digits in order to display estimated masses for smaller arthrodire taxa.")%>%
add_header_above(c(" "=3,"Omitting swimbladder as explanatory variable"=2,"Assuming no swim bladder"=2,"Assuming presence of swim bladder"=2))%>%
column_spec(1,italic=T)%>%
kable_styling()
Taxon | Specimen | Total Length | Est. | 95% P.I. | Est. | 95% P.I. | Est. | 95% P.I. |
---|---|---|---|---|---|---|---|---|
Millerosteus minor | Composite Millerosteus | 14.9 | 0.037 | (0.021–0.065) | 0.035 | (0.02–0.061) | 0.039 | (0.022–0.068) |
Latocamurus coulthardi | WAM 86.9.699 | 24.0 | 0.086 | (0.049–0.152) | 0.083 | (0.047–0.146) | 0.092 | (0.052–0.161) |
Camuropiscis concinnus | WAM P50976 | 30.0 | 0.175 | (0.1–0.307) | 0.169 | (0.096–0.296) | 0.187 | (0.106–0.328) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 0.197 | (0.112–0.347) | 0.191 | (0.109–0.336) | 0.211 | (0.12–0.373) |
Torosteus pulchellus | Composite pulchellus | 36.0 | 0.335 | (0.191–0.589) | 0.326 | (0.186–0.573) | 0.361 | (0.205–0.636) |
Mcnamaraspis kaprios | WAM 86.9.676 | 34.6 | 0.347 | (0.197–0.609) | 0.337 | (0.192–0.592) | 0.372 | (0.211–0.657) |
Compagopiscis croucheri | WAM 70.4.263 | 40.3 | 0.401 | (0.228–0.704) | 0.392 | (0.223–0.688) | 0.433 | (0.245–0.763) |
Compagopiscis croucheri | P50942 | 37.9 | 0.434 | (0.247–0.763) | 0.423 | (0.241–0.742) | 0.467 | (0.265–0.824) |
Harrytoombsia elegans | WAM P50914 | 37.0 | 0.476 | (0.271–0.837) | 0.463 | (0.264–0.814) | 0.512 | (0.29–0.903) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 0.566 | (0.322–0.995) | 0.553 | (0.314–0.971) | 0.611 | (0.346–1.078) |
Torosteus tuberculatus | Composite tuberculatus | 40.2 | 0.609 | (0.346–1.071) | 0.594 | (0.338–1.043) | 0.656 | (0.372–1.158) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 0.784 | (0.446–1.378) | 0.757 | (0.431–1.33) | 0.837 | (0.475–1.473) |
Gymnotrachelus hydei | Recon. (Carr 1994) | 74.4 | 2.144 | (1.22–3.77) | 2.127 | (1.211–3.736) | 2.352 | (1.331–4.156) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 3.189 | (1.809–5.624) | 3.145 | (1.785–5.541) | 3.477 | (1.963–6.157) |
Eastmanosteus calliaspis | 70.4.864 | 79.3 | 4.991 | (2.834–8.79) | 4.951 | (2.814–8.71) | 5.473 | (3.092–9.688) |
Paramylostoma arcualis | CMNH 6054 | 84.6 | 5.147 | (2.926–9.054) | 5.104 | (2.904–8.968) | 5.642 | (3.191–9.974) |
Heintzichthys gouldii | NHMUK PV P 9335 | 113.1 | 16.281 | (9.233–28.708) | 16.246 | (9.224–28.615) | 17.960 | (10.127–31.853) |
Bungartius perissus | CMNH 7573 | 179.8 | 57.403 | (32.641–100.951) | 57.394 | (32.672–100.825) | 63.448 | (35.858–112.266) |
Dunkleosteus terrelli | CMNH 7424 | 188.9 | 106.270 | (60.137–187.792) | 106.733 | (60.464–188.408) | 117.991 | (66.325–209.905) |
Dunkleosteus terrelli | CMNH 7054 | 295.5 | 377.371 | (213.036–668.473) | 381.415 | (215.534–674.962) | 421.646 | (236.229–752.595) |
Dunkleosteus terrelli | CMNH 6090 | 283.3 | 387.796 | (218.669–687.732) | 391.650 | (221.066–693.864) | 432.960 | (242.322–773.577) |
Dunkleosteus terrelli | CMNH 5768 | 340.7 | 997.161 | (557.764–1782.708) | 1008.407 | (564.623–1800.995) | 1114.771 | (618.875–2008.022) |
Unusually, the presence of a swim bladder seems to predict higher body masses in fishes, contrary to theoretical expectations (Alexander 1967). One possibility is this might be due to a large, oil-filled liver in sharks, which occupies most of the gut cavity and can represent 20-25% of total body mass in many pelagic species (Corner et al. 1969, Kauffman 1950, De Maddalena et al. 2003). Shark liver is much denser than a swim bladder (0.9 versus 0.00122 g/cm3; Baldridge 1970), but because it occupies a proportionally greater volume of the body cavity it results in the density of the entire animal being lower. This is similar to how in birds and sauropod dinosaurs whole-body density is only about 0.7 g/cm3 due to the presence of extensive air sacs and pneumaticity (Wedel 2009), despite the rest of the animal’s tissues being comparably in density to other tetrapods.
It is not clear if arthrodires should be treated as having a liver comparable in size to sharks. Preserved liver remains have been documented for Incisoscutum ritchei (see Trinajstic et al. 2022), but these specimens suggest a liver far smaller than seen in extant sharks (Engelman, unpublished data in prep). Because of this uncertainty (and to limit the scope of the present contribution), the author prefers to leave the question of liver size alone for now and merely consider the present or absence of a swim bladder, as the absence of this organ is better-established in arthrodires (Goujet 2011, Trinajstic et al. 2022)
16.2.1 Estimating mass using only large, pelagic fishes
Because Dunkleosteus and Heintzichthys are so similar in length-weight relationship to lamnid sharks and tunas, it is worth considering how an equation using only large, pelagic fishes estimates body mass in these taxa. This equation considers three main groups: Scombridae, Lamniformes, and Istiophoriformes. For this model fork length was used instead of precaudal length, as fork length is the typical unit of measurement in these three fish groups and often requires no estimation (contra precaudal/standard length, which for tunas often encompasses most of the caudal fin due to the morphology of the peduncle). No compensation was made for caudal fin structure in this model due to using fork length.
Note: Mitsukurina owstoni was excluded because it is a bathydemersal taxon with a long caudal fin and lacks fork length, and trying to back-calculate fork length and add Mitsukurina to this analysis results in massive error for M. owstoni
<-
fit.ellipsoid_pelagiclm(log(body_mass)~I(log(girth)^2)*log(fork_length)+
log(girth)*log(fork_length)+swimbladder+
log(fork_length)*log(head_length)-log(head_length),
%>%
data_finalfilter(family %in% c("Scombridae")|
%in% c("Lamniformes","Istiophoriformes"),
order !genus %in% c("Mitsukurina"))%>%
filter(length_as=="total length")%>%
mutate(fork_length=ifelse(is.na(fork_length)|
==precaudal_length,
total_length-1,
total_length
fork_length),girth=ifelse(!is.na(girth),girth,
ramanujan.approx(body_depth,body_width))))
summary(fit.ellipsoid_pelagic)
##
## Call:
## lm(formula = log(body_mass) ~ I(log(girth)^2) * log(fork_length) +
## log(girth) * log(fork_length) + swimbladder + log(fork_length) *
## log(head_length) - log(head_length), data = data_final %>%
## filter(family %in% c("Scombridae") | order %in% c("Lamniformes",
## "Istiophoriformes"), !genus %in% c("Mitsukurina")) %>%
## filter(length_as == "total length") %>% mutate(fork_length = ifelse(is.na(fork_length) |
## total_length == precaudal_length, total_length - 1, fork_length),
## girth = ifelse(!is.na(girth), girth, ramanujan.approx(body_depth,
## body_width))))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.54702 -0.06120 0.00738 0.07700 0.67936
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 9.01229 3.40056 2.650 0.008736 **
## I(log(girth)^2) 1.27201 0.22869 5.562 9.17e-08 ***
## log(fork_length) 0.29833 0.68882 0.433 0.665439
## log(girth) -7.08215 1.75850 -4.027 8.21e-05 ***
## swimbladderTRUE -0.36946 0.03997 -9.242 < 2e-16 ***
## I(log(girth)^2):log(fork_length) -0.18821 0.03895 -4.832 2.82e-06 ***
## log(fork_length):log(girth) 1.15934 0.31480 3.683 0.000302 ***
## log(fork_length):log(head_length) -0.02306 0.02415 -0.955 0.340869
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.1465 on 186 degrees of freedom
## (221 observations deleted due to missingness)
## Multiple R-squared: 0.9907, Adjusted R-squared: 0.9904
## F-statistic: 2840 on 7 and 186 DF, p-value: < 2.2e-16
regression.stats(fit.ellipsoid_pelagic)
%>%
fossil_taxamutate(girth2=girth,
girth=ifelse(!is.na(girth),girth,
ramanujan.approx(body_depth,body_width)))%>%
augment(fit.ellipsoid_pelagic,
newdata=.,
interval="predict")%>%
mutate(girth=girth2)%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.ellipsoid_pelagic)$CF))%>%
mutate(body_mass=.fitted)%>%
drop_na(body_mass)%>%
filter(genus %in% c("Dunkleosteus","Heintzichthys"))%>%
arrange(body_mass)%>%
mutate(across(c(body_mass,.lower,.upper),~./1000))%>%
select(taxon,specimen,total_length,body_mass,.lower,.upper)%>%
kable(digits=1,col.names=c("Taxon","Specimen","Total Length","Est.","Lower 95% P.I.","Upper 95% P.I."),
caption="Body masses of pelagic arthrodires estimated using a multivariate model based on the three major living groups of fusiform, pelagic fishes (Lamniformes, Scombridae, and Istiophoriformes). Body masses reported in kg.")%>%
kable_styling()
Taxon | Specimen | Total Length | Est. | Lower 95% P.I. | Upper 95% P.I. |
---|---|---|---|---|---|
Heintzichthys gouldii | NHMUK PV P 9335 | 113.1 | 23.6 | 17.2 | 32.2 |
Dunkleosteus terrelli | CMNH 7424 | 188.9 | 166.7 | 120.7 | 230.1 |
Dunkleosteus terrelli | CMNH 7054 | 295.5 | 545.0 | 393.0 | 755.8 |
Dunkleosteus terrelli | CMNH 6090 | 283.3 | 561.3 | 401.8 | 784.2 |
Dunkleosteus terrelli | CMNH 5768 | 340.7 | 1204.1 | 833.1 | 1740.5 |
16.3 Length-weight relationships in arthrodires
16.3.1 All fishes
ggplot(data_final%>%
filter(length_as!="estimated t.l."|clade=="Placodermi",
==F|!is.na(girth)|!is.na(body_width)&!is.na(body_depth),
is_body_mass_estimated!(total_length==precaudal_length)),
aes(y=body_mass,x=total_length))+
geom_star(aes(starshape=clade,fill=clade))+
geom_smooth(formula=y~x,method="lm")+
geom_star(data=fossil_taxa%>%
mutate(girth=ifelse(is.na(girth),ramanujan.approx(body_depth,body_width),girth))%>%
augment(fit.ellipsoid,
newdata=.,
interval="predict")%>%
mutate(body_mass=exp(.fitted)*regression.stats(fit.ellipsoid)$CF),
aes(starshape=clade,fill=clade),color="white",
size=3.5,show.legend=F)+
scale_starshape_manual(values=c(15,13,11,1,28))+
scale_fill_manual(values=c(hue_pal()(4)[1:3],"black",hue_pal()(4)[4]))+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans="log10",
breaks = trans_breaks("log10", function(x) 10^x,n=8),
labels = trans_format("log10", math_format(10^.x)))+
labs(y="Body Mass (g)",x="Total Length (cm)",fill="Clade",starshape="Clade")+
theme(legend.position=c(0.8,0.2))
Figure 16.1: Plot of length versus weight across all fishes with weight data in this study, showing how fishes in general follow a consistent length-weight relationship (with significant interspecific variation; Froese 2006) and that predicted body masses for complete arthrodires fall within the range of variation seen in modern fishes. Regression line represents the simple length-weight relationship for all fishes, not the best fit curve for the ellipsoid model.
Dunkleosteus has a length-weight relationship that is on the edge of the range of variation of fishes, but this is to be expected given the overall short, deep body of this taxon. For example coelocanths (Latimeria spp.), which are also very deep-bodied and heavy relative to their length, show a similar length-weight relationship.
Note that the lower regression line for elasmobranchs is not strictly due to clade-specific differences in body mass relative to the physical dimensions of these animals, but due to the fact that elasmobranchs in general tend to be much longer for their weight relative to osteichthyans and placoderms. This can be seen in the fact that elasmobranch chondrichthyans and “elongate-bodied” osteichthyans plot along similar lines, though elasmobranchs tend to show larger heads relative to osteichthyans with elongate trunks because an aspect ratio that would be generalized fusiform for elasmobranchs is elongate for actinopterygians due to differences in body proportions between the clades (see manuscript).
Similarly, compressiform
fishes show higher length-weight relationships than typical fishes. All of this is to be expected. Fishes with long, narrow bodies are going to be lighter at the same unit length as a fusiform fish, and short, deep-bodied fish are going to be heavier.
Overall, what this means is that it is safe to use this model to estimate the body mass of arthrodires, because the differences between elasmobranchs and osteichthyans here are due to physical proportions, which are accounted for by the girth
measurements in the ellipsoid model, rather than due to a difference that cannot be measurably quantified by this dataset.
ggplot(data_final%>%
filter(length_as!="estimated t.l."|clade=="Placodermi",
==F|!is.na(girth)|!is.na(body_width)&!is.na(body_depth),
is_body_mass_estimated!(total_length==precaudal_length))%>%
mutate(clade=ifelse(clade %in% c("Actinopterygii","Sarcopterygii"),
"Osteichthyes",clade),
shape2=case_when(clade=="Chondrichthyes"~"Chondrichthyes",
=="fusiform"~"fusiform",
shape%in% c("anguilliform","elongate")~"anguilliform/elongate",
shape =="compressiform" ~ "compressiform"))%>%
shapemutate(shape2=factor(shape2,ordered=T,levels=c("Chondrichthyes",
"anguilliform/elongate",
"fusiform",
"compressiform")))%>%
filter(shape!="flattened",!(clade %in% c("Petromyzontiformes","Placodermi")),
!="macruriform"|clade=="Chondrichthyes")%>%
shapedrop_na(body_mass),
aes(y=body_mass,x=total_length))+
geom_star(aes(starshape=clade,fill=shape2))+
geom_star(data=.%>%filter(clade=="Chondrichthyes"),
aes(starshape=clade,fill=shape2),size=2.5,show.legend=F)+
geom_smooth(formula=y~x,method="lm",aes(color=shape2))+
geom_star(data=.%>%filter(taxon=="Coccosteus cuspidatus"),
aes(starshape=clade,fill=shape2))+
scale_starshape_manual(values=c(11,15),guide="none")+
scale_fill_manual(values=c(hue_pal()(4)))+
scale_color_manual(values=c(hue_pal()(4)))+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans="log10",
breaks = trans_breaks("log10", function(x) 10^x,n=8),
labels = trans_format("log10", math_format(10^.x)))+
labs(y="Body Mass (g)",x="Total Length (cm)",fill="Group",starshape="Clade",color="Group")+
theme(legend.position=c(0.8,0.25))+
guides(fill = guide_legend(override.aes = list(starshape = c(11,15,15,15))))
Figure 16.2: Plot of length versus weight in fishes, showing that sharks and actinopterygians with elongate trunks (either elongate or anguilliform) plot along similar regression lines.
16.3.2 Comparing arthrodires to tunas and sharks
<-ggplot(data_final%>%
(arthrodire_length_weightfilter(is_body_mass_estimated==F|specimen=="MZL 23981", #MZL 23981 was not dropped because although its weight was estimated this value was very close to the reported total weight
!(body_mass==1980000&genus=="Cetorhinus"), #This individual was dropped because Springer and Gilbert (1976) noted it to be unusually underweight and thin
=="Chondrichthyes"|genus %in% c("Thunnus",
clade"Allothunnus",
"Auxis",
"Euthynnus",
"Katsuwonus"),
!order %in% c("Rajiformes","Rhinopristiformes","Chimaeriformes"),
!genus %in% c("Alopias"))%>%
bind_rows(.,fossil_taxa%>%filter(!is.na(body_width),clade=="Placodermi"))%>%
drop_na(body_mass,total_length)%>%
mutate(clade=factor(case_when(clade=="Actinopterygii"~"Thunnini",
=="Lamnidae"~"Lamnidae",
family=="Oxynotus"~"Oxynotus",
genus=="Chondrichthyes"~"Other Elasmobranchii",
clade=="Placodermi"~"Arthrodira"),
cladeordered=T,
levels=c("Arthrodira","Lamnidae","Oxynotus",
"Other Elasmobranchii","Thunnini")))%>%
arrange(desc(clade)),
aes(y=body_mass,x=total_length))+
geom_smooth(aes(color=clade),method="lm",formula=y~x,alpha=0.25)+
geom_star(aes(starshape=clade,fill=clade),size=3)+
scale_starshape_manual(values=c(1,13,13,13,15),
labels=c("Arthrodira","Lamnidae","*Oxynotus*",
"Other Chondrichthyes","Thunnini"))+
scale_color_manual(values=c(hue_pal()(4)[1:2],"tan",hue_pal()(4)[3:4]),
labels=c("Arthrodira","Lamnidae","*Oxynotus*",
"Other Chondrichthyes","Thunnini"))+
scale_fill_manual(values=c(hue_pal()(4)[1:2],"tan",hue_pal()(4)[3:4]),
labels=c("Arthrodira","Lamnidae","*Oxynotus*",
"Other Chondrichthyes","Thunnini"))+
geom_smooth(aes(color=clade),method="lm",formula=y~x,se=F,show.legend=F)+
geom_smooth(data=.%>%filter(clade=="Arthrodira"),
aes(color=clade),method="lm",formula=y~x,se=F,show.legend=F)+
geom_errorbar(data=.%>%filter(clade=="Arthrodira"),
aes(ymin=mass1.lower,ymax=mass1.upper),width=.02)+
geom_star(data=.%>%filter(clade=="Arthrodira"),
aes(starshape=clade,fill=clade),size=3.5,show.legend = F)+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans="log10",
breaks = trans_breaks("log10", function(x) 10^x,n=8),
labels = trans_format("log10", math_format(10^.x)))+
labs(y="Body Mass (g)",x="Total Length (cm)",fill="Clade",starshape="Clade",color="Clade")+
theme_classic()+
theme(legend.position = c(0.8,0.25),
legend.text=element_markdown()))
Figure 16.3: Graph of total length versus body mass for all sharks and tunas (Thunnini) in which weight was directly recorded, compared to estimated weights for arthrodires in this study
ggsave("Figure 11 (Arthrodire Length-Weights).tiff",
device="tiff",compression="lzw",dpi=600,units="mm",width=165,height=110) arthrodire_length_weight,
ggplot(data_final%>%
filter(!(body_mass==1980000&genus=="Cetorhinus"), #This individual was dropped because Springer and Gilbert (1976) noted it to be unusually underweight and thin
=="Chondrichthyes"|genus %in% c("Thunnus",
clade"Allothunnus",
"Auxis",
"Euthynnus",
"Katsuwonus"),
!order %in% c("Rajiformes","Rhinopristiformes","Chimaeriformes"),
!genus %in% c("Alopias"))%>%
bind_rows(.,fossil_taxa%>%filter(!is.na(body_width),clade=="Placodermi"))%>%
drop_na(body_mass,total_length)%>%
mutate(clade=factor(case_when(clade=="Actinopterygii"~"Thunnini",
=="Lamnidae"~"Lamnidae",
family=="Oxynotus"~"Oxynotus",
genus=="Chondrichthyes"~"Other Elasmobranchii",
clade=="Placodermi"~"Arthrodira"),
cladeordered=T,
levels=c("Arthrodira","Lamnidae","Oxynotus",
"Other Elasmobranchii","Thunnini")))%>%
arrange(desc(clade)),
aes(y=body_mass,x=total_length))+
geom_smooth(aes(color=clade),method="lm",formula=y~x,alpha=0.25)+
geom_star(aes(starshape=clade,fill=clade),size=3)+
geom_smooth(aes(color=clade),method="lm",formula=y~x,alpha=0.25,show.legend=F)+
geom_smooth(data=.%>%filter(clade=="Arthrodira"),
aes(color=clade),method="lm",formula=y~x,se=F,show.legend=F)+
geom_errorbar(data=.%>%filter(clade=="Arthrodira"),
aes(ymin=mass1.lower,ymax=mass1.upper),width=.02)+
geom_star(data=.%>%filter(clade=="Arthrodira"),
aes(starshape=clade,fill=clade),size=3.5,show.legend = F)+
scale_starshape_manual(values=c(1,13,13,13,15),
labels=c("Arthrodira","Lamnidae","*Oxynotus*",
"Other Chondrichthyes","Thunnini"))+
scale_color_manual(values=c(hue_pal()(4)[1:2],"tan",hue_pal()(4)[3:4]),
labels=c("Arthrodira","Lamnidae","*Oxynotus*",
"Other Chondrichthyes","Thunnini"))+
scale_fill_manual(values=c(hue_pal()(4)[1:2],"tan",hue_pal()(4)[3:4]),
labels=c("Arthrodira","Lamnidae","*Oxynotus*",
"Other Chondrichthyes","Thunnini"))+
scale_x_continuous(trans='log10')+
scale_y_continuous(trans="log10",
breaks = trans_breaks("log10", function(x) 10^x,n=8),
labels = trans_format("log10", math_format(10^.x)))+
labs(y="Body Mass (g)",x="Total Length (cm)",fill="Clade",starshape="Clade",color="Clade")+
theme_classic()+
theme(legend.position = c(0.8,0.2),
legend.text=element_markdown())
Figure 16.4: Graph of total length versus body mass in arthrodires, sharks, and tunas (Thunnini), including specimens whose mass was estimated through length-weight equations
Overall, this shows that arthrodires exhibit a length-weight relationship more similar to tunas than non-lamnid sharks, and are thus extremely heavy for their length. This includes non-pelagic taxa like Incisoscutum and Coccosteus. Later Devonian pelagic arthrodires (Heintzichthys, Dunkleosteus) show values more similar to tunas (Thunnini) and lamnid sharks, whereas geologically older species show values that are roughly intermediate between thunnins/lamnids and “typical” sharks like carcharhinids, hexanchiids, etc.
16.4 Estimating weight of Dunkleosteus based on length-weight equation of Carcharodon carcharias
<-fossil_taxa%>%
dunk_weights_carcharodonleft_join(.,dunkleosteus_jaws%>%select(specimen,JM1:inferognathal_length),by="specimen")%>%
filter(genus=="Dunkleosteus")%>%
mutate(JM5=ifelse(specimen=="CMNH 5768",mean(26.2,29.3),JM5))%>%
mutate(JM5=ifelse(specimen=="CMNH 6090",mean(20.39,21.09),JM5))%>%
mutate(JM5=ifelse(specimen=="CMNH 7054",mean(23.73,22.81),JM5))%>%
mutate(total_length=exp(predict(fit.shape_clade3,.))*
regression.stats(fit.shape_clade3)$CF)%>%
mutate(precaudal_length=exp(predict(total_length_to_standard_length,.))*
regression.stats(total_length_to_standard_length)$CF)%>%
mutate(weight=45.98*((girth/100)^2*(precaudal_length/100))^0.9267,
body_depth_ratio=body_depth/OOL,
jawratio=body_depth/JM5)%>%
filter(!is.na(weight))
%>%
dunk_weights_carcharodonrownames_to_column()%>%
select(specimen,OOL,body_depth_ratio,jawratio,total_length,precaudal_length,girth,weight)%>%
arrange(weight)%>%
kable(digits=1,
align=c("l","c","c","c","c","c","c","c"),
col.names=c("Specimen","OOL","Body Depth/OOL","Body Depth/JM5","Estimated Total Length","Estimated Precaudal Length","Girth","Estimated Body Mass"),
caption="Estimated body masses for <i>Dunkleosteus terrelli</i>, assuming proportions similar to a great white shark (<i>Carcharodon carcharias</i>) and using the regression model of Mollet and Caillet (1996). All lengths in cm and all weights in kg")%>%
kable_styling()
Specimen | OOL | Body Depth/OOL | Body Depth/JM5 | Estimated Total Length | Estimated Precaudal Length | Girth | Estimated Body Mass |
---|---|---|---|---|---|---|---|
CMNH 7424 | 29.0 | 1.3 | 3.1 | 188.9 | 147.2 | 147.9 | 136.0 |
CMNH 7054 | 45.5 | 1.6 | 3.1 | 295.5 | 230.6 | 215.3 | 413.2 |
CMNH 6090 | 43.6 | 1.7 | 3.7 | 283.3 | 221.0 | 223.0 | 423.9 |
CMNH 5768 | 52.5 | 2.2 | 4.4 | 340.7 | 265.9 | 312.7 | 941.5 |
16.5 Length-weight equations in Dunkleosteus
16.5.1 Using masses from ellipsoid model
<-lm(log(body_mass)~log(total_length),
dunk_length_weight%>% filter(genus=="Dunkleosteus"))
fossil_taxa summary(dunk_length_weight)
##
## Call:
## lm(formula = log(body_mass) ~ log(total_length), data = fossil_taxa %>%
## filter(genus == "Dunkleosteus"))
##
## Residuals:
## 5 8 9 11
## 0.07779 -0.06327 -0.24051 0.22599
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -7.1494 3.1209 -2.291 0.1491
## log(total_length) 3.5581 0.5567 6.392 0.0236 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2439 on 2 degrees of freedom
## (7 observations deleted due to missingness)
## Multiple R-squared: 0.9533, Adjusted R-squared: 0.93
## F-statistic: 40.85 on 1 and 2 DF, p-value: 0.02362
16.5.2 Using masses from Carcharodon model
summary(lm(log(weight)~log(total_length),dunk_weights_carcharodon))
##
## Call:
## lm(formula = log(weight) ~ log(total_length), data = dunk_weights_carcharodon)
##
## Residuals:
## 1 2 3 4
## 0.06299 -0.04592 -0.20166 0.18459
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -11.2720 2.5723 -4.382 0.0483 *
## log(total_length) 3.0758 0.4588 6.704 0.0215 *
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.201 on 2 degrees of freedom
## Multiple R-squared: 0.9574, Adjusted R-squared: 0.9361
## F-statistic: 44.94 on 1 and 2 DF, p-value: 0.02154
16.5.3 Length-Weight Curve for Dunkleosteus terrelli
<- function(plot_data){
lm_eqn.all <- dunk_length_weight;
m <- substitute(italic("body mass") == a %.% italic("total length")^b*","~~italic(r)^2~"="~r2,
eq list(a = format(unname(exp(coef(m)[1])), digits = 5),
b = format(unname(coef(m)[2]), digits = 5),
r2 = format(summary(m)$r.squared, digits = 3)))
as.character(as.expression(eq));
}#Plotting length-weight curve
<-ggplot(fossil_taxa%>%filter(genus=="Dunkleosteus")%>%drop_na(body_mass),
dunk_length_weight_graphaes(x=total_length,y=body_mass/1000))+
geom_errorbar(aes(ymin=mass1.lower/1000,ymax=mass1.upper/1000),width=2)+
geom_smooth(formula=y~I(x^dunk_length_weight$coefficients[2]),method="lm")+
geom_point()+
labs(x="Total Length (cm)",y="Body Mass (kg)")+
geom_text(aes(x = 188, y = 2000, label = lm_eqn.all(plot_data)),hjust=0,
parse = TRUE,data.frame())+
theme_cowplot()
<-ggdraw() +
(dunk_length_weight_graph2draw_image("Devonian Fish Tale Supplementary File 9 (Big Dunk Silhouette).png",
x=0.33,y=0.27,scale=0.16) +
draw_image("Devonian Fish Tale Supplementary File 8 (Medium Dunk Silhouette).png",
x=-0.010,y=0.06,scale=0.14) +
draw_image("Devonian Fish Tale Supplementary File 7 (Little Dunk Silhouette).png",
x=-0.3,y=0.02,scale=0.12) +
draw_plot(dunk_length_weight_graph))
Figure 16.5: Length-weight curve for Dunkleosteus terrelli using the ellipsoid model, with silhouettes of D. terrelli at different life stages showing how this organism becomes deeper-bodied with growth. Total lengths and body masses are both estimates based on the present study.
ggsave("Dunkleosteus Length-Weight.tiff",dunk_length_weight_graph2,
device="tiff",width=165,height=124,units="mm",dpi=600,compression="lzw")
ggsave("Dunkleosteus Length-Weight.png",dunk_length_weight_graph2,
device="png",width=165,height=124,units="mm",dpi=300)
If the same allometric effect that affects actinopterygians also affects arthrodires, then the smaller Dunkleosteus may be slightly shorter than reconstructed here (by ~10% in CMNH 7424?). However, just looking at armor dimensions alone there is still a clear deepening effect with size. Note that normally creating a length-weight curve out of N = 4 is not recommended, and is only done here because of the limited number of specimens of D. terrelli for which 3D reconstructions are available that body mass can be estimated.
The resulting allometric exponent suggests that Dunkleosteus became heavier relative to its length throughout ontogeny, which agrees with the observation that there is a general deepening of the thoracic armor throughout the observed ontogenetic series. Note: if it is eventually demonstrated that the positive allometry in OOL characterizes sharks and all fishes more generally, then this might reduce the allometric exponent somewhat. That is, this would make the younger individuals of Dunkleosteus shorter, which then would make them potentially heavier relative to their reduced anteroposterior length estimates (as girth is unchanged). Froese (2006) notes that allometric exponents in excess of 3.5 are very unusual for fishes, and this suggests that while Dunkleosteus does appear to get deeper-bodied throughout ontogeny (as indicated by its dorsoventral trunk proportions relative to measurable anteroposterior dimensions like OOL or thoracic armor length), the allometric exponent estimated here might prove to be a slight overestimate.
16.6 Armor weight of CMNH 6090
Element | Volume (cm^3) |
---|---|
Head and thoracic shield | 21133.93 |
Right posteroventrolateral plate | 882.10 |
Left posteroventrolateral plate | 711.46 |
Right anteroventrolateral plate | 685.98 |
Left anteroventrolateral plate | 674.54 |
Posterior median plate | 209.61 |
Anterior median plate | 88.96 |
Total volume | 24386.59 |
Note: the volume estimation of the head and thoracic shield does not subtract the volume of the metal armature, which is located very close to the specimen and cannot be easily separated from the 3D model of the fossil. However, the armature is small and unobtrusive enough that the estimated volume for the head and trunk armor should be close to the actual value, if slightly higher due to the presence of the armature.
data.frame("armor_mass"=c(24386.59*1.2),"density"=(1.20),"source"="whole bone, Wall et al. 1983")%>%
add_row("armor_mass"=c(24386.59*1.3),"density"=(1.30),"source"="whole bone, ICRP 1995")%>%
add_row("armor_mass"=c(24386.59*1.236),"density"=(1.236),"source"="whole bone, Shephard 1991")%>%
add_row("armor_mass"=c(24386.59*1.86),"density"=(1.86),"source"="Assuming entire bone is cortical bone, Blanton and Biggs 1968")%>%
mutate(density=as.character(density))%>%
add_row("armor_mass"=c(24386.59*0.25*1.86+24386.59*0.75*1.06),"density"=c("1.86 (cortical), 1.06 (cancellous)"),"source"="Assuming 25% of the bone volume is cortical, following Wall et al. 1983, densities from Blanton and Biggs 1968")%>%
mutate(armor_mass=armor_mass/1000,
percent_mass=(armor_mass/dunk_weights%>%
filter(specimen=="CMNH 6090")%>%pull(body_mass))*100)%>% select(armor_mass,density,percent_mass,source) %>%
kable(digits=c(2,3,2,1),align=c("c"),
col.names = c("Mass of Armor (kg)","Density (g/cm3)","Armor Weight as Percent Armor-Free Body Mass","References"),caption="Armor masses of CMNH 6090 (estimated mass without making assumptions for armor using ellipsoid model")%>%
kable_styling()
Mass of Armor (kg) | Density (g/cm3) | Armor Weight as Percent Armor-Free Body Mass | References |
---|---|---|---|
29.26 | 1.2 | 7.47 | whole bone, Wall et al. 1983 |
31.70 | 1.3 | 8.09 | whole bone, ICRP 1995 |
30.14 | 1.236 | 7.70 | whole bone, Shephard 1991 |
45.36 | 1.86 | 11.58 | Assuming entire bone is cortical bone, Blanton and Biggs 1968 |
30.73 | 1.86 (cortical), 1.06 (cancellous) | 7.85 | Assuming 25% of the bone volume is cortical, following Wall et al. 1983, densities from Blanton and Biggs 1968 |
16.7 How large would a shark have to be in order to equal the body masses of Dunkleosteus terrelli?
<-lm(log(total_length)~log(body_mass),
fit.shark_bodymass%>%filter(clade=="Chondrichthyes",
data_final!order %in% c("Rhinobatiformes","Rajiformes","Chimaeriformes")))
%>%
dunk_weightsfilter(taxon=="Dunkleosteus terrelli")%>%
mutate(body_mass=body_mass*1000)%>%
augment(fit.shark_bodymass,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(fit.shark_bodymass)$CF),
diff=.fitted-total_length,
body_mass=round(body_mass/1000,1))%>%
select(specimen,total_length,body_mass,.fitted,.lower,.upper,diff)%>%
kable(digits=1,col.names=c("Specimen","Total Length","Estimated Mass (kg)","Est.","Lower 95% P.I.","Upper 95% P.I.","% Diff."),align="c",
caption="Size of sharks (in cm) necessary to achieve weights similar to individuals of <i>Dunkleosteus terrelli</i>, showing much greater weight relative to length of latter taxon")%>%
add_header_above(c(" "=3,"Estimated Total Length of Shark"=3," "=1))%>%
kable_styling()
Specimen | Total Length | Estimated Mass (kg) | Est. | Lower 95% P.I. | Upper 95% P.I. | % Diff. |
---|---|---|---|---|---|---|
CMNH 7424 | 188.9 | 106.7 | 256.3 | 199.2 | 329.6 | 67.3 |
CMNH 7054 | 295.5 | 381.4 | 375.2 | 291.5 | 482.9 | 79.7 |
CMNH 6090 | 283.3 | 391.7 | 378.2 | 293.8 | 486.7 | 94.9 |
CMNH 5768 | 340.7 | 1008.4 | 501.9 | 389.8 | 646.4 | 161.3 |
Note that although the estimated weight of a shark the size of CMNH 5768 gets very close to the reported total length of the Lausanne Carcharodon (De Maddalena et al. 2003), lamnid sharks in general have a much shorter and heavier body than most sharks do. As this regression equation is based on all sharks (i.e., carcharhinids, hexanchiids, cetorhinids, etc.) CMNH 5768 is still expected to be much smaller than a large lamnid like MZL 23981.
16.8 Weight of the largest known specimen of Dunkleosteus (CMNH 5936)
# Estimated length for CMNH 5936 was calculated as the mean of the estimated lengths using JM3 and JM5 using the model "fit.shape_clade3"
<-data.frame(OOL=mean(c(predict(fit.JM5,data.frame(JM5=33.9)),
CMNH_5936_dimensionspredict(fit.JM3,data.frame(JM3=18.63)))),
clade="Placodermi",shape="fusiform",habitat="pelagic",swimbladder=F,heterocercal=T,
family="Dunkleosteidae",
length5768=exp(predict(fit.shape_clade3,fossil_taxa%>%filter(specimen=="CMNH 5768")))*
regression.stats(fit.shape_clade3)$CF)%>%
mutate(total_length=exp(predict(fit.shape_clade3,.))*regression.stats(fit.shape_clade3)$CF,
girth=total_length*(fossil_taxa%>%filter(specimen=="CMNH 5768")%>%pull(girth)/
length5768),head_length=total_length*(fossil_taxa%>%filter(specimen=="CMNH 5768")%>%pull(head_length)/
%>%
length5768))mutate(precaudal_length=exp(predict(total_length_to_standard_length,.))*
regression.stats(total_length_to_standard_length)$CF,
fork_length=exp(predict(total_length_to_fork_length,.))*
regression.stats(total_length_to_fork_length)$CF)
rbind(predict(fit.ellipsoid,CMNH_5936_dimensions,interval="predict")%>%exp(),
predict(fit.ellipsoid_pelagic,CMNH_5936_dimensions,interval="predict")%>%exp())%>%
data.frame()%>%
add_row(fit=exp(predict(dunk_length_weight,CMNH_5936_dimensions))*
regression.stats(dunk_length_weight)$CF,
lwr=exp(predict(dunk_length_weight,CMNH_5936_dimensions,interval="prediction")[2])*
regression.stats(dunk_length_weight)$CF,
upr=exp(predict(dunk_length_weight,CMNH_5936_dimensions,interval="prediction")[3])*
regression.stats(dunk_length_weight)$CF)%>%
mutate(across(everything(),~./1000))%>%
add_row(fit=
%>%
CMNH_5936_dimensionsmutate(weight_carcharodon=45.98*((girth/100)^2*(precaudal_length/100))^0.9267)%>%
pull(weight_carcharodon))%>%
rownames_to_column()%>%
add_column(model=c("Ellipsoid Model, All Fishes","Ellipsoid Model, Pelagic Fishes","Dunkleosteus Length-Weight Model","Carcharodon Length-Weight Model"))%>%
mutate(range=ifelse(is.na(lwr),NA,paste0("(",round(lwr,1),"–",round(upr,1),")")))%>%
column_to_rownames("model")%>%select(-rowname,-lwr,-upr)%>%
kable(digits=1,col.names=c("Est.","95% P.I."),align="c",
caption="Weight estimates of the largest known specimen of <i>Dunkleosteus terrelli</i> (CMNH 5936), assuming missing proportions were similar to CMNH 5768. All body masses in kg.")%>%
kable_styling()
Est. | 95% P.I. | |
---|---|---|
Ellipsoid Model, All Fishes | 1763.9 | (982.2–3168) |
Ellipsoid Model, Pelagic Fishes | 1731.6 | (1175.9–2549.8) |
Dunkleosteus Length-Weight Model | 1495.7 | (331.3–6752.1) |
Carcharodon Length-Weight Model | 1494.2 | NA |
17 Miscellaneous analyses
17.1 Calculating the length of CMNH 5768 using “entering angle of the body”
One of the few previous methods to explicitly estimate total length in Dunkleosteus using statistical methods other than scaling off of Coccosteus was that of Hussakof (1906), who estimated total length in a juvenile Dunkleosteus terrelli (= “Dinichthys intermedius” of this author) using “entering angle of the body”. This measurement represents the anteroposterior length of the animal from the anteriormost point on the body to the location of greatest body depth, following Dean (1902) and Parsons (1888). The entering angle of the body ends “with wonderful uniformity” (Parsons, 1888) at approximately 36% the total length of the animal, and this appears to be consistent across nektonic fishes and marine tetrapods (= cetaceans), suggesting a biomechanical reason for its existence.
Assuming the apex of the mediodorsal represents the tallest point on the body in Dunkleosteus terrelli, the “entering angle of the body” in CMNH 5768 is estimated to measure 125–128 cm (depending on whether this is measured to the anterior end of the skull roof or the protruding supragnathals). Assuming the “entering angle” represents 36% of total body length the estimated total length for CMNH 5768 is 347–355 cm, very similar to the total lengths calculated via OOL. This increases the confidence that OOL accurately predicts total length in D. terrelli.
17.2 With only specimens measured directly
Because so much of the data comes from the previously published literature, there is a concern that errors in data reporting might bias results. Thus, an analysis was performed using only specimens measured by the author either directly or from published photographs in the literature.
<-lm(log(total_length)~log(OOL),
fit.engelman_measureddata=data_final%>%
filter(`Method of Measurement` %in% (c("measured from figure/photo",
"measured from photo",
"measured from specimen",
"mixed"))))
rbind("All Specimens"=regression.stats(fit.OOL),
"Specimens Measured Directly"=regression.stats(fit.engelman_measured))
Error rates of the two models are about the same, and this is compounded by the fact that many of the taxa that could only be taken from literature data includes some species with unusual body proportions, which could inflate the error of the model including all specimens examined.
17.3 Estimating body size in Dunkleosteus terrelli using (clade-corrected) mouth dimensions
Ferrón et al. (2017) estimated body size in Dunkleosteus terrelli using mouth dimensions in sharks. However, these method do not appear to reliably predict body size in arthrodires, due to arthrodires having proportionally larger mouths than sharks (Engelman, in press). However, running a regression model using mouth width data for arthrodires and sharks from Engelman (in press) and adding an additional coefficient to control for differences in mouth proportions between arthrodires and sharks produces the following results…
<-
fit.mouthwidth.clade_correctedlm(log(total_length)~log(mouth_width)+clade,
data=data_final%>%filter(clade %in% c("Placodermi","Chondrichthyes"),
!order %in% c("Chimaeriformes","Rajiformes"),
!genus %in% c("Alopias"))%>%
filter(length_as=="total length"))
summary(fit.mouthwidth.clade_corrected)
##
## Call:
## lm(formula = log(total_length) ~ log(mouth_width) + clade, data = data_final %>%
## filter(clade %in% c("Placodermi", "Chondrichthyes"), !order %in%
## c("Chimaeriformes", "Rajiformes"), !genus %in% c("Alopias")) %>%
## filter(length_as == "total length"))
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.90723 -0.13517 0.01429 0.14832 0.59746
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.93008 0.02828 103.616 <2e-16 ***
## log(mouth_width) 0.81183 0.01312 61.887 <2e-16 ***
## cladePlacodermi -0.74742 0.07861 -9.508 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.2203 on 442 degrees of freedom
## (112 observations deleted due to missingness)
## Multiple R-squared: 0.8989, Adjusted R-squared: 0.8984
## F-statistic: 1964 on 2 and 442 DF, p-value: < 2.2e-16
Based on this, arthrodires and sharks show significantly different mouth sizes, and including the additional term has a significant effect on the resulting predictions.
%>%
fossil_taxadrop_na(mouth_width)%>%
filter(!!fossil.specimens)%>%
mutate(total_length=ifelse(genus=="Dunkleosteus",NA,total_length))%>%
augment(fit.mouthwidth.clade_corrected,newdata=.,
interval="prediction")%>%
mutate(across(.fitted:.upper,~exp(.)*
regression.stats(fit.mouthwidth.clade_corrected)$CF),
range=paste0("(",round(.lower,1),"–",round(.upper,1),")"),
PE=paste0("(",
round(.fitted*(1-regression.stats(fit.mouthwidth.clade_corrected)$adjPE/100),
1),
"–",
round(.fitted*(1+regression.stats(fit.mouthwidth.clade_corrected)$adjPE/100),
1),
")"
%>%
))rename(fitted_mouthwidth=.fitted)%>%
augment(fit.shape_clade3,newdata=.)%>%
rename(fitted_OOL=.fitted)%>%
mutate(fitted_OOL=exp(fitted_OOL)*regression.stats(fit.shape_clade3)$CF)%>%
select(taxon, specimen, total_length, fitted_OOL, fitted_mouthwidth, PE, range)%>%
kable(digits=1,align=c("l","c","c","c","c","c","c"),
col.names = c("Taxon","Specimen","Actual Length","Estimated Length using OOL","Est.","+/- %PE","95% P.I."),
caption="Lengh estimates for <i>Dunkleosteus terrelli</i> and other arthrodires using mouth width and a combined dataset of sharks and arthrodires, with an additional coefficient for clade membership")%>%
add_header_above(c(" "=4,"Estimating using Clade-Corrected Mouth Width"=3))%>%
column_spec(1, italic = T)%>%
column_spec(5, bold = T)%>%
kable_styling()
Taxon | Specimen | Actual Length | Estimated Length using OOL | Est. | +/- %PE | 95% P.I. |
---|---|---|---|---|---|---|
Millerosteus minor | Composite Millerosteus | 14.9 | 15.6 | 15.2 | (12.6–17.7) | (9.6–24) |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 30.8 | 31.0 | (25.7–36.2) | (19.6–49) |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 42.7 | 43.3 | (36–50.6) | (27.3–68.5) |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 49.9 | 50.3 | (41.8–58.8) | (31.8–79.6) |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 49.7 | 65.2 | (54.2–76.2) | (41.2–103.2) |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 63.4 | 70.1 | (58.3–82) | (44.3–111) |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 66.5 | 51.2 | (42.6–59.9) | (32.4–81.1) |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 75.7 | 63.6 | (52.9–74.3) | (40.2–100.7) |
Dunkleosteus terrelli | CMNH 7424 | NA | 188.9 | 143.1 | (118.9–167.2) | (90.3–226.8) |
Dunkleosteus terrelli | CMNH 6090 | NA | 283.3 | 221.6 | (184.2–259) | (139.6–351.7) |
Dunkleosteus terrelli | CMNH 7054 | NA | 295.5 | 225.4 | (187.4–263.4) | (142–357.9) |
Dunkleosteus terrelli | CMNH 5768 | NA | 340.7 | 290.1 | (241.2–339) | (182.6–461) |
Thus, when corrected for differences in mouth proportions between arthrodires and sharks, mouth width produces estimates of body size for Dunkleosteus terrelli that are close to estimates under OOL, though slightly lower.
%>%
data_finalfilter(clade %in% c("Chondrichthyes","Placodermi"),
!order %in% c("Chimaeriformes","Rajiformes"),
!="Alopias")%>%
genusggplot(aes(total_length,mouth_width))+
geom_star(aes(starshape=clade,fill=clade),
data=.%>%filter(genus!="Dunkleosteus"))+
scale_x_continuous(trans="log10")+
scale_y_continuous(trans="log10")+
geom_smooth(data=.%>%
mutate(clade="Chondrichthyes")%>%
augment(fit.mouthwidth.clade_corrected,newdata=.)%>%
mutate(.fitted=exp(.fitted)*regression.stats(fit.mouthwidth.clade_corrected)$CF),
aes(x=.fitted,y=mouth_width,color=clade),formula=y~x,method="lm",se=F)+
geom_smooth(data=.%>%
mutate(clade="Placodermi",!!fossil.specimens)%>%
augment(fit.mouthwidth.clade_corrected,newdata=.)%>%
mutate(.fitted=exp(.fitted)*regression.stats(fit.mouthwidth.clade_corrected)$CF),
aes(x=.fitted,y=mouth_width,color=clade),formula=y~x,method="lm",se=F)+
geom_vline(xintercept=300,linetype="dashed")+
geom_star(aes(x=total_length,y=mouth_width,starshape=clade,fill=clade),
data=fossil_taxa %>% filter(genus=="Amazichthys"))+
geom_star(aes(x=total_length,y=mouth_width,starshape=clade,fill=clade),
data=fossil_taxa %>% filter(clade=="Placodermi",!!fossil.specimens) %>%
drop_na(total_length) %>%
filter(genus!="Dunkleosteus"),
size=2,show.legend=F)+
geom_star(aes(x=.fitted,y=mouth_width,starshape=clade),
data=fossil_taxa %>% filter(genus=="Dunkleosteus",!!fossil.specimens) %>%
augment(fit.mouthwidth.clade_corrected,newdata=.)%>%
mutate(.fitted=exp(.fitted)*
regression.stats(fit.mouthwidth.clade_corrected)$CF),
color="black",fill="white",size=3,show.legend=F)+
labs(x="Total Length (cm)",y="Mouth Width (cm)",
color="Clade",starshape="Clade",fill="Clade")+
scale_starshape_manual(values=c(15,1))+
annotate(geom="text",x=290,y=1.5,hjust=1,label="3 m")+
theme(legend.position=c(0.85,0.2))
Figure 17.1: Estimated length of Dunkleosteus terrelli (in white) using mouth width making corrections for the wider mouths of arthrodires.
17.4 Estimating length in Dunkleosteus using arthrodires only
Because of the wide variety of fishes examined in this study, it is worth examining arthrodires known from whole-body fossils alone to see if using only these taxa to estimate length in Dunkleosteus produces similar results.
<-lm(log(total_length)~log(OOL),
placoderms_only_OOL%>%filter(!!fossil.specimens,genus!="Dunkleosteus"))
data_final<-lm(log(total_length)~log(head_length),
placoderms_only_headlength%>%filter(!!fossil.specimens,genus!="Dunkleosteus"))
data_final
rbind("Using Head Length"=regression.stats(placoderms_only_headlength),
"Using OOL"=regression.stats(placoderms_only_OOL))
%>%
fossil_taxafilter(!!fossil.specimens)%>%
mutate(total_length=ifelse(length_as=="estimated t.l.",NA,total_length))%>%
augment(placoderms_only_headlength,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(placoderms_only_headlength)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(placoderms_only_OOL,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~exp(.)*regression.stats(placoderms_only_OOL)$CF))%>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(range1=paste0("(",round(fit1.lower,1),"-",round(fit1.upper,1),")"),
range2=paste0("(",round(fit2.lower,1),"-",round(fit2.upper,1),")"),
PE1_lower=fit1.fitted*(1-(regression.stats(placoderms_only_headlength)$adjPE)/100),
PE1_upper=fit1.fitted*(1+(regression.stats(placoderms_only_headlength)$adjPE)/100),
PE2_lower=fit2.fitted*(1-(regression.stats(placoderms_only_OOL)$adjPE)/100),
PE2_upper=fit2.fitted*(1+(regression.stats(placoderms_only_OOL)$adjPE)/100),
PE_range1=paste0("(",round(PE1_lower,1),"-",round(PE1_upper,1),")"),
PE_range2=paste0("(",round(PE2_lower,1),"-",round(PE2_upper,1),")"),
PE=((fit1.fitted-total_length)/fit1.fitted),
PE2=((fit2.fitted-total_length)/fit2.fitted))%>%
select(taxon,specimen,total_length,
fit1.fitted,PE_range1,range1,PE,%>%
fit2.fitted,PE_range2,range2,PE2)kable(digits=c(1,1,1,1,1,1,3,1,1,1,3),
col.names=c("Taxon","Specimen","Actual","Est.","+/- PE","95% P.I.","%PE",
"Est.","+/- PE","95% C.I.","%PE"),
align=c("l","c","c","c","c","c","c","c","c","c","c"),
caption="Length estimates for <i>Dunkleosteus terrelli</i> and complete arthrodires using only data from arthrodire specimens with whole body remains. All measurements in cm.")%>%
column_spec(1, italic = T)%>%
column_spec(c(4,8), bold = T)%>%
add_header_above(c(" "=3,"Using Head Length"=4,"Using OOL"=4))%>%
kable_styling()
Taxon | Specimen | Actual | Est. | +/- PE | 95% P.I. | %PE | Est. | +/- PE | 95% C.I. | %PE |
---|---|---|---|---|---|---|---|---|---|---|
Millerosteus minor | FMNH PF 1089 | 13.7 | 12.5 | (11.3-13.7) | (9.1-17.1) | -0.098 | 13.3 | (12-14.6) | (9.5-18.6) | -0.034 |
Millerosteus minor | Composite Millerosteus | 14.9 | 15.7 | (14.2-17.2) | (11.6-21.2) | 0.048 | 15.3 | (13.8-16.7) | (11-21.2) | 0.020 |
Africanaspis dorissa | Gess and Trinajstic 2017 | 23.0 | 24.0 | (21.8-26.2) | (18.2-31.8) | 0.042 | 22.9 | (20.6-25.1) | (16.8-31.1) | -0.006 |
Incisoscutum ritchei | Recon. (Trinajstic 2013) | 30.3 | 29.9 | (27.1-32.7) | (22.7-39.3) | -0.013 | 29.2 | (26.4-32.1) | (21.7-39.5) | -0.035 |
Coccosteus cuspidatus | NMS 1893.107.27 | 29.6 | 32.4 | (29.4-35.4) | (24.7-42.6) | 0.086 | 32.3 | (29.2-35.4) | (24-43.6) | 0.083 |
Coccosteus cuspidatus | NMS 1897.55.6 | 32.3 | 33.6 | (30.5-36.7) | (25.6-44.1) | 0.039 | 33.2 | (30-36.3) | (24.6-44.7) | 0.027 |
Coccosteus cuspidatus | FMNH PF 1673 | 37.1 | 35.0 | (31.7-38.2) | (26.6-46) | -0.061 | 33.6 | (30.3-36.8) | (24.9-45.2) | -0.106 |
Coccosteus cuspidatus | Recon. (M & W 1968) | 39.4 | 36.6 | (33.2-40.1) | (27.9-48.1) | -0.075 | 40.1 | (36.2-43.9) | (29.7-54) | 0.017 |
Coccosteus cuspidatus | NMS 1900.12.12 | 34.4 | 36.8 | (33.4-40.3) | (28.1-48.4) | 0.067 | 39.4 | (35.6-43.2) | (29.2-53) | 0.127 |
Coccosteus cuspidatus | ROM VP 52664 | 37.5 | 39.9 | (36.2-43.6) | (30.3-52.4) | 0.059 | 38.8 | (35.1-42.6) | (28.8-52.3) | 0.034 |
Plourdosteus canadensis | MNHM 2-177 | 37.5 | 44.8 | (40.7-49) | (34.1-59) | 0.163 | 46.6 | (42.1-51.1) | (34.5-62.9) | 0.195 |
Dickosteus threiplandi | NMS 1987.7.118 | 43.7 | 47.4 | (43-51.8) | (36-62.4) | 0.078 | 50.7 | (45.8-55.6) | (37.5-68.5) | 0.138 |
Holonema westolli | Recon. (Miles 1971) | 60.6 | 49.5 | (44.9-54.1) | (37.6-65.2) | -0.226 | 46.4 | (41.9-50.9) | (34.4-62.6) | -0.307 |
Watsonosteus fletti | NMS G.1995.4.2 | 56.6 | 58.8 | (53.3-64.2) | (44.4-77.8) | 0.037 | 58.6 | (53-64.2) | (43.2-79.6) | 0.034 |
Gen. et sp. nov. | CMNH 50233 | 63.0 | 63.0 | (57.2-68.9) | (47.5-83.6) | 0.000 | 61.3 | (55.4-67.3) | (45.1-83.4) | -0.027 |
Dickosteus threiplandi | NHMUK PV P 49663 | 52.3 | 64.4 | (58.4-70.4) | (48.5-85.5) | 0.188 | 62.2 | (56.2-68.2) | (45.7-84.6) | 0.159 |
Amazichthys trinajsticae | AA.MEM.DS.8 | 89.7 | 69.0 | (62.6-75.4) | (51.8-91.9) | -0.300 | 69.5 | (62.8-76.2) | (50.8-95.1) | -0.291 |
Dunkleosteus terrelli | CMNH 7424 | NA | 168.4 | (152.8-184.1) | (119.2-237.9) | NA | 167.4 | (151.3-183.6) | (114.8-244.3) | NA |
Dunkleosteus terrelli | CMNH 6090 | NA | 249.8 | (226.6-273) | (170.5-366) | NA | 247.1 | (223.3-271) | (162.8-375.1) | NA |
Dunkleosteus terrelli | CMNH 7054 | NA | 262.2 | (237.9-286.6) | (178.1-386.1) | NA | 257.4 | (232.6-282.2) | (168.8-392.5) | NA |
Dunkleosteus terrelli | CMNH 5768 | NA | 298.7 | (271-326.5) | (200.2-445.6) | NA | 295.1 | (266.7-323.5) | (190.6-456.8) | NA |
Head length and OOL are both very accurate in predicting length in complete arthrodires (mostly coccosteomorphs). However, they result in dramatic underestimates of total length in Amazichthys trinajsticae, likely because of the very small head and signs of an elongate body plan in this taxon (see below and manuscript).
The estimated lengths for Dunkleosteus under these models is similar to the lengths predicted using the all-fish model, specifically the model using head length by itself. However, as mentioned in the manuscript, lengths of less than 3 m are unlikely for CMNH 5768 because this would require a body plan with next to no caudal fin or caudal peduncle. It is likely the head size of the Achannaras coccosteomorphs is slightly above average based on their proportions (specifically, the location of the cranio-thoracic joint), whereas Amazichthys’ head size is below average, especially for arthrodires.
Additionally, it is highly likely the model is being influenced by extrapolation error, as it must be extrapolated roughly five times the span of the data in order to predict body size in Dunkleosteus. It is for these reasons that the model considering only arthrodires is not favored here.
Additionally, despite having a percent error of only about 8%, the 95% prediction intervals for the model are very large, almost as large as the model fit using all fishes. This is, as stated in the manuscript, in part due to the back-transformation of errors from a logarithmic scale.
Also note that the length estimates here are not the same as the estimates cited as “Simple scaling from Coccosteus, head length” in the manuscript. That is calculated based on the proportions of the reconstruction of Coccosteus cuspidatus in Miles and Westoll (1968), rather than a regression equation.
17.4.1 Scaling of head size in Arthrodira
%>%
fossil_taxa filter(length_as=="total length") %>%
mutate(taxon=ifelse(genus=="Newspecies","CMNH aspinothoracid",taxon)) %>%
mutate(clade2=case_when(genus %in% c("Amazichthys","Newspecies")~"Aspinothoracida",
%in% c("Millerosteus","Dickosteus",
genus "Watsonosteus","Coccosteus",
"Incisoscutum","Plourdosteus")~"Coccosteomorpha",
%in% c("Africanaspis","Holonema")~"Basal Arthrodira",)) %>%
genus augment(lm(total_length~head_length,.),newdata=.)%>%
ggplot(aes(head_length,total_length))+
geom_smooth(method="lm",formula=y~x,alpha=0.2)+
geom_star(starshape=15,aes(fill=clade2))+
geom_text(aes(label=taxon,
y=total_length+
ifelse(.resid<0|genus %in% c("Amazichthys","Millerosteus"),-2,3)+
ifelse(genus %in% c("Millerosteus"),-1,0)+
ifelse(genus %in% c("Africanaspis"),1,0),
fontface=ifelse(genus=="Newspecies",1,3),
hjust=ifelse((.resid>0|genus=="Amazichthys")&genus!="Millerosteus",1,
ifelse(specimen %in% c("CMNH 50233"),0.25,
ifelse(specimen %in% c("NHMUK PV P 49663"),0.5,0)))),
size=4)+
labs(fill="Arthrodire Clade",x="Head Length (cm)",y="Total Length (cm)")+
theme(legend.position=c(0.85,0.2))
Figure 17.2: Plot of head size versus total length on a (non log-transformed) dataset of all arthrodires with complete remains
17.5 Residuals of Amazichthys trinajsticae
%>%
OOL_residualsmutate(shape=factor(shape,levels=c("macruriform","anguilliform","elongate","fusiform","compressiform")))%>%
filter(ontogeny %in% c("adult","subadult")|is.na(ontogeny))%>%
group_by(taxon)%>%
summarise(residuals=mean(residuals),clade=unique(clade),genus=unique(genus),shape=unique(shape))%>%
filter(genus %in% c("Amazichthys","Kajikia","Istiompax","Esox","Loxodon","Chiloscyllium","Sphyraena","Scomberoides","Thyrsitoides","Albula"))%>%
select(!genus)%>%
mutate(taxon=str_replace(taxon,"_"," "))%>%
arrange(desc(clade))%>%
kable(digits=3,align=c("l","c","c","c"),
col.names=c("Taxon","Residuals","Clade","Body Shape"),
caption="Residuals of <i>Amazichthys trinajsticae</i> compared to similar fishes, showing how <i>A. trinajsticae</i> best compares to elongate or 'semi-elongate' fishes that have some degree of axial elongation")%>%
column_spec(1, italic = T)%>%
row_spec(1, bold = T)%>%
kable_styling()
Taxon | Residuals | Clade | Body Shape |
---|---|---|---|
Amazichthys trinajsticae | 0.158 | Placodermi | elongate |
Chiloscyllium griseum | 0.172 | Chondrichthyes | elongate |
Chiloscyllium punctatum | 0.180 | Chondrichthyes | elongate |
Loxodon macrorhinus | 0.159 | Chondrichthyes | fusiform |
Albula argentea | 0.145 | Actinopterygii | fusiform |
Albula glossodonta | 0.126 | Actinopterygii | fusiform |
Albula vulpes | 0.130 | Actinopterygii | fusiform |
Esox aquitanicus | -0.006 | Actinopterygii | fusiform |
Esox lucius | 0.107 | Actinopterygii | elongate |
Esox masquinongy | 0.137 | Actinopterygii | elongate |
Esox niger | 0.153 | Actinopterygii | elongate |
Istiompax indica | 0.156 | Actinopterygii | fusiform |
Kajikia albida | 0.265 | Actinopterygii | elongate |
Kajikia audax | 0.169 | Actinopterygii | elongate |
Scomberoides commersonnianus | 0.120 | Actinopterygii | fusiform |
Scomberoides lysan | 0.268 | Actinopterygii | fusiform |
Scomberoides tala | 0.331 | Actinopterygii | fusiform |
Scomberoides tol | 0.260 | Actinopterygii | fusiform |
Sphyraena acutipinnis | 0.083 | Actinopterygii | elongate |
Sphyraena afra | 0.139 | Actinopterygii | elongate |
Sphyraena africana | 0.032 | Actinopterygii | elongate |
Sphyraena arabiansis | 0.108 | Actinopterygii | elongate |
Sphyraena barracuda | 0.129 | Actinopterygii | elongate |
Sphyraena chrysotaenia | -0.026 | Actinopterygii | elongate |
Sphyraena flavicauda | 0.062 | Actinopterygii | elongate |
Sphyraena guaguancho | -0.003 | Actinopterygii | elongate |
Sphyraena idiastes | 0.037 | Actinopterygii | elongate |
Sphyraena jello | 0.114 | Actinopterygii | elongate |
Sphyraena obtustata | -0.073 | Actinopterygii | elongate |
Sphyraena putnamae | 0.129 | Actinopterygii | elongate |
Sphyraena qenie | 0.105 | Actinopterygii | elongate |
Sphyraena toxeuma | 0.069 | Actinopterygii | elongate |
Sphyraena viridensis | 0.086 | Actinopterygii | elongate |
Thyrsitoides marleyi | 0.219 | Actinopterygii | elongate |
Based on this, Amazichthys best compares to taxa that show a slight degree of axial elongation, such as Esox spp., larger species of Sphyraena spp., Istiompax indica, Kajikia audax (but not K. albida), and Scomberoides commersonnianus.
17.6 Relative pelvis position across non-acanthopterygian fishes
17.6.1 Using individual observations
<-data_final%>%
pelvic_lengths_allspecimensmutate(percent_prepelvic_length=prepelvic_length/total_length,
pectoral_pelvic_length=prepelvic_length-prepectoral_length,
pectoral_precaudal_length=precaudal_length-prepectoral_length,
higher_group=factor(higher_group,levels=c("Petromyzontiformes","Arthrodira","Chondrichthyes","Sarcopterygii","Basal Actinopterygii","Basal Teleostei","Ostariophysi","Stem Euteleostei","Acanthopterygii")),
order2=ifelse(order %in% c("Carcharhiniformes","Squaliformes"),
%>%
family,order))select(taxon,specimen,references,percent_prepelvic_length,pectoral_pelvic_length,
everything())%>%
pectoral_precaudal_length,arrange(higher_group,order,taxon)%>%
filter(higher_group!="Acanthopterygii")
<- pelvic_lengths_allspecimens %>%
level_info_2 arrange(higher_group, order2) %>%
pull(order2) %>%
unique()
<-pelvic_lengths_allspecimens%>%
pelvic_lengths_allspecimensmutate(order2=factor(order2,levels=rev(level_info_2)))%>%
drop_na(prepelvic_length,total_length,precaudal_length,prepectoral_length)
grid.arrange(
ggplot(pelvic_lengths_allspecimens,aes(percent_prepelvic_length,order2))+
geom_vline(aes(xintercept=mean(percent_prepelvic_length)),linetype="dashed")+
geom_violin(scale="width",aes(fill=higher_group))+
geom_boxplot()+
ggtitle("A")+
coord_cartesian(xlim=c(0,1))+
labs(x="Prepelvic Length as Percent of Total Length",y="Order")+
theme(legend.position="none"),
ggplot(pelvic_lengths_allspecimens%>%
drop_na(precaudal_length,prepectoral_length),
aes(pectoral_pelvic_length/pectoral_precaudal_length,order2))+
geom_vline(aes(xintercept=mean(pectoral_pelvic_length/pectoral_precaudal_length),group=higher_group),
linetype="dashed")+
geom_violin(scale="width",aes(fill=higher_group))+
geom_boxplot()+
ggtitle("B")+
coord_cartesian(xlim=c(0,1))+
labs(x="Prepectoral-Prepelvic Length as Percent of Prepectoral-Precaudal Length",y="Order")+
theme(legend.position="none"))
Figure 17.3: (A) Prepelvic-length as a percentage of total length in non-acanthopterygian fishes, showing how this value is about 45% of total length. (B) the length from the origin of the pectoral and pelvic fins as a percentage of the length from the origin of the pectoral fin to the base of the caudal peduncle in non-acanthopterygian fishes, showing how the pelvic fin is positioned about midway between the origin of the pectoral fin to the caudal peduncle, especially in sharks and arthrodires. These graphs calculated using all specimens.
17.6.2 Using species averages
<-data_final %>%
pelvic_lengths_speciesaveragesmutate(order2=ifelse(order %in% c("Carcharhiniformes","Squaliformes"),family,order)) %>%
drop_na(prepelvic_length,precaudal_length,prepectoral_length,total_length) %>%
group_by(taxon) %>%
summarise(across(c(prepelvic_length,prepectoral_length,precaudal_length,total_length),mean),
across(c(clade,order2,higher_group),unique)) %>%
mutate(percent_prepelvic_length=prepelvic_length/total_length,
pectoral_pelvic_length=prepelvic_length-prepectoral_length,
pectoral_precaudal_length=precaudal_length-prepectoral_length,
higher_group=factor(higher_group,levels=c("Petromyzontiformes","Arthrodira","Chondrichthyes","Sarcopterygii","Basal Actinopterygii","Basal Teleostei","Ostariophysi","Stem Euteleostei","Acanthopterygii"))) %>%
arrange(higher_group,order2,taxon) %>%
filter(higher_group!="Acanthopterygii") %>%
mutate(order2=factor(order2,levels=rev(level_info_2)))
grid.arrange(
ggplot(pelvic_lengths_speciesaverages,aes(percent_prepelvic_length,order2))+
geom_vline(aes(xintercept=mean(percent_prepelvic_length)),linetype="dashed")+
geom_violin(scale="width",aes(fill=higher_group))+
geom_boxplot()+
coord_cartesian(xlim=c(0,1))+
labs(x="Prepelvic Length as Percent of Total Length",y="Order")+
theme(legend.position="none"),
ggplot(pelvic_lengths_speciesaverages%>%
drop_na(precaudal_length,prepectoral_length),
aes(pectoral_pelvic_length/pectoral_precaudal_length,order2))+
geom_vline(aes(xintercept=mean(pectoral_pelvic_length/pectoral_precaudal_length),
group=higher_group),
linetype="dashed")+
geom_violin(scale="width",aes(fill=higher_group))+
geom_boxplot()+
coord_cartesian(xlim=c(0,1))+
labs(x="Prepectoral-Prepelvic Length as Percent of Prepectoral-Precaudal Length",y="Order")+
theme(legend.position="none"))
Figure 17.4: (A) Prepelvic-length as a percentage of total length in non-acanthopterygian fishes, showing how this value is about 45% of total length. (B) the length from the origin of the pectoral and pelvic fins as a percentage of the length from the origin of the pectoral fin to the base of the caudal peduncle in non-acanthopterygian fishes, showing how the pelvic fin is positioned about midway between the origin of the pectoral fin to the caudal peduncle, especially in sharks and arthrodires. These graphs calculated using species averages.
Based on this, it is clear that the pelvic girdle is typically located about midway along the animal’s body in most non-acanthopterygian fishes, particularly those with unspecialized body shapes. These include Carcharhiniformes, Hexanchiformes, some Squaliformes (i.e., Squalidae), Orectolobiformes, Actinistia, Amiiformes, Elopiformes, etc. This also appears to be the case for arthrodires which are known from complete remains (i.e., Millerosteus, Coccosteus, Watsonosteus, Incisoscutum, Amazichthys, etc.)
Additionally, the pelvic girdle tends to be midway between the origin of the pectoral girdle and the base of the tail fin in most non-acanthopterygian fishes, though the groups more closely related to Acanthopterygii tend to show more acanthopterygian-like proportions. Again, this includes arthrodires for which complete body fossil are known. Given that the pelvic girdle is usually just posterior to the ventral end of the armor in arthrodires, a predicted value of about ~155-160 cm in CMNH 5768, this further suggests lengths of about 3.6 m for typical adult individuals of Dunkleosteus terrelli
17.7 Length of Titanichthys
<-lm(log(total_length)~log(OOL),
fit.filterfeeder%>%filter(genus %in% c("Megachasma","Cetorhinus","Rhincodon")))
data_initial# Juvenile specimens for these genera were included as otherwise there were no specimens smaller than ~400 cm total length
%>%
fossil_taxafilter(genus=="Titanichthys")%>%
augment(fit.shape_clade3,newdata=.,interval="prediction")%>%
mutate(across(c(.fitted:.upper),~exp(.)*regression.stats(fit.shape_clade3)$CF)) %>%
rename_at(vars(starts_with('.')), funs(paste0("fit1",.)))%>%
augment(fit.filterfeeder,newdata=.,interval="prediction")%>%
mutate(across(c(.fitted:.upper),~exp(.)*regression.stats(fit.filterfeeder)$CF)) %>%
rename_at(vars(starts_with('.')), funs(paste0("fit2",.)))%>%
mutate(PE_1=paste0("(",round(fit1.fitted*(1-(regression.stats(fit.shape_clade3)$adjPE/100)),1),
"–",round(fit1.fitted*(1+(regression.stats(fit.shape_clade3)$adjPE/100)),1),")"),
range_1=paste0("(",round(fit1.lower,1),"–",round(fit1.upper,1),")"),
PE_2=paste0("(",round(fit2.fitted*(1-(regression.stats(fit.filterfeeder)$adjPE/100)),1),
"–",round(fit2.fitted*(1+(regression.stats(fit.filterfeeder)$adjPE/100)),1),")"),
range_2=paste0("(",round(fit2.lower,1),"–",round(fit2.upper,1),")"))%>%
select(specimen,OOL,fit1.fitted,PE_1,range_1,fit2.fitted,PE_2,range_2) %>%
kable(digits=1,align=c("l","c","c","c","c"),
col.names=c("Taxon","Specimen","Est.","+/-PE","95% P.I.","Est.","+/-PE","95% P.I."),
caption="Length estimates for <i>Titanichthys clarki</i> using the model with additional coefficients for shape and variable slopes between chondrichthyans and non-chondrichthyans (fit.shape_clade3)")%>%
add_header_above(c(" "=2,"All Taxa"=3,"Filter-Feeding sharks Only"=3))%>%
column_spec(c(3,6), bold = T)%>%
kable_styling()
Taxon | Specimen | Est. | +/-PE | 95% P.I. | Est. | +/-PE | 95% P.I. |
---|---|---|---|---|---|---|---|
CMNH 50319 | 57.2 | 371.3 | (325.3–417.3) | (267.1–516.2) | 296.7 | (277.1–316.2) | (239.6–367.4) |
AMNH 7134 | 64.0 | 414.8 | (363.3–466.2) | (298.3–576.6) | 334.4 | (312.4–356.5) | (270.7–413.1) |
AMNH FF 7134 is the very large individual of Titanichthys which, at the time of this writing, is mounted in the American Museum of Natural History’s Hall of Vertebrate Origins. CMNH 50319 is the associated subadult individual described by Boyle and Ryan (2017). Remains of Titanichthys tend to be fragmentary and much less common than those of Dunkleosteus, often fragments only assigned to Titanichthys based on armor thinness and texture (Boyle and Ryan 2017, D. Chapman pers. comm.), but all the specimens of Titanichthys the author has examined are either similar in size to AMNH FF 7134 or are much smaller in size (e.g., those figured in Dunkle and Bungart 1942).
As can be seen from these results, Titanichthys is roughly comparable in size to Dunkleosteus, accounting for the fact that there are fewer individuals known from anatomically identifiable material.
17.8 Body mass of Rhizodus hibberti
data.frame(total_length=563,precaudal_length=456.78,rowname="Using proportions of juvenile Strepsodus",habitat="benthic",
body_depth=89.55,body_width=89.55,head_length=104.14,
swimbladder=T,heterocercal=T)%>%
add_row(total_length=514,precaudal_length=417,rowname="Using trunk proportions of Goolongongia",habitat="benthic",
body_depth=76.16,body_width=76.16,head_length=104.14,
swimbladder=T,heterocercal=T)%>%
mutate(girth=ramanujan.approx(body_depth,body_width))%>%
augment(fit.ellipsoid,newdata=.,interval="predict")%>%
mutate(across(.fitted:.upper,~(exp(.)*regression.stats(fit.ellipsoid)$CF/1000)))%>%
column_to_rownames("rowname")%>%
select(total_length,.fitted,.lower,.upper)%>%
kable(digits=1,align="c",
col.names=c("Estimated Length (cm)","Est.","Lower 95% P.I.","Upper 95% P.I."),
caption="Estimated body masses of <i>Rhizodus hibberti</i> using dimensions of the juvenile <i>Strepsodus anculonamensis</i> from Andrews (1985) and trunk proportions of <i>Goolongongia loomesi</i> from Johanson and Ahlberg (1998) (i.e., trunk depth and total length but treating trunks as cylindrical because Devonian rhizodonts unlike Carboniferous ones are dorsoventrally compressed; Jeffery, pers. comm.)")%>%
add_header_above(c(" "=2,"Estimated Body Mass (kg)"=3))%>%
kable_styling()
Estimated Length (cm) | Est. | Lower 95% P.I. | Upper 95% P.I. | |
---|---|---|---|---|
Using proportions of juvenile Strepsodus | 563 | 1463.2 | 814.3 | 2629.1 |
Using trunk proportions of Goolongongia | 514 | 1019.7 | 570.6 | 1822.1 |
It is possible these estimates might be overestimates if Rhizodus did not have a perfectly cylindrical trunk and instead had a trunk that was slightly deeper than wide.
18 References
Afrisal, M.; Nurjirana; Irmawati; Burhanuddin, A.I. Osteological study of Titan Trigger fish, Balistoides viridescens (Bloch and Schneider, 1801) (Balistidae: Tetraodontiformes) from the Spermonde Archipelago Waters. IOP Conference Series: Earth and Environmental Science 2019, 370, doi:10.1088/1755-1315/370/1/012035.
Alexander, R.M. Functional Design in Fishes; Hutchinson University Library: London, 1967.
Ault, J.S.; Luo, J. A reliable game fish weight estimation model for Atlantic tarpon (Megalops atlanticus). Fisheries Research 2013, 139:110-117. doi:https://doi.org/10.1016/j.fishres.2012.10.004
Baker C.F.; Rossi C.R.; Quiroga P.; White E.; Williams P.; Kitson, J; Bice, C.M.; Renaud, C.B.; Potter, I.; Neira, F.J.; and Baigún, C. Morphometric and physical characteristics distinguishing adult Patagonian lamprey, Geotria macrostoma from the pouched lamprey, Geotria australis. PLoS ONE 2019, 16(5): e0250601. https://doi.org/10.1371/journal.pone.0250601
Baldridge, H.D. Sinking Factors and Average Densities of Florida Sharks as Functions of Liver Buoyancy. Copeia 1970, 1970, 744-754, doi:10.2307/1442317.
Blanton, P.L.; Biggs, N.L. Density of fresh and embalmed human compact and cancellous bone. American Journal of Physical Anthropology 1968, 29, 39-44, doi:https://doi.org/10.1002/ajpa.1330290113.
Bone, Q. Buoyancy and Hydrodynamic Functions of Integument in the Castor Oil Fish, 8Ruvettus pretiosus* (Pisces: Gempylidae). Copeia 1972, 22, 135-156. doi:10.1017/scs.2017.12
Boyle, J.; Ryan, M.J. New information on Titanichthys (Placodermi, Arthrodira) from the Cleveland Shale (Upper Devonian) of Ohio, USA. J Paleontol 2017, 91, 318–336, doi:10.1017/jpa.2016.136.
Brassey, C.A. Body-mass estimation in paleontology: a review of volumetric techniques. The Paleontological Society Papers 2016, 22, 135-156. doi:10.1017/scs.2017.12
Carr, R.K. Paleoecology of Dunkleosteus terrelli. Kirtlandia 2010, 57, 36-45.
Collette BB, and Nauen CE. Scombrids of the world: an annotated and illustrated catalogue of tunas, mackerels, bonitos, and related species known to date. Food and Agriculture Organization of the United Nations: Rome, 1983.
Compagno, L.J.V. Sharks of the world. An annotated and illustrated catalogue of shark species known to date. Part 1. Hexanchiformes to Lamniformes Food and Agriculture Organization of the United Nations: Rome, 1984.
Corner, E.D.S.; Denton, E.J.; Forster, G. On the buoyancy of some deep-sea sharks. Proceedings of the Royal Society of London. Series B. Biological Sciences 1969, 171, 415-429, doi:10.1098/rspb.1969.0003
Cupello, C.; Brito, P.M.; Herbin, M.; Meunier, F.J.; Janvier, P.; Dutel, H.; Clément, G. Allometric growth in the extant coelacanth lung during ontogenetic development. Nature Communications 2015, 6, 8222, doi:10.1038/ncomms9222.
Dean, B. Biometric Evidence in the Problem of the Paired Limbs of the Vertebrates. American Naturalist 1902, 36, 837-847
Dean, B. Notes on a newly mounted Titanichthys. Memoirs of the American Museum of Natural History 1909, 5, 270–271.
De Maddalena, A.; Glaizot, O.; Olivier, G. On the Great White Shark, Carcharodon carcharias (Linnaeus, 1758), preserved in the Museum of Zoology in Lausanne. Marine Life 2003, 13, 53-59.
Dunkle, D. H.; Bungart, P. A. The infero-gnathal plates of Titanichthys. Scientific Publications of the Cleveland Museum of Natural History 1942, 8, 49-59.
Engelman, R.K. Giant, swimming mouths: oral dimensions of extant sharks do not accurately predict body size in Dunkleosteus terrelli (Placodermi: Arthrodira). In Press.
Engelman, R.K. Reconstruction of Dunkleosteus terrelli (Placodermi: Arthrodira): a new look for the Devonian’s most famous predator. In Prep.
Ferrón, H.G.; Martínez-Pérez, C.; Botella, H. Ecomorphological inferences in early vertebrates: reconstructing Dunkleosteus terrelli (Arthrodira, Placodermi) caudal fin from palaeoecological data. PeerJ 2017, 5, e4081, doi:10.7717/peerj.4081
Freedman, J.A.; Noakes, D.L.G. Why are there no really big bony fishes? A point-of-view on maximum body size in teleosts and elasmobranchs. Reviews in Fish Biology and Fisheries 2002, 12, 403-416, doi:https://doi.org/10.1023/A:1025365210414
Froese, R. Cube law, condition factor and weight–length relationships: history, meta-analysis and recommendations. Journal of Applied Ichthyology 2006, 22, 241-253, doi:https://doi.org/10.1111/j.1439-0426.2006.00805.x.
Goujet, D. “Lungs” in Placoderms, a persistent palaeobiological myth related to environmental preconceived interpretations. Comptes Rendus Palevol 2011, 10, 323–329, doi:https://doi.org/10.1016/j.crpv.2011.03.008.
Hussakof, L. Notes on the Devonian “placoderm” Dinichthys intermedius Newb. Bulletin of the American Museum of Natural History 1905, 21, 27-36.
Kauffman, D.E. Notes on the biology of the tiger shark (Galeocerdo arcticus) from Philippine waters; 16; U. S. Fish & Wildlife Service: Washington D.C., 1950; pp. 1- 10.
ICRP. Basic anatomical and physiological data: The skeleton. Annals of the ICRP 1995, 25, 1-80, doi:10.1016/S0146-6453(00)80004-4.
McCune, A.R.; Carlson, R.L. Twenty ways to lose your bladder: common natural mutants in zebrafish and widespread convergence of swim bladder loss among teleost fishes. Evolution and Development 2004, 6, 246-259, doi:https://doi.org/10.1111/j.1525-142X.2004.04030.x.
Miles, R.S.; Westoll, T.S. The Placoderm Fish Coccosteus cuspidatus Miller ex Agassiz from the Middle Old Red Sandstone of Scotland. Part I. Descriptive Morphology. Transactions of the Royal Society of Edinburgh 1968, 67, 373-476, doi:10.1017/S0080456800024078.
Miller, R.G. Beyond ANOVA, Basics of Applied Statistics; John Wiley and Sons: New York 1986; p. 317.
Mollet, H.F.; Cailliet, G.M. Using allometry to predict body mass from linear measurements of the white shark. In Great White Sharks: The Biology of Carcharodon carcharias, Klimley, A.P., Ainley, D.G., Eds.; Academic Press: New York, 1996; pp. 81-89.
Parsons. Displacement and Area Curves of Fishes. Transactions of the American Society of Mechanical Engineers 1888, 9, 679-695.
Ramanujan, S. Ramanujan’s Collected Works; Chelsea, New York, 1962.
Robins, C.R. Summer concentration of white marlin, Tetrapturus albidus, west of the straits of Gibraltar. In Proceedings of the international billfish symposium Kailua-Kona, Hawaii, 9-12 August 1972. Part 2. Review and Contributed Papers, Shomura, S., Williams, F., Eds.; National Oceanic and Atmospheric Administration, NOAA Technical Report NMFS SSRF-675: 1974; pp. 164-174.
Robins, C.R.; De Sylva, D.P. A new western Atlantic spearfish, Tetrapturus pfluegeri, with a redescription of the Mediterranean spearfish Tetrapturus belone. Bulletin of Marine Science of the Gulf and Caribbean 1963, 13, 85–122.
Schultze, H.-P. Juvenile specimens of Eusthenopteron foordi Whiteaves, 1881 (osteolepiform rhipidistian, Pisces) from the Late Devonian of Miguasha, Quebec, Canada. Journal of Vertebrate Paleontology 1984, 4, 1-16. https://doi.org/10.1080/02724634.1984.10011982
Shephard, R.J. Body Composition in Biological Anthropology; Cambridge University Press: Cambridge, 1991; p. 368.
Springer, S.; Gilbert, P.W. The Basking Shark, Cetorhinus maximus, from Florida and California, with Comments on Its Biology and Systematics. Copeia 1976,1, 47-54. https://doi.org/10.2307/1443770
Trinajstic, K. New anatomical information on Holonema (Placodermi) based on material from the Frasnian Gogo Formation and the Givetian-Frasnian Gneudna Formation, Western Australia. Geodiversitas 1999, 21, 69-84.
Trinajstic, K.; Long, J.A.; Sanchez, S.; Boisvert, C.A.; Snitting, D.; Tafforeau, P.; Dupret, V.; Clement, A.M.; Currie, P.D.; Roelofs, B.; et al. Exceptional preservation of organs in Devonian placoderms from the Gogo lagerstätte. Science 2022, 377, 1311-1314, doi:10.1126/science.abf3289
Varojean, D.H. Systematics of the genus Echinorhinus Blainville, based on a study of the prickly shark Echinorhinus cookei Pietschmann. Fresno State College, Fresno, 1972.
Villarino, M.B. Ramanujan’s Perimeter of an Ellipse. ArXiv Math 2008. doi:https://doi.org/10.48550/arXiv.math/0506384
Wall, W.P. The Correlation between High Limb-Bone Density and Aquatic Habits in Recent Mammals. Journal of Paleontology 1983, 57, 197-207.
Wedel, M.J. Evidence for bird-like air sacs in saurischian dinosaurs. Journal of Experimental Zoology 2009, 311A, 611-628. doi:https://doi.org/10.1002/jez.513
19 Session Information
::session_info() xfun
## R version 4.2.1 (2022-06-23 ucrt)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 22621)
##
## Locale: LC_COLLATE=English_United States.utf8 LC_CTYPE=English_United States.utf8 LC_MONETARY=English_United States.utf8 LC_NUMERIC=C LC_TIME=English_United States.utf8
##
## Package version:
## askpass_1.1 assertthat_0.2.1 backports_1.4.1 base64enc_0.1.3 bit_4.0.4 bit64_4.0.5 blob_1.2.3 bookdown_0.30 broom_1.0.1 bslib_0.4.1 cachem_1.0.6 callr_3.7.3 cellranger_1.1.0 class_7.3-20 cli_3.4.1 clipr_0.8.0 colorspace_2.0-3 commonmark_1.8.1 compiler_4.2.1 cowplot_1.1.1 cpp11_0.4.3 crayon_1.5.2 curl_4.3.3 data.table_1.14.4 DBI_1.1.3 dbplyr_2.2.1 digest_0.6.30 dplyr_1.0.10 dtplyr_1.2.2 e1071_1.7-12 ellipsis_0.3.2 evaluate_0.18 fansi_1.0.3 farver_2.1.1 fastmap_1.1.0 forcats_0.5.2 fs_1.5.2 gargle_1.2.1 generics_0.1.3 ggplot2_3.4.0 ggstar_1.0.4 ggtext_0.1.2 glue_1.6.2 googledrive_2.0.0 googlesheets4_1.0.1
## graphics_4.2.1 grDevices_4.2.1 grid_4.2.1 gridExtra_2.3 gridtext_0.1.5 gtable_0.3.1 haven_2.5.1 highr_0.9 hms_1.1.2 htmltools_0.5.3 httr_1.4.4 ids_1.0.1 isoband_0.2.7 jpeg_0.1.9 jquerylib_0.1.4 jsonlite_1.8.3 kableExtra_1.3.4 knitr_1.40 labeling_0.4.2 lattice_0.20-45 lifecycle_1.0.3 lubridate_1.9.0 magick_2.7.3 magrittr_2.0.3 markdown_1.3 MASS_7.3.58.1 Matrix_1.5-1 memoise_2.0.1 methods_4.2.1 mgcv_1.8-40 mime_0.12 modelr_0.1.10 munsell_0.5.0 nlme_3.1-160 openssl_2.0.4 openxlsx_4.2.5.1 pillar_1.8.1 pkgconfig_2.0.3 png_0.1.7 prettyunits_1.1.1 processx_3.8.0 progress_1.2.2 proxy_0.4-27 ps_1.7.2 purrr_0.3.5
## R6_2.5.1 ragg_1.2.4 rappdirs_0.3.3 RColorBrewer_1.1.3 Rcpp_1.0.9 readr_2.1.3 readxl_1.4.1 rematch_1.0.1 rematch2_2.1.2 reprex_2.0.2 rlang_1.0.6 rmarkdown_2.18 rmdformats_1.0.4.9000 rstudioapi_0.14 rvest_1.0.3 sass_0.4.2 scales_1.2.1 selectr_0.4.2 splines_4.2.1 stats_4.2.1 stringi_1.7.8 stringr_1.4.1 svglite_2.1.0 sys_3.4.1 systemfonts_1.0.4 textshaping_0.3.6 tibble_3.1.8 tidyr_1.2.1 tidyselect_1.2.0 tidyverse_1.3.2 timechange_0.1.1 tinytex_0.42 tools_4.2.1 tzdb_0.3.0 utf8_1.2.2 utils_4.2.1 uuid_1.1.0 vctrs_0.5.0 viridisLite_0.4.1 vroom_1.6.0 webshot_0.5.4 withr_2.5.0 xfun_0.34 xml2_1.3.3 yaml_2.3.6
## zip_2.2.2