library(knitr)

knitr::opts_chunk$set(fig.align="center",eval.after="fig.cap",
                      fig.width=7,fig.height=4,
                      echo=TRUE, warning=FALSE, message=FALSE,
                      cache.lazy = FALSE,results="hide")
setwd("C:/Users/nebet/Documents/Fossiles/Oxfordien du Poitou/Photos 2")
library(dplyr)
library(FactoMineR)
library(factoextra)
library(ggrepel)
library(umap)
library(pheatmap)
library(kableExtra)
library(patchwork)

# functions to compute coeff ####
coeffBatch=function(x,batch=batch) {
  
  design = matrix(1, nrow(x), 1)
  
  batch <- as.factor(batch)
  contrasts(batch) <- contr.sum(levels(batch))
  batch <- model.matrix(~batch)[, -1, drop = FALSE]
  rownames( batch)=rownames(x)
  
  fit <- limma::lmFit(t(x), cbind(design, batch))
  beta <- fit$coefficients[, -(1:ncol(design)), drop = FALSE]
  beta[is.na(beta)] <- 0
  return(beta)
  
}

Introduction

J’adore les fossiles, et plus particulièrement les ammonites. J’en ai ramassé des centaines, notamment dans le Poitou. J’aime bien les examiner, les nettoyer et essayer de les identifier (au moins au niveau du genre ou de la famille). Hélas ! Une famille d’ammonites, les Perisphinctidae me donne du fil à retordre. Non seulement je n’arrive pas à les identifier, mais je n’arrive même pas à les classer en fonction de leur ressemblance. Toutes les formes intermédiaires semblent exister, ce qui suscite beaucoup de frustration chez moi…

knitr::include_graphics("ammo.png")
Les Perisphinctidae sont des ammonites avec une coquille
généralement évolute et costulée

Les Perisphinctidae sont des ammonites avec une coquille généralement évolute et costulée

J’ai décidé récemment de prendre le taureau par les cornes et d’employer les grands moyens : je mesurerai différents caractères morphologiques des coquilles de mes ammonites (taille, épaisseur, etc.) et je demanderai aux mathématiques et aux statistiques de créer des groupes d’ammonites cohérents.

Cela permettra déjà de répondre à un premier objectif (strictement personnel) : classer ma collection et pouvoir mieux ranger mes tiroirs.

Mais j’ai l’intention d’aller plus loin : comparer mes ammonites à des ammonites identifiées et pour lesquels je peux obtenir les mêmes données morphologiques que pour les miennes. Cela permettra de me fournir des pistes pour l’identification (l’identification des Perisphinctidae étant extrêmement complexe, il vaut mieux ne pas être trop affirmatif/ve).

Enfin, ce projet se veut utile à d’autres collectionneurs et collectionneuses. Je vous proposerai une application shiny, déjà disponible ici, permettant de comparer vos ammonites aux miennes, et ainsi de vous donner des pistes pour l’identification.

Attention : cette comparaison n’est pertinente que si vos ammonites proviennent du même référentiel que le mien, à savoir des Perisphinctidae de petite taille (pas plus de 12 cm) et provenant du même niveau que moi : Oxfordien moyen, zone à Transversarium, sous-zone à Parandieri. Si vos ammonites proviennent d’un niveau proche (par exemple, sous-zone à Luciaeformis), je pense qu’une comparaison peut rester pertinente dans une certaine mesure.

Matériel

# Loading data ####
dirs=list.dirs() %>% .[.!="."]
dirs=dirs[grepl("Ammonite",dirs)]

data=c()
for (d in dirs) {
  N=gsub("./Ammonite","",d) %>% as.numeric()
  data_D=read.csv(paste0(d,"/ammonite",gsub("./Ammonite","",d),".csv"))
  rownames(data_D)=c("dm","wh","uw","e")
  data_D2=read.csv(paste0(d,"/ammonite",gsub("./Ammonite","",d),"ww.csv"))
  rownames(data_D2)="ww"
  data_D3=rbind(data_D[,6,drop=FALSE],data_D2[,6,drop=FALSE]) %>% data.frame()
  data=rbind(data,t(data_D3))
  rownames(data)[nrow(data)]=N
}
data=data.frame(data, check.names=FALSE)


