Visualización de datos

Última actualización: 2026-11-11 | Mejora esta página

Tiempo estimado: 120 minutos

Hoja de ruta

Preguntas

  • Visualización en R

Objetivos

  • Crear gráficos de dispersión, de cajas, de líneas, etc., utilizando ggplot.
  • Configurar los ajustes universales del gráfico.
  • Describa qué es el faceting y aplique el faceting en ggplot.
  • Modifique la estética de un gráfico ggplot existente (incluyendo las etiquetas de los ejes y el color).
  • Crear gráficos complejos y personalizados a partir de datos de una tabla de datos.

Este episodio se basa en la lección Data Analysis and Visualisation in R for Ecologists de Data Carpentries.

Visualización de datos


Comenzamos cargando los paquetes necesarios. ggplot2 está incluido en el paquete tidyverse.

R

library("tidyverse")

Si aún no se encuentra en el espacio de trabajo, cargue los datos que guardamos en la lección anterior.

R

rna <- read.csv("data/rnaseq.csv")

La Hoja de trucos de visualización de datos cubrirá los conceptos básicos y las funciones más avanzadas de ggplot2, y ayudará, además de servir como recordatorio, a obtener una visión general de las numerosas representaciones de datos disponibles en el paquete. Los siguientes videotutoriales (parte 1 y parte 2) de Thomas Lin Pedersen también son muy instructivos.

Representación gráfica con ggplot2


ggplot2 es un paquete de gráficos que facilita la creación de gráficos complejos a partir de datos de una tabla de datos. Proporciona una interfaz más programática para especificar qué variables representar, cómo mostrarlas y las propiedades visuales generales. La base teórica que sustenta a ggplot2 es la Grammar of Graphics ( Wilkinson (2005) ). Al utilizar este enfoque, solo necesitamos cambios mínimos si los datos subyacentes cambian o si decidimos pasar de un gráfico de barras a un gráfico de dispersión. Esto ayuda a crear gráficos de calidad editorial con la mínima cantidad de ajustes y retoques.

