Introducción

Este tutorial presenta un análisis de expresión diferencial utilizando datos de RNA-seq en el telencéfalo de ratón, utilizando el paquete DESeq2 en R. Los pasos incluyen normalización, análisis de expresión diferencial y visualización de resultados, fundamentales para interpretar cambios de expresión bajo condiciones experimentales específicas. Para más detalles, consulta el artículo en Frontiers in Genetics.

Objetivo

Identificar genes diferencialmente expresados entre las condiciones experimentales “M9.5” y “M10.5”, aplicando métodos de normalización y visualización para detectar genes relevantes sin intrones diferencialmente expresados. Los términos M9.5 y M10.5 se refieren a estadios embrionarios en el desarrollo de ratones, expresados en días post coitum (dpc) o días después de la fertilización. Estos números indican la cantidad de días desde la concepción, y cada punto decimal marca fracciones del día.

En la investigación en biología del desarrollo, los estadios embrionarios específicos son críticos para comprender el proceso de diferenciación celular y formación de tejidos. Cada día (e incluso cada fracción de día) en el desarrollo del ratón corresponde a cambios rápidos y específicos en la formación de órganos y sistemas.

Preprocesamiento de Lecturas (Read Preprocessing)

Después de la secuenciación, se obtienen archivos FASTQ que requieren procesamiento en BASH para eliminar lecturas de baja calidad y adaptadores. Este paso sí incluye código y se puede realizar con herramientas como FastQC para evaluación de calidad y Trimmomatic para recorte y filtrado.

Ejecutar FastQC para evaluar la calidad de los archivos FASTQ

fastqc sample_R1.fastq sample_R2.fastq -o output_directory/.

Recorte de adaptadores y bases de baja calidad con Trimmomatic

Ejecutar Trimmomatic para recortar adaptadores y bases de baja calidad

trimmomatic PE -phred33
sample_R1.fastq sample_R2.fastq
sample_R1_trimmed.fastq sample_R1_unpaired.fastq
sample_R2_trimmed.fastq sample_R2_unpaired.fastq
ILLUMINACLIP:TruSeq3-PE.fa:2:30:10 LEADING:3 TRAILING:3 SLIDINGWINDOW:4:15 MINLEN:36
.

Mapeo de Lecturas al Genoma de Referencia (Read Alignment)

Para alinear las lecturas al genoma del ratón (mm10), se puede utilizar Tophat o HISAT2. Aquí mostramos el uso de Tophat.

Ejecutar Tophat para alinear lecturas al genoma mm10

tophat2 -o output_directory/ -G mm10_annotation.gtf mm10_index sample_R1_trimmed.fastq sample_R2_trimmed.fastq. Esto generará un archivo BAM con las lecturas alineadas.

Conteo de Lecturas (Read Counting)

Para contar las lecturas alineadas en cada gen, se uso HTSeq-count junto con el archivo GTF de Ensembl correspondiente al genoma de ratón (mm10).

Ejecutar HTSeq-count para obtener los conteos de lecturas en cada gen

htseq-count -f bam -r pos -s no -i gene_id sample_aligned.bam mm10_annotation.gtf > read_counts.txt. Esto generará un archivo BAM con las lecturas alineadas.


PIPELINE

Preparación del Ambiente

Primero, instalaremos y cargaremos los paquetes necesarios. Nos aseguraremos de que los paquetes estén instalados antes de cargarlos, para facilitar su uso en otros entornos.