# Reference ammonites ####
ref.df=openxlsx::read.xlsx("references.xlsx")
ref.df$Numéro=as.character(ref.df$Numéro)
rownames(ref.df)=ref.df$Numéro
ref.df=ref.df[ref.df$Numéro%in%rownames(data),]
notParanideri=ref.df$Numéro[ref.df$Parandieri=="Non"]
data=data[!rownames(data)%in%notParanideri,]
ref.df=ref.df[ref.df$Parandieri=="Oui",]
data$ref="No"
data$ref[rownames(data)%in%ref.df$Numéro]="Yes"
table_ref=table(data$ref)

# Computing ratios ####
data=data.frame(data)
data$UWI=data$uw/data$dm #evolution
data$WWI=data$ww/data$wh #dépression
data$WHI=data$wh/data$dm # Whorld height index 
data$Shape = data$ww/data$dm # Shape
data$WER =  (data$dm/(data$dm-data$wh))^2 #Whorl expansion rate 
data$o=data$e/data$dm #ornementations

Cette analyse a été réalisée sur des Perisphinctidae de ma collection (59 individus) et sur des Perisphinctidae décrites dans la littérature scientifique (18 individus). Toutes mes Perisphinctidae sont originaires d’un seul champs situé dans la Vienne (86). Elles proviennent de la zone à Transversarium, sous-zone à Parandieri. Mes ammonites ont un diamètre allant de 2.18 à 11.847 cm. Il n’y a pas de forme macroconque (c’est-à-dire des coquilles de grande taille, provenant d’individus femelles adultes).

Méthode

Photographies

Pour pouvoir prendre des mesures sur mes ammonites, je les photographie de deux façons : de face et sur le côté, à chaque fois avec une échelle. Pour la photo sur le côté, je me situe “perpendiculairement” à la dernière spire (cf. la position de l’oeil sur l’image ci-dessous) image

Concrètement, pour chacune des ammonites que je souhaite mesures, j’obtiens ce genre d’image :

Mesures

J’utilise le logiciel imageJ pour réaliser mes mesures.

Les mesures que j’ai réalisées sont pour la plupart très classiques et on peut les trouver dans de nombreuses publications scientifiques :

  • diamètre total (dm)
  • hauteur de la spire (wh)
  • épaisseur de la spire (ww)
  • diamètre de l’ombilic (uw).

J’ai rajouté une mesure inédite : l’écart entre les côtes au niveau de la dernière spire (e) afin de prendre en compte la densité de la costulation. image

Ammonites références

Dans le livre “Les Ammonites et les Oursin de l’Oxfordien du Poitou” (1995), P. Branger cite un nombre limité d’espèces de Perisphinctidae présentes dans la zous-zone à Parandieri (tableaux 2&3, planches 8&9) :

  • Passendorferia birmensdorfense
  • Sequeirosia trichoplocus
  • Otosphinctes crotalinus
  • Otosphinctes siemiradzkii
  • Dichotomosphinctes elisabethae
  • Subdiscosphinctes mindowe

Afin d’avoir des points de références, j’ai récupéré dans la littérature scientifiques ou sur certains sites les données de différents individus appartenant aux les espèces citées ci-dessus. J’ai rajouté à ces espèces Dichotomosphinctes luciae et Dichotomosphinctes luciaeformis (d’après Głowniak 2007, D. elisabethae, D. lucia et D. luciaeformis sont différents morphes de la même espèce). J’ai également rajouté Subdiscosphinctes kreutzi car j’ai trouvé très peu d’information concernant S. mindowe.

Avec des diamètre allant de allant de 5 à 14.1 cm, les ammonites “références” sont en moyenne plus grandes que celles de ma collection.

Les données de ces ammonites références ont été intégrées à mes données et servent à comparer mes ammonites aux ammonites de la littérature.

Ci-dessous vous trouverez la provenance et l’espèce des ammonites références utilisées dans cette analyse :