Existe un libro sobre ggplot2 ( Wickham (2016) ) que ofrece una buena visión general, pero está desactualizado. La tercera edición está en preparación y estará disponible gratuitamente en línea. La página web de ggplot2 (https://ggplot2.tidyverse.org) proporciona una documentación amplia.

ggplot2 funciona con datos en formato «largo», es decir, una columna por cada dimensión y una fila por cada observación. Los datos bien estructurados le ahorrarán mucho tiempo al crear figuras con ggplot2.

Los gráficos de ggplot se construyen paso a paso añadiendo nuevos elementos. Añadir capas de esta manera permite una gran flexibilidad y personalización de los gráficos.

La idea detrás de la Gramática de Gráficos es que puedes construir cualquier gráfico a partir de los mismos 3 componentes: (1) un conjunto de datos, (2) un sistema de coordenadas y (3) geoms — es decir, marcas visuales que representan puntos de datos 1

Para crear un ggplot, utilizaremos la siguiente plantilla básica que puede emplearse para diferentes tipos de gráficos:

ggplot(data = <DATA>, mapping = aes(<MAPPINGS>)) +  <GEOM_FUNCTION>()
  • utilice la función ggplot() y vincule el gráfico a una tabla de datos específica mediante el argumento data

R

ggplot(data = rna)
  • defina un mapeo (utilizando la función aesthetic (aes)), seleccionando las variables a representar y especificando cómo presentarlas en el gráfico, por ejemplo, como posiciones x/y o características como el tamaño, la forma, el color, etc.

R

ggplot(data = rna, mapping = aes(x = expression))
  • añada ‘geoms’ - geometrías, o representaciones gráficas de los datos en el gráfico (puntos, líneas, barras). ggplot2 ofrece muchas geometrías diferentes; hoy utilizaremos algunas comunes, entre ellas:

    * `geom_point()` for scatter plots, dot plots, etc.
    * `geom_histogram()` for histograms
    * `geom_boxplot()` for, well, boxplots!
    * `geom_line()` for trend lines, time series, etc.

Para añadir una geometría al gráfico, use el operador +. Empecemos usando geom_histogram():

R

ggplot(data = rna, mapping = aes(x = expression)) +
  geom_histogram()

SALIDA

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Default histogram produced by ggplot() and geom_histogram() for the expression data.

El + del paquete ggplot2 es particularmente útil porque permite modificar objetos ggplot existentes. Esto significa que puede configurar fácilmente plantillas de gráficos y explorar cómodamente diferentes tipos de gráficos, por lo que el gráfico anterior también puede generarse con un código como este:

R

# Assign plot to a variable
rna_plot <- ggplot(data = rna,
                   mapping = aes(x = expression))

# Draw the plot
rna_plot + geom_histogram()
Desafío

Desafío

Probablemente hayas notado un mensaje automático que aparece al dibujar el histograma:

SALIDA

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

Cambie los argumentos bins o binwidth de geom_histogram() para cambiar el número o el ancho de los intervalos.

R

# change bins
ggplot(rna, aes(x = expression)) +
    geom_histogram(bins = 15)
Histograms produced by ggplot() and geom_histogram() for the expression data with bin set of 15 (top) and binwith set to 2000 (bottom).

R

# change binwidth
ggplot(rna, aes(x = expression)) +
    geom_histogram(binwidth = 2000)
Histograms produced by ggplot() and geom_histogram() for the expression data with bin set of 15 (top) and binwith set to 2000 (bottom).

Aquí podemos observar que los datos están sesgados hacia la derecha. Podemos aplicar una transformación logarítmica en base 2 para obtener una distribución más simétrica. Tenga en cuenta que aquí añadimos un pequeño valor constante (+1) para evitar que se devuelvan valores de -Inf para valores de expresión iguales a 0.

R

rna <- rna |>
  mutate(expression_log = log2(expression + 1))

Si ahora trazamos el histograma de las expresiones transformadas logarítmicamente en base 2, la distribución es, en efecto, más cercana a una distribución normal.

R

ggplot(rna, aes(x = expression_log)) + geom_histogram()

SALIDA

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.
Histogram produced by ggplot() and geom_histogram() for the pre-computed log of expression.

A partir de ahora, trabajaremos con los valores de expresión transformados logarítmicamente.

Desafío

Desafío

Otra forma de visualizar esta transformación es considerar la escala de las observaciones. Por ejemplo, puede valer la pena cambiar la escala del eje para distribuir mejor las observaciones en el espacio del gráfico. Cambiar la escala de los ejes se hace de manera similar a añadir o modificar otros componentes (es decir, añadiendo comandos de forma incremental). Intente realizar esta modificación:

  • Represente la expresión sin transformar en la escala log10; consulte scale_x_log10(). Compárela con el gráfico anterior. ¿Por qué ahora aparecen mensajes de advertencia?

R

ggplot(data = rna,mapping = aes(x = expression))+
  geom_histogram() +
  scale_x_log10()

ADVERTENCIA

Warning in scale_x_log10(): log-10 transformation introduced infinite values.

SALIDA

`stat_bin()` using `bins = 30`. Pick better value `binwidth`.

ADVERTENCIA

Warning: Removed 507 rows containing non-finite outside the scale range
(`stat_bin()`).
Histogram produced by ggplot(), geom_histogram() and scale_x_log10() for the log of expression.

Notas

  • Cualquier elemento que incluya en la función ggplot() será visible en cualquier capa geom que añada (es decir, se trata de configuraciones globales del gráfico). Esto incluye el mapeo de los ejes x e y que configure en aes().
  • También puede especificar mapeos para un geom determinado de forma independiente de los mapeos definidos globalmente en la función ggplot().
  • El signo + utilizado para añadir nuevas capas deberá colocarse al final de la línea que contiene la capa anterior. Si, en cambio, se añade el signo + al principio de la línea que contiene la nueva capa, ggplot2 no añadirá la nueva capa y devolverá un mensaje de error.

R

# This is the correct syntax for adding layers
rna_plot +
  geom_histogram()

# This will not add the new layer and will return an error message
rna_plot
  + geom_histogram()

Creación iterativa de gráficos


A continuación, dibujaremos un gráfico de dispersión con dos variables continuas y la función geom_point(). Este gráfico representará los cambios relativos de expresión en escala log2 comparando el tiempo 8 frente al tiempo 0, y el tiempo 4 frente al tiempo 0. Para ello, primero necesitamos calcular los promedios de los valores de expresión transformados logarítmicamente por gen y tiempo, y luego los cambios relativos en escala logarítmica restando el promedio de las expresiones logarítmicas entre el tiempo 8 y el tiempo 0, y entre el tiempo 4 y el tiempo 0. Tenga en cuenta que aquí también incluimos el biotipo del gen que utilizaremos más adelante para representar los genes. Guardaremos los cambios relativos de expresión en una nueva tabla de datos llamada rna_fc..

R

rna_fc <- rna |> select(gene, time,
                         gene_biotype, expression_log) |>
  group_by(gene, time, gene_biotype) |>
  summarize(mean_exp = mean(expression_log)) |>
  pivot_wider(names_from = time,
              values_from = mean_exp) |>
  mutate(time_8_vs_0 = `8` - `0`, time_4_vs_0 = `4` - `0`)

SALIDA

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, time, and gene_biotype.
ℹ Output is grouped by gene and time.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time, gene_biotype))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

