🎨 Taller: Visualización de datos con R y ggplot2

Encuentro 2: Diseño y estética

Pablo Tiscornia

Estación R

2025-09-04

Bienvenidos y bienvenidas al Encuentro 2 🎨

Repaso del encuentro anterior

✅ Lo que ya sabemos

  • Gramática de los gráficos: data + aesthetics + geoms
  • Estructura básica de ggplot2: ggplot(data, aes(x, y)) + geom_*()
  • Diferencia entre mapeo (aes()) y fijación de parámetros


🎯 Lo que veremos hoy

  • Personalización visual: colores, títulos, etiquetas
  • Paletas de colores profesionales y accesibles
  • Organización espacial: facets y patchwork
  • Buenas prácticas de diseño

🎨 Personalización visual

Títulos y etiquetas con labs()

ggplot(tbl_desocup_2020_25, 
       aes(x = Anio, y = n)) +
  geom_col(fill = "#4F7CFF") +
  labs(
    title = "Evolución de la desocupación",
    subtitle = "Argentina 2020-2025", 
    x = "Año",
    y = "Cantidad de desocupados"
  )

Elementos que podés personalizar:

  • title: Título principal
  • subtitle: Subtítulo
  • x, y: Etiquetas de ejes
  • caption: Pie de gráfico
  • fill, color: Etiquetas de leyenda

📏 Escalas en ggplot2

¿Qué son las escalas?

Una capa más en la gramática

  • Traducen datos en propiedades visuales
  • Controlan rangos y límites de ejes y colores
  • Formatean etiquetas (números, fechas, porcentajes)
  • Se agregan automáticamente pero se pueden personalizar

Sintaxis general

scale_<aesthetic>_<type>(
  name = "Etiqueta",
  limits = c(min, max),
  labels = función_formato,
  breaks = valores_ejes
)

Tipos de escalas

🗺️ Escalas de posición

Controlan ejes X e Y

  • scale_x_continuous(): números
  • scale_y_discrete(): categorías
  • scale_x_date(): fechas
  • scale_y_log10(): transformaciones

Mapeo: aes(x = variable, y = variable)

🎨 Escalas estéticas

Controlan colores, formas, tamaños

  • scale_fill_manual(): colores de relleno
  • scale_color_brewer(): colores de líneas/puntos
  • scale_size_continuous(): tamaños
  • scale_shape_discrete(): formas

Mapeo: aes(fill = variable, color = variable)

Control de escalas

Eje Y: formato y límites

ggplot(tbl_desocup_2020_25, aes(x = Anio, y = n)) +
  geom_col(fill = "#4F7CFF") +
  scale_y_continuous(
    labels = label_comma(),
    limits = c(0, max(tbl_desocup_2020_25$n) * 1.1),
    breaks = scales::pretty_breaks(n = 6)
  ) +
  theme_minimal()

Control de escalas

Eje X: categorías y orden

ggplot(tbl_desocup_2020_25, aes(x = factor(Anio), y = n)) +
  geom_col(fill = "#4F7CFF") +
  scale_x_discrete(
    labels = paste0("'", substr(tbl_desocup_2020_25$Anio, 3, 4))
  ) +
  labs(x = "Año") +
  theme_minimal()

🌈 Paletas de colores

El poder del color en visualización

Color como información

  • Categorías: distinguir grupos
  • Magnitudes: mostrar intensidad
  • Emociones: transmitir sensaciones
  • Jerarquías: destacar elementos importantes

Consideraciones importantes

  • Accesibilidad: daltonismo
  • Contraste: legibilidad
  • Contexto cultural: significados
  • Medio: pantalla vs. impresión

Tipos de paletas

Cualitativas

Para categorías sin orden

Set2, Dark2, Accent

Secuenciales

Para valores ordenados

Blues, Reds, viridis

Divergentes

Para datos con punto medio

RdYlBu, RdBu, Spectral

Aplicando paletas con RColorBrewer

Variables categóricas

ggplot(tbl_desocup_2020_25, 
       aes(x = Anio, y = n, fill = factor(Anio))) +
  geom_col() +
  scale_fill_brewer(type = "qual", palette = "Set2") +
  theme_minimal() +
  guides(fill = "none")