Espèce Source Abrévation
Passendorferia birmensdorfense https://www.ammonites.org/ PassBir
Dichotomosphinctes elisabethae https://www.ammonites.org/ DichEli
Subdiscosphinctes mindowe Głowniak 2007 fig9 SubMin
Otosphinctes http://jsdfossiles.com/ OtoSP
Subdiscosphinctes http://jsdfossiles.com/ SubSP
Dichotomosphinctes elisabethae http://jsdfossiles.com/ DichEli
Passendorferia birmensdorfense https://www.ammonites.org/ PassBir
Otosphinctes crotalinus Głowniak 2007 fig48 tab27 OtoCro
Dichotomosphinctes elisabethae Gygi 2001 fig106B tab39 DichEli
Otosphinctes crotalinus Gygi 2001 fig67 tab21 OtoCro
Passendorferia birmensdorfense Gygi 2001 fig225c, tab90 PassBir
Dichotomosphinctes luciaeformis Gygi 2001 fig110, tab 41 DichLuciaef
Passendorferia birmensdorfense Gygi 2001 fig134B, tab51 PassBir
Sequeirosia trichoplocus Gygi 2001 fig136, tab52 SeqTri
Dichotomosphinctes elisabethae Gygi 2001 fig180b, tab71 DichEli
Subdiscosphinctes kreutzi Gygi 2001 fig122, tab46 SubKreu
Subdiscosphinctes kreutzi Głowniak 2007 fig7, tab2 SubKreu
Dichotomosphinctes elisabethae Enay 1966 planche31,6 DichEli

Calcul de ratios

J’ai calculé différents ratios que l’on trouve pour la plupart dans la littérature scientifique :

  • UWI = uw/dm : Umbilical Width Index = Indice de Largeur Ombilical, représente le rapport entre le diamètre de l’ombilic et celui de la coquille, ce qui permet de mesurer le degré d’involution (plus une coquille est involute, plus les tours se recouvrent)
  • WWI = ww/wh : Whorl width index = Indice de Largeur de la Spire, mesure le ratio entre la largeur et la hauteur d’une spire. Cela permet de mesurer si une coquille est plutôt mince ou épaisse (niveau de compression).
  • Shape = ww/dm : Shape = Forme, représente ici la largeur de la coquille sur son diamètre. C’est une autre mesure du niveau de compression de la coquille.
  • WER = (dm/(dm-wh))^2 : Whorl expansion rate = Taux d’expansion des spires, représente le taux auquel le diamètre de la coquille augmente par tour.
  • WHI = wh/dm : Whorl height index = Indice de Hauteur de la spire, represente le ratio de la hauteur de la dernière spire et le diamètre de la coquille entière. C’est une autre façon de calculer le taux auquel le diamètre de la coquille augmente par tour
  • o = e/dm : ornementation, densité de la costulation

Méthode d’analyse

# harmoniser ####
HC_JDS=ref.df[ref.df$Source%in%c("HC","JSD"),"Numéro"]
data$DirectMeasure="No"
data[as.numeric(rownames(data))>=500,"DirectMeasure"]="Yes"
data[HC_JDS,"DirectMeasure"]="No"

varToCorrect=c("UWI","WWI","WHI","Shape","WER")
varToCorrect=c("WWI","Shape")
data0=data
x=as.matrix(data0[,varToCorrect])
batch=data0$DirectMeasure
data[,varToCorrect]=t(limma::removeBatchEffect(t(x), batch=batch))

beta=coeffBatch(x,batch=batch)
saveRDS(beta,"C:/Users/nebet/Documents/Fossiles/Oxfordien du Poitou/Photos 2/shiny/midOxfPeri/beta.RDS")


# Labeling ammonites ####
data$label="?"
data[as.character(ref.df$Numéro),"label"]=ref.df$Espèce_dim
data$label2="?"
data[as.character(ref.df$Numéro),"label2"]=ref.df$Name

# Colors of labels ####
col_label=hues::iwanthue(n=length(unique(data$label))) %>% setNames(unique(data$label))
col_cl0=c( yellow = "#f3c300", purple = "#875692", 
         orange = "#f38400", lightblue = "#a1caf1", red = "darkgreen", buff = "#c2b280", 
         gray = "#848482", green = "#008856", purplishpink = "#e68fac", 
         blue = "#0067a5", yellowishpink = "#f99379", violet = "#604e97", 
         orangeyellow = "#f6a600", purplishred = "#b3446c", greenishyellow = "#dcd300", 
         reddishbrown = "#882d17", yellowgreen = "#8db600", yellowishbrown = "#654522", 
         reddishorange = "#e25822", olivegreen = "#2b3d26")  %>% setNames(paste0("cl",1:20))