A continuación, podemos crear un ggplot con el conjunto de datos recién creado rna_fc. Crear gráficos con ggplot2 suele ser un proceso iterativo. Comenzamos definiendo el conjunto de datos que utilizaremos, disponiendo los ejes y eligiendo un geom:

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point()
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are black.

A continuación, comenzamos a modificar este gráfico para extraer más información de él. Por ejemplo, podemos añadir transparencia (alpha) para evitar el solapamiento:

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are semi-transparent black.

También podemos añadir colores a todos los puntos:

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3, color = "blue")
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. All dots are semi-transparent blue.

O bien, para colorear cada gen en el gráfico de manera diferente, podría utilizar un vector como entrada para el argumento color. ggplot2 proporcionará un color diferente correspondiente a distintos valores del vector. Aquí tiene un ejemplo donde se colorea con gene_biotype:

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_point(alpha = 0.3, aes(color = gene_biotype))
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype.

También podemos especificar los colores directamente dentro del mapeo proporcionado en la función ggplot(). Esto será visible en cualquier capa geom y el mapeo se determinará según la configuración de los ejes x e y en aes().

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_point(alpha = 0.3)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype.

Por último, también podríamos añadir una línea diagonal con la función geom_abline():

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_point(alpha = 0.3) +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype. A black line of slope 1 crossing the origin was added by geom_abline().

Nótese que podemos cambiar la capa geom de geom_point a geom_jitter y los colores seguirán determinados por gene_biotype.

R

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0,
                                color = gene_biotype)) +
  geom_jitter(alpha = 0.3) +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_point() comparing the log-foldchanges computed above. Dots are colour-coded based on the gene's biotype. A black line of slope 1 crossing the origin was added by geom_abline().
Desafío

Desafío

Los gráficos de dispersión pueden ser herramientas exploratorias útiles para conjuntos de datos pequeños. Para conjuntos de datos con un gran número de observaciones, como el conjunto de datos rna_fc, la superposición de puntos puede representar una limitación de los gráficos de dispersión. Una estrategia para manejar tales escenarios consiste en utilizar el agrupamiento hexagonal de las observaciones. El espacio del gráfico se tesela en hexágonos. A cada hexágono se le asigna un color basado en el número de observaciones que caen dentro de sus límites.

  • Para utilizar el agrupamiento hexagonal en ggplot2, primero instale el paquete de R hexbin desde CRAN y cárguelo.

  • A continuación, utilice la función geom_hex() para generar la figura de hexbin.

  • ¿Cuáles son las fortalezas y debilidades relativas de un gráfico de binaje hexagonal en comparación con un gráfico de dispersión? Examine el gráfico de dispersión anterior y compárelo con el gráfico de binaje hexagonal que creó.

R

install.packages("hexbin")

R

library("hexbin")

ggplot(data = rna_fc, mapping = aes(x = time_4_vs_0, y = time_8_vs_0)) +
  geom_hex() +
  geom_abline(intercept = 0)
Scatter plot produced by ggplot() and geom_hexbin() comparing the log-foldchanges computed above shows hexagons coloured based on the underlying dot density. A black line of slope 1 crossing the origin was added by geom_abline().
Desafío

Desafío

Utiliza lo que acabas de aprender para crear un gráfico de dispersión de expression_log sobre sample a partir del conjunto de datos rna, con el tiempo mostrado en diferentes colores. ¿Es esta una buena manera de representar este tipo de datos?

R

ggplot(data = rna, mapping = aes(y = expression_log, x = sample)) +
    geom_point(aes(color = time))
Figures showing a stretch of overlapping points indicating the log of expression + 1 for each sample. The points are coloured with different shades of blue for samples collected at different time points.

Gráfico de cajas


Podemos utilizar gráficos de cajas para visualizar la distribución de la expresión génica dentro de cada muestra:

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_boxplot()
Boxplot showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is filled with white colour.

Al añadir puntos al gráfico de cajas, podemos tener una mejor idea del número de mediciones y de su distribución:

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_jitter(alpha = 0.2, color = "tomato") +
  geom_boxplot(alpha = 0)
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured and behind the boxpots.
Desafío

Desafío

Observa cómo la capa del gráfico de cajas está por delante de la capa de jitter. ¿Qué debes cambiar en el código para colocar el gráfico de cajas debajo de los puntos?