# Instalar y cargar paquetes necesarios
if (!requireNamespace("BiocManager", quietly = TRUE)) install.packages("BiocManager")
if (!requireNamespace("dplyr", quietly = TRUE)) BiocManager::install("dplyr")
if (!requireNamespace("DESeq2", quietly = TRUE)) install.packages("DESeq2")
if (!requireNamespace("pheatmap", quietly = TRUE)) install.packages("pheatmap")
if (!requireNamespace("ggplot2", quietly = TRUE)) install.packages("ggplot2")
#BiocManager::install("DESeq2")
library(DESeq2)
## Loading required package: S4Vectors
## Loading required package: stats4
## Loading required package: BiocGenerics
## 
## Attaching package: 'BiocGenerics'
## The following objects are masked from 'package:stats':
## 
##     IQR, mad, sd, var, xtabs
## The following objects are masked from 'package:base':
## 
##     anyDuplicated, aperm, append, as.data.frame, basename, cbind,
##     colnames, dirname, do.call, duplicated, eval, evalq, Filter, Find,
##     get, grep, grepl, intersect, is.unsorted, lapply, Map, mapply,
##     match, mget, order, paste, pmax, pmax.int, pmin, pmin.int,
##     Position, rank, rbind, Reduce, rownames, sapply, setdiff, table,
##     tapply, union, unique, unsplit, which.max, which.min
## 
## Attaching package: 'S4Vectors'
## The following object is masked from 'package:utils':
## 
##     findMatches
## The following objects are masked from 'package:base':
## 
##     expand.grid, I, unname
## Loading required package: IRanges
## Loading required package: GenomicRanges
## Loading required package: GenomeInfoDb
## Loading required package: SummarizedExperiment
## Loading required package: MatrixGenerics
## Loading required package: matrixStats
## 
## Attaching package: 'MatrixGenerics'
## The following objects are masked from 'package:matrixStats':
## 
##     colAlls, colAnyNAs, colAnys, colAvgsPerRowSet, colCollapse,
##     colCounts, colCummaxs, colCummins, colCumprods, colCumsums,
##     colDiffs, colIQRDiffs, colIQRs, colLogSumExps, colMadDiffs,
##     colMads, colMaxs, colMeans2, colMedians, colMins, colOrderStats,
##     colProds, colQuantiles, colRanges, colRanks, colSdDiffs, colSds,
##     colSums2, colTabulates, colVarDiffs, colVars, colWeightedMads,
##     colWeightedMeans, colWeightedMedians, colWeightedSds,
##     colWeightedVars, rowAlls, rowAnyNAs, rowAnys, rowAvgsPerColSet,
##     rowCollapse, rowCounts, rowCummaxs, rowCummins, rowCumprods,
##     rowCumsums, rowDiffs, rowIQRDiffs, rowIQRs, rowLogSumExps,
##     rowMadDiffs, rowMads, rowMaxs, rowMeans2, rowMedians, rowMins,
##     rowOrderStats, rowProds, rowQuantiles, rowRanges, rowRanks,
##     rowSdDiffs, rowSds, rowSums2, rowTabulates, rowVarDiffs, rowVars,
##     rowWeightedMads, rowWeightedMeans, rowWeightedMedians,
##     rowWeightedSds, rowWeightedVars
## Loading required package: Biobase
## Welcome to Bioconductor
## 
##     Vignettes contain introductory material; view with
##     'browseVignettes()'. To cite Bioconductor, see
##     'citation("Biobase")', and for packages 'citation("pkgname")'.
## 
## Attaching package: 'Biobase'
## The following object is masked from 'package:MatrixGenerics':
## 
##     rowMedians
## The following objects are masked from 'package:matrixStats':
## 
##     anyMissing, rowMedians
library(dplyr)
## 
## Attaching package: 'dplyr'
## The following object is masked from 'package:Biobase':
## 
##     combine
## The following object is masked from 'package:matrixStats':
## 
##     count
## The following objects are masked from 'package:GenomicRanges':
## 
##     intersect, setdiff, union
## The following object is masked from 'package:GenomeInfoDb':
## 
##     intersect
## The following objects are masked from 'package:IRanges':
## 
##     collapse, desc, intersect, setdiff, slice, union
## The following objects are masked from 'package:S4Vectors':
## 
##     first, intersect, rename, setdiff, setequal, union
## The following objects are masked from 'package:BiocGenerics':
## 
##     combine, intersect, setdiff, union
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(pheatmap)

Exploración de los Datos de Conteo

Cargamos los datos de conteo de genes desde un archivo de texto que contiene los conteos de cada gen para cada muestra. Para cargar los datos, usaremos el archivo mouse_read_counts.txt. asegurate de que esté en el mismo directorio que este archivo RMarkdown o de lo contrario especifica la ruta completa de localización.

setwd("/Users/katiaavinapadilla/Desktop")
file_path <- "mouse_read_counts.txt"
count_data <- read.table(file_path, header = TRUE, row.names = 1)
head(count_data)
##                    M9.5a M9.5b M9.5c M9.5d M10.5a M10.5b M10.5c M10.5d
## ENSMUSG00000024112   285   451   169   148    905    783    571    546
## ENSMUSG00000040447    25    20    16     8    175    122    112     74
## ENSMUSG00000096847   454   504   296   255    926    838    576    550
## ENSMUSG00000039860     6    20     5     9    169    133     66     69
## ENSMUSG00000030310    48    54    24    29    379    201    178    169
## ENSMUSG00000034227   124   109    29    35    520    449    288    247

