library(tidyverse) # Manipulacion de datos
library(reshape2)
library(phytools) # Manipulacion de arboles filogeneticos
library(ape)
library(viridisLite)
library(viridis)
library(scales)
library(cowplot)
Figura 3
Distribución Taxonómica de los Elementos Genéticos Móviles
A. Prevalencia de las categorías de MGEs y predominio de los elementos transponibles en distintas clases taxonómicas (con al menos 10 genomas), ordenadas según la filogenia basada en genes marcadores taxonómicos (38).
B. Asociación de las categorías de MGEs (promedio de MGEs por especie) con diferentes clases taxonómicas (prueba de rango de Wilcoxon, * indica un valor de P < 0.05 después de la corrección de Bonferroni).
PASO 1: Importar datos
<- read_tsv("data/raw_data/species_with_atleast_2genomes.list.gz", col_names=F)
tax <-read_tsv("data/processed_data/mge_bins_per_genome_final.txt.gz", col_names = T)
db <-read_tsv("data/raw_data/genome_size.txt.gz", col_names = T)
gs <- read.tree("data/raw_data/progenomes2_class_tree.nwk")
class_tree <- read_tsv("data/raw_data/genome_status_supplementary_tableS2.txt.gz", col_names = T) glist
Cargar paleta de colores
# Paleta general de colores
<- c("#D55E00", "#E69F00", "#F0E442", "#56B4E9", "#009E73", "#0072B2","#CECCCC")
colc names(colc) <- c("IS_Tn", "Phage", "Phage_like", "CE", "Integron", "MI", "Cellular")
Cargar funciones
source("scripts/phylo_function.R")
PASO 2: Manipulación y Limpieza de los datos
# Obtener los genomas con la mas alta calidad
<- glist %>%
glist_high filter(genome_quality == "high")
# Renombra las columnas del dataframe tax para un nombre más legible
colnames(tax) <- c("specI", "genomeID", "kingdom", "phylum", "class", "genus")
# Reestructura la base de datos 'db' de formato ancho a largo usando reshape2::melt
<- db %>% reshape2::melt()
mdb
# Renombra las columnas de la base de datos reestructurada para claridad
<- mdb %>%
mdb ::rename(mge = variable, count = value, genomeID = 'Genome') %>%
dplyr# Filtra para incluir solo los genomas de alta calidad (genomas en glist_high$genome)
filter(genomeID %in% glist_high$genome)
PASO 3: Data.frame con combinaciones
Datos de formato
Crear un data.frame que contenga para cada specI para cada MGE: recuentos genómicos (genomeCnt),
- conteos totales (cnt_tot),
- promedio de recuentos entre genomas (avg_cnt),
- número de genomas en los que estaba presente el MGE (pa),
- la fracción de genomas con el MGE presente (frac) más información taxonómica
# Selecciona las columnas necesarias para trabajar con los datos
<- mdb %>% select(1, 7, 8)
mdb_cnt # Obtiene los valores únicos de MGE
<- unique(mdb$mge)
all_mge
# Inicializa un data.frame vacío donde se almacenarán las combinaciones
<- NULL
db_tax
# Itera sobre todos los valores únicos de MGE
for(i in 1:length(all_mge)){
# Para cada MGE, se agrega una nueva columna 'mge' con el valor del MGE actual
<- tax %>% add_column(mge = all_mge[i])
db_tax_sing # Une el data.frame actual con el anterior (rbind), creando una tabla con todas las combinaciones
<- rbind(db_tax, db_tax_sing)
db_tax
}# Muestra las primeras filas del data.frame resultante
head(db_tax)
# A tibble: 6 × 7
specI genomeID kingdom phylum class genus mge
<chr> <chr> <chr> <chr> <chr> <chr> <fct>
1 specI_v3_Cluster1 100053.SAMN02947772 Bacteria Spirochaetes Spirochaetia Leptospirales IS_Tn
2 specI_v3_Cluster201 1000561.SAMN02471202 Bacteria Proteobacteria Gammaproteobacteria Pseudomonadales IS_Tn
3 specI_v3_Cluster361 1000562.SAMN03114893 Bacteria Firmicutes Bacilli Lactobacillales IS_Tn
4 specI_v3_Cluster371 1000565.SAMN02471991 Bacteria Proteobacteria Betaproteobacteria Nitrosomonadales IS_Tn
5 specI_v3_Cluster564 1000568.SAMN00255229 Bacteria Firmicutes Negativicutes Veillonellales IS_Tn
6 specI_v3_Cluster565 1000569.SAMN00255226 Bacteria Firmicutes Negativicutes Veillonellales IS_Tn
PASO 4: Contar el número de genomas por especie y clase taxonómica
# Filtra los genomas que están en 'glist_high$genome' y los combina con los recuentos de MGE
<- db_tax %>%
db_cnt_all filter(genomeID %in% glist_high$genome) %>% # Filtra para obtener solo los genomas que están en 'glist_high$genome'
left_join(., mdb_cnt, by = c("genomeID", "mge")) # Realiza una unión de izquierda con 'mdb_cnt' usando 'genomeID' y 'mge'
# Reemplaza todos los valores NA en el data.frame por 0
is.na(db_cnt_all)] <- 0
db_cnt_all[
# Contar el número de genomas por especie y clase taxonómica
%>%
db_cnt_all # Selecciona las columnas relevantes: 'specI', 'genomeID', y 'class'
select(specI, genomeID, class) %>%
# Elimina duplicados, dejando solo combinaciones únicas de especie, genoma y clase
unique() %>%
# Agrupa los datos por clase taxonómica ('class')
group_by(class) %>%
# Cuenta el número de genomas por cada clase
summarise(count = n()) %>%
# Filtra para solo mostrar las clases que tienen más de 9 genomas
filter(count > 9) %>%
head()
# A tibble: 6 × 2
class count
<chr> <int>
1 Acidithiobacillia 18
2 Actinobacteria 9859
3 Alphaproteobacteria 2001
4 Bacilli 25644
5 Bacteroidia 570
6 Betaproteobacteria 3998
# Crear un data.frame de presencia y ausencia
## Agregar información de presencia y ausencia
<- db_cnt_all %>% mutate(presAbs = ifelse(count > 0, 1, 0))
db_pa_all
head(db_pa_all)
# A tibble: 6 × 9
specI genomeID kingdom phylum class genus mge count presAbs
<chr> <chr> <chr> <chr> <chr> <chr> <fct> <dbl> <dbl>
1 specI_v3_Cluster1 100053.SAMN02947772 Bacteria Spirochaetes Spirochaetia Leptospirales IS_Tn 22 1
2 specI_v3_Cluster201 1000561.SAMN02471202 Bacteria Proteobacteria Gammaproteobacteria Pseudomonada… IS_Tn 5 1
3 specI_v3_Cluster361 1000562.SAMN03114893 Bacteria Firmicutes Bacilli Lactobacilla… IS_Tn 5 1
4 specI_v3_Cluster371 1000565.SAMN02471991 Bacteria Proteobacteria Betaproteobacteria Nitrosomonad… IS_Tn 24 1
5 specI_v3_Cluster564 1000568.SAMN00255229 Bacteria Firmicutes Negativicutes Veillonellal… IS_Tn 3 1
6 specI_v3_Cluster565 1000569.SAMN00255226 Bacteria Firmicutes Negativicutes Veillonellal… IS_Tn 2 1
PASO 5: Agrupar todos los genomas por especie (specI)
## Resumir: avg_cnt = promedio de recuento por MGE por especie (specI), frac = fracción de genomas por especie con cada MGE
<- db_pa_all %>%
db_specI # Agrupar los datos por especie (specI) y MGE
group_by(specI, mge) %>%
# Contar el número de genomas por combinación de 'specI' y 'mge'
summarise(genomeCnt = n(),
# Calcular el promedio de recuento por MGE por especie
avg_cnt = mean(count),
# Calcular la presencia (1) total para cada MGE por especie
pa = sum(presAbs),
# Calcular el total de recuentos para cada MGE por especie
cnt_tot = sum(count)) %>%
# Calcular la fracción de genomas por especie que tienen el MGE
mutate(frac = pa / genomeCnt) %>%
# Unir los datos con la información taxonómica de 'tax' utilizando 'specI'
left_join(., tax, by = "specI") %>%
# Eliminar la columna 'genomeID' que no es necesaria
select(-genomeID) %>%
# Eliminar filas duplicadas
unique(.)
## Resumir: avg_cnt = promedio de recuento por MGE por genoma, frac = fracción de genomas con cada MGE
<- db_pa_all %>%
db_genome # Agrupar los datos por genoma (genomeID) y MGE
group_by(genomeID, mge) %>%
# Contar el número de combinaciones de genoma y MGE
summarise(genomeCnt = n(),
# Calcular el promedio de recuento de cada MGE por genoma
avg_cnt = mean(count),
# Calcular la presencia total de MGE en cada genoma
pa = sum(presAbs),
# Calcular el total de recuentos de MGE por genoma
cnt_tot = sum(count)) %>%
# Calcular la fracción de genomas con el MGE
mutate(frac = pa / genomeCnt) %>%
# Unir los datos con la información taxonómica utilizando 'genomeID'
left_join(., tax, by = "genomeID") %>%
# Eliminar filas duplicadas
unique(.)
Crear data frames separados para los recuentos de MGE y las fracciones de MGE.
# Promedio de recuentos de cada MGE por especie (specI), donde los MGEs son las columnas y las especies (specI) las filas
<- db_specI %>%
all_cnt_specI select(specI, mge, avg_cnt) # Selecciona las columnas 'specI' (especie), 'mge' (MGE), y 'avg_cnt' (promedio de recuentos)
<- db_specI %>%
all_frac_specI select(specI, mge, frac) # Selecciona las columnas 'specI' (especie), 'mge' (MGE), y 'frac' (fracción de genomas con el MGE)
<- db_genome %>%
all_cnt_genome select(genomeID, mge, avg_cnt) # Selecciona las columnas 'genomeID' (ID de genoma), 'mge' (MGE), y 'avg_cnt' (promedio de recuentos)
PASO 6: Análisis por especie (specI) a nivel de clase
Se utiliza la prueba de Mann-Whitney para analizar asociaciones de los MGEs a nivel de clase. El análisis se basa en la fracción de genomas por especiación (SpecI) que contiene el MGE para evitar sesgos de muestreo.
# entrada de datos
<- db_specI %>%
all_avg_cnt_tax_class select(specI, mge, avg_cnt, class) %>% # Selecciona las columnas: 'specI', 'mge', 'avg_cnt' y 'class'
filter(., !grepl("Hotspot", mge)) %>% # Filtra para excluir los MGEs que contienen "Hotspot" en su nombre
filter(., !grepl("Cellular", mge)) # Filtra para excluir los MGEs que contienen "Cellular" en su nombre
<- unique(all_avg_cnt_tax_class$mge) # Extrae los valores únicos de MGEs
allMges
# Filtrar para clases con al menos 10 genomas
<- all_avg_cnt_tax_class %>%
allClasses filter(mge == all_avg_cnt_tax_class$mge[1]) %>% # Filtra para mantener solo el primer MGE
group_by(class) %>% # Agrupa los datos por clase
summarise(cntClass = n()) %>% # Cuenta cuántos genomas existen por clase
filter(cntClass > 9) # Filtra las clases con más de 9 genomas
# Selección final de datos para el análisis
<- all_avg_cnt_tax_class %>%
all_avg_cnt_tax_class_sel_pre filter(class %in% allClasses$class) # Filtra las especies para incluir solo aquellas pertenecientes a clases con al menos 10 genomas
PASO 7: Normalización por tamaño de genoma
Se calcula el tamaño promedio del genoma por cada especie (SpecI) y se normaliza el recuento de MGEs por el tamaño del genoma.
# Promedio de tamaño de genoma por especie (SpecI)
<- gs %>%
gs_int group_by(SpecI_id_v3) %>%
summarise(avg_gs = mean(ProteinGeneCounts)) %>%
::rename(specI = SpecI_id_v3)
dplyr
# Unir la información de tamaño de genoma con el promedio de recuentos de MGEs por especie y normalizar los recuentos por tamaño de genoma
<- left_join(all_avg_cnt_tax_class_sel_pre, gs_int, by = "specI") %>%
all_avg_cnt_tax_class_sel mutate(norm_count = avg_cnt / avg_gs) %>% # Normalización: se divide el recuento promedio por el tamaño del genoma
::rename(count = avg_cnt, avg_cnt = norm_count) # Renombrar las columnas para mayor claridad dplyr
Realizar la prueba de Mann-Whitney para comparar recuentos de MGE entre clases.
<- NULL
MW_all for(i in 1:length(allMges)){ # Iterar sobre todos los MGEs
<- allMges[i] # Seleccionar el MGE actual
mgeX <- all_avg_cnt_tax_class_sel %>% filter(mge == mgeX) # Filtrar los datos para el MGE seleccionado
mgeDat
<- sapply(seq_along(allClasses$class), function(j){
MW <- allClasses$class[j] # Seleccionar la clase actual
class_sel <- mgeDat %>% filter(class == class_sel) # Filtrar datos de la clase seleccionada (ingroup)
ingroup <- mgeDat %>% filter(class != class_sel) # Filtrar datos de las clases no seleccionadas (outgroup)
outgroup
# Realizar la prueba de Mann-Whitney para comparar los recuentos promedio de MGE entre las clases
<- wilcox.test(ingroup$avg_cnt, outgroup$avg_cnt, alternative = "greater")
MWout <- c(class_sel, MWout$p.value) # Guardar el resultado de la prueba (clase y p-value)
out return(out)
})
<- as.data.frame(t(MW[2,])) # Convertir los resultados de la prueba en un data frame
MWOut colnames(MWOut) <- MW[1,] # Asignar los nombres de las clases como nombres de columna
rownames(MWOut) <- mgeX # Asignar el nombre del MGE como nombre de fila
<- rbind(MW_all, MWOut) # Unir los resultados de la prueba para todos los MGEs
MW_all
}
# Transponer los resultados finales de la prueba
<- as.data.frame(t(MW_all))
MW_all_mod
head(MW_all_mod)
IS_Tn Phage Phage_like CE
Actinobacteria 0.999999917916124 1 1 1
Alphaproteobacteria 0.0178414060867117 0.0001231858382891 0.0588004481841716 8.61021742019938e-11
Bacilli 1.98748444995478e-06 8.27765421556004e-16 7.42579596027798e-13 0.854734318526737
Bacteroidia 0.00833722978655579 1 0.902740265915529 1.19966727801307e-41
Betaproteobacteria 0.107452414634065 2.00283676907074e-05 0.746214226095515 0.999999817280502
Chlamydiia 0.997521561347641 0.99991406834231 0.988672166822885 0.999936175938603
Integron MI
Actinobacteria 1 0.999999678245156
Alphaproteobacteria 0.00014653261414839 0.999997587920911
Bacilli 1 2.06109350055861e-10
Bacteroidia 9.34842687990597e-06 9.19715441949629e-44
Betaproteobacteria 0.000506083290088997 0.788218472081803
Chlamydiia 0.962626875393123 0.999998724073782
Ajuste de valores p para múltiples comparaciones.
<- NULL # Inicializar un objeto vacío para almacenar los resultados ajustados
MW_all_adj
# Iterar sobre cada columna de los resultados de la prueba de Mann-Whitney
for(k in 1:ncol(MW_all_mod)){
<- as.matrix(MW_all_mod) # Convertir el data frame en una matriz para facilitar el acceso a las columnas
MW_all_mod2 <- c(MW_all_mod2[,k]) # Extraer la columna k, que contiene los valores p de la prueba de Mann-Whitney
pVec <- p.adjust(pVec, "BH") # Ajustar los valores p utilizando el método de Benjamini-Hochberg ("BH")
adjP <- cbind(MW_all_adj, adjP) # Unir los valores p ajustados a la matriz final
MW_all_adj
}
# Asignar los nombres de las columnas originales a los resultados ajustados
colnames(MW_all_adj) <- colnames(MW_all_mod)
# Convertir el resultado final en un data frame
<- as.data.frame(MW_all_adj) MW_all_fin
Crear una tabla binaria con valores p < 0.1 --> 1, de lo contrario 0
<- NULL # Inicializar un objeto vacío para almacenar los resultados binarios
MW_all_stat
# Iterar sobre cada columna de los resultados ajustados (MW_all_fin)
for(l in 1:ncol(MW_all_fin)){
# Crear una columna "signP" con valor 1 si el valor p es menor a 0.1, y 0 en caso contrario
<- MW_all_fin %>% mutate(signP=ifelse(MW_all_fin[,l]>0.1,0,1))
MW_test <- cbind(MW_all_stat, MW_test$signP) # Unir los resultados binarios
MW_all_stat
}
# Convertir la matriz a un data frame
<- as.data.frame(MW_all_stat)
MW_all_stat
# Asignar los nombres de las columnas y filas a la tabla binaria
colnames(MW_all_stat) <- colnames(MW_all_fin)
rownames(MW_all_stat) <- rownames(MW_all_fin)
# Sumar los valores de "signP" por fila para obtener el número total de pruebas significativas por MGE
<- MW_all_stat %>% mutate(sumSign=rowSums(.))
MW_all_stat_sum
# Agregar los nombres de las filas a la tabla para obtener un formato adecuado
<- cbind(rownames(MW_all_stat), MW_all_stat)
MW_all_stat2 colnames(MW_all_stat2)[1] <- "class" # Renombrar la primera columna como "class"
<- cbind(rownames(MW_all_fin), MW_all_fin)
MW_all_fin2 colnames(MW_all_fin2)[1] <- "class"
PASO 8: Tabla con pvalues y especies
# 1. Reorganizar el dataframe 'MW_all_fin2' de formato ancho a largo (long format).
# Esto es útil para preparar los datos para ggplot o análisis por variable.
<- reshape2::melt(MW_all_fin2)
melted_specI_class
# 2. Añadir una columna 'signP' que marque con "*" si el valor (p-valor) es significativo (menor o igual a 0.05).
# Si el valor es mayor a 0.05, deja la celda vacía.
<- melted_specI_class %>%
melted_specI_class1 mutate(signP = ifelse(value > 0.05, "", "*"))
# 3. Calcular el promedio de 'count' por combinación de clase taxonómica ('class') y elemento genético móvil ('mge'),
# y renombrar la columna 'mge' como 'variable' para que coincida con el dataframe anterior.
<- all_avg_cnt_tax_class_sel %>%
all_avg_cnt_tax_class_sel1 group_by(class, mge) %>%
summarise(avg_class = mean(count), .groups = "drop") %>%
::rename(variable = mge)
dplyr
# 4. Unir los datos con los valores derretidos y la información de significancia.
# La unión se hace por las columnas 'class' y 'variable'.
<- left_join(melted_specI_class1, all_avg_cnt_tax_class_sel1, by = c("class", "variable"))
plot_table_w_g9
# 5. (Redundante) Se repite la unión anterior. Puedes eliminar esta línea si no necesitas tener dos versiones del mismo objeto.
<- left_join(melted_specI_class1, all_avg_cnt_tax_class_sel1, by = c("class", "variable")) plot_table
PASO 9: Datos para Mapa de colores para filogenia
Crear el mapa de calor filogenético con normalización de los valores
<- function(x) { # Función para normalizar los valores entre 0 y 1
normalize /max(x)
x
}
# Crear la matriz de datos para el mapa de calor filogenético
<- all_avg_cnt_tax_class_sel1 %>%
phylo_heatmap_mat # Filtrar clases que no contienen "NA"
filter(!grepl("NA ", class)) %>%
# Convertir los datos en formato ancho (cada variable como columna)
spread(variable, avg_class) %>%
# Seleccionar las variables de interés
::select(class, IS_Tn, Phage, Phage_like, CE, Integron, MI) %>%
dplyr# Establecer las clases como nombres de fila
column_to_rownames(var = "class")
# Crear el árbol filogenético manteniendo solo las especies que están en la matriz de datos del mapa de calor
<- keep.tip(class_tree, tip = rownames(phylo_heatmap_mat))
class_tree_w_g9
## Ajuste de colores para el mapa de calor filogenético para datos sesgados
<- unique(sort(unlist(phylo_heatmap_mat)))[2] # Encuentra el segundo valor más pequeño en la matriz de datos para establecer un umbral
small_value <- small_value - small_value %% 0.001 # Redondea el valor a 3 decimales para crear un valor pequeño ajustado
small_value
# Definir los puntos de corte para el mapa de calor según la distribución de los datos
<- c(0, small_value, 1, 2, 3, 4, seq(5, 55, 10))
heatmap_breaks
# Definir una paleta de colores basada en viridis, con un sesgo hacia valores más bajos
<- c("white", colorRampPalette((viridis(10)), bias = 5)(length(heatmap_breaks) - 2))
plot_colors
# Crear una matriz de significancia (signP) para etiquetar el mapa de calor
<- plot_table_w_g9 %>%
sig_mat select(class, variable, signP) # Selecciona las columnas relevantes de los datos
# Filtra las filas que contienen "NA" en la columna "class" y transforma los datos a formato ancho
<- sig_mat %>%
sig_mat filter(!grepl("NA ", class)) %>%
spread(variable, signP) %>% # Transforma los datos para que las variables sean columnas
column_to_rownames(var = "class") # Establece la columna "class" como nombres de fila
# Alinea la matriz de significancia con el árbol filogenético
<- sig_mat[class_tree_w_g9$tip.label, colnames(phylo_heatmap_mat)] sig_mat
Figura 3B. Mapa de colores
# 1. Extraer coordenadas del heatmap filogenético para añadir anotaciones manuales posteriormente
<- phylo.heatmap.coords(
xx_yy # árbol filogenético de clases
class_tree_w_g9, # matriz de abundancias promedio por clase y MGE
phylo_heatmap_mat, fsize = c(0.8, 0.9, 0.7), # tamaños de fuente (árbol, heatmap, leyenda)
colors = plot_colors, # colores personalizados para el heatmap
grid = TRUE, # mostrar rejilla en el heatmap
split = c(0.7, 0.3), # proporción de espacio entre árbol y heatmap
lwd = 1, # grosor de líneas
breaks = heatmap_breaks, # puntos de corte para los colores
mar = c(1.2,1.2,1.2,1.2) # márgenes
)
## 2. Generar el heatmap con leyenda incluida, usando los mismos parámetros que el paso anterior
phylo.heatmap.legendmod(
class_tree_w_g9,
phylo_heatmap_mat,fsize = c(0.8, 0.9, 0.7),
colors = plot_colors,
grid = TRUE,
split = c(0.7, 0.3),
lwd = 1,
breaks = heatmap_breaks,
mar = c(1.2,1.2,1.2,1.2)
)
## 3. Añadir símbolos de significancia ("*") en cada celda de la matriz que lo indique (en 'sig_mat')
for(i in 1:nrow(sig_mat)) {
for(j in 1:ncol(sig_mat)) {
if(sig_mat[i,j] == "*") {
<- rownames(sig_mat)[i] # nombre de la fila (clase taxonómica)
rnm <- colnames(sig_mat)[j] # nombre de la columna (MGE)
cnm
# Añadir el símbolo "*" en la posición correspondiente del heatmap
points(
$xx[j], xx_yy$yy[i], # coordenadas x, y para esa celda
xx_yycex = 1.5, # tamaño del símbolo
col = if (phylo_heatmap_mat[rnm, cnm] < heatmap_breaks[3]) "white" else "black",
pch = "*" # símbolo a dibujar
)
}
} }
Figura 3A: Filogenia
Obtener el numero de genomas por Class:
<- db_genome %>%
genomes_per_class distinct(genomeID, class) %>% # eliminar duplicados por genomeID y class
group_by(class) %>%
summarise(n_genomes = n()) %>%
arrange(desc(n_genomes))
genomes_per_class
# A tibble: 60 × 2
class n_genomes
<chr> <int>
1 Gammaproteobacteria 27249
2 Bacilli 25644
3 Actinobacteria 9859
4 Betaproteobacteria 3998
5 Epsilonproteobacteria 2693
6 Alphaproteobacteria 2001
7 Clostridia 1621
8 Bacteroidia 570
9 Spirochaetia 501
10 Flavobacteriia 375
# ℹ 50 more rows
Modificar los nombres en el árbol:
# -------------- Modificaciones de las etiquetas de las especies (numero de geneomas) -------------
<- class_tree_w_g9$tip.label
species_labels # Crear nombres con el número de genomas
<- paste0(genomes_per_class$class, " (", genomes_per_class$n_genomes, ")")
new_labels
# Cambiar nombres en el árbol
<- match(class_tree_w_g9$tip.label, genomes_per_class$class)
match_idx
# Asegúrate que no hay NA antes de continuar
$tip.label <- ifelse(
class_tree_w_g9!is.na(match_idx),
new_labels[match_idx],$tip.label
class_tree_w_g9
)
# -------------- Obtener el nodo más reciente común (MRCA) para cada grupo -------------------------
# > Obtener el numero del nodo Archaea
<- getMRCA(class_tree_w_g9, c("Halobacteria (95)", "Methanomicrobia (89)"))
node_archaea
# > Obtener el numero del nodo Bacterias
# Obtener todos los nodos
<- class_tree_w_g9$tip.label
all_classes
# 2. Excluir los que no quieres
<- c("Halobacteria (95)", "Methanomicrobia (89)")
excluded <- setdiff(all_classes, excluded)
included_classes
# 3. Obtener el nodo común para los restantes
<- getMRCA(class_tree_w_g9, included_classes) node_bacteria
Extraer coordenadas del heatmap filogenético para añadir anotaciones manuales posteriormente:
# Guardar la figura como archivo temporal
<- tempfile(fileext = ".png")
tmp_file
# Crear la imagen del árbol + heatmap
png(tmp_file, width = 1000, height = 1500, res = 150)
# Filogenia
<- phylo.heatmap.coords(
xx_yy
class_tree_w_g9,
phylo_heatmap_mat,fsize = c(0.8, 0.9, 0.7),
colors = plot_colors,
grid = TRUE,
split = c(0.7, 0.3),
lwd = 1,
breaks = heatmap_breaks,
mar = c(1.2,1.2,1.2,1.2)
)# Agregar titulos de los nodos
nodelabels("Bacteria", node = node_bacteria, frame = "none", adj = c(1.1, -0.1), font = 2, cex = 1)
nodelabels("Archaea", node = node_archaea, frame = "none", adj = c(1.1, -0.1), font = 2, cex = 1)
dev.off()
png
2
# Leer imagen y convertirla en un objeto ggdraw
<- ggdraw() + draw_image(tmp_file)
p_phylo_heatmap p_phylo_heatmap
Figura 3A Barplot de abundancia relativa de MGEs por clase taxonómica
# 1. Seleccionar clases que aparecen al menos 10 veces para asegurar una representación confiable.
<- all_avg_cnt_tax_class %>%
allclass_all # Usar una sola MGE como referencia para el conteo por clase
filter(mge == all_avg_cnt_tax_class$mge[1]) %>%
group_by(class) %>%
summarise(cntclass = n()) %>%
# Incluir solo clases con al menos 10 ocurrencias
filter(cntclass > 9)
# 2. Filtrar datos: eliminar MGEs de tipo "Cellular" o "Hotspot" y mantener solo las clases seleccionadas previamente.
<- all_avg_cnt_tax_class %>%
all_avg_cnt_tax_class_sel_all filter(!grepl("Cellular", mge)) %>%
filter(!grepl("Hotspot", mge)) %>%
filter(class %in% allclass_all$class) %>%
group_by(mge, class) %>%
# Promediar por combinación de clase y MGE
summarise(avg_class = mean(avg_cnt), .groups = "drop")
# 3. Calcular la suma total de abundancia de MGEs por clase (para obtener proporciones después)
<- all_avg_cnt_tax_class_sel_all %>%
all_avg_cnt_tax_class_sel_all_mge_all group_by(class) %>%
summarise(total_mge = sum(avg_class), .groups = "drop")
# 4. Combinar abundancia promedio por clase y MGE con el total por clase
# Calcular la fracción relativa de cada MGE dentro de cada clase
<- left_join(
all_avg_cnt_tax_class_sel_4bar_all
all_avg_cnt_tax_class_sel_all,
all_avg_cnt_tax_class_sel_all_mge_all,by = "class"
%>%
) group_by(class, mge, total_mge) %>%
summarise(frac = avg_class / total_mge, .groups = "drop")
# 5. Limpiar datos y ordenar clases según el orden filogenético del árbol
<- all_avg_cnt_tax_class_sel_4bar_all %>%
barplot_mat # Eliminar clases no identificadas
filter(!grepl("NA ", class))
# Mantener orden del árbol filogenético
$class <- factor(barplot_mat$class,
barplot_matlevels = species_labels)
# 6. Preparar datos auxiliares para anotaciones en el barplot (por ejemplo, totales por clase)
<- all_avg_cnt_tax_class_sel_all_mge_all %>%
barplot_mat_for_n filter(!grepl("NA ", class))
$class <- factor(barplot_mat_for_n$class,
barplot_mat_for_nlevels = species_labels)
Crear barplot apilado (horizontal) de la proporción relativa de MGEs por clase taxonómica
# Define el orden deseado de las categorías en la leyenda (de MI a IS_Tn)
<- c("MI", "Integron", "CE", "Phage_like", "Phage", "IS_Tn")
category_order
# Generar la grafica base
<- ggplot(barplot_mat, aes(y = class, x = frac, fill = mge)) +
barplot_specI_class_count_all # Barras horizontales, borde gris
geom_bar(stat = "identity", color = "grey60") +
# Colores personalizados para los MGEs
scale_fill_manual("MGE", values = colc)
## Añadir detalles estéticos y anotaciones
<- barplot_specI_class_count_all +
Fig3A_barplot # Límite extendido para espacio de anotaciones
scale_x_continuous(
breaks = c(0, 0.25, 0.5, 0.75, 1.0),
limits = c(0, 1.1)
+
) geom_text(
data = barplot_mat_for_n,
# Mostrar suma total de MGEs por clase
mapping = aes(y = class, x = 1.05, label = paste("", round(total_mge))),
inherit.aes = FALSE,
col = "black",
size = 6) +
# Agregar un título en una posición personalizada
annotate("text", x = 1.05, y = 23.5, label = "Avg. MGE", size = 6, fontface = "bold", color = "black") +
# etiquetas
labs(title = "Relative proportion",y = "", x = "") +
# Estética limpia estilo Cowplot
theme_cowplot(font_size = 20) +
# Etiquetas del eje X horizontales
theme(
axis.text.y = element_blank(), # axis.text.y = element_text(hjust = 0, vjust = 0.5) # Alinear texto del eje Y
axis.text.x = element_text(angle = 0),
legend.position = "bottom", # Leyenda abajo
legend.direction = "horizontal", # Disposición horizontal de la leyenda
plot.title = element_text(hjust = 0.5, size = 24) # Centrar y estilizar el título
+
) # Asegura que las categorías estén en una sola fila
guides(fill = guide_legend(ncol = length(category_order)))
Fig3A_barplot
Unir figura
<- plot_grid(p_phylo_heatmap, Fig3A_barplot, ncol = 2, align = "v", rel_widths = c(1.5, 1))
Fig3A_final_plot Fig3A_final_plot
Puedes encontrar el script completo en Figura3_modificado.R.