Este texto documenta el proceso asociado al estudio de la historia evolutiva de los datos de salmones provenientes del Laboratory of Genomics, Molecular Ecology and Evolutionary Studies, Universidad de Santiago de Chile.
Para leer las secuencias se listará cada secuencia de DNA que está en la carpeta Data, para luego abrirle usando la función read.fasta() de la biblioteca seqinr. Se usarán funciones que operan sobre cadenas de texto, biblioteca stringr, con el fin de estandarizar y reducir el nombre de las secuencias, dejándolas en el siguiente formato: secuencias$ALKBH5_Oncorhynchus_kisutch_LOC109886893.
#Bibliotecas
library("seqinr")
library("kmer")
library("phangorn")
library("stringr")
library("phytools")
library("treespace")
library("igraph")
library("ggplot2")
library("factoextra")
library("phangorn")
#--------------------------
#Apertura de archivos
#--------------------------
#Hacer listado de archivos en carpeta
= list.files(pattern = "\\.fna$",recursive = T)
archivos
#Abrir archivo por archivo generando etiquetas para los nombres
=NULL
secuenciasfor (a in 1:length(archivos))
{=c(secuencias,read.fasta(archivos[a],whole.header = T))
secuencias=strsplit(names(secuencias[a])," ")[[1]][2]
localizacion=str_replace(strsplit(strsplit(names(secuencias[a]),"organism=")[[1]][2],"]")[[1]][1]," ","_")
especie=strsplit(archivos[a],"/")[[1]][2]
gen=""
copiaif (grepl("like",archivos[[a]],fixed=F)) {copia="like"}
=paste(gen,copia,especie,localizacion,sep="_")
nuevo_nombrenames(secuencias)[a]= nuevo_nombre
}
Para crear el árbol filogenético de referencia asociado a las secuencias de DNA enviadas por el equipo especialista, se usará la estrategia kmers (Gamage et al. 2020). Con ello se evita sesgar las características de cada gen al efectuar alineamiento múltiple de las mismas, creando directamente una matriz de distancia sobre las secuencias no alineadas al usar la función kdistance() de la biblioteca kmer. El parámetro \(k\) se variará desde 1 a un máximo de 8, limitado por memoria, comparándole mediante distancia Euclidiana.
El árbol respectivo se generará usando el método de Neighbour joining (Saitou and Nei 1987).
#-----------------------------
# Creación de árbol kmers
#-----------------------------
#Creación de árboles usando kmers
=NULL
arbolesset.seed(1)
for (a in 1:8)
{#Kmers k:1-8
= kdistance(secuencias, k = a,method = "euclidean")
distancia
#Neighbour joining
=NJ(distancia)
arbol
#Eliminación de aristas negativas (si aparecen)
$edge.length[which(arbol$edge.length<0)]=0
arbol
#Eliminación de multifurcaciones
=multi2di(arbol)
arbol
=midpoint(arbol)
arbol
#Almacenamiento de árboles
=arbol
arboles[[a]]
}
#Resultados en estructura multiPhylo
class(arboles)="multiPhylo"
Posteriormente se calculará la distancia Robinson-Foulds (Briand et al. 2020) entre árboles usando la función multiDist() de la biblioteca treespace, con el fin de encontrar el árbol representativo (medoide). La matriz de distancia respectiva con y sin normalizar su amplitud, con respecto a la cantidad máxima de operaciones topológicas puede ser representada como sigue:
#-----------------------------
# Búsqueda de medoide
#-----------------------------
#Distancia sin normalizar
=as.matrix(multiDist(arboles))
distancia_RFprint(ncol(distancia_RF))
## [1] 8
print(nrow(distancia_RF))
## [1] 8
for (a in 1:length(arboles))
{ for (b in 1:length(arboles))
{=RF.dist(arboles[[a]], arboles[[b]], normalize = F) }
{distancia_RF[a,b]
}
}
#Gráfico
colnames(distancia_RF)=paste("tree",colnames(distancia_RF),sep="_")
rownames(distancia_RF)=paste("tree",rownames(distancia_RF),sep="_")
fviz_dist(dist.obj = as.dist(distancia_RF), order = F, lab_size = 12,gradient = list(low = "white", mid = "gray", high = "black"))
#Distancia normalizada
=distancia_RF
distancia_RF_norm
for (a in 1:length(arboles))
{ for (b in 1:length(arboles))
{=RF.dist(arboles[[a]], arboles[[b]], normalize = T) }
{distancia_RF_norm[a,b]
}
}
#Gráfico
fviz_dist(dist.obj = as.dist(distancia_RF_norm), order = F, lab_size = 12,gradient = list(low = "white", mid = "gray", high = "black"))
#Medoide
=which.min(colSums(distancia_RF)/nrow(distancia_RF))
ind_medoideprint(paste("El árbol medoide es el número",ind_medoide,sep=" "))
## [1] "El árbol medoide es el número 6"
#Guardado de árboles en formato newick
write.tree(arboles,"arboles_referencia.newick")
Finalmente, los árboles representativos se almacenarán en formato newick en caso de que se requiera liberar recursos del procesador, siendo el árbol númerp 6 el medoide.
La siguiente figura corresponde a una previsualización del árbol medoide. Para una mejor visualización se recomienda usar las aplicaciones Figtree o MEGA.
plot(arboles[[ind_medoide]],cex=0.6,type = "phylogram",use.edge.length = T)
edgelabels(round(arboles[[ind_medoide]]$edge.length,4), col = "black",frame = "none", cex=0.6)
Con el fin de comprobar la idoneidad del árbol de referencia obtenido en la sección anterior respecto a una metodología incorrecta, como podría ser el uso de alineamiento múltiple sobre todas las secuencias (MSA, por su sigla en inglés), se inferirá el árbol respectivo. Para ello se guardarán las secuencias en un archivo, transformándolas desde el formato SeqFastadna al DNAStringSet usando funciones de la biblioteca Biostrings (código comentado). Posteriormente este archivo se abrió en MEGA, realizando el correspondiente MSA, almacenándolo en el archivo secuencia_alineada.fasta.
El árbol asociado al MSA se inferirá usando el método de Neighbour joining.
#-----------------------------
# Inferencia de árbol MSA
#-----------------------------
#library(Biostrings)
#library(seqinr)
#FUN = function(x)
# paste(getSequence(x), collapse = "")
#sec_fasta=as(vapply(secuencias, FUN, character(1)), "DNAStringSet")
#writeXStringSet(sec_fasta, 'secuencia.fasta')
#Lectura de secuencias alineadas
=read.phyDat(file = "secuencia_alineada.fasta",type = "DNA",format = "fasta")
secuencia_alineada
#Cálculo de árboles
=dist.hamming(secuencia_alineada)
distancia_Hamming=NJ(as.matrix(distancia_Hamming))
arbol_msa
#Eliminación de aristas negativas (si aparecen)
$edge.length[which(arbol_msa$edge.length<0)]=0
arbol_msa
#Puntos
=midpoint(arbol)
arbol
#Eliminación de multifurcaciones
=multi2di(arbol_msa) arbol_msa
Como se puede apreciar, la mayoría de las hojas del árbol teóricamente relacionadas por los genes estudiados no quedan asociadas, validando al árbol de referencia basado en kmers.
#-----------------------------
# Comparación árbol kmers vs MSA
#-----------------------------
#Graficar árbol
plot(arbol_msa,cex=0.6,type = "phylogram",use.edge.length =T)
edgelabels(round(arboles[[ind_medoide]]$edge.length,4), col = "black",frame = "none", cex=0.6)
#Distancia y homologación de nombres
=arboles[[ind_medoide]]
arbol1$tip.label=str_replace_all(arbol1$tip.label, fixed("_"), "")
arbol1=arbol_msa
arbol2$tip.label=str_replace_all(arbol2$tip.label, fixed(" "), "")
arbol2=RF.dist(arbol1,arbol2,normalize = F)
distancia_nnorm=RF.dist(arbol1,arbol2,normalize = T)
distancia_norm
print(paste("La distancia no normalizada entre ambos árboles es",distancia_nnorm,"operaciones",sep=" "))
## [1] "La distancia no normalizada entre ambos árboles es 256 operaciones"
print(paste("La distancia normalizada entre ambos árboles es",round(distancia_norm,3),sep=" "))
## [1] "La distancia normalizada entre ambos árboles es 0.992"