Deberíamos cambiar el orden de estos dos geoms:

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_boxplot(alpha = 0) +
  geom_jitter(alpha = 0.2, color = "tomato")
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured. This time, the boxplots are behind the dots.

Es posible que notes que los valores del eje x todavía no son correctamente legibles. Cambiemos la orientación de las etiquetas y ajustémoslas vertical y horizontalmente para que no se solapen. Puedes usar un ángulo de 90 grados, o experimentar para encontrar el ángulo adecuado para las etiquetas orientadas diagonalmente:

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_jitter(alpha = 0.2, color = "tomato") +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). Each boxplot is transparent and the jittered dots are semi-transparent tomato-coloured. The sample labels are displayed vertically and readable.
Desafío

Desafío

Añada color a los puntos de datos de su gráfico de cajas según la duración de la infección (time).

Pista: Revisa la clase de time. Considera cambiar la clase de time de entero a factor directamente en la asignación de ggplot. ¿Por qué esto cambia la forma en que R crea el gráfico?

R

# time as integer
ggplot(data = rna,
         mapping = aes(y = expression_log,
                       x = sample)) +
  geom_jitter(alpha = 0.2, aes(color = time)) +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). On the first figure, each boxplot is transparent and the jittered dots are semi-transparent and coloured in different shares of blue. On the second figures, each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.

R

# time as factor
ggplot(data = rna,
         mapping = aes(y = expression_log,
                       x = sample)) +
  geom_jitter(alpha = 0.2, aes(color = as.factor(time))) +
  geom_boxplot(alpha = 0) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Boxplot and dots showing the distribution of log expression + 1 values for each sample, as produced by geom_boxlpot(). On the first figure, each boxplot is transparent and the jittered dots are semi-transparent and coloured in different shares of blue. On the second figures, each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.
Desafío

Desafío

Los gráficos de cajas son resúmenes útiles, pero ocultan la forma de la distribución. Por ejemplo, si la distribución es bimodal, no se vería en un gráfico de cajas. Una alternativa al gráfico de cajas es el gráfico de violín, donde se dibuja la forma (de la densidad de los puntos).

  • Sustituya el gráfico de cajas por un gráfico de violín; consulte geom_violin(). Rellene los violines según el tiempo con el argumento fill.

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_violin(aes(fill = as.factor(time))) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Violin plot showing the distribution of log expression + 1 values for each sample, as produced by geom_violin(). Each boxplot is transparent and the jittered dots are semi-transparent and coloured red, green and blue.
Desafío

Desafío

  • Modifique el gráfico en forma de violín para rellenar los violines mediante sex.

R

ggplot(data = rna,
         mapping = aes(y = expression_log, x = sample)) +
  geom_violin(aes(fill = sex)) +
  theme(axis.text.x = element_text(angle = 90,  hjust = 0.5, vjust = 0.5))
Violin plot showing the distribution of log expression + 1 values for each sample, as produced by geom_violon(). Each violin plot is coloured in red or blue depending on the sex variable.

Gráficos de líneas


Calculemos la expresión media por duración de la infección para los 10 genes con los mayores cambios relativos de expresión en escala logarítmica al comparar el tiempo 8 con el tiempo 0. Primero, debemos seleccionar los genes y crear un subconjunto de rna llamado sub_rna que contenga los 10 genes seleccionados; luego, debemos agrupar los datos y calcular la expresión génica media dentro de cada grupo:

R

rna_fc <- rna_fc |> arrange(desc(time_8_vs_0))

genes_selected <- rna_fc$gene[1:10]

sub_rna <- rna |>
    filter(gene %in% genes_selected)

mean_exp_by_time <- sub_rna |>
  group_by(gene,time) |>
    summarize(mean_exp = mean(expression_log))

SALIDA

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene and time.
ℹ Output is grouped by gene.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

mean_exp_by_time

SALIDA

# A tibble: 30 × 3
# Groups:   gene [10]
   gene   time mean_exp
   <chr> <int>    <dbl>
 1 Acr       0     5.07
 2 Acr       4     5.54
 3 Acr       8     7.31
 4 Aipl1     0     3.70
 5 Aipl1     4     3.89
 6 Aipl1     8     6.56
 7 Bst1      0     3.20
 8 Bst1      4     3.77
 9 Bst1      8     5.22
10 Chil3     0     4.00
# ℹ 20 more rows

Podemos crear el gráfico de líneas con la duración de la infección en el eje x y la expresión media en el eje y:

R

ggplot(data = mean_exp_by_time, mapping = aes(x = time, y = mean_exp)) +
  geom_line()
Line plot, as produced by geom_line(), but the lines are clearly not show what we expect.