Descripción de los Datos

Cada celda en el conjunto de datos contiene el número de lecturas asignadas a un gen específico en una muestra específica. Estos valores reflejan la expresión relativa de cada gen en cada muestra, pero deben normalizarse para asegurar comparabilidad.

Una matriz de conteos es una representación de datos de RNA-seq que contiene los conteos brutos de lecturas asignadas a cada gen (o transcripto) en cada muestra. Aquí tienes una descripción detallada:

Filas: Cada fila representa un gen o transcripto específico.

Columnas: Cada columna representa una muestra individual.

Celdas: El valor de cada celda es el conteo bruto de lecturas alineadas a ese gen en esa muestra. Estos conteos son enteros y reflejan la abundancia relativa de cada gen en cada muestra.

Información que Proporciona la Matriz de Conteos

Abundancia de Genes: El conteo bruto refleja la abundancia de transcritos de cada gen en una muestra. Los genes con mayor número de conteos son más abundantemente expresados en esa muestra.

Comparabilidad entre Muestras: Aunque los conteos brutos muestran la abundancia, no son directamente comparables entre muestras sin normalización, debido a las diferencias en la profundidad de secuenciación y otros factores técnicos.

Variabilidad entre Genes y Condiciones: Al comparar los conteos entre genes o entre condiciones (como tratamiento y control), podemos inferir patrones de expresión y explorar cómo se regula la expresión génica en diferentes contextos biológicos.

Importancia en el Análisis de Expresión Diferencia

La matriz de conteos es elpunto de partida para el análisis de expresión diferencial. Herramientas de Generación de Matrices de Conteos: HTSeq, FeatureCounts

Conteos Brutos vs. Normalizados: Los conteos brutos reflejan los datos iniciales y se utilizan para la normalización. Los conteos normalizados permiten comparaciones precisas entre muestras.

Creación del Objeto de Condiciones conocido como Metadatos

Definimos las condiciones experimentales, “M9.5” y “M10.5”. Asumimos que cada condición tiene cuatro réplicas, y especificamos estas condiciones en un marco de datos (colData). para usarlas en el análisis de expresión diferencial. La creación del objeto de condiciones o metadatos en un análisis de expresión diferencial es un paso importante, ya que define las categorías o grupos experimentales que queremos comparar. En este caso, estamos trabajando con un conjunto de datos de expresión de genes en el telencéfalo de ratón en dos momentos de desarrollo: “M9.5” y “M10.5”.

¿Por Qué Definir las Condiciones? Al analizar la expresión diferencial con DESeq2, es fundamental indicar al programa qué muestras pertenecen a cada grupo (en este caso, “M9.5” y “M10.5”). Esto permite que el análisis estadístico compare estos grupos para identificar genes cuya expresión cambia significativamente entre las dos condiciones.

samples <- colnames(count_data)
condition <- factor(c(rep("M9.5", 4), rep("M10.5", 4)))
col_data <- data.frame(row.names = samples, condition = condition)
col_data
##        condition
## M9.5a       M9.5
## M9.5b       M9.5
## M9.5c       M9.5
## M9.5d       M9.5
## M10.5a     M10.5
## M10.5b     M10.5
## M10.5c     M10.5
## M10.5d     M10.5

Contenido: Las muestras M9.5a, M9.5b, M9.5c y M9.5d están etiquetadas bajo la condición M9.5. Estas son las cuatro réplicas biológicas de la condición experimental M9.5. Las muestras M10.5a, M10.5b, M10.5c y M10.5d están etiquetadas bajo la condición M10.5, representando las cuatro réplicas biológicas de la condición experimental M10.5.

Creación del Objeto DESeqDataSet

Este marco de datos (col_data) se utiliza para definir las condiciones experimentales de cada muestra cuando se crea el objeto “DESeqDataSet en DESeq2.La columna condition le indica a DESeq2 qué muestras deben compararse en el análisis de expresión diferencial, en este caso, comparando las condiciones M9.5 y M10.5.

Este marco de datos de metadatos permite a DESeq2 identificar qué muestras pertenecen a cada condición experimental, permitiendo realizar la comparación entre las condiciones M9.5 y M10.5 en el análisis de expresión diferencial.