# Selecting variables for PCA + scaling ####
sel_var=c("dm","WWI","WER","UWI","Shape","WHI","o")
data_pca=data[,sel_var]
data_pca=scale(data_pca) %>% data.frame()

# PCA #####
res.pca=PCA(data_pca,graph = FALSE)
pc_var=cumsum(res.pca$eig[,2])
nb_axe=min(which(pc_var>80))
pca.coord=rbind(res.pca$ind$coord,res.pca$ind.sup$coord)
data_plot=merge(pca.coord,data,by="row.names") %>%
  data.frame()

plot(res.pca,choix="var")
plot(res.pca,c(1,3),choix="var")
data_plot$names=data_plot$Row.names
data_plot$names[as.numeric(data_plot$Row.names)>=500]=data_plot$label2[as.numeric(data_plot$Row.names)>=500]
rownames(data_plot)=data_plot$Row.names

# clustering #####
FUNcluster=function(x,k) {
  hc=hclust(dist(x), method="ward.D2")
  clustering=cutree(hc,k=k) #%>% setNames(rownames(x))
  res=list()
  res[["cluster"]]=clustering
  return(res)
}
FUNcluster2=function(x,k) {
  hc=hclust(dist(x), method="complete")
  clustering=cutree(hc,k=k) #%>% setNames(rownames(x))
  res=list()
  res[["cluster"]]=clustering
  return(res)
}



# Determiner le nombre optimal de clusters
fviz_nbclust(pca.coord[,1:nb_axe], FUNcluster, method = "silhouette")+ theme_classic()
k=6
# Bootrapping ####
pc=0.7
R=500

boot=matrix(0,nrow=nrow(pca.coord),ncol=nrow(pca.coord))
for (r in 1:R) {
  set.seed(r)
  index_r=sample(rownames(pca.coord),round(pc*nrow(pca.coord)))
  clustering_r=(FUNcluster(pca.coord[index_r,1:nb_axe],k=k))$cluster
  boot_r=matrix(0,nrow=nrow(pca.coord),ncol=nrow(pca.coord))
  colnames(boot_r)=rownames(boot_r)=rownames(pca.coord)
  for (clr in clustering_r) {
    ind_cl=index_r[clustering_r==clr]
    boot_r[ind_cl,ind_cl]=1

  }
  boot=boot+boot_r
 # print(max(boot))
}
colnames(boot)=rownames(boot)=rownames(pca.coord)
nb_cl=apply(boot,1,max)
boot2=boot/nb_cl
colnames(boot2)=rownames(boot2)=rownames(pca.coord)
pheatmap(boot2, clustering_method="complete")
fviz_nbclust(boot2, FUNcluster2, method = "silhouette")+ theme_classic()
clustering_boot=paste0("cl",FUNcluster2(boot2,k=6)$cluster)
names(clustering_boot)=names(FUNcluster2(boot2,k=6)$cluster)

col_cl2=col_cl0[unique(clustering_boot)]


# Umap ####
# library(uwot)
# set.seed(11)
# res_umap=uwot::umap(pca.coord[,1:nb_axe],ret_model = TRUE,n_neighbors = 15, min_dist = 0.001)
# umap.coord=res_umap$embedding %>% data.frame()
# rds : pour garder mêmes coorodnnnées
umap.coord=readRDS("C:/Users/nebet/Documents/Fossiles/Oxfordien du Poitou/Photos 2/shiny/midOxfPeri/umap.coord.RDS")
colnames(umap.coord)=paste0("UMAP",1:2)
data_plot2=merge(data_plot,umap.coord,by.x="Row.names",by.y="row.names")
rownames(data_plot2)=data_plot2$Row.names
data_plot2$clustering_boot=clustering_boot[data_plot2$Row.names]

# Saving files ####
saveRDS(data_plot2,"C:/Users/nebet/Documents/Fossiles/Oxfordien du Poitou/Photos 2/shiny/midOxfPeri/data.RDS")

L’analyse n’a porté que sur les variables suivantes :

  • dm
  • WWI
  • WER
  • UWI
  • Shape
  • WHI
  • o