Lamentablemente, esto no funciona porque representamos los datos de todos los genes juntos. Necesitamos indicar a ggplot que dibuje una línea para cada gen modificando la función estética para incluir group = gene:

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp, group = gene)) +
  geom_line()
Line plot, as produced by geom_line(), with 10 lines showing increasing expression values over time.

Podremos distinguir los genes en el gráfico si añadimos colores (el uso de color también agrupa automáticamente los datos):

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line()
Line plot, as produced by geom_line(), with 10 colour-coded lines showing increasing expression values over time.

Faceting


ggplot2 cuenta con una técnica especial llamada faceting que permite al usuario dividir un gráfico en múltiples gráficos (subgráficos) basándose en un factor incluido en el conjunto de datos. Estos diferentes subgráficos heredan las mismas propiedades (límites de los ejes, marcas, …) para facilitar su comparación directa. Lo utilizaremos para crear un gráfico de líneas a lo largo del tiempo para cada gen:

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp)) + geom_line() +
  facet_wrap(~ gene)
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing one line with increasing expression values over time. All y-scales are identical.

Aquí, tanto el eje x como el y tienen la misma escala en todos los subgráficos. Puede cambiar este comportamiento predeterminado modificando scales para permitir una escala libre para el eje y:

R

ggplot(data = mean_exp_by_time,
       mapping = aes(x = time, y = mean_exp)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y")
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing one line with increasing expression values over time. y-scales are now adapted to the expression range for each facet/gene.

Ahora queremos dividir la línea en cada gráfico según el sexo de los ratones. Para ello, necesitamos calcular la expresión media en la tabla de datos agrupada por gene, time y sex:

R

mean_exp_by_time_sex <- sub_rna |>
  group_by(gene, time, sex) |>
    summarize(mean_exp = mean(expression_log))

SALIDA

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by gene, time, and sex.
ℹ Output is grouped by gene and time.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(gene, time, sex))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

mean_exp_by_time_sex

SALIDA

# A tibble: 60 × 4
# Groups:   gene, time [30]
   gene   time sex    mean_exp
   <chr> <int> <chr>     <dbl>
 1 Acr       0 Female     5.13
 2 Acr       0 Male       5.00
 3 Acr       4 Female     5.93
 4 Acr       4 Male       5.15
 5 Acr       8 Female     7.27
 6 Acr       8 Male       7.36
 7 Aipl1     0 Female     3.67
 8 Aipl1     0 Male       3.73
 9 Aipl1     4 Female     4.07
10 Aipl1     4 Male       3.72
# ℹ 50 more rows

Ahora podemos crear el gráfico facetado dividiendo aún más por sexo utilizando color (dentro de un único gráfico):

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y")
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing two coloured lines (red for Female and blue for Make) with increasing expression values over time.

Por lo general, los gráficos con fondo blanco resultan más legibles al imprimirlos. Podemos establecer el fondo en blanco utilizando la función theme_bw(). Además, podemos eliminar la cuadrícula:

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())
Line plot, as produced by geom_line(), with 10 sub-plots/facets, each showing two coloured lines (red for Female and blue for Make) with increasing expression values over time. The figure background is now white.
Desafío

Desafío

Utiliza lo que acabas de aprender para crear un gráfico que represente cómo varía la expresión promedio de cada cromosoma a lo largo de la duración de la infección.

R

mean_exp_by_chromosome <- rna |>
  group_by(chromosome_name, time) |>
  summarize(mean_exp = mean(expression_log))

SALIDA

`summarise()` has regrouped the output.
ℹ Summaries were computed grouped by chromosome_name and time.
ℹ Output is grouped by chromosome_name.
ℹ Use `summarise(.groups = "drop_last")` to silence this message.
ℹ Use `summarise(.by = c(chromosome_name, time))` for per-operation grouping
  (`?dplyr::dplyr_by`) instead.

R

ggplot(data = mean_exp_by_chromosome, mapping = aes(x = time,
                                y = mean_exp)) +
  geom_line() +
  facet_wrap(~ chromosome_name, scales = "free_y")
Line plot, as produced by geom_line(), with 21 sub-plots/facets, each showing one line with expression values over time for each chromosome.

La geometría facet_wrap extrae los gráficos en un número arbitrario de dimensiones para que quepan correctamente en una sola página. Por otro lado, la geometría facet_grid permite especificar explícitamente cómo se desea que estén dispuestos los gráficos mediante la notación de fórmula (rows ~ columns; un . puede utilizarse como marcador que indique una sola fila o columna).

Modifiquemos el gráfico anterior para comparar cómo ha cambiado la expresión génica media de los machos y las hembras a lo largo del tiempo:

