Geoms básicos: punto, línea, barra

r
visualizacion
ggplot2
Los tres geoms que cubren el 80% de los gráficos. geom_point con jitter y alpha para overplotting, geom_line con group, y la distinción crítica entre geom_col y geom_bar.

El rey del EDA: geom_point

Si solo pudieras aprender un geom, sería este. geom_point dibuja un punto por fila del data frame. Es la base del scatter plot y la primera herramienta para explorar la relación entre dos variables.

library(ggplot2)
library(palmerpenguins)

ggplot(penguins, aes(x = bill_length_mm, y = flipper_length_mm)) +
  geom_point()

Tres parámetros que vas a usar todo el tiempo:

geom_point(
  size  = 2.5,     # tamaño del marcador
  alpha = 0.6,     # transparencia (0 = invisible, 1 = opaco)
  shape = 21       # forma; 21 permite color (borde) + fill (relleno)
)

Overplotting: cuando hay demasiados puntos

Con muchos datos (>5 000 puntos) los marcadores se solapan y pierdes información. Dos remedios:

alpha para transparencia:

ggplot(diamonds, aes(carat, price)) +
  geom_point(alpha = 0.05)

Cada punto se vuelve casi transparente. Donde hay muchos solapados, la suma se opaca. Es una mini-visualización de densidad gratis.

geom_jitter para datos discretos:

ggplot(penguins, aes(species, flipper_length_mm)) +
  geom_jitter(width = 0.2, alpha = 0.5)

geom_jitter añade ruido aleatorio en X (y opcionalmente en Y). Cuando una variable categórica fuerza a todos los puntos a colocarse en la misma línea vertical, el jitter los reparte para que se vean.

Series y trayectorias: geom_line

geom_line conecta puntos con líneas. Casi siempre se usa para series temporales (X = tiempo) o trayectorias (X = ordenable).

ggplot(economics, aes(date, unemploy)) +
  geom_line()

El problema de group

Cuando hay varias series, hay que decirle a ggplot2 cuál es cuál:

# Mal: una sola línea que zigzaguea entre grupos
ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_line()

# Bien: una línea por especie (group implícito por color)
ggplot(penguins, aes(bill_length_mm, flipper_length_mm, color = species)) +
  geom_line()

# Equivalente con group explícito (sin colorear)
ggplot(penguins, aes(bill_length_mm, flipper_length_mm, group = species)) +
  geom_line()

Cualquier aesthetic categórico (color, linetype, group) agrupa automáticamente. Si no hay ninguno, ggplot2 dibuja una sola línea conectando todos los puntos en el orden en que aparecen, y eso casi nunca es lo que quieres.

Regla mental: si tu gráfico de líneas se ve como una madeja, te falta group.

Barras: geom_col vs geom_bar

Aquí está la decisión más subestimada de ggplot2. Lee con atención:

  • geom_bar() toma una variable categórica en X y cuenta cuántas filas hay de cada categoría. La Y la calcula automáticamente. No le pases Y.
  • geom_col() toma X y Y y dibuja barras de esa altura. La Y la pasas tú.
# geom_bar: cuenta cuántos pingüinos hay de cada especie
ggplot(penguins, aes(x = species)) +
  geom_bar()

# geom_col: dibuja barras con la altura que tú especifiques
resumen <- penguins |>
  dplyr::group_by(species) |>
  dplyr::summarise(media_peso = mean(body_mass_g, na.rm = TRUE),
                   .groups = "drop")

ggplot(resumen, aes(x = species, y = media_peso)) +
  geom_col()

Confundirlos es el error clásico:

ggplot(resumen, aes(x = species, y = media_peso)) +
  geom_bar()   # ERROR — geom_bar no acepta Y por defecto

Esto fallaba en versiones antiguas. Ahora avisa: “prefer geom_bar(stat = 'identity') or use geom_col(). La opción limpia es geom_col().

Regla mental: ¿estoy contando? geom_bar. ¿tengo ya el valor? geom_col.

Apilar vs agrupar

Cuando una barra se subdivide por otra categoría:

# Apiladas (default)
ggplot(penguins, aes(species, fill = sex)) +
  geom_bar()

# Lado a lado (dodged)
ggplot(penguins, aes(species, fill = sex)) +
  geom_bar(position = "dodge")

# Apiladas pero normalizadas al 100%
ggplot(penguins, aes(species, fill = sex)) +
  geom_bar(position = "fill")

position controla cómo se resuelve la superposición. "identity" (no resolverla) tiene poco sentido en barras pero existe.

Combinar geoms en capas

Lo que hace ggplot2 distinto: los geoms se acumulan. Un scatter con línea de tendencia es dos capas:

ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_point(alpha = 0.5) +
  geom_smooth(method = "lm", se = TRUE)

geom_smooth añade una línea suavizada (con bandas de error si se = TRUE). Método "lm" para regresión lineal, "loess" para suavizado local, "gam" para regresiones aditivas generalizadas.

# Puntos coloreados por especie + smooth global en negro
ggplot(penguins, aes(bill_length_mm, flipper_length_mm)) +
  geom_point(aes(color = species), alpha = 0.5) +
  geom_smooth(method = "lm", color = "black", se = FALSE)

Aquí el geom_point colorea por especie (mapeo dentro de aes). El geom_smooth es negro fijo (constante, fuera de aes), porque queremos una sola línea para todo el dataset, no una por especie.

Trampas habituales

  • geom_bar con y = aesthetic. El error que ocurre cuando uno aprende ggplot2 con tutoriales antiguos. Usa geom_col() cuando ya tengas la altura calculada.
  • Líneas que zigzaguean. Te falta group = (o un color =, que agrupa implícitamente). Caso típico: serie temporal con múltiples cohortes y has olvidado el group = cohorte.
  • alpha demasiado bajo. alpha = 0.05 funciona con miles de puntos. Con doscientos hace que el gráfico parezca vacío. Empieza con alpha = 0.5 y baja si el overplotting persiste.
  • size en lugar de linewidth para líneas. Desde ggplot2 3.4, size solo aplica al tamaño del marcador en geoms de puntos. Para grosor de línea es linewidth. El warning lo dice claro. Léelo.

En la siguiente entrega

Has cubierto los tres geoms más útiles. Quedan los que se ocupan específicamente de mostrar distribuciones: histogram, density, boxplot y violin. Cada uno responde una pregunta distinta sobre los mismos datos, y elegir el correcto separa visualizaciones honestas de las que mienten por accidente. Es lo siguiente.