# Crear el objeto DESeqDataSet
dds <- DESeqDataSetFromMatrix(countData = count_data, colData = col_data, design = ~ condition)
# Verificar el contenido del objeto DESeqDataSet
dds
## class: DESeqDataSet 
## dim: 12902 8 
## metadata(1): version
## assays(1): counts
## rownames(12902): ENSMUSG00000024112 ENSMUSG00000040447 ...
##   ENSMUSG00000023391 ENSMUSG00000063804
## rowData names(0):
## colnames(8): M9.5a M9.5b ... M10.5c M10.5d
## colData names(1): condition

Este formato es esencial para el análisis, ya que le indica a DESeq2 cómo están organizadas las condiciones experimentales en el conjunto de datos, permitiéndole realizar comparaciones adecuadas entre los grupos.

Filtrado de Genes con Baja Expresión Para mejorar la precisión del análisis, filtramos los genes con conteos bajos en todas las muestras. Esto reduce el ruido en el análisis y aumenta la potencia estadística. El filtrado de genes con baja expresión se realiza para excluir aquellos genes que no muestran un nivel de expresión significativo en las muestras, ya que pueden agregar “ruido” al análisis estadístico y dificultar la identificación de patrones reales.

¿Qué significa >= 10 y >= 2 en el código?

>= 10: Este umbral especifica que solo se mantendrán los genes que tienen un mínimo de 10 lecturas (conteos) en una muestra. Esto ayuda a eliminar genes con muy baja expresión, que probablemente son ruido o artefactos del experimento en lugar de expresiones biológicamente significativas.

>= 2: Este segundo umbral indica que el gene debe cumplir el criterio anterior (>= 10) en al menos 2 muestras. De esta forma, se garantiza que el gen tiene un nivel mínimo de expresión en más de una muestra, lo cual es importante para la robustez del análisis y permite capturar una expresión que pueda estar presente en un grupo de muestras o condición específica.

# Filtrar genes con baja expresión
dds <- dds[rowSums(counts(dds) >= 10) >= 2, ]

Normalización y Análisis de Expresión Diferencial La función “DESeq () en el paquete DESeq2 realiza tanto la normalización como el análisis de expresión diferencial de los datos de RNA-seq. Aplicamos la función DESeq () para normalizar los datos y calcular la expresión diferencial entre las condiciones “M9.5” y “M10.5”. Este paso incluye la estimación de factores de tamaño y dispersión, y el ajuste de un modelo lineal generalizado para cada gen.

Estimación de Factores de Tamaño: DESeq2 ajusta cada muestra en función de su profundidad de secuenciación mediante la mediana geométrica de conteos. Estimación de Dispersión: DESeq2 estima la dispersión para cada gen, lo que permite distinguir entre variabilidad técnica y biológica. Ajuste del Modelo GLM: DESeq2 ajusta un modelo lineal generalizado para cada gen y calcula el cambio de expresión entre condiciones.

# Ejecutar el análisis de expresión diferencial
dds <- DESeq(dds)
## estimating size factors
## estimating dispersions
## gene-wise dispersion estimates
## mean-dispersion relationship
## final dispersion estimates
## fitting model and testing
res <- results(dds)
# Visualizar los primeros resultados
head(res)
## log2 fold change (MLE): condition M9.5 vs M10.5 
## Wald test p-value: condition M9.5 vs M10.5 
## DataFrame with 6 rows and 6 columns
##                     baseMean log2FoldChange     lfcSE      stat      pvalue
##                    <numeric>      <numeric> <numeric> <numeric>   <numeric>
## ENSMUSG00000024112  454.3526      -1.339967  0.188711  -7.10061 1.24204e-12
## ENSMUSG00000040447   64.3561      -2.675618  0.294419  -9.08779 1.01076e-19
## ENSMUSG00000096847  524.4864      -0.816289  0.104892  -7.78221 7.12677e-15
## ENSMUSG00000039860   53.8936      -3.290078  0.376133  -8.74712 2.18876e-18
## ENSMUSG00000030310  125.9156      -2.452229  0.246547  -9.94629 2.61773e-23
## ENSMUSG00000034227  207.0286      -2.266683  0.297384  -7.62208 2.49617e-14
##                           padj
##                      <numeric>
## ENSMUSG00000024112 4.33693e-11
## ENSMUSG00000040447 6.50256e-18
## ENSMUSG00000096847 3.05043e-13
## ENSMUSG00000039860 1.24912e-16
## ENSMUSG00000030310 2.12116e-21
## ENSMUSG00000034227 1.01521e-12