R

# One column, facet by rows
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line() +
  facet_grid(sex ~ .)
Two line plots above each other, each showing 10 lines coloured by gene. The top facet shows the expression values for Female sample, the bottom one for Male samples.

R

# One row, facet by column
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = gene)) +
  geom_line() +
  facet_grid(. ~ sex)
Two line plots next to each other, each showing 10 lines coloured by gene. The left facet shows the expression values for Female sample, the right one for Male samples.

Temas de ggplot2


Además de theme_bw(), que cambia el fondo del gráfico a blanco, ggplot2 incluye varios otros temas que pueden resultar útiles para cambiar rápidamente la apariencia de su visualización. La lista completa de temas está disponible en https://ggplot2.tidyverse.org/reference/ggtheme.html. theme_minimal() y theme_light() son populares, y theme_void() puede resultar útil como punto de partida para crear un nuevo tema diseñado a mano.

El paquete ggthemes ofrece una amplia variedad de opciones (incluido un tema de Excel 2003). El sitio web de extensiones ggplot2 proporciona una lista de paquetes que amplían las capacidades de ggplot2, incluidos temas adicionales.

Personalización


Volvamos al gráfico facetado de la expresión media según el tiempo y el gen, coloreado por sexo.

Echa un vistazo a la hoja de trucos ggplot2 y piensa en formas de mejorar el gráfico.

Ahora, podemos cambiar los nombres de los ejes por algo más informativo que ‘time’ y ‘mean_exp’, y añadir un título a la figura:

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")
Line plot with white background and custom title and axis legends.

Los ejes tienen nombres más informativos, pero su legibilidad puede mejorarse aumentando el tamaño de la fuente:

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")  +
  theme(text = element_text(size = 16))
Line plot with white background and larger custom title and axis legends.

Tenga en cuenta que también es posible cambiar las fuentes de sus gráficos. Si utiliza Windows, es posible que tenga que instalar el paquete extrafont.

Podemos personalizar aún más el color del texto de los ejes x e y, el color de la cuadrícula, etc. También podemos, por ejemplo, mover la leyenda a la parte superior estableciendo legend.position en "top".

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  labs(title = "Mean gene expression by duration of the infection",
       x = "Duration of the infection (in days)",
       y = "Mean gene expression")  +
  theme(text = element_text(size = 16),
        axis.text.x = element_text(colour = "royalblue4", size = 12),
        axis.text.y = element_text(colour = "royalblue4", size = 12),
        panel.grid = element_line(colour="lightsteelblue1"),
        legend.position = "top")
Line plot with white background and larger custom title and axis legends and blue grid.

Si te gustan más los cambios que has realizado que el tema predeterminado, puedes guardarlos como un objeto para poder aplicarlos fácilmente a otros gráficos que crees. Aquí tienes un ejemplo con el histograma que creamos anteriormente.

R

blue_theme <- theme(axis.text.x = element_text(colour = "royalblue4",
                                               size = 12),
                    axis.text.y = element_text(colour = "royalblue4",
                                               size = 12),
                    text = element_text(size = 16),
                    panel.grid = element_line(colour="lightsteelblue1"))

ggplot(rna, aes(x = expression_log)) +
  geom_histogram(bins = 20) +
    blue_theme
Custrom 'blue_theme() showing a blue grid and blue axis legends.
Desafío

Desafío

Con toda esta información a mano, tómese otros cinco minutos para mejorar uno de los gráficos generados en este ejercicio o crear su propio gráfico impecable. Utilice la hoja de trucos ggplot2 de RStudio para inspirarse. Aquí tiene algunas ideas:

  • Mira si puedes cambiar el grosor de las líneas.
  • ¿Puedes encontrar una forma de cambiar el nombre de la leyenda? ¿Y sus etiquetas? (pista: busca una función de ggplot que empiece por scale_)
  • Prueba a utilizar una paleta de colores diferente o a especificar manualmente los colores de las líneas (consulta https://www.cookbook-r.com/Graphs/Colors_(ggplot2)/).

Por ejemplo, basándose en este gráfico:

R

ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())
Plain facetted line plot, as produced by theme_bw() and a blank grid above.

Podemos personalizarlo de las siguientes maneras:

R

# change the thickness of the lines
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line(size=1.5) +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank())

ADVERTENCIA

Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
This warning is displayed once per session.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
generated.
Plain facetted line plot, as produced by theme_bw() and a blank grid with wide lines.

R

# change the name of the legend and the labels
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_discrete(name = "Gender", labels = c("F", "M"))
Plain facetted line plot, as produced by theme_bw() and a blank grid with renamed colour labels.

R

