Analítica de Personas · Semestre otoño 2026 · Semana 1 · Prof. René Gempp
ggplot2 construye gráficos capa por capa, como si fueras apilando transparencias. Cada capa agrega un elemento visual. Las capas se conectan con el signo + (no con el pipe |>).
+, no |>
Dentro de ggplot2, las capas se conectan con +. El pipe |> se usa para pasar datos antes de ggplot, pero una vez que escribes ggplot(), todo lo que sigue usa +. Es el error más común de la semana 1.
aes(): mapeo de variables a propiedades visualesaes() (de aesthetics) le dice a ggplot qué variable del dataset controla qué propiedad visual del gráfico:
| Propiedad | Qué controla | Ejemplo |
|---|---|---|
x | Posición en el eje horizontal | aes(x = edad) |
y | Posición en el eje vertical | aes(y = ingreso_mensual) |
fill | Color de relleno (barras, áreas) | aes(fill = genero) |
color | Color de borde o línea | aes(color = departamento) |
size | Tamaño del punto o línea | aes(size = antiguedad) |
aes()
Si una propiedad visual depende de una variable del dataset, va dentro de aes(). Si es un valor fijo para todos los datos, va fuera:
# El COLOR depende de la variable "genero" → dentro de aes()
ggplot(innovaco, aes(x = departamento, fill = genero)) +
geom_bar()
# TODAS las barras son verdes (valor fijo) → fuera de aes()
ggplot(innovaco, aes(x = departamento)) +
geom_bar(fill = "#2C5F2D")
Cada geom_*() dibuja los datos de una manera distinta. La elección depende de qué tipo de variables tienes y qué pregunta quieres responder:
| Quiero ver... | Variable(s) | geom |
|---|---|---|
| Distribución de una variable numérica | 1 numérica | geom_histogram() |
| Conteo por categorías | 1 categórica | geom_bar() |
| Valores ya calculados en barras | 1 categórica + 1 numérica | geom_col() |
| Comparar distribuciones entre grupos | 1 categórica + 1 numérica | geom_boxplot() |
| Relación entre dos numéricas | 2 numéricas | geom_point() |
| Distribución suavizada | 1 numérica | geom_density() |
geom_histogram() — Distribución de una variable numéricaDivide una variable numérica en intervalos (bins) y cuenta cuántas observaciones caen en cada uno. Ideal para responder: ¿cómo se distribuye la edad/ingreso/antigüedad?
ggplot(innovaco, aes(x = edad)) +
geom_histogram(
binwidth = 3, # Ancho de cada barra: cada 3 años
fill = "#2C5F2D", # Color de relleno
color = "white" # Color del borde
) +
labs(
title = "Distribución de Edad en InnovaCo",
x = "Edad (años)",
y = "Número de empleados"
) +
theme_minimal()
| Argumento | Qué hace | Valores típicos |
|---|---|---|
binwidth | Ancho de cada barra (en unidades de la variable) | 3 para edad, 100000 para ingreso |
bins | Número total de barras (alternativa a binwidth) | 20, 30 |
fill | Color de relleno de las barras | "#2C5F2D", "steelblue" |
color | Color del borde de las barras | "white", "black" |
binwidth o bins?
Usa binwidth cuando la unidad tiene significado (3 años de edad, $100.000 de ingreso). Usa bins cuando solo quieres controlar cuántas barras hay. Si no pones ninguno, R usa 30 bins por defecto y te avisa con un mensaje.
geom_bar() — Contar automáticamente por categoríaCuenta cuántas filas hay por cada valor de la variable categórica. No necesitas calcular nada antes: ggplot cuenta por ti.
# Conteo simple por departamento
ggplot(innovaco, aes(x = departamento)) +
geom_bar(fill = "#065A82") +
labs(title = "Empleados por departamento", x = NULL, y = "Cantidad") +
theme_minimal()
# Barras agrupadas por género (fill dentro de aes)
ggplot(innovaco, aes(x = departamento, fill = genero)) +
geom_bar(position = "dodge") +
labs(title = "Composición por departamento y género") +
theme_minimal()
| Argumento | Qué hace | Opciones |
|---|---|---|
position | Cómo se organizan las barras cuando hay grupos | "stack" (apiladas, default), "dodge" (lado a lado), "fill" (proporcional) |
fill | Color de relleno (fijo, fuera de aes) | Cualquier color |
position = "dodge" vs "fill"
"dodge" muestra barras lado a lado (compara cantidades absolutas). "fill" normaliza cada barra al 100% (compara proporciones). Para comparar tasas de rotación entre departamentos, "fill" es más útil.
geom_col() — Barras con valores ya calculadosA diferencia de geom_bar() que cuenta por ti, geom_col() necesita que le des tanto el eje x como el eje y. Úsalo cuando ya calculaste los valores con summarise():
# Primero calculo la tasa de rotación por departamento
rotacion_depto <- innovaco |>
group_by(departamento) |>
summarise(tasa_rotacion = mean(rotacion == "Sí"))
# Luego grafico con geom_col (necesito x e y)
ggplot(rotacion_depto, aes(x = departamento, y = tasa_rotacion)) +
geom_col(fill = "#B85042") +
scale_y_continuous(labels = scales::percent) +
labs(title = "Tasa de rotación por departamento") +
theme_minimal()
geom_bar() o geom_col()?geom_bar(): ggplot cuenta por ti → solo necesitas aes(x = variable)
geom_col(): tú ya calculaste los valores → necesitas aes(x = categoría, y = valor)
geom_boxplot() — Comparar distribuciones entre gruposMuestra la mediana, cuartiles y valores atípicos de una variable numérica, separada por grupos. Ideal para preguntas como: ¿varía el ingreso entre niveles jerárquicos?
ggplot(innovaco, aes(x = nivel_jerarquico, y = ingreso_mensual)) +
geom_boxplot(fill = "#A7BEAE", color = "#2C5F2D") +
labs(
title = "Distribución de ingreso por nivel jerárquico",
x = "Nivel", y = "Ingreso mensual (CLP)"
) +
theme_minimal()
Lectura de un boxplot: La línea gruesa del centro es la mediana. La caja va del primer cuartil (25%) al tercer cuartil (75%). Los puntos fuera de los "bigotes" son valores atípicos.
labs(), scale_*() y theme_*()labs()labs(
title = "Título principal del gráfico",
subtitle = "Subtítulo que aporta contexto",
x = "Nombre del eje X",
y = "Nombre del eje Y",
fill = "Nombre de la leyenda", # si usas fill en aes
caption = "Fuente: HRIS InnovaCo" # nota al pie
)
scale_*()# Eje Y como porcentaje
+ scale_y_continuous(labels = scales::percent)
# Eje Y como pesos chilenos
+ scale_y_continuous(labels = scales::comma)
# Colores personalizados para categorías
+ scale_fill_manual(values = c("Hombre" = "#065A82", "Mujer" = "#F96167"))
# Límites del eje
+ scale_y_continuous(limits = c(0, 0.5))
| Tema | Estilo | Recomendación |
|---|---|---|
theme_minimal() | Limpio, fondo blanco, sin bordes | Nuestro default en el curso |
theme_classic() | Solo ejes, sin grilla | Estilo publicación académica |
theme_bw() | Fondo blanco con marco | Formal |
theme_gray() | Default de ggplot (fondo gris) | Evitar en reportes ejecutivos |
coord_flip()Cuando los nombres de las categorías son largos (como nombres de departamento), las barras horizontales son más legibles:
ggplot(rotacion_depto, aes(x = reorder(departamento, tasa_rotacion),
y = tasa_rotacion)) +
geom_col(fill = "#B85042") +
coord_flip() + # Voltea el gráfico
theme_minimal()
reorder(departamento, tasa_rotacion) ordena las barras de menor a mayor tasa. Así el departamento con más rotación queda arriba (más visible).
geom_text()+ geom_text(
aes(label = scales::percent(tasa_rotacion, accuracy = 0.1)),
hjust = -0.1, # Desplaza el texto a la derecha de la barra
size = 3.5 # Tamaño del texto
)
facet_wrap()# Un histograma de edad por cada departamento
ggplot(innovaco, aes(x = edad)) +
geom_histogram(binwidth = 3, fill = "#065A82", color = "white") +
facet_wrap(~departamento, ncol = 2) + # ~ antes de la variable
theme_minimal()
Copia y modifica esta plantilla para cualquier gráfico de barras en el curso:
# --- Plantilla de gráfico de barras ---
ggplot(MIS_DATOS, aes(x = reorder(MI_VARIABLE_X, MI_VARIABLE_Y),
y = MI_VARIABLE_Y)) +
geom_col(fill = "#0D9488") +
geom_text(aes(label = round(MI_VARIABLE_Y, 1)),
hjust = -0.1, size = 3.5) +
coord_flip() +
labs(
title = "MI TÍTULO",
subtitle = "Mi subtítulo con el hallazgo",
x = NULL,
y = "Mi eje Y",
caption = "Fuente: HRIS InnovaCo"
) +
theme_minimal()
| Error | Causa | Solución |
|---|---|---|
Error: unexpected '+' o gráfico incompleto |
El + quedó al inicio de la línea siguiente en vez del final de la anterior |
Siempre deja el + al final de la línea, no al principio de la siguiente |
| Se abre una ventana de gráfico vacía | Escribiste ggplot(datos, aes(...)) sin agregar un geom_*() |
Agrega al menos un geom: + geom_bar() |
object 'rotacion_depto' not found |
Usas una tabla calculada que no creaste antes | Ejecuta primero el código que crea rotacion_depto con summarise() |
Usaste |> en vez de + entre capas de ggplot |
ggplot usa + para agregar capas, no el pipe |
Cambia |> geom_bar() por + geom_bar() |
Colores iguales para todos a pesar de usar fill = genero |
fill = genero está fuera de aes() |
Muévelo adentro: aes(fill = genero) |