Paletas viridis: accesibles por defecto

ggplot(tbl_desocup_2020_25, 
       aes(x = Anio, y = n, fill = n)) +
  geom_col() +
  scale_fill_viridis_c(option = "plasma") +
  theme_minimal()

Ejercicio 🎯 - Personalización básica

Usando los datos tbl_desocup_2020_25, creá un gráfico que incluya:


  1. Título: “Desocupación en Argentina”
  2. Subtítulo: “Período 2020-2025”
  3. Etiquetas de ejes apropiadas
  4. Paleta de colores de tu elección
  5. Formato de números con separador de miles


⏰ Tiempo: 5 minutos

Solución - Personalización básica

ggplot(tbl_desocup_2020_25, 
       aes(x = Anio, y = n, fill = factor(Anio))) +
  geom_col() +
  scale_fill_brewer(type = "qual", palette = "Set2") +
  scale_y_continuous(labels = label_comma()) +
  labs(
    title = "Desocupación en Argentina",
    subtitle = "Período 2020-2025",
    x = "Año",
    y = "Cantidad de desocupados",
    caption = "Fuente: EPH - INDEC"
  ) +
  theme_minimal() +
  guides(fill = "none")

🏗️ Organización espacial

Facetas: dividir para conquistar

Un gráfico por categoría con facet_wrap()

df_por_aglo <- df_eph |> 
  filter(ESTADO %in% c(1, 2)) |>
  count(ANO4, AGLOMERADO, ESTADO, name = "poblacion")

ggplot(df_por_aglo, aes(x = ANO4, y = poblacion)) +
  geom_line(aes(color = factor(ESTADO)), size = 1.2) +
  facet_wrap(~ AGLOMERADO, scales = "free_y") +
  theme_minimal()

Configurando facetas

Controlando escalas y disposición

ggplot(df_por_aglo, aes(x = ANO4, y = poblacion, color = factor(ESTADO))) +
  geom_line(size = 1.2) +
  facet_wrap(~ AGLOMERADO, ncol = 3, scales = "fixed") +
  scale_color_manual(values = c("1" = "#4F7CFF", "2" = "#FF6B6B"), 
                     labels = c("1" = "Ocupados", "2" = "Desocupados")) +
  theme_minimal() +
  labs(color = "Estado laboral")

Patchwork: combinando gráficos

Instalación y carga

# install.packages("patchwork")
library(patchwork)

Sintaxis simple e intuitiva

p1 <- ggplot(tbl_desocup_2020_25, aes(x = Anio, y = n)) +
  geom_col(fill = "#4F7CFF") + theme_minimal()

p2 <- ggplot(tbl_desocup_2020_25, aes(x = Anio, y = n)) +
  geom_line(group = 1, color = "#FF6B6B", size = 1.5) + 
  geom_point(color = "#FF6B6B", size = 3) + theme_minimal()

p1 + p2

Layouts complejos con patchwork

p3 <- ggplot(tbl_desocup_2020_25, aes(x = factor(Anio), y = n)) +
  geom_boxplot(fill = "#66C2A5") + theme_minimal()

(p1 + p2) / p3

🎯 Buenas prácticas de diseño

Principios fundamentales

1. Claridad

  • Una idea principal por gráfico
  • Títulos descriptivos y precisos
  • Ejes etiquetados claramente
  • Leyendas necesarias solamente

2. Simplicidad

  • Menos es más: eliminar elementos innecesarios
  • Colores con propósito: máximo 5-7 colores
  • Tipografía consistente
  • Espacios en blanco estratégicos


3. Consistencia

  • Paletas coherentes en serie de gráficos
  • Escalas similares para comparación
  • Formato uniforme de números y fechas

4. Accesibilidad

  • Contraste suficiente (4.5:1 mínimo)
  • Paletas daltonismo-friendly
  • Texto alternativo para lectores de pantalla

❌ Errores comunes a evitar

El gráfico de torta 3D

Problemas:

  • Difícil comparar proporciones
  • Colores muy saturados
  • 3D distorsiona percepción
  • Muchas categorías

✅ Mejor alternativa: gráfico de barras