# using a different color palette
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_brewer(name = "Gender", labels = c("F", "M"), palette = "Dark2")
Plain facetted line plot, as produced by theme_bw() and a blank grid with a different color palette and renamed colour labels.

R

# manually specifying the colors
ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  theme_bw() +
  theme(panel.grid = element_blank()) +
  scale_color_manual(name = "Gender",  labels = c("F", "M"),
                     values = c("royalblue", "deeppink"))
Plain facetted line plot, as produced by theme_bw() and a blank grid with a manually-set colors and renamed colour labels..

Composición de gráficos


El faceting es una herramienta excelente para dividir un gráfico en múltiples subgráficos, pero a veces es posible que desee crear una sola figura que contenga varios gráficos independientes, es decir, gráficos basados en variables diferentes o incluso en tablas de datos distintas.

Comencemos creando los dos gráficos que queremos disponer uno junto al otro:

El primer gráfico cuenta el número de genes únicos por cromosoma. Primero debemos reordenar los niveles de chromosome_name y filtrar los genes únicos por cromosoma. También cambiamos la escala del eje y a una escala logarítmica en base 10 para mejorar la legibilidad.

R

rna$chromosome_name <- factor(rna$chromosome_name,
                               levels = c(1:19,"X","Y"))

count_gene_chromosome <- rna |>
  select(chromosome_name, gene) |>
  distinct() |> ggplot() +
  geom_bar(aes(x = chromosome_name), fill = "seagreen",
           position = "dodge", stat = "count") +
  labs(y = "log10(n genes)", x = "chromosome") +
  scale_y_log10()

count_gene_chromosome
A simple histogram with greed bars showing the log10 number of genes per chromosome.

A continuación, también eliminamos la leyenda por completo estableciendo legend.position en "none".

R

exp_boxplot_sex <- ggplot(rna, aes(y=expression_log, x = as.factor(time),
                 color=sex)) +
   geom_boxplot(alpha = 0) +
  labs(y = "Mean gene exp",
       x = "time") + theme(legend.position = "none")

exp_boxplot_sex
Transparently-filled red and blue boxplots for Female and Male expression values for different time points.

El paquete patchwork ofrece un enfoque elegante para combinar figuras utilizando + para organizarlas (normalmente una al lado de la otra). Más concretamente, | las organiza explícitamente una al lado de la otra y / las apila una sobre otra.

R

install.packages("patchwork")

R

library("patchwork")
count_gene_chromosome + exp_boxplot_sex
A composed figure show the histogram (left) and boxplots (right) next to each other.

R

## or count_gene_chromosome | exp_boxplot_sex

R

count_gene_chromosome / exp_boxplot_sex
A composed figure show the histogram (top) and boxplots (bottom) on top or each other.

Podemos controlar aún más la disposición de la composición final con plot_layout para crear diseños más complejos:

R

count_gene_chromosome + exp_boxplot_sex + plot_layout(ncol = 1)
A composed figure show the histogram (top) and boxplots (bottom) on top or each other.

R

count_gene_chromosome +
 (count_gene_chromosome + exp_boxplot_sex) +
 exp_boxplot_sex +
 plot_layout(ncol = 1)
A figure composed of 4 plots with on top the histogram, in the middle the histogram and the boxpot, side-by-side, and at the bottom, the boxplot.

El último gráfico también puede crearse utilizando los compositores | y /:

R

count_gene_chromosome /
 (count_gene_chromosome | exp_boxplot_sex) /
 exp_boxplot_sex
As above, a figure composed of 4 plots with on top the histogram, in the middle the histogram and the boxpot, side-by-side, and at the bottom, the boxplot.

Obtenga más información sobre patchwork en su página web o en este video.

Otra opción es el paquete gridExtra, que permite combinar ggplots independientes en una sola figura mediante grid.arrange():

R

install.packages("gridExtra")

R

library("gridExtra")
grid.arrange(count_gene_chromosome, exp_boxplot_sex, ncol = 2)
A composed figure with the histogram (left) and boxplot (right) side-by-side.

Además de los argumentos ncol y nrow, utilizados para realizar diseños sencillos, existen herramientas para construir diseños más complejos.

Exportación de gráficos


Tras crear su gráfico, puede guardarlo en un archivo en su formato preferido. La pestaña Exportar en el panel Plot de RStudio guardará sus gráficos a baja resolución, la cual no será aceptada por muchas revistas y no escalará bien para pósteres.

En su lugar, utilice la función ggsave(), que le permite cambiar fácilmente la dimensión y la resolución de su gráfico ajustando los argumentos correspondientes (width, height y dpi).