L’idée de l’analyse est la suivante : identifier des groupes d’ammonites se ressemblant et créer un graphique résumant les caractéristiques de toutes les ammonites. Le graphique se nomme une UMAP, chaque point représente une ammonite et plus ces points-ammonites sont proches, plus ils se ressemblent. Au contraire, plus ils sont éloignées, plus ils sont morphologiquement différents.

Si vous souhaitez en savoir plus sur le détail de l’analyse, cliquez ci-dessous :

J’ai d’abord réalisé une ACP à partir des variables ci-dessus (centrées-réduites). Voici les résultats de l’ACP.

Tout d’abord le pourcentage de variance expliquées par chaque axe de l’ACP :

h=res.pca$eig[,2] %>% setNames(paste0("Dim",1:nrow(res.pca$eig)))
barplot(h, main="Pourcentage de variance de chaque axe", las=2)

Voici les graphiques des variables qui montrent les corrélations entre les variables et les axes de l’ACP:

plot(res.pca,choix="var")

plot(res.pca,c(1,3),choix="var")

J’ai choisi de travailler sur les trois premiers axes, qui cumulent une variance d’au moins 80%.

Ces trois premiers axes ont été utilisés pour réaliser un clustering hiérarchique. Pour avoir un clustering plus robuste, j’ai fait du bootstraping. J’ai rééchantillonné 500 fois mon échantillon avec 70% des individus. A chaque fois j’ai réalisé un clustering (distances euclidiennes, méthode de Ward). Cela m’a permis de savoir à quelles fréquences les individus clusterisent entre eux. Ces fréquences peuvent correspondre à des distances : plus des individus clusterisent souvent ensemble, plus ils sont proches. J’ai réalisé un clustering final sur ces distances (méthode “complete”). J’ai obtenu 6 clusters.

Ci-dessous, vous trouverez plusieurs représentation de l’ACP, avec des couleurs représentant ces clusters, l’indice ombilical, le diamètre et l’épaisseur.

# Clusters
    p1 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.2,label=names)) +
      geom_point(aes(color = clustering_boot), size=1) + 
      ggtitle("Groupes")+
  theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = clustering_boot),size=2.5) +
  scale_color_manual(values=col_cl2) +
  theme(legend.position = "bottom")

    p2 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.3,label=names)) +
      geom_point(aes(color = clustering_boot), size=1) + 
      #ggtitle("Groupes")+
      theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = clustering_boot),size=2.5) +
  scale_color_manual(values=col_cl2) +
  theme(legend.position = "none")


p=p1+p2
print(p)

# UWI

    p1 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.2,label=names)) +
      geom_point(aes(color = UWI), size=1) + 
      ggtitle("UWI : index omibilical")+
  theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = UWI),size=2.5) +
  scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous")) +
  theme(legend.position = "bottom")

    p2 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.3,label=names)) +
      geom_point(aes(color = UWI), size=1) + 
      #ggtitle("Groupes")+
      theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = UWI),size=2.5) +
  scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous")) +
  theme(legend.position = "none")


p=p1+p2
print(p)

# Diamètre

    p1 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.2,label=names)) +
      geom_point(aes(color = dm), size=1) + 
      ggtitle("Diamètre (cm)")+
  theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = dm),size=2.5) +
  scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous")) +
  theme(legend.position = "bottom")

    p2 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.3,label=names)) +
      geom_point(aes(color = dm), size=1) + 
      #ggtitle("Groupes")+
      theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = dm),size=2.5) +
  scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous")) +
  theme(legend.position = "none")


p=p1+p2
print(p)

# Epaisseur

    p1 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.2,label=names)) +
      geom_point(aes(color = Shape), size=1) + 
      ggtitle("Epaisseur rapportée au diamètre")+
  theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = Shape),size=2.5) +
  scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous")) +
  theme(legend.position = "bottom")

    p2 <- ggplot(data_plot2,aes(x=Dim.1,y=Dim.3,label=names)) +
      geom_point(aes(color = Shape), size=1) + 
      #ggtitle("Groupes")+
      theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = Shape),size=2.5) +
  scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous")) +
  theme(legend.position = "none")


p=p1+p2
print(p)

Enfin, j’ai réalisé une UMAP, qui sert avant tout à la visualisation. Son objectif est de représenter en deux dimensions des distances dans des espaces de plus grandes dimensions (ici, 3 dimensions). C’est une façon de représenter de manière synthétique les 3 premières dimensions de l’ACP.

