Cómo evitar solapamiento de texto en ggplot

Continuamos un post más con edición avanzada de texto en ggplot con R. En el post de hoy aprenderemos a evitar el solapamiento de texto en ggplot, algo muy habitual cuando se trabaja con etiquetas en un gráfico. ¡Empezamos!

Datos y gráfico de Netflix

Utilizamos el dataset del último post con nuevas variables: el año de estreno de la película y su duración en minutos. Así, representaremos una variable frente a la otra y, a modo de ejemplo, añadiremos las etiquetas del top 3 de títulos de mayor y menor duración.

library(tidyverse)
library(lubridate)

df <- read.csv('https://raw.githubusercontent.com/elartedeldato/datasets/main/netflix_titles.csv')
df %>% 
  filter(str_detect(description, 'high school'), type=='Movie') %>%
  mutate(duration:=as.numeric(str_remove(duration, ' min'))) %>%
  select(release_year, duration, title) -> df_title

df_title %>%
  mutate(top_duration:=rank(desc(duration))) -> df_title
  
ggplot(df_title) + 
  geom_point(aes(x=release_year, y=duration), color='red') + 
  theme_bw() +
  theme(legend.position= 'none',
        axis.title = element_text(family='PermanentMarker-Regular', size=10, color='white', margin=margin(5,0,5,0)),
        axis.text = element_text(family='PermanentMarker-Regular', size=10, color='white'),
        panel.grid = element_blank(),
        panel.grid.major.y = element_line(size=0.05, color='white'),
        panel.background = element_rect(fill='black'),
        plot.background = element_rect(fill='black', color='black'),
        panel.border = element_blank(),
        plot.title = element_text(family='BebasNeue-Regular', color='red',size=45, margin=margin(15,0,5,0)),
        plot.subtitle = element_text(family='PermanentMarker-Regular', size=10, color='white'),
        plot.caption =  element_text(family='PermanentMarker-Regular', color='white',size=7,  margin=margin(30,0,0,0))) +
  labs(title='Netflix',
       subtitle='Duración de las películas sobre High School por año de estreno',
       caption = "Fuente: Kaggle",
       x='Año de estreno', y='Duración en min') -> p

p

Añadir etiquetas de texto

Existen dos geometrías en ggplot que permiten añadir texto. Una es, geom_text() y la otra geom_label(). Ambas están pensadas para visualizar variables de tipo carácter de un dataset, aunque la segunda dibuja a mayores una caja rectangular que contiene el texto, facilitando así su lectura.

p +   geom_text(data=subset(df_title, top_duration<=3 | top_duration>=78), 
            aes(x=release_year, y=duration, label=title), 
            family='PermanentMarker-Regular', size=4, color='white', nudge_y=3)

Como vemos, es complicado discernir los títulos entre sí y entender el texto. Además, en las etiquetas situadas muy cerca de los límites del panel se meustran cortadas. Ésto nos obliga a expandir los límites del gráfico y mover manualmente cada etiqueta, lo cuál es posible, pero sin duda muy engorroso.

También hemos incluido el argumento nudge_y=3, para “subir” el texto 3 puntos verticalmente, y no solaparse con los putnos del gráfico, pero aún así los problemas de lectura permanecen.

Evitar solapamiento del texto con ggrepel

El solapamiento del texto se puede evitar utilizando una de las librerías extra de ggplot más conocidas: ggrepel. Esta librería proporciona dos geometrías equivalentes a las anteriormente nombradas, véase geom_text_repel() y geom_label_repel() con las mismas diferencias y similitudes que las originales de ggplot.

La salvedad, es que automáticamente ajustan el espacio entre elementos del gráfico y sus márgenes y sitúan generalmente en posiciones visibles las diferentes etiquetas. Decimos generalmente porque realmente hay situaciones en las que es difícil evitar un reajuste manual de la posiciones de los labels.

library(ggrepel)
p + geom_text_repel(data=subset(df_title, top_duration<=3 | top_duration>=78), 
            aes(x=release_year, y=duration, label=title), 
            family='PermanentMarker-Regular', size=4, color='white')

Alejar las etiquetas de texto

Otra idea para que quede más claro a qué punto se refiere cada etiqueta, es expandir el tamaño de la caja contenedora (invisible) de la geometría geom_text_repel, aumentando el box.padding.

p + geom_text_repel(data=subset(df_title, 
                                top_duration<=3 | top_duration>=78), 
            aes(x=release_year, y=duration, label=title), 
            family='PermanentMarker-Regular', size=4, color='white', box.padding = 0.6)

Paula L. Casado
Paula L. Casado
Data Scientist

Científica de datos especializada en visualización de datos.

Relacionado