Asegúrese de tener la carpeta fig_output/ en su directorio de trabajo.

R

my_plot <- ggplot(data = mean_exp_by_time_sex,
       mapping = aes(x = time, y = mean_exp, color = sex)) +
  geom_line() +
  facet_wrap(~ gene, scales = "free_y") +
  labs(title = "Mean gene expression by duration of the infection",
         x = "Duration of the infection (in days)",
         y = "Mean gene expression") +
  guides(color=guide_legend(title="Gender")) +
  theme_bw() +
  theme(axis.text.x = element_text(colour = "royalblue4", size = 12),
        axis.text.y = element_text(colour = "royalblue4", size = 12),
        text = element_text(size = 16),
        panel.grid = element_line(colour="lightsteelblue1"),
        legend.position = "top")
ggsave("fig_output/mean_exp_by_time_sex.png", my_plot, width = 15,
       height = 10)

# This also works for grid.arrange() plots
combo_plot <- grid.arrange(count_gene_chromosome, exp_boxplot_sex,
                           ncol = 2, widths = c(4, 6))
ggsave("fig_output/combo_plot_chromosome_sex.png", combo_plot,
       width = 10, dpi = 300)

Nota: Los parámetros width y height también determinan el tamaño de la fuente en el gráfico guardado.

Otros paquetes para la visualización


ggplot2 es un paquete muy potente que encaja a la perfección en nuestro pipeline de datos ordenados y herramientas ordenadas. Existen otros paquetes de visualización en R que no deben pasarse por alto.

Gráficos básicos

El sistema gráfico predeterminado que incluye R, a menudo llamado gráficos básicos de R, es sencillo y rápido. Se basa en el modelo del pintor o del lienzo, donde diferentes resultados se superponen directamente entre sí (véase la figura siguiente ). Esta es una diferencia fundamental con ggplot2 (y con lattice, descrito más adelante), que devuelve objetos dedicados que se renderizan en pantalla o en un archivo, e incluso pueden actualizarse.

R

par(mfrow = c(1, 3))
plot(1:20, main = "First layer, produced with plot(1:20)")

plot(1:20, main = "A horizontal red line, added with abline(h = 10)")
abline(h = 10, col = "red")

plot(1:20, main = "A rectangle, added with rect(5, 5, 15, 15)")
abline(h = 10, col = "red")
rect(5, 5, 15, 15, lwd = 3)
The 'base' figures, side-by-side, showing (from left to right) 20 empty dots along the diagonal, same with a vertical red line, and same as the second one with a rectangle overlaid in the middle of the plot.
Successive layers added on top of each other.

Otra diferencia principal es que las funciones de trazado de los gráficos básicos intentan hacer lo correcto según el tipo de entrada; es decir, adaptan su comportamiento en función de la clase de su entrada. Esto es, nuevamente, muy diferente a lo que tenemos en ggplot2, que solo acepta tablas de datos como entrada y requiere que los gráficos se construyan poco a poco.

R

par(mfrow = c(2, 2))
boxplot(rnorm(100),
        main = "Boxplot of rnorm(100)")
boxplot(matrix(rnorm(100), ncol = 10),
        main = "Boxplot of matrix(rnorm(100), ncol = 10)")
hist(rnorm(100))
hist(matrix(rnorm(100), ncol = 10))
A two-by-two composition of 2 boxplots at the top, and 2 histograms at the bottom.
Plotting boxplots (top) and histograms (bottom) vectors (left) or a matrices (right).

El enfoque estándar de los gráficos básicos puede ser muy eficiente para figuras sencillas y estándar, que pueden producirse muy rápidamente con una sola línea de código y una sola función como plot, o hist, o boxplot, … Sin embargo, los valores predeterminados no siempre son los más atractivos, y el ajuste de las figuras, especialmente cuando estas se vuelven más complejas (por ejemplo, para producir facetas), puede resultar largo y engorroso.

El paquete lattice

El paquete lattice es similar a ggplot2 en que utiliza tablas de datos como entrada, devuelve objetos gráficos y admite el faceting. lattice, sin embargo, no se basa en la gramática de gráficos y tiene una interfaz más compleja.

Una buena referencia para el paquete lattice es Deepayan (2008).

Puntos Clave
  • Visualización en R
Deepayan, Sarkar. 2008. Lattice: Multivariate Data Visualization with r. Springer. http://lmdvr.r-forge.r-project.org.
Wickham, Hadley. 2016. ggplot2: Elegant Graphics for Data Analysis. Springer-Verlag New York. http://ggplot2.org.
Wilkinson, Leland. 2005. The Grammar of Graphics (Statistics and Computing). Springer-Verlag.