Résultats

La UMAP résumant les données est présentée ci-dessous. Les couleurs représentent les six clusters (=groupes de ressemblance) qui ont été identifiés.

    p <- ggplot(data_plot2,aes(x=UMAP1,y=UMAP2,label=names)) +
      geom_point(aes(color = clustering_boot), size=3) + 
      ggtitle("Groupes")+theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = clustering_boot)) +
  scale_color_manual(values=col_cl2) 

print(p)

Regardons maintenant le diamètre des ammonites :

    p <- ggplot(data_plot2,aes(x=UMAP1,y=UMAP2,label=names)) +
      geom_point(aes(color = dm), size=3) + 
      ggtitle("Diamètre (cm)")+theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = dm)) +
      scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous"))

print(p)

On constate que les clusters cl1, cl3 et cl6 correspondent plutôt à des ammonites de grande taille, alors que les clusters cl2, cl4 et cl5 représentent des ammonites de petite taille.

data_ref=data_plot2[data_plot2$label2!="?",]
rownames(ref.df)=ref.df$Numéro
ref.df2=  ref.df[rownames(ref.df)%in%rownames(data_ref)&!is.na(ref.df$Genre),]
ref.df2$clustering_boot=data_plot2[rownames(ref.df2),"clustering_boot"]


X=table(ref.df2$clustering_boot,ref.df2$Genre)

Nous constatons qu’aucune ammonite “référence” ne se trouve dans les groupes de petites ammonites. Laissons ces groupes de côté et concentrons nous sur les grandes ammonites (cl1, cl3 et cl6).

Sur la UMAP, ces clusters cl6, cl3 et cl1 ne semblent pas vraiment constituer des groupes clairement distincts, mais semblent plutôt représenter une sorte de continuum. Cela semble surtout vrai pour les clusters cl1 et cl3.

Tous les Otosphinctes et Passendorferia “références” se trouvent dans le cl6. Le cluster cl1 ne comprend, parmi les ammonites références, que deux Subdoscosphinctes. Toutes les Dichotomosphinctes se trouvent dans le cl3, mais ce cluster comprend également deux Subdiscosphinctes et le seul Sequeirosia du jeu de données. Cela suggère qu’il est probable que mes ammonites du cl6 appartiennent aux genres Otosphinctes et Passendorferia. Quant aux ammonites des clusters cl1 et cl3, on peut davantage s’orienter vers les genre Sequeirosia, Dichotomosphinctes ou Subdichotomosphinctes, en privilégiant l’hypothèse “Subdichotomosphinctes” pour le cl1.

Examinons désormais l’indice largeur ombilicale (UWI) qui nous indique si une ammonite est plutôt évolute (ombilic large) ou involute (ombilic étroit) :

    p <- ggplot(data_plot2,aes(x=UMAP1,y=UMAP2,label=names)) +
      geom_point(aes(color = UWI), size=3) + 
      ggtitle("UWI")+theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = UWI)) +
      scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous"))

print(p)

Concentrons nous toujours sur les grandes ammonites. On constate que plus une ammonite est évolute, plus elle est située à gauche du graphique, et plus elle est involute, plus elle est située à droite. Les ammonites références sont situées le long d’un continuum qui correspond aux descriptions que l’on trouve dans la littérature : les Otosphinctes et Passendorferia sont décrites comme des genres évolutes, Sequeirosia comme légèrement plus involutes que Passendorferia, Dichotomosphinctes comme étant “plutôt évolute” et Subdichotomosphinctes comme étant “involute”. On constate que le caractère “evolute”/“involute” est vraiment continu : il ne semble pas y avoir de seuil franc, surtout entre les cl1 et cl3.

Concentrons nous désormais sur les clusters de petites ammonites : cl2, cl4 et cl5. Il est intéressant de remarquer, que ces petites ammonites présentent le même “motif” que les grandes : les plus évolutes sont situés à gauche, les plus involutes à droite. Il est à noter que le cl5 se distingue par une épaisseur inhabituelle comme le montre le graphique ci-dessous:

    p <- ggplot(data_plot2,aes(x=UMAP1,y=UMAP2,label=names)) +
      geom_point(aes(color = Shape), size=3) + 
      ggtitle("Epaisseur rapportée au diamètre")+theme_bw()+ 
      ggrepel::geom_text_repel(data=data_plot2[data_plot2$label!="?",],
                      aes(label=label,color = Shape)) +
      scale_color_gradientn(colours=wesanderson::wes_palette("Zissou1", 100, type = "continuous"))

