¿Arte? Nubes aleatorias en {ggplot2}

8/11/2024

Temas: ggplot2 gráficos curiosidades

Probando un poco de arte generativo en {ggplot2}. La idea era generar gráficos que parecieran nubes o humo.

Tomé el dataframe iris, configuré algunos elementos aleatorios en el gráfico, le agregué un efecto de desenfoque a los puntos, y luego hice un loop que genera 9 gráficos con parámetros aleatorios.

library(dplyr)
library(glue)
library(ggplot2)
library(ggfx)
library(purrr)

Partimos con un gráfico base usando los datos de iris, donde los puntos crecen en base a una variable, y también aumentan su transparencia en la misma medida que aumentan su tamaño. De esta forma, los puntos más grandes son también menos visibles.

iris |> 
  ggplot(aes(x = Sepal.Length, y = Sepal.Width, alpha = Petal.Length,
             size = Petal.Length, color = Sepal.Width)) +
  geom_point() +
  theme_void() +
  scale_size(range = c(2, 5)) +
  scale_alpha(range = c(.7, .1)) +
  scale_color_gradient2(low = "red", mid = "purple", high = "blue", 
                        midpoint = mean(iris$Sepal.Width)) +
  theme(legend.position = "none") +
  theme(plot.margin = margin(rep(2, 4))) + # margen interior del gráfico
  coord_cartesian(clip = "off") +
  theme(plot.background = element_rect(fill = "#E9DEED", linewidth = 0))

Luego que tenemos un gráfico base, hacemos una prueba aplicando geom_jitter() a los puntos, que hace que la posición de los puntos sea siempre aleatoria, y cambiamos los rangos de tamaño y de transparencia:

iris |> 
  ggplot(aes(x = Sepal.Length, y = Sepal.Width, alpha = Petal.Length,
             size = Petal.Length, color = Sepal.Width)) +
  geom_jitter(width = 1, height = 1) +
  theme_void() +
  scale_size(range = c(8, 70)) +
  scale_alpha(range = c(.1, .0)) +
  scale_color_gradient2(low = "red", mid = "purple", high = "blue", 
                        midpoint = mean(iris$Sepal.Width)) +
  theme(legend.position = "none") +
  theme(plot.margin = margin(rep(60, 4))) + # margen interior del gráfico
  coord_cartesian(clip = "off") +
  theme(plot.background = element_rect(fill = "#E9DEED", linewidth = 0))

Ahora que tenemos un gráfico de movimiento aleatorio, agregamos a geom_jitter() la función with_blur() del paquete {ggfx}, que desenfoca el elemento al que se la apliquemos. Así creamos el efecto de humo o nube:

iris |> 
  ggplot(aes(x = Sepal.Length, y = Sepal.Width, alpha = Petal.Length,
             size = Petal.Length, color = Sepal.Width)) +
  geom_jitter(width = 1, height = 1) |> with_blur(sigma = 7) +
  theme_void() +
  scale_size(range = c(8, 70)) +
  scale_alpha(range = c(.1, .0)) +
  scale_color_gradient2(low = "red", mid = "purple", high = "blue", 
                        midpoint = mean(iris$Sepal.Width)) +
  theme(legend.position = "none") +
  theme(plot.margin = margin(rep(60, 4))) + # margen interior del gráfico
  coord_cartesian(clip = "off") +
  theme(plot.background = element_rect(fill = "#E9DEED", linewidth = 0))

Una vez que tenemos un gráfico interesante, le agregamos más parámetros aleatorios, y lo metemos dentro de purrr::map() para generar muchos gráficos de una sola vez:

map(1:9, ~{
  # parámetros aleatorios
  jitter_x = sample(seq(0.7, 1.2, 0.1), 1) # 1
  jitter_y = sample(seq(0.7, 1.2, 0.1), 1) # 1
  tamaño_max = sample(seq(40, 80, 5), 1) # 60
  tamaño_min = sample(seq(5, 20, 5), 1) # 10
  centro_color = sample(iris$Sepal.Width, 1)
  
  # generar
  iris |> 
    ggplot(aes(x = Sepal.Length, y = Sepal.Width, alpha = Petal.Length,
               size = Petal.Length, color = Sepal.Width)) +
    geom_jitter(width = jitter_x, height = jitter_y) |> with_blur(sigma = 9) +
    theme_void() +
    scale_size(range = c(tamaño_min, tamaño_max)) +
    scale_alpha(range = c(.07, .0)) +
    scale_color_gradient2(low = "red", mid = "purple", high = "blue", 
                          midpoint = centro_color) +
    theme(legend.position = "none") +
    theme(plot.margin = margin(rep(60, 4))) + # margen interior del gráfico
    coord_cartesian(clip = "off") +
    theme(plot.background = element_rect(fill = "#E9DEED", linewidth = 0))
  
  # guardar
  # ggsave(glue("nubes/orbe_{sample(111:999, 1)}.png"), 
  #        width = 3, height = 3, scale = 2, dpi = 200)
})
[[1]]
[[2]]
[[3]]
[[4]]
[[5]]
[[6]]
[[7]]
[[8]]
[[9]]

Si queremos guardar los resultados a una carpeta, agregamos el siguiente código dentro de la iteración con map() para guardar los gráficos en una carpeta, dándole a los archivos nombres aleatorios para que no se sobreescriban.

# guardar
ggsave(glue("nubes_{sample(111:999, 1)}.png"),
       width = 3, height = 3, scale = 2, dpi = 200)
Fecha de publicación:
November 8, 2024
Extensión:
3 minute read, 622 words
Tags:
ggplot2 gráficos curiosidades
Ver también:
Portafolio de trabajos previos en R
Visualización y scraping de resultados en vivo de las elecciones municipales 2024
Números romanos en R