Filtrado de Resultados Significativos Filtramos los genes con un valor ajustado (padj) menor a 0.05 para identificar aquellos con cambios significativos en la expresión entre condiciones. Explicación

*res$padj < 0.05: Filtra los genes con un valor ajustado (padj) menor a 0.05, lo que indica significancia estadística después de la corrección por FDR.

*rabs(res$log2FoldChange) > 1 : Filtra los genes cuyo log2 Fold Change (cambio en la expresión entre condiciones) es mayor a 1 en valor absoluto. Esto significa que se seleccionan solo aquellos genes que tienen un cambio de expresión relevante en magnitud.

*El uso de abs() permite seleccionar tanto aumentos como disminuciones en la expresión que cumplan con el criterio de cambio significativo.

# Filtrar genes con cambio de expresión significativo y log2 Fold Change mayor a 1
res_filtered <- res[which(res$padj < 0.05 & abs(res$log2FoldChange) > 1), ]
# Visualizar los genes filtrados
head(res_filtered)
## log2 fold change (MLE): condition M9.5 vs M10.5 
## Wald test p-value: condition M9.5 vs M10.5 
## DataFrame with 6 rows and 6 columns
##                     baseMean log2FoldChange     lfcSE      stat      pvalue
##                    <numeric>      <numeric> <numeric> <numeric>   <numeric>
## ENSMUSG00000024112  454.3526       -1.33997  0.188711  -7.10061 1.24204e-12
## ENSMUSG00000040447   64.3561       -2.67562  0.294419  -9.08779 1.01076e-19
## ENSMUSG00000039860   53.8936       -3.29008  0.376133  -8.74712 2.18876e-18
## ENSMUSG00000030310  125.9156       -2.45223  0.246547  -9.94629 2.61773e-23
## ENSMUSG00000034227  207.0286       -2.26668  0.297384  -7.62208 2.49617e-14
## ENSMUSG00000034796   80.0761        1.40734  0.239606   5.87353 4.26617e-09
##                           padj
##                      <numeric>
## ENSMUSG00000024112 4.33693e-11
## ENSMUSG00000040447 6.50256e-18
## ENSMUSG00000039860 1.24912e-16
## ENSMUSG00000030310 2.12116e-21
## ENSMUSG00000034227 1.01521e-12
## ENSMUSG00000034796 9.63519e-08

Visualización de Resultados

Análisis de Componentes Principales (PCA)

El análisis PCA nos permite visualizar cómo las muestras se agrupan en función de su perfil de expresión, proporcionando una visión general de la variabilidad entre condiciones.

# Transformación de Variance Stabilizing Transformation (VST)
vsd <- vst(dds, blind = FALSE)
plotPCA(vsd, intgroup = "condition") + ggtitle("PCA of Mouse Gene Expression Data")
## using ntop=500 top features by variance

Interpretación: La clara separación a lo largo de PC1 indica que los patrones de expresión génica difieren notablemente entre los grupos M9.5 y M10.5. Esta separación podría deberse a diferencias en las etapas de desarrollo, efectos de tratamiento u otros factores biológicos específicos de cada grupo. La agrupación dentro de cada grupo sugiere consistencia en los perfiles de expresión génica entre los réplicas o muestras dentro del mismo grupo.

Volcano Plot

El Volcano Plot muestra los genes con cambios de expresión significativos, permitiendo identificar visualmente aquellos que tienen mayor cambio de expresión entre condiciones.

# Convertir los resultados a DataFrame para el plot
res_df <- as.data.frame(res)
# Filtrar genes significativos y dividir en inducidos y reprimidos
res_df <- res_df %>%
  mutate(gene_label = rownames(res_df)) %>% # Crear columna con los nombres de los genes
  mutate(color = case_when(
    log2FoldChange > 1 & padj < 0.05 ~ "induced",  # Genes inducidos
    log2FoldChange < -1 & padj < 0.05 ~ "repressed", # Genes reprimidos
    TRUE ~ "neutral" # Genes no significativos
  ))
# Seleccionar los 5 genes más inducidos y los 5 más reprimidos
top_induced <- res_df %>%
  filter(color == "induced") %>%
  arrange(desc(log2FoldChange)) %>%
  head(5)