ggplot(datos_malos, aes(x = reorder(categoria, valor), y = valor)) +
  geom_col(fill = "#4F7CFF") +
  coord_flip() +
  scale_y_continuous(labels = label_percent(scale = 1)) +
  theme_minimal() +
  labs(
    title = "✅ Fácil de interpretar",
    x = "Categoría",
    y = "Porcentaje"
  )

Mejoras:

  • Comparación directa
  • Colores sobrios
  • Ordenado por valor
  • Etiquetas claras

Preparación para publicación

theme() para ajustes finos

ggplot(tbl_desocup_2020_25, aes(x = Anio, y = n)) +
  geom_col(fill = "#4F7CFF") +
  scale_y_continuous(labels = label_comma()) +
  labs(
    title = "Desocupación en Argentina",
    subtitle = "Evolución 2020-2025",
    x = "Año", y = "Desocupados"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 16, face = "bold", hjust = 0.5),
    plot.subtitle = element_text(size = 12, hjust = 0.5, color = "grey50"),
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 10)
  )

Ejercicio integrador 🚀

Creá una visualización completa que incluya:

  1. Datos: Usar df_eph filtrado por región y estado laboral
  2. Facetas: Un panel por región
  3. Colores: Paleta profesional para estados laborales
  4. Personalización: Títulos, subtítulos, etiquetas
  5. Tema: Limpio y profesional

Pista:

df_ejercicio <- df_eph |> 
  filter(ESTADO %in% c(1, 2), AGLOMERADO %in% c(32, 17, 30)) |>
  count(ANO4, AGLOMERADO, ESTADO)

⏰ Tiempo: 10 minutos

Solución - Ejercicio integrador

df_ejercicio <- df_eph |> 
  filter(ESTADO %in% c(1, 2), AGLOMERADO %in% c(32, 17, 30)) |>
  count(ANO4, AGLOMERADO, ESTADO) |>
  mutate(
    AGLOMERADO = case_when(
      AGLOMERADO == 32 ~ "CABA",
      AGLOMERADO == 17 ~ "Neuquén - Plottier", 
      AGLOMERADO == 30 ~ "Santa Rosa - Toay",
    ),
    ESTADO = factor(ESTADO, labels = c("Ocupados", "Desocupados"))
  )


ggplot(df_ejercicio, aes(x = ANO4, y = n, fill = ESTADO)) +
  geom_col(position = "dodge") +
  facet_wrap(~ AGLOMERADO, scales = "free_y") +
  scale_fill_manual(values = c("Ocupados" = "#4F7CFF", "Desocupados" = "#FF6B6B")) +
  scale_y_continuous(labels = label_comma()) +
  labs(
    title = "Población activa por región",
    subtitle = "Ocupados y desocupados 2020-2025",
    x = "Año", y = "Población", fill = "Estado"
  ) +
  theme_minimal() +
  theme(
    plot.title = element_text(size = 14, face = "bold"),
    strip.text = element_text(face = "bold")
  )

📚 Recursos para la próxima clase

Lo que veremos en el Encuentro 3

📝 Anotaciones inteligentes

  • annotate(), geom_text(), geom_label()
  • Resaltar puntos importantes
  • Narrativas visuales efectivas


🚀 Interactividad básica

  • ggplotly() para gráficos interactivos
  • Tooltips y zoom
  • Exportación con ggsave()


🎯 Para practicar

  • Experimentar con diferentes paletas
  • Crear layouts complejos con {patchwork}
  • Explorar temas avanzados

Tarea para el próximo encuentro

🏠 Práctica recomendada:

  1. Elegí un dataset de tu interés
  2. Creá 3 visualizaciones diferentes usando lo aprendido:
    • Una con facetas
    • Una con paleta personalizada
    • Una combinación con patchwork
  3. Aplicá buenas prácticas de diseño
  4. Compartí en Slack tus creaciones


Recordá: La práctica hace al maestro. ¡Experimentá sin miedo!

¡Gracias!

🎨 ¡Seguimos visualizando!

Nos vemos en el Encuentro 3

📧 pablotiscornia@estacion-r.com

🌐 www.estacion-r.com

🐦 @estacion_erre