print(p)

Mon hypothèse pour l’instant est que les clusters cl5, cl2 et cl4 constituent plus ou moins les reflets des clusters cl6, cl3 et cl1 et représentent leurs formes juvéniles.

Ce qui me questionne, c’est le le cluster cl5. Est-il vraiment la forme juvénile du cluster cl6 ? Ou bien, les formes juvéniles du cluster cl6 ne seraient-elles pas plutôt dans le cluster cl2, aux côtés des formes juvéniles du cl3 ? Ou peut-être dans les deux ?

Ces analyses apportent des informations, mais il reste encore beaucoup de questions à résoudre.

Conclusion

Ces analyses m’ont permis de classer mes 59 ammonites dans 6 groupes à la morphologie similaire. Ces groupes ne sont pas tous clairement distincts, et représentent parfois une coupure quelque peu arbitaire le long d’un continuum.

Même si ces groupes ne correspondent pas exactement à la taxonomie, on ne peut pas nier qu’il existe un lien entre ce “clustering” et celle-ci. Le contraire aurait été étonnant puisque chaque genre et/ou espèce a des caractéristiques morphologiques particulières.

Ainsi, cette petite étude me permettra de partir sur les pistes suivantes :

  • les ammonites du cluster cl6 sont probablement des Otosphinctes et Passendorferia
  • les ammonites du cluster cl3 sont probablement des Sequeirosia, Dichotomosphinctes ou des Subdichotomosphinctes à “tendance évolute”
  • les ammonites du cluster cl1 sont probablement des Subdichotomosphinctes

Je pourrai vérifier ces pistes en examinant des caractéristiques morphologiques supplémentaires qui n’ont pas été mesurées dans cette petite “étude” (forme de la section et diverses caractéristiques de l’ornementation, notamment).

Quant aux clusters cl2, cl4 et cl5 qui représentent des petites ammonites, je partirai (pour l’instant) sur ces hypothèses :

  • les ammonites du cluster cl5 sont peut-être des Otosphinctes et Passendorferia juvéniles
  • les ammonites du cluster cl2 sont peut-être des formes juvéniles de Sequeirosia, Dichotomosphinctes ou de Subdichotomosphinctes à “tendance évolute”
  • les ammonites du cluster cl4 sont peut-être des Subdichotomosphinctes juvéniles

Je n’ai trouvé aucune description de petites Perisphinctidae (< 4 cm) dans la littérature, pour la sous-zone à Parandieri en tout cas. J’ai plusieurs fois demandé sur des forums ou groupes spécialisés ce que pouvaient être ces petites ammonites, et j’ai obtenu peu de réponses, ce qui indique à mon avis, que l’on ne sait pas trop de dont il s’agit. Une personne m’a répondu qu’il pouvait s’agir de formes juvéniles et/ou de tours internes de Dichotomosphinctes. Je reste donc sur l’hypothèse “juvéniles/tours internes”.

En l’absence de toute description de petites Perisphinctidae dans la littérature, je ne peux pas vraiment vérifier mes hypothèses sur les clusters cl2, cl4 et cl5. Mais je crois qu’avoir des hypothèses et avoir su les regrouper, c’est déjà pas mal.

Science collaborative : application shiny

J’ai créé une application. Si vous vous y connectez, vous verrez deux choses :

  • un panneau gauche où vous pourrez entrer des données et choisir ce que vous souhaitez visualiser.
  • une “UMAP” à droite, avec chaque point représentant une ammonite. Rappelez vous que sur une UMAP, la distance entre les points représentent à quel point ils sont différents ou similaires.

Remarque : Vous noterez que la UMAP de l’application n’est pas exactement la même que celle représentée sur cette page. C’est parce que l’algorithme de la UMAP utilise des techniques aléatoires pour trouver la meilleure représentation. Ce qui compte, c’est la distance entre les points (et vous constaterez Zque de ce point de vue là, les deux umaps sont très similaires.)