top_repressed <- res_df %>%
  filter(color == "repressed") %>%
  arrange(log2FoldChange) %>%
  head(5)
# Crear el Volcano Plot
ggplot(res_df, aes(x = log2FoldChange, y = -log10(padj), color = color)) +
  geom_point(alpha = 0.4) +
  scale_color_manual(values = c("induced" = "red", "repressed" = "blue", "neutral" = "gray")) +
  geom_text(data = top_induced, aes(label = gene_label), vjust = -1, color = "red", size = 1) +
  geom_text(data = top_repressed, aes(label = gene_label), vjust = 1.5, color = "blue", size = 1) +
  labs(title = "Volcano Plot of Differential Expression",
       x = "Log2 Fold Change",
       y = "-Log10 Adjusted P-Value") +
  theme_minimal()

# Crear una tabla con los 10 genes top (5 up, 5 down)
top_genes <- bind_rows(top_induced, top_repressed) %>%
  select(gene_label, log2FoldChange, padj) %>%
  arrange(desc(log2FoldChange))
# Mostrar la tabla de los 10 genes top en el documento
knitr::kable(top_genes, caption = "Top 10 Differentially Expressed Genes (5 Induced, 5 Repressed)")
Top 10 Differentially Expressed Genes (5 Induced, 5 Repressed)
gene_label log2FoldChange padj
ENSMUSG00000000805 ENSMUSG00000000805 5.092952 0.0000000
ENSMUSG00000027750 ENSMUSG00000027750 4.624025 0.0000000
ENSMUSG00000023886 ENSMUSG00000023886 4.004762 0.0000008
ENSMUSG00000027375 ENSMUSG00000027375 3.981459 0.0001192
ENSMUSG00000022510 ENSMUSG00000022510 3.881713 0.0062039
ENSMUSG00000019146 ENSMUSG00000019146 -7.012011 0.0000000
ENSMUSG00000042532 ENSMUSG00000042532 -7.146135 0.0000000
ENSMUSG00000046178 ENSMUSG00000046178 -7.297091 0.0000000
ENSMUSG00000000214 ENSMUSG00000000214 -7.679289 0.0000000
ENSMUSG00000051354 ENSMUSG00000051354 -9.588639 0.0000000

Interpretación:Los puntos en el cuadrante superior derecho (rojo) representan genes significativamente inducidos, y los del cuadrante superior izquierdo (azul) representan genes significativamente reprimidos. La mayoría de los genes inducidos o reprimidos tienen valores p ajustados significativos, lo que sugiere que hay diferencias importantes en la expresión génica entre las condiciones comparadas.Estos genes representan los más afectados en términos de expresión entre las condiciones comparadas. Los genes más inducidos pueden estar asociados con funciones específicas que se activan en la condición experimental, mientras que los genes más reprimidos podrían estar inhibidos o regulados negativamente en respuesta a esa condición.

Heatmap de Genes Significativamente Expresados

Un heatmap nos permite visualizar los patrones de expresión de los genes diferencialmente expresados entre las diferentes muestras. Esto es útil para observar agrupaciones de genes con expresiones similares entre condiciones.

# Obtener conteos normalizados
norm_counts <- counts(dds, normalized = TRUE)
sig_genes <- rownames(res_filtered)
# Crear Heatmap
pheatmap(norm_counts[sig_genes, ],
         cluster_rows = TRUE,
         cluster_cols = TRUE,
         scale = "row",
         annotation_col = col_data,
         show_rownames = FALSE,
         main = "Heatmap of Differentially Expressed Genes")

Interpretación General: Este mapa de calor sugiere que existen patrones de expresión diferencial claros entre M9.5 y M10.5. Los genes en rojo en M10.5 están inducidos en esta condición en comparación con M9.5, mientras que los genes en azul en M9.5 podrían estar reprimidos o simplemente menos expresados.Este tipo de visualización puede ayudar a identificar subconjuntos de genes específicos de cada condición, que podrían ser relevantes en los procesos biológicos o en las etapas de desarrollo representadas por M9.5 y M10.5.

write.csv(as.data.frame(res), file = "resultados_expresion_diferencial_completo.csv", row.names = TRUE)
write.csv(as.data.frame(res), file = "resultados_expresion_diferencial_filtrados.csv", row.names = TRUE)