Equipo: Equipo 4
Integrantes:
Correos electrónicos: leoianayaglz@gmail.com | rubimarch201@gmail.com
Este entregable continúa a partir del Entregable 3, donde se realizó
el control de calidad con FastQC/MultiQC, la eliminación de adaptadores
con Trimmomatic, el pseudoalineamiento con Kallisto y
el alineamiento con STAR, seguidos de la importación de
datos en R mediante tximport. Los objetos dds
(Kallisto) y dds_star (STAR) fueron construidos con DESeq2,
filtrados (≥10 cuentas en ≥3 muestras) y con diseño
~ genotype (referencia: WT).
En este entregable realizamos:
library(DESeq2) # Normalización y análisis de expresión diferencial
library(tximport) # Importar datos de Kallisto
library(rhdf5) # Leer archivos .h5 de Kallisto
library(ggplot2) # Visualización
library(dplyr) # Manipulación de datos
library(reshape2) # Conversión wide → long (melt)
library(pheatmap) # Heatmaps
library(RColorBrewer) # Paletas de colores
library(knitr) # Tablas en el documento
library(kableExtra) # Formato de tablas
library(ggrepel) # Etiquetas sin superposición
library(gprofiler2) # Análisis de enriquecimiento funcional
library(VennDiagram) # Diagramas de Venn
library(grid) # Para dibujar Venn
library(limma) # Corrección de batch effect
library(apeglm) # Prior para lfcShrink# Rutas
ruta_kallisto <- "/Users/dubsirubs/Desktop/RNAseq_Equipo4/results_final/kallisto"
star_dir <- "/Users/dubsirubs/Desktop/RNAseq_Equipo4/results_final/STAR"
outdir <- "/Users/dubsirubs/Desktop/RNAseq_Equipo4/results_final/"
figdir <- "/Users/dubsirubs/Desktop/RNAseq_Equipo4/results_final/figures/"
samples <- c("SRR33445252","SRR33445253","SRR33445254",
"SRR33445260","SRR33445261","SRR33445262")
# Metadata
metadata <- read.csv("/Users/dubsirubs/Desktop/RNAseq_Equipo4/metadata.csv")
metadata$genotype <- factor(metadata$genotype, levels = c("WT", "Dp16"))
rownames(metadata) <- metadata$sample
# Kallisto → tximport → DESeq2
archivos_h5 <- file.path(ruta_kallisto, samples, "abundance.h5")
names(archivos_h5) <- samples
tx2gene <- read.csv("/Users/dubsirubs/Desktop/RNAseq_Equipo4/results_final/tx2gene_kallisto.csv")
txi.kallisto <- tximport(archivos_h5,
type = "kallisto",
tx2gene = tx2gene,
txOut = FALSE,
ignoreTxVersion = FALSE,
ignoreAfterBar = TRUE)
dds <- DESeqDataSetFromTximport(txi.kallisto,
colData = metadata,
design = ~ genotype)
# Filtro: genes con ≥10 cuentas en al menos 3 muestras
keep <- rowSums(counts(dds) >= 10) >= 3
dds <- dds[keep, ]
# STAR → DESeq2
count_list <- lapply(samples, function(s) {
f <- file.path(star_dir, s, paste0(s, ".ReadsPerGene.out.tab"))
read.table(f, skip = 4, header = FALSE)[, c(1, 2)]
})
counts_star <- do.call(cbind, lapply(count_list, function(x) x[, 2]))
rownames(counts_star) <- count_list[[1]][, 1]
colnames(counts_star) <- samples
dds_star <- DESeqDataSetFromMatrix(countData = counts_star,
colData = metadata,
design = ~ genotype)
keep_star <- rowSums(counts(dds_star) >= 10) >= 3
dds_star <- dds_star[keep_star, ]
cat("Genes retenidos — Kallisto:", nrow(dds), "| STAR:", nrow(dds_star), "\n")## Genes retenidos — Kallisto: 14715 | STAR: 14091
Las cuentas crudas de RNA-seq no son comparables entre muestras
porque dependen del tamaño total de la librería y, en el caso de
Kallisto, también de la longitud de los transcritos. La VST
(Variance Stabilizing Transformation) estabiliza la varianza a
lo largo de todo el rango de expresión: los genes de baja expresión
dejan de tener una varianza artificialmente alta, y los datos quedan en
una escala apta para PCA, heatmaps y clustering. Se usa
blind = FALSE porque conocemos el diseño experimental —
esto permite que la transformación tome en cuenta el genotipo, lo cual
es correcto cuando el objetivo es visualización comparativa.
vsd_kallisto <- vst(dds, blind = FALSE)
cat("Dimensiones VST Kallisto (genes × muestras):", dim(vsd_kallisto), "\n")## Dimensiones VST Kallisto (genes × muestras): 14715 6
vsd_star <- vst(dds_star, blind = FALSE)
cat("Dimensiones VST STAR (genes × muestras):", dim(vsd_star), "\n")## Dimensiones VST STAR (genes × muestras): 14091 6
El boxplot muestra la distribución de los valores VST por muestra. Si la normalización fue exitosa, las medianas de todas las cajas deben estar al mismo nivel, indicando que las muestras son comparables entre sí independientemente del tamaño de su librería.
melted_norm_counts <- data.frame(melt(assay(vsd_kallisto)))
colnames(melted_norm_counts) <- c("gene", "sample", "normalized_counts")
melted_norm_counts <- left_join(
melted_norm_counts,
data.frame(sample = rownames(metadata), genotype = metadata$genotype),
by = "sample"
)
ggplot(melted_norm_counts,
aes(x = sample, y = normalized_counts, fill = genotype)) +
geom_boxplot(outlier.size = 0.3, alpha = 0.8) +
scale_fill_manual(values = c("WT" = "steelblue", "Dp16" = "firebrick3")) +
labs(title = "Distribución de cuentas normalizadas (VST) por muestra",
x = "Muestra", y = "Cuentas normalizadas (VST)", fill = "Genotipo") +
theme_bw(base_size = 12) +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.background = element_rect(fill = "white"))Figura 1. Distribución de cuentas normalizadas (VST, Kallisto) por muestra. Las medianas alineadas indican que la normalización fue exitosa y las muestras son comparables.
Interpretación: La Figura 1 muestra que las medianas de las seis muestras se encuentran alineadas en torno a 9, lo que confirma que la normalización VST corrigió exitosamente las diferencias de tamaño de librería. Los rangos intercuartílicos son homogéneos entre muestras, sin outliers sistemáticos que indiquen problemas técnicos. Los puntos extremos superiores (~17–21) corresponden a genes altamente expresados presentes en todas las muestras por igual, lo que refleja una característica biológica esperada. La ausencia de separación sistemática entre genotipos (WT vs Dp16) en esta distribución global es correcta: las diferencias específicas por gen se detectarán en el análisis diferencial.
El z-score estandariza cada gen a media = 0 y desviación estándar = 1
a través de todas las muestras. Esto elimina las diferencias de escala
absoluta entre genes (algunos tienen expresión basalmente alta y otros
baja) y resalta los patrones de expresión relativa, lo que facilita el
clustering y la visualización en heatmaps. Se aplica
t(scale(t(x))) porque scale() opera por
columnas — al transponer dos veces, escalamos por filas (por gen).
counts_raw <- counts(dds)
# Eliminar genes con varianza = 0 (misma expresión en todas las muestras)
var_non_zero <- apply(counts_raw, 1, var) != 0
filtered_counts <- counts_raw[var_non_zero, ]
# t(scale(t(x))): transponer → escalar por gen → transponer de vuelta
zscores <- t(scale(t(filtered_counts)))
zscore_mat <- as.matrix(zscores)
cat("Genes con varianza > 0:", nrow(zscore_mat), "\n")## Genes con varianza > 0: 14715
## Muestras: 6
De los ~20,000+ genes del genoma de ratón, 14,715 muestran al menos algo de variación entre las 6 muestras. Esto es normal ya que muchos genes housekeeping se expresan de forma constitutiva e idéntica en todas las muestras y quedan fuera. Estos 14,715 son los informativos para clustering y heatmaps.
El PCA reduce la dimensionalidad de los datos (miles de genes) a componentes que capturan la mayor variación. Su propósito es verificar que las muestras agrupan por la variable biológica de interés (genotipo) y no por variables técnicas (fecha, técnico, equipo de secuenciación), lo que indicaría un batch effect.
mat_k <- assay(vsd_kallisto)
pc_k <- prcomp(t(mat_k)) # t() porque prcomp espera muestras en filas
var_exp_k <- pc_k$sdev^2 / sum(pc_k$sdev^2) * 100
pca_df_k <- data.frame(
PC1 = pc_k$x[, 1],
PC2 = pc_k$x[, 2],
genotype = metadata$genotype,
sample = rownames(metadata)
)
ggplot(pca_df_k, aes(x = PC1, y = PC2, color = genotype, label = sample)) +
geom_point(size = 4) +
geom_text_repel(size = 3, show.legend = FALSE) +
stat_ellipse(aes(group = genotype), linetype = "dashed", level = 0.8) +
scale_color_manual(values = c("WT" = "steelblue", "Dp16" = "firebrick3")) +
labs(title = "PCA — Kallisto (VST)",
x = sprintf("PC1 (%.1f%% varianza)", var_exp_k[1]),
y = sprintf("PC2 (%.1f%% varianza)", var_exp_k[2]),
color = "Genotipo") +
theme_minimal(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 2. PCA de muestras normalizadas con VST (Kallisto). Cada punto representa una muestra; el color indica el genotipo (azul = WT, rojo = Dp16). Las elipses muestran la dispersión de cada grupo.
Interpretación: La Figura 2 muestra una separación clara entre genotipos a lo largo de PC1(43.9% de la varianza total): las tres réplicas WT se agrupan a valores negativos y las tres réplicas Dp16 a valores positivos. Esto indica que el genotipo es la principal fuente de variación en los datos, lo cual es la señal biológica esperada en un modelo de trisomía. PC2 (24.9%) captura variabilidad dentro de los grupos, consistente con la variación biológica natural entre réplicas individuales con n = 3. No se observa ninguna muestra fuera de su grupo genotípico, lo que descarta batch effects evidentes en este primer análisis exploratorio.
El scree plot muestra qué porcentaje de la varianza total captura cada componente principal. Es útil para saber cuántos PCs son informativos: un “codo” pronunciado indica que los primeros PCs concentran la mayor parte de la información.
df_scree <- data.frame(
Componente = seq_along(var_exp_k),
Varianza = var_exp_k,
Etiqueta = paste0("PC", seq_along(var_exp_k), ": ",
round(var_exp_k, 1), "%")
)
ggplot(df_scree, aes(x = Componente, y = Varianza)) +
geom_point(color = "steelblue", size = 3) +
geom_line(color = "steelblue") +
geom_text_repel(data = df_scree[1:4, ],
aes(label = Etiqueta),
size = 4, color = "darkred", fontface = "bold",
box.padding = 0.4) +
labs(title = "Scree plot — varianza explicada por PCA (Kallisto)",
x = "Componente principal",
y = "% de varianza explicada") +
theme_minimal(base_size = 12) +
theme(plot.background = element_rect(fill = "white"))Figura 3. Scree plot: porcentaje de varianza explicada por cada componente principal (Kallisto). Las etiquetas muestran los primeros cuatro componentes.
Interpretación: PC1 y PC2 capturan conjuntamente el 68.8% de la varianza total, lo que indica que la representación bidimensional del PCA es una descripción fiel de la estructura global de los datos. La caída pronunciada entre PC1 (43.9%) y los componentes siguientes confirma que la mayor parte de la variación está concentrada en el primer eje, consistente con una diferencia transcriptómica dominante entre genotipos.
mat_s <- assay(vsd_star)
pc_s <- prcomp(t(mat_s))
var_exp_s <- pc_s$sdev^2 / sum(pc_s$sdev^2) * 100
pca_df_s <- data.frame(
PC1 = pc_s$x[, 1],
PC2 = pc_s$x[, 2],
genotype = metadata$genotype,
sample = rownames(metadata)
)
ggplot(pca_df_s, aes(x = PC1, y = PC2, color = genotype, label = sample)) +
geom_point(size = 4) +
geom_text_repel(size = 3, show.legend = FALSE) +
stat_ellipse(aes(group = genotype), linetype = "dashed", level = 0.8) +
scale_color_manual(values = c("WT" = "steelblue", "Dp16" = "firebrick3")) +
labs(title = "PCA — STAR (VST)",
x = sprintf("PC1 (%.1f%% varianza)", var_exp_s[1]),
y = sprintf("PC2 (%.1f%% varianza)", var_exp_s[2]),
color = "Genotipo") +
theme_minimal(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 4. PCA de muestras normalizadas con VST (STAR). Se esperan los mismos patrones de agrupamiento que en Kallisto si ambos alineadores son concordantes.
Interpretación: El PCA de STAR reproduce el mismo patrón que Kallisto: las tres réplicas WT se agrupan a valores negativos de PC1 (44.6%) y las tres réplicas Dp16 a valores positivos. La concordancia entre ambos pipelines confirma que la separación entre genotipos no es un artefacto del método de cuantificación sino una señal biológica reproducible, independientemente de si se usa pseudoalineamiento (Kallisto) o alineamiento directo al genoma (STAR).
Aunque no tenemos un batch effect conocido en este experimento,
aplicamos limma::removeBatchEffect como buena práctica para
visualización. El argumento design protege la señal
biológica del genotipo durante la corrección: la función solo elimina la
variación que no está explicada por el genotipo.
Nota importante: Esta corrección es únicamente para visualización (PCA y heatmaps). El análisis diferencial con DESeq2 siempre se corre sobre los datos originales sin corregir; si hubiera un batch real, se incluiría como covariable en la fórmula de diseño (
~ batch + genotype).
vsd_bc <- vsd_kallisto # copia para no modificar el original
mm_design <- model.matrix(~ genotype, colData(vsd_bc))
mat_bc <- assay(vsd_bc)
mat_bc <- removeBatchEffect(mat_bc, design = mm_design)
assay(vsd_bc) <- mat_bc
pcaData_bc <- plotPCA(vsd_bc, intgroup = "genotype", returnData = TRUE)
percentVar_bc <- round(100 * attr(pcaData_bc, "percentVar"))
ggplot(pcaData_bc, aes(PC1, PC2, color = genotype, label = name)) +
geom_point(size = 4) +
geom_text_repel(size = 3, show.legend = FALSE) +
scale_color_manual(values = c("WT" = "steelblue", "Dp16" = "firebrick3")) +
labs(title = "PCA post-corrección de batch (Kallisto VST)",
x = paste0("PC1: ", percentVar_bc[1], "% varianza"),
y = paste0("PC2: ", percentVar_bc[2], "% varianza"),
color = "Genotipo") +
theme_minimal(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 5. PCA post-corrección de batch effect (Kallisto VST). Sin batch conocido, la corrección elimina solo la variación residual no explicada por el genotipo, lo que generalmente refuerza la separación entre grupos.
Interpretación: Tras la corrección, PC1 aumenta de 43.9% a 67%, lo que indica que la variación asociada al genotipo se concentra aún más en el primer componente al eliminar el ruido técnico residual. La separación entre WT y Dp16 se mantiene clara, confirmando que la señal biológica es sólida y no dependía de efectos técnicos. SRR33445254 continúa ligeramente elevado en PC2, sugiriendo variabilidad biológica propia de esa réplica que no corresponde a un artefacto corregible.
DESeq2 modela las cuentas con una distribución binomial negativa que captura la sobredispersión típica de RNA-seq. El análisis realiza tres pasos: (1) estimación de factores de tamaño para corregir diferencias en el total de lecturas, (2) estimación de la dispersión gen a gen, y (3) ajuste del modelo lineal generalizado y prueba de Wald para obtener log2FC y p-values.
# relevel: WT como referencia para que todos los FC se interpreten como "Dp16 vs WT"
dds$genotype <- relevel(dds$genotype, ref = "WT")
dds <- DESeq(dds)
resultsNames(dds)## [1] "Intercept" "genotype_Dp16_vs_WT"
res_kallisto <- results(dds,
contrast = c("genotype", "Dp16", "WT"),
alpha = 0.05)
summary(res_kallisto)##
## out of 14715 with nonzero total read count
## adjusted p-value < 0.05
## LFC > 0 (up) : 171, 1.2%
## LFC < 0 (down) : 229, 1.6%
## outliers [1] : 17, 0.12%
## low counts [2] : 0, 0%
## (mean count < 5)
## [1] see 'cooksCutoff' argument of ?results
## [2] see 'independentFiltering' argument of ?results
Genes con baja expresión o pocas réplicas pueden presentar log2FC muy grandes e inestables, no porque realmente cambien mucho, sino porque hay poca información para estimarlos. El shrinkage con apeglm aplica un prior adaptativo que “contrae” esos valores extremos hacia 0, sin modificar los p-values ni el número de genes significativos. El resultado son estimaciones de FC más confiables biológicamente y visualizaciones más limpias.
# coef debe coincidir exactamente con un nombre de resultsNames(dds)
res_kallisto_shrink <- lfcShrink(dds,
coef = "genotype_Dp16_vs_WT",
type = "apeglm")
summary(res_kallisto_shrink)##
## out of 14715 with nonzero total read count
## adjusted p-value < 0.1
## LFC > 0 (up) : 240, 1.6%
## LFC < 0 (down) : 297, 2%
## outliers [1] : 17, 0.12%
## low counts [2] : 0, 0%
## (mean count < 5)
## [1] see 'cooksCutoff' argument of ?results
## [2] see 'independentFiltering' argument of ?results
dds_star$genotype <- relevel(dds_star$genotype, ref = "WT")
dds_star <- DESeq(dds_star)
resultsNames(dds_star)## [1] "Intercept" "genotype_Dp16_vs_WT"
res_star <- results(dds_star,
contrast = c("genotype", "Dp16", "WT"),
alpha = 0.05)
summary(res_star)##
## out of 14091 with nonzero total read count
## adjusted p-value < 0.05
## LFC > 0 (up) : 152, 1.1%
## LFC < 0 (down) : 211, 1.5%
## outliers [1] : 10, 0.071%
## low counts [2] : 0, 0%
## (mean count < 5)
## [1] see 'cooksCutoff' argument of ?results
## [2] see 'independentFiltering' argument of ?results
res_star_shrink <- lfcShrink(dds_star,
coef = "genotype_Dp16_vs_WT",
type = "apeglm")
summary(res_star_shrink)##
## out of 14091 with nonzero total read count
## adjusted p-value < 0.1
## LFC > 0 (up) : 237, 1.7%
## LFC < 0 (down) : 289, 2.1%
## outliers [1] : 10, 0.071%
## low counts [2] : 0, 0%
## (mean count < 5)
## [1] see 'cooksCutoff' argument of ?results
## [2] see 'independentFiltering' argument of ?results
sig_kallisto <- as.data.frame(res_kallisto_shrink) %>%
filter(!is.na(padj) & padj < 0.05)
sig_star <- as.data.frame(res_star_shrink) %>%
filter(!is.na(padj) & padj < 0.05)
resumen <- data.frame(
Alineador = c("Kallisto", "STAR"),
Genes_totales = c(nrow(dds), nrow(dds_star)),
DEGs_total = c(nrow(sig_kallisto), nrow(sig_star)),
Up_regulated = c(sum(sig_kallisto$log2FoldChange > 0),
sum(sig_star$log2FoldChange > 0)),
Down_regulated = c(sum(sig_kallisto$log2FoldChange < 0),
sum(sig_star$log2FoldChange < 0))
)
kable(resumen,
col.names = c("Alineador", "Genes totales", "DEGs (padj<0.05)",
"Up-regulated", "Down-regulated"),
caption = "Tabla 1. Resumen de genes diferencialmente expresados por alineador (Dp16 vs WT, padj < 0.05).") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)| Alineador | Genes totales | DEGs (padj<0.05) | Up-regulated | Down-regulated |
|---|---|---|---|---|
| Kallisto | 14715 | 400 | 171 | 229 |
| STAR | 14091 | 363 | 152 | 211 |
Interpretación: El análisis diferencial identificó 400 DEGs en Kallisto y 363 en STAR (padj < 0.05), con un balance consistente entre pipelines: aproximadamente 57% de los genes están reprimidos en Dp16 respecto a WT y 43% activados. Este patrón sugiere que la trisomía del cromosoma 16 no simplemente incrementa la expresión génica global, sino que genera una reorganización transcriptómica donde la represión domina ligeramente sobre la activación en hígado adulto.
La concordancia entre Kallisto y STAR (~90% en el total de DEGs y balance up/down idéntico) indica que este patrón es robusto e independiente del método de cuantificación. La diferencia en magnitud respecto a los ~1,500 DEGs reportados por Dunn et al. (2026) es atribuible al menor poder estadístico de este análisis (n=3 por genotipo vs n=6 en el paper original); los genes detectados aquí representan los cambios de expresión más robustos y de mayor magnitud del dataset.
top20_k <- sig_kallisto %>%
arrange(padj) %>%
head(20) %>%
select(baseMean, log2FoldChange, lfcSE, pvalue, padj) %>%
mutate(across(where(is.numeric), ~ round(.x, 4)))
kable(top20_k,
col.names = c("Expr. media", "log2FC", "SE", "p-value", "p-adj"),
caption = "Tabla 2. Top 20 genes más significativos — Kallisto (Dp16 vs WT, padj < 0.05). Los genes están ordenados por p-value ajustado de menor a mayor.") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)| Expr. media | log2FC | SE | p-value | p-adj | |
|---|---|---|---|---|---|
| ENSMUSG00000097148.2 | 221.5899 | -3.8684 | 0.4515 | 0 | 0 |
| ENSMUSG00000001665.11 | 2301.2742 | 1.6308 | 0.1995 | 0 | 0 |
| ENSMUSG00000117780.1 | 615.5616 | -3.1112 | 0.3911 | 0 | 0 |
| ENSMUSG00000032080.6 | 13254.4287 | -1.2916 | 0.1689 | 0 | 0 |
| ENSMUSG00000029417.9 | 817.9000 | -1.8694 | 0.2546 | 0 | 0 |
| ENSMUSG00000006494.11 | 3493.7405 | 1.4713 | 0.2022 | 0 | 0 |
| ENSMUSG00000069456.4 | 3868.0862 | 1.3199 | 0.1866 | 0 | 0 |
| ENSMUSG00000094708.1 | 105.7300 | 10.9872 | 3.0280 | 0 | 0 |
| ENSMUSG00000095937.1 | 105.7300 | 10.9872 | 3.0280 | 0 | 0 |
| ENSMUSG00000029822.15 | 127.7477 | -2.3736 | 0.3493 | 0 | 0 |
| ENSMUSG00000057074.6 | 6673.3986 | 1.0001 | 0.1484 | 0 | 0 |
| ENSMUSG00000078606.8 | 488.7620 | -1.4457 | 0.2314 | 0 | 0 |
| ENSMUSG00000027596.10 | 39.5124 | -9.6737 | 2.9575 | 0 | 0 |
| ENSMUSG00000037827.5 | 45.5567 | 9.5875 | 2.8760 | 0 | 0 |
| ENSMUSG00000095597.2 | 40.6972 | 9.4140 | 2.8425 | 0 | 0 |
| ENSMUSG00000024899.7 | 9075.8872 | 0.8624 | 0.1441 | 0 | 0 |
| ENSMUSG00000078922.9 | 427.4633 | -2.1887 | 0.3718 | 0 | 0 |
| ENSMUSG00000074240.5 | 144.8147 | -4.3150 | 0.7433 | 0 | 0 |
| ENSMUSG00000090381.2 | 41.3654 | -5.4125 | 0.9232 | 0 | 0 |
| ENSMUSG00000063590.3 | 94.0080 | -4.3512 | 0.7631 | 0 | 0 |
top20_s <- sig_star %>%
arrange(padj) %>%
head(20) %>%
select(baseMean, log2FoldChange, lfcSE, pvalue, padj) %>%
mutate(across(where(is.numeric), ~ round(.x, 4)))
kable(top20_s,
col.names = c("Expr. media", "log2FC", "SE", "p-value", "p-adj"),
caption = "Tabla 3. Top 20 genes más significativos — STAR (Dp16 vs WT, padj < 0.05). Los genes están ordenados por p-value ajustado de menor a mayor.") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)| Expr. media | log2FC | SE | p-value | p-adj | |
|---|---|---|---|---|---|
| ENSMUSG00000117780.1 | 624.4800 | -3.3229 | 0.3469 | 0 | 0 |
| ENSMUSG00000029417.9 | 772.7797 | -1.8147 | 0.1940 | 0 | 0 |
| ENSMUSG00000097148.2 | 186.4670 | -3.8658 | 0.4495 | 0 | 0 |
| ENSMUSG00000001665.11 | 1001.2573 | 1.5612 | 0.1837 | 0 | 0 |
| ENSMUSG00000069456.4 | 3676.6815 | 1.3136 | 0.1731 | 0 | 0 |
| ENSMUSG00000057074.6 | 6515.7780 | 1.0052 | 0.1393 | 0 | 0 |
| ENSMUSG00000032080.6 | 2017.0016 | -1.2743 | 0.1793 | 0 | 0 |
| ENSMUSG00000024411.11 | 72.6810 | -2.6860 | 0.4011 | 0 | 0 |
| ENSMUSG00000021416.11 | 57.1663 | 5.8161 | 0.8390 | 0 | 0 |
| ENSMUSG00000015090.13 | 61.9050 | 3.7672 | 0.5926 | 0 | 0 |
| ENSMUSG00000040938.16 | 392.8636 | 1.3553 | 0.2179 | 0 | 0 |
| ENSMUSG00000056131.13 | 325.1514 | -1.3199 | 0.2152 | 0 | 0 |
| ENSMUSG00000023057.5 | 858.5779 | -0.9842 | 0.1614 | 0 | 0 |
| ENSMUSG00000020926.16 | 202.3003 | 2.4592 | 0.4055 | 0 | 0 |
| ENSMUSG00000028359.4 | 228.2812 | 2.3011 | 0.3817 | 0 | 0 |
| ENSMUSG00000034220.7 | 244.6405 | -2.5862 | 0.4312 | 0 | 0 |
| ENSMUSG00000074240.5 | 149.4177 | -4.2809 | 0.7191 | 0 | 0 |
| ENSMUSG00000024899.7 | 9192.1437 | 0.8076 | 0.1360 | 0 | 0 |
| ENSMUSG00000078922.9 | 151.4595 | -1.9564 | 0.3323 | 0 | 0 |
| ENSMUSG00000027596.10 | 28.4416 | -9.1148 | 2.8936 | 0 | 0 |
Interpretación de las tablas: baseMean
es la expresión promedio del gen en todas las muestras (a mayor
baseMean, más abundante es el transcrito). log2FoldChange
indica la dirección y magnitud del cambio en Dp16 respecto a WT: un
valor positivo significa que el gen está más expresado en Dp16, negativo
que está menos expresado. lfcSE es el error estándar del FC
después del shrinkage. El padj es el p-value corregido por
el método de Benjamini-Hochberg para controlar la tasa de falsos
positivos.
El volcano plot enfrenta la magnitud del cambio (log2FC,
eje X) contra la significancia estadística (-log10(padj),
eje Y). Los genes biológicamente más relevantes se encuentran en las
esquinas superiores: alto FC y muy significativos. Las líneas
discontinuas marcan los umbrales de corte: |log2FC| > 1 (cambio de al
menos 2 veces) y padj < 0.05.
df_k <- as.data.frame(res_kallisto_shrink) %>%
mutate(
gene = rownames(.),
Expression = case_when(
log2FoldChange >= 1 & padj < 0.05 ~ "Up-regulated",
log2FoldChange <= -1 & padj < 0.05 ~ "Down-regulated",
TRUE ~ "Unchanged"
)
)
top_labels_k <- df_k %>%
filter(Expression != "Unchanged") %>%
arrange(padj) %>%
head(10)
ggplot(df_k, aes(x = log2FoldChange, y = -log10(padj))) +
geom_point(aes(color = Expression), size = 0.8, alpha = 0.7) +
geom_text_repel(data = top_labels_k, aes(label = gene),
size = 2.8, max.overlaps = 15, show.legend = FALSE) +
scale_color_manual(values = c("Up-regulated" = "firebrick3",
"Down-regulated" = "dodgerblue3",
"Unchanged" = "gray70")) +
geom_vline(xintercept = c(-1, 1), linetype = "dashed", alpha = 0.5) +
geom_hline(yintercept = -log10(0.05), linetype = "dashed", alpha = 0.5) +
labs(title = "Volcano Plot — Kallisto (Dp16 vs WT)",
x = expression("log"[2]*"FC (shrinkage apeglm)"),
y = expression("-log"[10]*"padj"),
color = "Expresión") +
theme_bw(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 6. Volcano plot — Kallisto (Dp16 vs WT). Rojo: genes up-regulated en Dp16 (log2FC > 1, padj < 0.05). Azul: genes down-regulated (log2FC < -1, padj < 0.05). Gris: sin cambio significativo. Las etiquetas corresponden a los 10 genes con menor padj.
Interpretación: Los genes más significativos y con mayor cambio se concentran en ambas esquinas superiores, confirmando una respuesta transcriptómica clara en Dp16. Los genes etiquetados con mayor significancia en down-regulated (ENSMUSG00000097148.2, ENSMUSG00000117780.1) tienen log2FC entre -3 y -4, indicando una reducción de expresión de 8 a 16 veces respecto a WT. En up-regulated, ENSMUSG00000001665.11 destaca con alta significancia y log2FC ~1.6.El shrinkage es evidente: la nube gris está comprimida cerca de log2FC = 0, y los genes de baja expresión no dominan la gráfica.
df_s <- as.data.frame(res_star_shrink) %>%
mutate(
gene = rownames(.),
Expression = case_when(
log2FoldChange >= 1 & padj < 0.05 ~ "Up-regulated",
log2FoldChange <= -1 & padj < 0.05 ~ "Down-regulated",
TRUE ~ "Unchanged"
)
)
top_labels_s <- df_s %>%
filter(Expression != "Unchanged") %>%
arrange(padj) %>%
head(10)
ggplot(df_s, aes(x = log2FoldChange, y = -log10(padj))) +
geom_point(aes(color = Expression), size = 0.8, alpha = 0.7) +
geom_text_repel(data = top_labels_s, aes(label = gene),
size = 2.8, max.overlaps = 15, show.legend = FALSE) +
scale_color_manual(values = c("Up-regulated" = "firebrick3",
"Down-regulated" = "dodgerblue3",
"Unchanged" = "gray70")) +
geom_vline(xintercept = c(-1, 1), linetype = "dashed", alpha = 0.5) +
geom_hline(yintercept = -log10(0.05), linetype = "dashed", alpha = 0.5) +
labs(title = "Volcano Plot — STAR (Dp16 vs WT)",
x = expression("log"[2]*"FC (shrinkage apeglm)"),
y = expression("-log"[10]*"padj"),
color = "Expresión") +
theme_bw(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 7. Volcano plot — STAR (Dp16 vs WT). Mismos criterios de corte que Kallisto (|log2FC| > 1, padj < 0.05). La comparación visual entre ambos volcano plots permite evaluar la concordancia entre alineadores.
Interpretación: El patrón es concordante con Kallisto, los mismos genes (ENSMUSG00000117780.1, ENSMUSG00000029417.9, ENSMUSG00000097148.2) aparecen entre los más significativos en ambos alineadores, lo que confirma que son señales biológicas reales y no artefactos de un pipeline específico.
El MA plot muestra la relación entre la expresión media
(baseMean, eje X en log2) y el log2FC (eje Y). Es una
herramienta diagnóstica: en datos bien normalizados, los puntos grises
(no significativos) deben estar centrados en log2FC = 0 a lo largo de
todo el rango de expresión. El efecto del shrinkage es claramente
visible: los genes con baja expresión media (izquierda del eje X) tienen
FC contraídos hacia 0, mientras que los genes con alta expresión
mantienen sus FC originales.
ma_k <- as.data.frame(res_kallisto_shrink) %>%
mutate(
significant = !is.na(padj) & padj < 0.05,
baseMean_log = log2(baseMean + 1)
)
ggplot(ma_k, aes(x = baseMean_log, y = log2FoldChange, color = significant)) +
geom_point(size = 0.6, alpha = 0.6) +
scale_color_manual(values = c("FALSE" = "gray70", "TRUE" = "steelblue"),
labels = c("No significativo", "padj < 0.05")) +
geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
labs(title = "MA Plot — Kallisto (shrinkage apeglm)",
x = expression("log"[2]*"(expresión media + 1)"),
y = expression("log"[2]*"FC"),
color = "") +
theme_bw(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 8. MA plot — Kallisto (shrinkage apeglm). Azul: genes significativos (padj < 0.05). Gris: no significativos. La línea horizontal en log2FC = 0 sirve de referencia: puntos equilibrados sobre y bajo la línea indican ausencia de sesgo sistemático.
Interpretación:Los puntos grises están centrados en log2FC = 0 a lo largo de todo el rango de expresión, confirmando que la normalización no introdujo sesgos sistemáticos. Los DEGs significativos (azul) se distribuyen tanto por encima como por debajo de la línea de referencia, consistente con el balance observado de ~57% down y ~43% up. La compresión de puntos hacia 0 en el extremo izquierdo (genes poco expresados) es el efecto esperado del shrinkage apeglm.
ma_s <- as.data.frame(res_star_shrink) %>%
mutate(
significant = !is.na(padj) & padj < 0.05,
baseMean_log = log2(baseMean + 1)
)
ggplot(ma_s, aes(x = baseMean_log, y = log2FoldChange, color = significant)) +
geom_point(size = 0.6, alpha = 0.6) +
scale_color_manual(values = c("FALSE" = "gray70", "TRUE" = "steelblue"),
labels = c("No significativo", "padj < 0.05")) +
geom_hline(yintercept = 0, linetype = "dashed", color = "black") +
labs(title = "MA Plot — STAR (shrinkage apeglm)",
x = expression("log"[2]*"(expresión media + 1)"),
y = expression("log"[2]*"FC"),
color = "") +
theme_bw(base_size = 13) +
theme(plot.background = element_rect(fill = "white"))Figura 9. MA plot — STAR (shrinkage apeglm). Se esperan patrones similares a Kallisto. Diferencias en la densidad de puntos azules reflejan variaciones en el número de DEGs detectados por cada alineador.
Interpretación:El patrón es prácticamente idéntico al de Kallisto, con DEGs distribuidos simétricamente alrededor de log2FC = 0 y la misma compresión en genes de baja expresión. La densidad ligeramente menor de puntos azules refleja los 37 DEGs menos detectados respecto a Kallisto, atribuible a diferencias en cómo cada alineador maneja lecturas multi-mapeo.
El heatmap visualiza los patrones de expresión de los 20 genes con menor padj. Cada fila es un gen, cada columna es una muestra. Los colores representan la expresión estandarizada por fila (z-score dentro del heatmap): rojo = expresión alta relativa, azul = expresión baja relativa. El clustering jerárquico de filas y columnas se realiza de forma no supervisada — si las muestras del mismo genotipo se agrupan juntas, significa que los genes seleccionados realmente distinguen WT de Dp16.
top_genes_k <- head(order(res_kallisto$padj, na.last = TRUE), 20)
mat_heat_k <- assay(vsd_kallisto)[top_genes_k, ]
ann_col <- data.frame(Genotipo = metadata$genotype)
rownames(ann_col) <- rownames(metadata)
ann_colors <- list(Genotipo = c("WT" = "steelblue", "Dp16" = "firebrick3"))
pheatmap(mat_heat_k,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
annotation_col = ann_col,
annotation_colors = ann_colors,
scale = "row",
color = colorRampPalette(rev(brewer.pal(9, "RdBu")))(100),
fontsize_row = 9,
main = "Top 20 DEGs — Kallisto (escala por fila)")Figura 10. Heatmap de los 20 genes con menor padj — Kallisto (VST, escalado por fila/z-score). La barra de color en la parte superior indica el genotipo de cada muestra. El clustering jerárquico es no supervisado.
Interpretación: El clustering jerárquico no supervisado agrupa correctamente las tres réplicas Dp16 (izquierda) separadas de las tres réplicas WT (derecha), sin que se le indique el genotipo. Esto confirma que los 20 genes más significativos son suficientes para distinguir ambos genotipos. Se observan dos bloques principales de genes: uno con expresión alta en Dp16 (rojo) que incluye ENSMUSG00000001665.11 y ENSMUSG00000006494.11, y otro con expresión baja en Dp16 (azul) que incluye ENSMUSG00000097148.2 y ENSMUSG00000117780.1.
top_genes_s <- head(order(res_star$padj, na.last = TRUE), 20)
mat_heat_s <- assay(vsd_star)[top_genes_s, ]
pheatmap(mat_heat_s,
cluster_rows = TRUE,
cluster_cols = TRUE,
show_rownames = TRUE,
show_colnames = TRUE,
annotation_col = ann_col,
annotation_colors = ann_colors,
scale = "row",
color = colorRampPalette(rev(brewer.pal(9, "RdBu")))(100),
fontsize_row = 9,
main = "Top 20 DEGs — STAR (escala por fila)")Figura 11. Heatmap de los 20 genes con menor padj — STAR (VST, escalado por fila). La comparación con el heatmap de Kallisto (Figura 10) permite identificar genes consistentemente significativos en ambos alineadores.
Interpretación: El patrón de clustering es idéntico — Dp16 a la izquierda, WT a la derecha — y varios genes se repiten entre ambos top 20 (ENSMUSG00000001665.11, ENSMUSG00000069456.4, ENSMUSG00000029417.9, ENSMUSG00000074240.5), lo que los identifica como los candidatos más robustos del análisis.
genes_kallisto <- rownames(sig_kallisto)
genes_star <- rownames(sig_star)
genes_comunes <- intersect(genes_kallisto, genes_star)
genes_solo_k <- setdiff(genes_kallisto, genes_star)
genes_solo_s <- setdiff(genes_star, genes_kallisto)
venn.plot <- draw.pairwise.venn(
area1 = length(genes_kallisto),
area2 = length(genes_star),
cross.area = length(genes_comunes),
category = c("Kallisto", "STAR"),
fill = c("steelblue", "firebrick3"),
alpha = 0.4,
col = "white",
cex = 1.5,
cat.cex = 1.3,
cat.pos = c(-20, 20),
cat.dist = 0.07
)
grid.draw(venn.plot)Figura 12. Diagrama de Venn: DEGs compartidos entre Kallisto y STAR (padj < 0.05). El área de intersección representa genes detectados como diferencialmente expresados por ambos alineadores.
venn_resumen <- data.frame(
Categoría = c("Solo Kallisto", "Compartidos", "Solo STAR"),
N_genes = c(length(genes_solo_k), length(genes_comunes), length(genes_solo_s))
)
kable(venn_resumen,
caption = "Tabla 4. Distribución de DEGs entre alineadores (padj < 0.05).") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)| Categoría | N_genes |
|---|---|
| Solo Kallisto | 136 |
| Compartidos | 264 |
| Solo STAR | 99 |
Interpretación: De los 400 DEGs de Kallisto y 363 de STAR, 264 son compartidos (~66% del total). Esto indica una concordancia sólida entre pipelines. Los 136 exclusivos de Kallisto y 99 de STAR probablemente corresponden a genes con múltiples isoformas o regiones de mapeo ambiguo donde pseudoalineamiento y alineamiento directo difieren en la asignación de lecturas.
El análisis funcional convierte una lista de genes en significado biológico. gprofiler2 implementa una prueba hipergeométrica que evalúa si la proporción de genes de una categoría GO/KEGG/REAC en nuestra lista de DEGs es mayor de lo esperado por azar dado el universo de todos los genes analizados. Usamos los genes compartidos entre Kallisto y STAR para maximizar la confiabilidad biológica.
# Genes compartidos entre alineadores, clasificados por dirección del cambio
up_genes <- genes_comunes[sig_kallisto[genes_comunes, "log2FoldChange"] > 0]
down_genes <- genes_comunes[sig_kallisto[genes_comunes, "log2FoldChange"] < 0]
up_genes <- up_genes[!is.na(up_genes)]
down_genes <- down_genes[!is.na(down_genes)]
# Remover número de versión de IDs Ensembl (ENSMUSG00000001234.5 → ENSMUSG00000001234)
up_genes <- gsub("\\..*", "", up_genes)
down_genes <- gsub("\\..*", "", down_genes)
cat("Genes up-regulated (compartidos):", length(up_genes), "\n")## Genes up-regulated (compartidos): 113
## Genes down-regulated (compartidos): 151
## [1] "ENSMUSG00000001665" "ENSMUSG00000002588" "ENSMUSG00000002847"
## [4] "ENSMUSG00000003477" "ENSMUSG00000005373" "ENSMUSG00000005677"
## [1] "ENSMUSG00000000159" "ENSMUSG00000000303" "ENSMUSG00000000915"
## [4] "ENSMUSG00000001506" "ENSMUSG00000001763" "ENSMUSG00000002033"
Interpretación: De los 264 genes compartidos entre alineadores, 113 están sobreexpresados en Dp16 respecto a WT y 151 están reprimidos, manteniendo el balance observado en el análisis completo (~57% down, ~43% up). Los identificadores Ensembl fueron convertidos a formato sin versión (eliminando el sufijo numérico después del punto) para garantizar la compatibilidad con la base de datos de gprofiler2 para Mus musculus. Estas dos listas (genes up-regulated y down-regulated) se analizaron de forma independiente para identificar qué procesos biológicos se activan y cuáles se reprimen específicamente en el hígado del modelo Dp16.
sources_db <- c("GO:BP", "GO:MF", "GO:CC", "KEGG", "REAC")
# multi_query = FALSE: devuelve una fila por término por query,
# con columnas normales: query, p_value, intersection_size, source, term_name.
# Con multi_query = TRUE esas columnas son listas y causan errores al filtrar.
multi_gp <- gost(
query = list(
"Up-regulated" = up_genes,
"Down-regulated" = down_genes
),
organism = "mmusculus",
correction_method = "fdr",
user_threshold = 0.05,
multi_query = FALSE,
ordered_query = FALSE,
sources = sources_db,
evcodes = TRUE
)
cat("Columnas del resultado:", paste(colnames(multi_gp$result), collapse = ", "), "\n")## Columnas del resultado: query, significant, p_value, term_size, query_size, intersection_size, precision, recall, term_id, source, term_name, effective_domain_size, source_order, parents, evidence_codes, intersection
## Queries: Down-regulated, Up-regulated
## Términos enriquecidos totales: 720
Interpretación: El análisis con gprofiler2 identificó 720 términos enriquecidos en total entre genes up-regulated y down-regulated (FDR < 0.05), distribuidos en cinco bases de datos: GO:BP, GO:MF, GO:CC, KEGG y REAC. El alto número de términos significativos refleja que los 264 genes compartidos, aunque representan una fracción pequeña del transcriptoma analizado, convergen en procesos biológicos bien definidos y estadísticamente sobre-representados en ambas direcciones de cambio.
El manhattan plot de gprofiler2 muestra todos los términos enriquecidos organizados por base de datos (color) y ordenados en el eje X. El eje Y es el -log10(FDR): puntos más altos = más significativos. Es útil para tener una visión panorámica de qué bases de datos están más enriquecidas y dónde se concentran los términos significativos.
# gostplot() es la función nativa de gprofiler2 para este tipo de gráfico.
# Es la más robusta porque maneja internamente la estructura del objeto multi_gp.
gostplot(multi_gp, interactive = FALSE)Figura 14. Manhattan plot de términos GO (BP, MF, CC), KEGG y REAC enriquecidos en los genes DEG compartidos (FDR < 0.05). Cada color representa una base de datos diferente.
Interpretación: En los genes up-regulated, GO:MF presenta el término individual más significativo de todo el análisis (-log10 ~15), mientras que GO:BP concentra el mayor número de términos enriquecidos, varios de ellos superando el límite de >16. KEGG y REAC también muestran señal notable, indicando que las rutas metabólicas activadas están anotadas en múltiples bases de datos. En los genes down-regulated, GO:CC es la categoría más significativa con un término que alcanza -log10 ~10, mientras que GO:BP tiene muchos términos pero de significancia moderada (~2-4). KEGG y REAC tienen señal mínima en down-regulated, lo que indica que la represión inmune no converge en rutas metabólicas conocidas tan claramente como la activación.
if (!is.null(multi_gp$result)) {
gost_df <- as.data.frame(multi_gp$result)
bar_up <- gost_df %>%
filter(query == "Up-regulated") %>%
arrange(p_value) %>%
head(20) %>%
select(term_name, source, term_size, intersection_size, p_value) %>%
mutate(p_value = formatC(p_value, format = "e", digits = 2))
kable(bar_up,
col.names = c("Término GO", "Base de datos", "Tamaño del término",
"Genes en overlap", "p-value (FDR)"),
caption = "Tabla 5. Top 20 términos enriquecidos en genes up-regulated en Dp16 vs WT. 'Tamaño del término' indica cuántos genes del genoma pertenecen a esa categoría; 'Genes en overlap' es cuántos de nuestros DEGs caen en ella.") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)
}| Término GO | Base de datos | Tamaño del término | Genes en overlap | p-value (FDR) |
|---|---|---|---|---|
| small molecule metabolic process | GO:BP | 1549 | 44 | 1.54e-23 |
| lipid metabolic process | GO:BP | 1266 | 40 | 7.01e-23 |
| oxoacid metabolic process | GO:BP | 783 | 32 | 5.42e-21 |
| organic acid metabolic process | GO:BP | 789 | 32 | 5.42e-21 |
| carboxylic acid metabolic process | GO:BP | 769 | 30 | 4.36e-19 |
| monocarboxylic acid metabolic process | GO:BP | 549 | 26 | 2.46e-18 |
| catalytic activity | GO:MF | 5584 | 68 | 1.16e-15 |
| fatty acid metabolic process | GO:BP | 357 | 18 | 1.33e-12 |
| small molecule biosynthetic process | GO:BP | 500 | 20 | 2.43e-12 |
| Metabolic pathways | KEGG | 1646 | 40 | 1.00e-11 |
| organic acid biosynthetic process | GO:BP | 251 | 15 | 2.01e-11 |
| steroid metabolic process | GO:BP | 277 | 15 | 7.61e-11 |
| alcohol metabolic process | GO:BP | 287 | 15 | 1.16e-10 |
| carboxylic acid biosynthetic process | GO:BP | 247 | 14 | 2.21e-10 |
| Drug ADME | REAC | 105 | 13 | 2.79e-10 |
| oxidoreductase activity | GO:MF | 742 | 22 | 5.97e-10 |
| lipid biosynthetic process | GO:BP | 610 | 19 | 6.20e-10 |
| sulfur compound metabolic process | GO:BP | 224 | 13 | 9.03e-10 |
| monocarboxylic acid biosynthetic process | GO:BP | 176 | 12 | 9.03e-10 |
| Metabolism | REAC | 1740 | 39 | 1.61e-09 |
Interpretación: Los genes activados en Dp16 se enriquecen de forma masiva en procesos metabólicos hepáticos. Los dos términos más significativos “small molecule metabolic process” y “lipid metabolic process” tienen FDR de 1.54e-23 y 7.01e-23 respectivamente, valores extremadamente por encima del esperado por azar. El patrón es coherente a lo largo de los 20 términos: metabolismo y síntesis de lípidos, ácidos grasos, ácidos orgánicos y esteroides forman un bloque funcional activado en conjunto. El término “catalytic activity” de GO:MF (FDR 1.16e-15) con 68 genes en overlap indica que gran parte de los genes activados codifican enzimas metabólicas. Esto es directamente concordante con lo reportado por Dunn et al. (2026), que identifica disfunción del metabolismo lipídico y de ácidos biliares como el fenotipo hepático principal del modelo Dp16.
if (!is.null(multi_gp$result)) {
gost_df <- as.data.frame(multi_gp$result)
bar_down <- gost_df %>%
filter(query == "Down-regulated") %>%
arrange(p_value) %>%
head(20) %>%
select(term_name, source, term_size, intersection_size, p_value) %>%
mutate(p_value = formatC(p_value, format = "e", digits = 2))
kable(bar_down,
col.names = c("Término GO", "Base de datos", "Tamaño del término",
"Genes en overlap", "p-value (FDR)"),
caption = "Tabla 6. Top 20 términos enriquecidos en genes down-regulated en Dp16 vs WT. Procesos reprimidos en el modelo de trisomía 16 respecto al ratón silvestre.") %>%
kable_styling(bootstrap_options = c("striped","hover","condensed"),
full_width = FALSE)
}| Término GO | Base de datos | Tamaño del término | Genes en overlap | p-value (FDR) |
|---|---|---|---|---|
| extracellular region | GO:CC | 2340 | 44 | 5.80e-11 |
| extracellular space | GO:CC | 1136 | 24 | 2.79e-06 |
| membrane attack complex | GO:CC | 7 | 4 | 3.55e-06 |
| pore complex | GO:CC | 26 | 5 | 2.49e-05 |
| Terminal pathway of complement | REAC | 8 | 4 | 1.14e-04 |
| immune system process | GO:BP | 2557 | 33 | 4.06e-04 |
| defense response | GO:BP | 1633 | 25 | 4.06e-04 |
| response to stress | GO:BP | 3596 | 41 | 4.06e-04 |
| immune response | GO:BP | 1726 | 26 | 4.06e-04 |
| PPAR signaling pathway | KEGG | 89 | 7 | 7.17e-04 |
| Complement and coagulation cascades | KEGG | 94 | 7 | 7.17e-04 |
| endoplasmic reticulum | GO:CC | 1758 | 25 | 8.25e-04 |
| cell surface | GO:CC | 753 | 15 | 1.13e-03 |
| humoral immune response mediated by circulating immunoglobulin | GO:BP | 43 | 5 | 1.32e-03 |
| endomembrane system | GO:CC | 4005 | 41 | 2.22e-03 |
| response to external stimulus | GO:BP | 2346 | 29 | 2.27e-03 |
| response to stimulus | GO:BP | 9759 | 74 | 2.49e-03 |
| positive regulation of response to stimulus | GO:BP | 2034 | 26 | 2.49e-03 |
| response to other organism | GO:BP | 1566 | 22 | 2.49e-03 |
| response to external biotic stimulus | GO:BP | 1570 | 22 | 2.49e-03 |
Interpretación: Los genes reprimidos en Dp16 muestran dos patrones distintos en la tabla. El término más significativo es “extracellular region” de GO:CC (FDR 5.80e-11, 44 genes en overlap), seguido de “extracellular space” y “membrane attack complex” lo que indica que los genes reprimidos codifican principalmente proteínas secretadas o de la matriz extracelular. El segundo patrón es inmune: “immune system process”, “defense response”, “immune response” y “response to stress” comparten el mismo FDR (4.06e-04), y la presencia de “Terminal pathway of complement” en REAC y “Complement and coagulation cascades” en KEGG apunta específicamente a la represión de la cascada del complemento en el hígado Dp16.
Comparado con los términos up-regulated, los FDR son considerablemente menos extremos (máximo 5.80e-11 vs 1.54e-23), lo que indica que la señal metabólica activada es estadísticamente más robusta que la señal de represión. Esto es consistente con lo reportado por Dunn et al. (2026), que describe disfunción metabólica e inflamación como los fenotipos dominantes del hígado Dp16.
if (!is.null(multi_gp$result)) {
gost_df <- as.data.frame(multi_gp$result)
bar_up_plot <- gost_df %>%
filter(query == "Up-regulated", source == "GO:BP") %>%
arrange(p_value) %>%
head(20) %>%
mutate(log10p = round(-log10(p_value), 2),
num = seq_len(n()))
if (nrow(bar_up_plot) > 0) {
ggplot(bar_up_plot,
aes(x = log10p, y = reorder(term_name, log10p))) +
geom_bar(stat = "identity", fill = "firebrick3", alpha = 0.8) +
geom_text(aes(label = log10p), hjust = -0.1, size = 3) +
labs(title = "GO:BP — Up-regulated (Dp16 vs WT)",
x = "-log10(FDR)", y = NULL) +
theme_classic(base_size = 12) +
theme(plot.background = element_rect(fill = "white"))
}
}Figura 15. Top 20 procesos biológicos (GO:BP) enriquecidos en genes up-regulated en Dp16 vs WT. El eje X muestra la significancia en escala -log10(FDR): barras más largas = mayor enriquecimiento.
Interpretación: Los 20 procesos GO:BP más enriquecidos en genes up-regulated forman un bloque funcional coherente centrado en el metabolismo hepático. Los seis términos más significativos metabolismo de pequeñas moléculas, lípidos, oxoácidos, ácidos orgánicos, ácidos carboxílicos y ácidos monocarboxílicos todos superan -log10(FDR) de 17, indicando una activación masiva y coordinada de la maquinaria metabólica. La presencia de “fatty acid metabolic process”, “steroid metabolic process” y “acyl-CoA metabolic process” en los últimos puestos confirma que la activación no es de un solo proceso sino de toda la red metabólica hepática. Esto es directamente concordante con lo reportado por Dunn et al. (2026).
if (!is.null(multi_gp$result)) {
gost_df <- as.data.frame(multi_gp$result)
bar_down_plot <- gost_df %>%
filter(query == "Down-regulated", source == "GO:BP") %>%
arrange(p_value) %>%
head(20) %>%
mutate(log10p = round(-log10(p_value), 2),
num = seq_len(n()))
if (nrow(bar_down_plot) > 0) {
ggplot(bar_down_plot,
aes(x = log10p, y = reorder(term_name, log10p))) +
geom_bar(stat = "identity", fill = "dodgerblue3", alpha = 0.8) +
geom_text(aes(label = log10p), hjust = -0.1, size = 3) +
labs(title = "GO:BP — Down-regulated (Dp16 vs WT)",
x = "-log10(FDR)", y = NULL) +
theme_classic(base_size = 12) +
theme(plot.background = element_rect(fill = "white"))
}
}Figura 16. Top 20 procesos biológicos (GO:BP) enriquecidos en genes down-regulated en Dp16 vs WT. Procesos represados en el modelo de trisomía, ordenados por significancia.
Interpretación: Los procesos GO:BP reprimidos en Dp16 se concentran en respuesta inmune y defensa. Los cuatro términos más significativos “response to stress”, “immune system process”, “immune response” y “defense response” comparten exactamente el mismo FDR (-log10 = 3.39), lo que indica que forman un bloque co-reprimido. La presencia de “complement activation” por vía clásica y alternativa, y “humoral immune response mediated by circulating immunoglobulin” apunta específicamente a la represión de la inmunidad humoral en el hígado Dp16. Comparando ambas figuras, la escala es muy diferente: el máximo en down-regulated es 3.39 vs 22.81 en up-regulated, lo que refleja que la activación metabólica es el fenotipo dominante y estadísticamente más robusto en el hígado Dp16.
if (!dir.exists(figdir)) dir.create(figdir, recursive = TRUE)
# Resultados DEG completos (con shrinkage apeglm)
write.csv(as.data.frame(res_kallisto_shrink),
file = paste0(outdir, "DESeq2_kallisto_results.csv"))
write.csv(as.data.frame(res_star_shrink),
file = paste0(outdir, "DESeq2_STAR_results.csv"))
# Solo genes significativos (padj < 0.05)
write.csv(sig_kallisto,
file = paste0(outdir, "DESeq2_kallisto_significant.csv"))
write.csv(sig_star,
file = paste0(outdir, "DESeq2_STAR_significant.csv"))
# Resultados GO terms
if (!is.null(multi_gp$result)) {
gost_export <- multi_gp$result
# Convertir columnas tipo lista a texto para exportar en CSV
gost_export$parents <- sapply(gost_export$parents, paste, collapse = ";")
gost_export$evidence_codes <- sapply(gost_export$evidence_codes, paste, collapse = ";")
write.csv(gost_export,
file = paste0(outdir, "GOterms_gprofiler2_results.csv"),
row.names = FALSE)
}
# Objetos R: dds, vsd, resultados, z-score, melted counts
save(dds, dds_star,
vsd_kallisto, vsd_star,
res_kallisto_shrink, res_star_shrink,
zscore_mat, melted_norm_counts,
file = paste0(outdir, "DEG_objects.RData"))
cat("Todos los archivos guardados en:", outdir, "\n")## Todos los archivos guardados en: /Users/dubsirubs/Desktop/RNAseq_Equipo4/results_final/
Normalización exitosa: La transformación VST produjo distribuciones de expresión comparables entre todas las muestras (Figura 1). El PCA separó claramente los genotipos WT y Dp16 (Figuras 2 y 4), confirmando que el genotipo es la principal fuente de variación en los datos y que no existe un batch effect evidente. El scree plot (Figura 3) indica qué fracción de la varianza total está capturada en los dos primeros componentes.
Expresión diferencial robusta: Se identificaron 400 DEGs con Kallisto y 363 con STAR (padj < 0.05), con predominio de genes reprimidos (~57% down) en ambos pipelines. El shrinkage con apeglm estabilizó los log2FC de genes con baja expresión, como se observa en los MA plots (Figuras 8 y 9). Los heatmaps (Figuras 10 y 11) muestran que los 20 genes más significativos son suficientes para separar ambos genotipos de forma no supervisada.
Alta concordancia Kallisto vs STAR: El diagrama de Venn (Figura 12) muestra que 264 genes son compartidos entre ambos pipelines (~66% de Kallisto, ~73% de STAR), validando que la firma transcriptómica de Dp16 es reproducible independientemente del método de cuantificación.
Procesos biológicos alterados: El análisis funcional con gprofiler2 identificó 720 términos enriquecidos en los 264 genes compartidos. Los genes up-regulated se enriquecen masivamente en metabolismo de lípidos, ácidos grasos y ácidos orgánicos (FDR hasta 1.54e-23), mientras que los down-regulated se enriquecen en respuesta inmune y activación del complemento (FDR hasta 4.06e-04). Estos resultados son consistentes con la disfunción metabólica e inflamatoria hepática reportada por Dunn et al. (2026) en el modelo Dp16.
Nuestros resultados son consistentes con los hallazgos centrales reportados por Dunn et al. (2026) en el mismo modelo Dp(16)1Yey y el mismo tejido (hígado de ratón adulto). El artículo de referencia reporta disfunción metabólica hepática como fenotipo dominante en Dp16, caracterizada por alteración del metabolismo de ácidos biliares, fibrosis e inflamación. En nuestro análisis, los genes up-regulated en Dp16 se enriquecen masivamente en términos GO relacionados con metabolismo de lípidos, ácidos grasos y ácidos orgánicos (FDR hasta 1.54e-23), mientras que los down-regulated se concentran en respuesta inmune y cascada del complemento (FDR hasta 5.80e-11). Este patrón de activación metabólica combinada con represión de la inmunidad humoral replica la firma transcriptómica descrita por Dunn et al. (2026).
Una diferencia notable es el número de DEGs detectados: nuestro análisis identificó 400 genes (Kallisto) y 363 (STAR) con padj < 0.05, mientras que Dunn et al. reportan ~1,500 DEGs con el dataset completo. Esta diferencia es atribuible directamente al menor poder estadístico de usar solo 3 réplicas por genotipo en lugar de las 6 disponibles. A pesar de ello, la dirección de los cambios y los procesos biológicos identificados son concordantes, lo que valida la robustez de nuestra aproximación analítica.
El perfil transcriptómico observado en el hígado Dp16 se puede interpretar en el contexto más amplio de la fisiopatología del Síndrome de Down. Tian et al. (2023) realizaron un análisis metabólico multi-tejido exhaustivo del modelo Dp16, incluyendo hígado, músculo esquelético y tejido adiposo, y demostraron que la trisomía genera resistencia a la insulina, intolerancia a la glucosa y dislipidemia en ambos sexos. Sus datos transcriptómicos multi-tejido muestran activación de vías del metabolismo lipídico y supresión de la función mitocondrial como patrones compartidos. Nuestros resultados en hígado son compatibles con este patrón sistémico: la activación masiva de genes del metabolismo de lípidos y ácidos grasos que observamos en Dp16 refleja esta disfunción metabólica sistémica. La concordancia entre el análisis de un solo tejido (nuestro estudio) y el análisis multi-tejido de Tian et al. (2023) sugiere que el hígado es uno de los principales efectores del fenotipo metabólico de la trisomía 16.
La comparación entre pipelines que realizamos tiene respaldo metodológico en el artículo fundacional de DESeq2 (Love et al., 2014), donde se enfatiza que la precisión del análisis diferencial depende críticamente de la calidad de las estimaciones de conteo. Nuestro análisis muestra que 264 de los DEGs son compartidos entre Kallisto y STAR (~66–73% de overlap), lo que indica alta concordancia entre pseudoalineamiento y alineamiento directo al genoma para este dataset. La pequeña fracción de DEGs exclusivos de cada pipeline puede explicarse por las diferencias metodológicas: Kallisto trabaja a nivel de transcriptoma y propaga incertidumbre de asignación mediante bootstrap, mientras que STAR alinea al genoma completo y maneja lecturas multi-mapeo de forma diferente. Para el análisis de expresión diferencial en tejido hepático con genes bien anotados en GRCm39, ambas estrategias son equivalentes en términos prácticos, en línea con lo reportado por Love et al. (2014) sobre la robustez del modelo binomial negativo frente a distintas estrategias de cuantificación.
Un hallazgo particularmente relevante de nuestro análisis funcional es la represión de genes del complemento y la inmunidad humoral en el hígado Dp16. El hígado es el principal sitio de síntesis de proteínas del complemento, por lo que su represión en el contexto de Dp16 podría contribuir a la vulnerabilidad inmunológica observada clínicamente en personas con Síndrome de Down. Bray et al. (2016) demostraron que el pseudoalineamiento de Kallisto preserva la sensibilidad para detectar cambios en genes con expresión moderada-baja, que es precisamente el rango donde se ubican varios genes del complemento. Esto refuerza la confiabilidad de este hallazgo en nuestro análisis. El patrón de represión del complemento identificado aquí es consistente con lo reportado por Dunn et al. (2026) en sus análisis de enriquecimiento de vías, y sugiere que la disfunción hepática en trisomía 21 tiene consecuencias que van más allá del metabolismo y se extienden a la función inmune sistémica.
El principal factor limitante de este estudio es el tamaño de muestra (n=3 por genotipo), seleccionado por criterios de profundidad de secuenciación y porcentaje de duplicación a partir del dataset completo de 6 réplicas. Aunque el diseño estadístico de DESeq2 maneja adecuadamente réplicas triples cuando la señal biológica es fuerte (Love et al., 2014), el poder para detectar genes con cambios moderados (|log2FC| < 1) es reducido, lo que explica la diferencia en el número de DEGs respecto a Dunn et al. (2026). Adicionalmente, al ser análisis de bulk RNA-seq, no es posible distinguir qué tipos celulares específicos dentro del hígado contribuyen a cada cambio transcriptómico; este punto sería abordable con los datos de scRNA-seq del mismo bioproyecto. Finalmente, el análisis se realizó únicamente en ratones adultos de 19–26 semanas, por lo que los resultados no pueden extrapolarse directamente a otros estadios del desarrollo. Como perspectiva futura, incluir las 6 réplicas completas, integrar los datos de scRNA-seq disponibles en el mismo bioproyecto, y comparar el perfil transcriptómico hepático con el análisis multi-tejido de Tian et al. (2023) permitiría una caracterización más completa del fenotipo Dp16.
Los archivos de log de cada paso del pipeline están disponibles en el
repositorio en scripts/out_logs/. La tabla enlaza
directamente a cada archivo:
| Paso | Script | Outlogs |
|---|---|---|
| Descarga SRA | 01_download_adapters.sh |
download.out · download.err · download_Dp16.out · download_Dp16.err |
| Trimmomatic | trimmomatic_final.sh |
trimm_final_1611.out · trimm_final_1611.err |
| Kallisto (×6 muestras) | 03_kallisto.sh |
_0 · _1 · _2 · _3 · _4 · _5 |
| STAR index | 04_STAR_index.sh |
STAR_index.out · STAR_index.err |
| STAR align (×6 muestras) | 05_STAR_align.sh |
_0 · _1 · _2 · _3 · _4 · _5 |
Dunn, A. et al., 2026. Altered hepatic metabolism in Down syndrome. Cell Reports. DOI: 10.1016/j.celrep.2025.116835
Love, M.I., Huber, W., & Anders, S., 2014. Moderated estimation of fold change and dispersion for RNA-seq data with DESeq2. Genome Biology, 15, 550. DOI: 10.1186/s13059-014-0550-8
Tian, Y. et al., 2023. Gene dosage imbalance disrupts systemic metabolism in the Dp16 Down syndrome mouse model. bioRxiv / eLife. DOI: 10.64898/2026.01.13.699318
Bray, N.L., Pimentel, H., Melsted, P., & Pachter, L., 2016. Near-optimal probabilistic RNA-seq quantification. Nature Biotechnology, 34, 525–527. DOI: 10.1038/nbt.3519
## R version 4.5.2 (2025-10-31)
## Platform: aarch64-apple-darwin20
## Running under: macOS Tahoe 26.3
##
## Matrix products: default
## BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
## LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
##
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
##
## time zone: America/Mexico_City
## tzcode source: internal
##
## attached base packages:
## [1] grid stats4 stats graphics grDevices utils datasets
## [8] methods base
##
## other attached packages:
## [1] apeglm_1.32.0 limma_3.66.0
## [3] VennDiagram_1.8.2 futile.logger_1.4.9
## [5] gprofiler2_0.2.4 ggrepel_0.9.8
## [7] kableExtra_1.4.0 knitr_1.51
## [9] RColorBrewer_1.1-3 pheatmap_1.0.13
## [11] reshape2_1.4.5 dplyr_1.2.1
## [13] ggplot2_4.0.3 rhdf5_2.54.1
## [15] tximport_1.38.2 DESeq2_1.50.2
## [17] SummarizedExperiment_1.40.0 Biobase_2.70.0
## [19] MatrixGenerics_1.22.0 matrixStats_1.5.0
## [21] GenomicRanges_1.62.1 Seqinfo_1.0.0
## [23] IRanges_2.44.0 S4Vectors_0.48.1
## [25] BiocGenerics_0.56.0 generics_0.1.4
##
## loaded via a namespace (and not attached):
## [1] tidyselect_1.2.1 viridisLite_0.4.3 farver_2.1.2
## [4] bitops_1.0-9 S7_0.2.2 RCurl_1.98-1.18
## [7] fastmap_1.2.0 lazyeval_0.2.3 digest_0.6.39
## [10] lifecycle_1.0.5 statmod_1.5.1 magrittr_2.0.5
## [13] compiler_4.5.2 rlang_1.2.0 sass_0.4.10
## [16] tools_4.5.2 yaml_2.3.12 data.table_1.18.4
## [19] lambda.r_1.2.4 labeling_0.4.3 S4Arrays_1.10.1
## [22] htmlwidgets_1.6.4 curl_7.1.0 DelayedArray_0.36.1
## [25] plyr_1.8.9 xml2_1.5.2 abind_1.4-8
## [28] BiocParallel_1.44.0 numDeriv_2016.8-1.1 withr_3.0.2
## [31] purrr_1.2.2 Rhdf5lib_1.32.0 MASS_7.3-65
## [34] scales_1.4.0 mvtnorm_1.3-7 bbmle_1.0.25.1
## [37] cli_3.6.6 rmarkdown_2.31 otel_0.2.0
## [40] rstudioapi_0.18.0 httr_1.4.8 bdsmatrix_1.3-7
## [43] cachem_1.1.0 stringr_1.6.0 parallel_4.5.2
## [46] formatR_1.14 XVector_0.50.0 vctrs_0.7.3
## [49] Matrix_1.7-5 jsonlite_2.0.0 systemfonts_1.3.2
## [52] locfit_1.5-9.12 plotly_4.12.0 jquerylib_0.1.4
## [55] tidyr_1.3.2 glue_1.8.1 emdbook_1.3.14
## [58] codetools_0.2-20 stringi_1.8.7 gtable_0.3.6
## [61] tibble_3.3.1 pillar_1.11.1 htmltools_0.5.9
## [64] rhdf5filters_1.22.0 R6_2.6.1 textshaping_1.0.5
## [67] evaluate_1.0.5 lattice_0.22-9 futile.options_1.0.1
## [70] bslib_0.10.0 Rcpp_1.1.1-1.1 coda_0.19-4.1
## [73] svglite_2.2.2 SparseArray_1.10.10 xfun_0.57
## [76] pkgconfig_2.0.3
Documento generado con R Markdown.
Análisis realizado en el cluster
ken.lavis.unam.mx
Ruta del proyecto:
/mnt/data/bioinfo-estadistica-2/RNAseq_2026/equipos/Equipo4/