permettant deux choses :

  • visualiser mon jeu de données
  • comparer vos ammonites aux miennes

Visualier mon jeu de données

Si vous souhaitez uniquement visualiser mon jeu de données, vous pouvez cocher la case “Je n’ai pas de données à entrer”.

Sur la droite, vous aurez la fameuse “UMAP”.

En bas à gauche, le menu “Que visualiser ?” vous permettra de choisir la variable que vous choisissez visualiser : les groupes, le diamètre, la densité de la costulation, etc.

Comparer votre ammonites aux miennes

Comme je l’ai précisé en introduction, cette comparaison n’est pertinente que si vos ammonites proviennent du même référentiel que le mien, à savoir des Perisphinctidae de petite taille (pas plus de 12 cm) et provenant de l’Oxfordien moyen, zone à Transversarium, sous-zone à Parandieri. Si vos ammonites proviennent d’un niveau proche, je pense qu’une comparaison peut rester pertinente, mais restez prudent-e et critique.

Pour comparer votre ammonite à la mienne, il faudra la mesurer comme indiqué ci-dessus et entrer les mesures sur l’application. Je pense que mesurer sur à partir de photographies peut induire un biais via la perspective (biais que j’ai tenté de corriger dans l’analyse de données), c’est pour cela que j’ai fait en sorte que vous pouviez indiquer la méthode utilisée (mesures directes sur l’ammonite ou mesures à partir de photographies).

Votre ammonite se présentera sous la forme d’un point rouge appelé “Ton ammonite”. Vous pourrez visualiser son positionnement sur la UMAP. Ce positionnement vous permettra de vous comparer à moi, car les points proches représentent des ammonites similaires.

knitr::include_graphics("umap.png")
Je viens de rentrer les mesures d'une petite ammonite fine et plutôt évolute. Elle semble ressembler aux ammonites du cluster 2.

Je viens de rentrer les mesures d’une petite ammonite fine et plutôt évolute. Elle semble ressembler aux ammonites du cluster 2.

Amuez-vous bien ! et j’espère que cela pourra vous donner des pistes pour une identification :) !

# Organizing pictures in function of clusters ####
unlink("Clusters_pictures",recursive = TRUE)
dir.create("Clusters_pictures")
for (cl in unique(clustering_boot)) {
  dir.create(paste0("Clusters_pictures/",cl))
  Number_cl=data_plot2[data_plot2$clustering_boot==cl,"Row.names"]
  for (n in Number_cl) {
    nb_0=3-nchar(n)
    d=paste0("./Ammonite",paste0(rep(0,nb_0),collapse=""),n)
    pics=c(list.files(d)[grep(".jpg",list.files(d))],
           list.files(d)[grep(".png",list.files(d))])
    To_vec=c()
    for (i in 1:length(pics)) {
      from=paste0(d,"/",pics[i])
      
      to=paste0(d,"/ammonite",paste0(rep(0,nb_0),collapse=""),n,letters[i],".jpg")
      To_vec=c(To_vec,to)
      file.rename(from, to)
    }
    tofiles=  gsub(paste0(d,"/"),paste0("Clusters_pictures/",cl,"/"),To_vec)
    file.copy(To_vec,tofiles)
    
  }

}

Références

Branger, P., Nicolleau, P., & Vadet, A. (1995). Les ammonites et les oursins de l’Oxfordien du Poitou:(faciès à spongiaires de l’Oxfordien moyen et supérieur). Musees de la ville de Niort et Association pour la promotion de la geologie en Poitou-Charentes-Vendee.

Énay, R. (1966). L’Oxfordien dans la moitié sud du Jura français. Étude stratigraphique. Tome II. Publications du musée des Confluences, 8(2), 325-77.

Głowniak, E., & Wierzbowski, A. (2007). Taxonomical revision of the perisphinctid ammonites of the Upper Jurassic (Plicatilis to Planula zones) described by Józef Siemiradzki (1891) from the Kraków Upland. Volumina Jurassica, 5(1), 27-147.

Gygi, R. A., & Engesser, B. (2001). Perisphinctacean ammonites of the type Transversarium Zone (Middle Oxfordian, Late Jurassic) in northern Switzerland. Naturhistorisches Museum.