← Volver al inicio
Universidad Nacional de Costa Rica

Creación de gráficos en R

Visualización de datos efectiva: principios, buenas prácticas y código

Curso: EIY403 - Introducción al análisis de datos
Semana 12
II Semestre 2025
"Un gráfico bien diseñado comunica más en segundos que mil palabras en minutos"
1 / 18
Universidad Nacional de Costa Rica

Agenda de la sesión

Fundamentos de visualización

  • ¿Por qué visualizar datos?
  • Principios de diseño gráfico
  • Errores comunes a evitar

Buenas y malas prácticas

  • Comparaciones visuales
  • Ejemplos de gráficos mal diseñados
  • Cómo mejorarlos
  • Casos reales

Teoría del color

  • Psicología del color
  • Paletas apropiadas para datos
  • Accesibilidad y daltonismo
  • Colores en R

Tipos de gráficos

  • Cuándo usar cada tipo
  • Gráficos para datos categóricos
  • Gráficos para datos numéricos
  • Gráficos para relaciones
  • Gráficos especializados

Implementación en R

  • Gráficos con R base
  • Introducción a ggplot2
  • Personalización de gráficos
  • Exportar gráficos
  • Ejercicios prácticos
2 / 18
Universidad Nacional de Costa Rica

¿Por qué visualizar datos?

El poder de la visualización

Procesamiento visual

  • El cerebro procesa imágenes 60,000 veces más rápido que texto
  • 90% de la información transmitida al cerebro es visual
  • Recordamos 80% de lo que vemos vs 20% de lo que leemos

Identificación de patrones

  • Detecta tendencias instantáneamente
  • Identifica valores atípicos (outliers)
  • Revela relaciones entre variables
  • Muestra distribuciones de datos

Comunicación efectiva

  • Simplifica datos complejos
  • Cuenta historias con datos
  • Persuade con evidencia visual
  • Facilita toma de decisiones

Ejemplo: el cuarteto de Anscombe

Cuatro conjuntos de datos con las mismas estadísticas pero patrones visuales muy diferentes:

Todos tienen:

  • Media de X: 9.0
  • Media de Y: 7.5
  • Desviación estándar de X: 3.32
  • Desviación estándar de Y: 2.03
  • Correlación: 0.816
  • Ecuación de regresión: y = 3 + 0.5x

Pero al graficarlos...

  • Conjunto 1: Relación lineal perfecta
  • Conjunto 2: Relación no lineal (curva)
  • Conjunto 3: Relación lineal con outlier
  • Conjunto 4: Sin relación, solo un punto extremo
"Las estadísticas resumen pueden mentir. Los gráficos revelan la verdad"
# Ver el cuarteto de Anscombe en R data(anscombe) par(mfrow = c(2, 2)) for(i in 1:4) { plot(anscombe[, i], anscombe[, i+4], main = paste("Conjunto", i)) }
3 / 18
Universidad Nacional de Costa Rica

Principios de diseño gráfico

Principio 1: Claridad

  • Un mensaje principal: cada gráfico debe comunicar UNA idea
  • Título descriptivo: que explique qué muestra el gráfico
  • Ejes etiquetados: siempre con unidades
  • Leyenda clara: cuando hay múltiples series

Principio 2: Simplicidad

  • Menos es más: elimina elementos innecesarios
  • Sin chartjunk: nada de 3D, sombras, efectos
  • Ratio tinta-datos: maximiza información, minimiza decoración
  • Espacio en blanco: usa márgenes apropiados

Principio 3: Honestidad

  • Eje Y en cero: para gráficos de barras
  • Escalas apropiadas: no exagerar diferencias
  • Datos completos: no ocultar información relevante
  • Contexto necesario: incluye tamaño de muestra, errores

Principio 4: Consistencia

  • Colores uniformes: misma variable = mismo color
  • Tipografía coherente: una o dos fuentes máximo
  • Escalas comparables: entre gráficos relacionados
  • Estilo único: en toda la presentación/documento

Principio 5: Accesibilidad

  • Colores distinguibles: para personas con daltonismo
  • Tamaño de texto: legible a distancia
  • Contraste suficiente: fondo vs elementos
  • Alternativas: patrones además de colores

Principio 6: Contexto

  • Audiencia: adapta complejidad al público
  • Propósito: exploración vs presentación
  • Medio: impreso, pantalla, proyección
  • Comparaciones: incluye referencias o benchmarks
4 / 18
Universidad Nacional de Costa Rica

Malas prácticas: gráficos de barras

❌ MAL: Eje Y no empieza en cero
85
Producto A
90
Producto B
95
Producto C

Problema: Exagera las diferencias visuales. Parece que C es 2× mejor que A, pero solo es 11.8% mejor

✓ BIEN: Eje Y empieza en cero
85
Producto A
90
Producto B
95
Producto C

Mejor: Muestra las proporciones reales correctamente

Otros errores comunes en barras:

  • Usar 3D (distorsiona percepción)
  • Demasiadas categorías (ilegible)
  • Barras apiladas con muchas secciones
  • Ordenamiento aleatorio (dificulta comparación)
# Código R correcto ventas <- c(85, 90, 95) productos <- c("Producto A", "Producto B", "Producto C") # ✓ BIEN: ylim empieza en 0 barplot(ventas, names.arg = productos, ylim = c(0, 100), col = "#28a745", main = "Ventas por Producto", ylab = "Unidades vendidas") # ❌ MAL: ylim manipulado barplot(ventas, names.arg = productos, ylim = c(80, 100), # NO HACER ESTO col = "#e74c3c")
5 / 18
Universidad Nacional de Costa Rica

Malas prácticas: uso del color

❌ MAL: Colores sin sentido
Rojo
Verde
Amarillo
Magenta
Cian

Problemas: Colores saturados, no distinguibles para daltónicos, sin significado, cansa la vista

✓ BIEN: Paleta coherente
Azul oscuro
Azul medio
Azul claro
Azul suave
Azul pálido

Mejor: Gradiente suave, distinguible, profesional, representa magnitud

Errores de color a evitar:

  • Arcoíris: Usar todos los colores sin razón
  • Rojo-verde: 8% de hombres no los distinguen
  • Colores chillones: Saturación máxima (RGB puros)
  • Bajo contraste: Texto amarillo sobre blanco
  • Demasiados colores: Más de 7 categorías

Cuándo usar cada tipo de paleta:

  • Secuencial: Para magnitudes (temperatura, concentración)
  • Divergente: Para datos con punto medio (balance, diferencias)
  • Cualitativa: Para categorías sin orden
# Paletas recomendadas en R # 1. ColorBrewer (científicamente diseñadas) library(RColorBrewer) display.brewer.all(colorblindFriendly = TRUE) # Usar paleta secuencial Blues colores <- brewer.pal(5, "Blues") barplot(1:5, col = colores) # 2. Viridis (accesible para daltónicos) library(viridis) barplot(1:5, col = viridis(5)) # 3. Paletas grises para impresión B/N barplot(1:5, col = gray.colors(5)) # 4. Colores personalizados con transparencia colores <- c("#2c3e50", "#3498db", "#5dade2") barplot(1:3, col = colores) # Agregar transparencia (alpha) colores_trans <- adjustcolor(colores, alpha.f = 0.7)

Regla de oro:

Si tu gráfico se imprime en blanco y negro y sigue siendo comprensible, probablemente tiene buen diseño de color

6 / 18
Universidad Nacional de Costa Rica

Malas prácticas: chartjunk y efectos 3D

¿Qué es chartjunk?

Elementos visuales que no agregan información, solo decoración que distrae o confunde.

Ejemplos de chartjunk:

  • Efectos 3D: Distorsionan la percepción de valores
  • Gradientes excesivos: En barras o áreas
  • Sombras y brillos: No agregan información
  • Fondos con imágenes: Dificultan lectura
  • Grillas excesivas: Demasiadas líneas de referencia
  • Bordes gruesos: Resaltan el marco, no los datos
  • Iconos decorativos: Pictogramas innecesarios

El problema del 3D:

Los gráficos 3D son casi siempre una mala idea porque:

  • Distorsionan los valores reales por perspectiva
  • Ocultan datos (barras traseras)
  • Dificultan comparaciones precisas
  • Agregan complejidad sin beneficio

Ejemplo clásico: Gráfico de torta 3D

Las secciones del frente parecen más grandes que las del fondo, incluso con el mismo porcentaje. Es el peor tipo de gráfico posible.

Cómo evitarlo en R

# ❌ MAL: Gráfico con chartjunk datos <- c(20, 35, 25, 20) pie(datos, col = rainbow(4), # Colores chillones border = "white", # Sin propósito density = 10, # Líneas que distraen angle = 45) # Más distracción # ✓ BIEN: Gráfico limpio barplot(datos, col = "#3498db", # Un color sólido border = NA, # Sin bordes main = "Distribución de datos", ylab = "Frecuencia") grid(nx = NA, ny = NULL) # Solo líneas horizontales
# ❌ MAL: Efectos 3D (biblioteca scatterplot3d) # NO USAR - Solo para datos verdaderamente 3D # ✓ BIEN: Alternativas 2D efectivas # Para múltiples variables, usa paneles par(mfrow = c(2, 2)) for(i in 1:4) { plot(datos[[i]], main = paste("Variable", i)) }

Principio minimalista:

"Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away"

— Antoine de Saint-Exupéry

# Configuración minimalista en R base par( bty = "l", # Solo ejes izquierdo e inferior las = 1, # Etiquetas horizontales cex.axis = 0.9, # Texto de ejes más pequeño col.axis = "gray30", # Color suave para ejes fg = "gray30" # Color de líneas )
7 / 18
Universidad Nacional de Costa Rica

Tipos de gráficos: ¿cuándo usar cada uno?

📊
Gráfico de barras
Para: Comparar categorías
Cuándo: Pocas categorías (<10), valores discretos
Ejemplo: Ventas por producto
📈
Gráfico de líneas
Para: Mostrar tendencias en el tiempo
Cuándo: Datos continuos, series temporales
Ejemplo: Temperatura a lo largo del día
Gráfico de dispersión
Para: Relación entre dos variables
Cuándo: Buscar correlaciones, patrones
Ejemplo: Dosis vs efecto
📦
Boxplot
Para: Distribución y outliers
Cuándo: Comparar distribuciones entre grupos
Ejemplo: Concentración por laboratorio
📊
Histograma
Para: Distribución de frecuencias
Cuándo: Ver forma de la distribución
Ejemplo: Distribución de edades
🔥
Heatmap
Para: Matrices de valores con color
Cuándo: Muchas variables, correlaciones
Ejemplo: Matriz de correlación

❌ NUNCA (o casi nunca) usar:

  • Gráficos de torta (pie): El cerebro es malo comparando ángulos. Usa barras.
  • Gráficos de torta 3D: Aún peor. Distorsión por perspectiva.
  • Gráficos de dona: Como la torta pero con menos área para comparar.
  • Gráficos de radar: Difíciles de interpretar, mejor usar barras agrupadas.
"El único caso aceptable para gráfico de torta es mostrar proporciones de... una torta real"
8 / 18
Universidad Nacional de Costa Rica

Gráficos de barras en R

Barras simples (R base)

# Datos de ejemplo ventas <- c(45, 67, 52, 78, 61) productos <- c("A", "B", "C", "D", "E") # Gráfico básico barplot(ventas, names.arg = productos, main = "Ventas por producto", xlab = "Producto", ylab = "Unidades vendidas", col = "#3498db", border = NA) # Agregar valores sobre las barras text(x = barplot(ventas, plot = FALSE), y = ventas, labels = ventas, pos = 3, cex = 0.8)

Barras horizontales

# Barras horizontales (mejor para etiquetas largas) barplot(ventas, names.arg = productos, horiz = TRUE, main = "Ventas por producto", xlab = "Unidades vendidas", col = "#2ecc71", border = NA, las = 1) # Etiquetas horizontales

Barras agrupadas

# Datos: ventas por trimestre datos <- matrix(c(45, 67, 52, 50, 72, 58, 48, 70, 55, 53, 75, 60), nrow = 3, byrow = FALSE) rownames(datos) <- c("A", "B", "C") colnames(datos) <- c("Q1", "Q2", "Q3", "Q4") # Barras agrupadas barplot(datos, beside = TRUE, main = "Ventas por trimestre", xlab = "Trimestre", ylab = "Ventas", col = c("#3498db", "#2ecc71", "#f39c12"), legend = rownames(datos)) # Agregar grilla grid(nx = NA, ny = NULL, col = "gray90")

Barras apiladas

# Barras apiladas (mismos datos) barplot(datos, beside = FALSE, # FALSE para apilar main = "Composición de ventas", xlab = "Trimestre", ylab = "Total ventas", col = c("#3498db", "#2ecc71", "#f39c12"), legend = rownames(datos))

Ordenar por valor

# Ordenar de mayor a menor ventas_ord <- sort(ventas, decreasing = TRUE) productos_ord <- productos[order(ventas, decreasing = TRUE)] barplot(ventas_ord, names.arg = productos_ord, main = "Ventas ordenadas", col = "#9b59b6", border = NA)

Personalización avanzada

# Control total del diseño par(mar = c(5, 5, 4, 2), # Márgenes family = "sans") # Fuente bp <- barplot(ventas, names.arg = productos, ylim = c(0, max(ventas) * 1.2), col = colorRampPalette(c("#3498db", "#2c3e50"))(5), border = NA, main = "Ventas por producto", cex.names = 0.9, cex.axis = 0.9) # Línea de promedio abline(h = mean(ventas), col = "#e74c3c", lwd = 2, lty = 2) # Etiqueta del promedio text(0.5, mean(ventas), paste("Promedio:", round(mean(ventas), 1)), pos = 3, col = "#e74c3c")

Tip: Para nombres de categorías largos, usa barras horizontales (horiz = TRUE) o rota las etiquetas

9 / 18
Universidad Nacional de Costa Rica

Gráficos de líneas en R

Línea simple

# Datos de serie temporal tiempo <- 1:24 # horas temperatura <- c(15, 14, 13, 13, 14, 16, 18, 21, 24, 27, 29, 30, 31, 30, 29, 27, 25, 23, 21, 19, 18, 17, 16, 15) # Gráfico básico plot(tiempo, temperatura, type = "l", # l = línea main = "Temperatura diaria", xlab = "Hora del día", ylab = "Temperatura (°C)", col = "#e74c3c", lwd = 2) # Grosor de línea # Agregar puntos sobre la línea points(tiempo, temperatura, pch = 19, # Círculos rellenos col = "#c0392b", cex = 0.8) # Agregar grilla grid(col = "gray90")

Múltiples líneas

# Tres laboratorios midiendo temperatura lab_a <- temperatura + rnorm(24, 0, 0.5) lab_b <- temperatura + rnorm(24, 0, 0.5) lab_c <- temperatura + rnorm(24, 0, 0.5) # Primera línea plot(tiempo, lab_a, type = "l", ylim = range(c(lab_a, lab_b, lab_c)), main = "Comparación entre laboratorios", xlab = "Hora", ylab = "Temperatura (°C)", col = "#3498db", lwd = 2) # Agregar más líneas lines(tiempo, lab_b, col = "#2ecc71", lwd = 2) lines(tiempo, lab_c, col = "#f39c12", lwd = 2) # Leyenda legend("topleft", legend = c("Lab A", "Lab B", "Lab C"), col = c("#3498db", "#2ecc71", "#f39c12"), lwd = 2, bty = "n") # Sin caja

Línea con banda de confianza

# Calcular media y error estándar medias <- temperatura se <- 1.5 # error estándar # Límites de confianza superior <- medias + se inferior <- medias - se # Gráfico con banda plot(tiempo, medias, type = "l", ylim = range(c(inferior, superior)), main = "Temperatura ± SE", xlab = "Hora", ylab = "Temperatura (°C)", col = "#2c3e50", lwd = 2) # Agregar banda de confianza polygon(c(tiempo, rev(tiempo)), c(superior, rev(inferior)), col = adjustcolor("#3498db", alpha.f = 0.3), border = NA) # Redibujar la línea principal lines(tiempo, medias, col = "#2c3e50", lwd = 2)

Tipos de líneas

# Diferentes estilos plot(1:10, type = "n", main = "Tipos de líneas", xlab = "", ylab = "") # lty: tipo de línea # 1=sólida, 2=guiones, 3=puntos, 4=punto-guion for(i in 1:6) { lines(1:10, rep(7-i, 10), lty = i, lwd = 2) text(0.5, 7-i, paste("lty =", i), pos = 2) }

Línea suavizada (smooth)

# Datos con ruido x <- 1:50 y <- x + rnorm(50, 0, 5) # Puntos originales plot(x, y, pch = 19, col = "gray70", main = "Línea suavizada") # Agregar línea suavizada (loess) linea_suave <- lowess(x, y, f = 0.2) lines(linea_suave, col = "#e74c3c", lwd = 3)
10 / 18
Universidad Nacional de Costa Rica

Gráficos de dispersión en R

Dispersión básica

# Datos de ejemplo: dosis vs respuesta dosis <- c(10, 20, 30, 40, 50, 60, 70, 80) respuesta <- c(15, 28, 42, 55, 68, 75, 80, 82) # Gráfico básico plot(dosis, respuesta, main = "Relación dosis-respuesta", xlab = "Dosis (mg)", ylab = "Respuesta (%)", pch = 19, # Círculos rellenos col = "#3498db", cex = 1.5) # Tamaño de puntos # Agregar línea de tendencia modelo <- lm(respuesta ~ dosis) abline(modelo, col = "#e74c3c", lwd = 2, lty = 2) # Agregar R² r2 <- summary(modelo)$r.squared text(20, 75, paste("R² =", round(r2, 3)), pos = 4, cex = 1.2)

Diferentes símbolos (pch)

# Mostrar símbolos disponibles plot(1:25, rep(1, 25), pch = 1:25, cex = 2, ylim = c(0.5, 1.5), main = "Símbolos disponibles (pch)", xlab = "Número pch", ylab = "") text(1:25, rep(0.7, 25), 1:25, cex = 0.8)

Colorear por grupos

# Datos con grupos set.seed(123) grupo_a_x <- rnorm(30, 50, 10) grupo_a_y <- grupo_a_x + rnorm(30, 0, 5) grupo_b_x <- rnorm(30, 70, 10) grupo_b_y <- grupo_b_x + rnorm(30, 0, 5) # Combinar x <- c(grupo_a_x, grupo_b_x) y <- c(grupo_a_y, grupo_b_y) grupos <- rep(c("Control", "Tratamiento"), each = 30) # Colores por grupo colores <- ifelse(grupos == "Control", "#3498db", "#e74c3c") # Gráfico plot(x, y, pch = 19, col = colores, main = "Comparación de grupos", xlab = "Variable X", ylab = "Variable Y") # Leyenda legend("topleft", legend = c("Control", "Tratamiento"), col = c("#3498db", "#e74c3c"), pch = 19, bty = "n")

Tamaño de puntos por variable

# Tres variables: x, y, tamaño x <- rnorm(50, 50, 15) y <- x + rnorm(50, 0, 10) tamano <- runif(50, 10, 100) # Variable de tamaño # Normalizar tamaños para visualización cex_valores <- (tamano - min(tamano)) / (max(tamano) - min(tamano)) * 3 + 0.5 plot(x, y, pch = 19, col = adjustcolor("#3498db", alpha.f = 0.6), cex = cex_valores, main = "Burbuja: 3 variables", xlab = "Variable X", ylab = "Variable Y")

Matriz de dispersión

# Múltiples variables datos <- data.frame( temperatura = rnorm(50, 25, 3), presion = rnorm(50, 1.0, 0.2), pH = rnorm(50, 7, 0.5), rendimiento = rnorm(50, 75, 10) ) # Matriz de dispersión pairs(datos, main = "Matriz de dispersión", pch = 19, col = adjustcolor("#3498db", alpha.f = 0.5), lower.panel = NULL) # Solo mitad superior

Con transparencia

# Muchos puntos superpuestos x <- rnorm(1000, 50, 15) y <- x + rnorm(1000, 0, 10) # Sin transparencia (difícil ver densidad) plot(x, y, pch = 19, col = "#3498db", main = "Sin transparencia") # Con transparencia (muestra densidad) plot(x, y, pch = 19, col = adjustcolor("#3498db", alpha.f = 0.3), main = "Con transparencia")
11 / 18
Universidad Nacional de Costa Rica

Boxplots e histogramas en R

Boxplot simple

# Datos de ejemplo concentraciones <- rnorm(100, 50, 10) # Boxplot básico boxplot(concentraciones, main = "Distribución de concentraciones", ylab = "Concentración (mg/L)", col = "#3498db", border = "#2c3e50", horizontal = FALSE) # Agregar puntos individuales stripchart(concentraciones, vertical = TRUE, method = "jitter", add = TRUE, pch = 19, col = adjustcolor("#e74c3c", alpha.f = 0.3), cex = 0.5)

Boxplots múltiples

# Datos por grupos lab_a <- rnorm(50, 50, 8) lab_b <- rnorm(50, 55, 10) lab_c <- rnorm(50, 48, 7) # Combinar en lista datos_labs <- list("Lab A" = lab_a, "Lab B" = lab_b, "Lab C" = lab_c ) # Boxplots comparativos boxplot(datos_labs, main = "Comparación entre laboratorios", ylab = "Concentración (mg/L)", col = c("#3498db", "#2ecc71", "#f39c12"), border = "#2c3e50", notch = TRUE) # Muestra intervalo de confianza # Agregar línea del promedio global abline(h = mean(c(lab_a, lab_b, lab_c)), col = "#e74c3c", lty = 2, lwd = 2)

Interpretación del boxplot

Elementos del boxplot:

  • Línea central: Mediana (Q2)
  • Caja: Rango intercuartílico (Q1 a Q3)
  • Bigotes: Hasta 1.5 × IQR
  • Puntos fuera: Outliers potenciales

Boxplot horizontal

# Horizontal (mejor para etiquetas largas) boxplot(datos_labs, main = "Comparación horizontal", xlab = "Concentración (mg/L)", horizontal = TRUE, col = c("#3498db", "#2ecc71", "#f39c12"), las = 1) # Etiquetas horizontales

Histograma básico

# Datos datos <- rnorm(500, 50, 10) # Histograma hist(datos, main = "Distribución de concentraciones", xlab = "Concentración (mg/L)", ylab = "Frecuencia", col = "#3498db", border = "white", breaks = 20) # Número de bins # Agregar línea de densidad lines(density(datos), col = "#e74c3c", lwd = 3)

Histograma con densidad

# Histograma con probabilidad (no frecuencia) hist(datos, main = "Distribución con curva normal", xlab = "Concentración (mg/L)", ylab = "Densidad", col = adjustcolor("#3498db", alpha.f = 0.5), border = "white", freq = FALSE, # Densidad en lugar de frecuencia breaks = 25) # Agregar curva normal teórica curve(dnorm(x, mean = mean(datos), sd = sd(datos)), add = TRUE, col = "#e74c3c", lwd = 3) # Leyenda legend("topright", legend = c("Datos observados", "Normal teórica"), fill = c("#3498db", NA), border = c("white", NA), lty = c(NA, 1), col = c(NA, "#e74c3c"), lwd = c(NA, 3), bty = "n")

Histogramas superpuestos

# Dos grupos grupo1 <- rnorm(300, 50, 8) grupo2 <- rnorm(300, 55, 10) # Primer histograma hist(grupo1, main = "Comparación de distribuciones", xlab = "Valor", col = adjustcolor("#3498db", alpha.f = 0.5), border = "white", xlim = range(c(grupo1, grupo2)), freq = FALSE) # Segundo histograma superpuesto hist(grupo2, col = adjustcolor("#e74c3c", alpha.f = 0.5), border = "white", add = TRUE, freq = FALSE) # Leyenda legend("topright", legend = c("Grupo 1", "Grupo 2"), fill = c(adjustcolor("#3498db", alpha.f = 0.5), adjustcolor("#e74c3c", alpha.f = 0.5)), bty = "n")
12 / 18
Universidad Nacional de Costa Rica

Introducción a ggplot2

¿Por qué ggplot2?

Ventajas de ggplot2:

  • Gramática de gráficos: Sistema consistente y lógico
  • Estética superior: Gráficos profesionales por defecto
  • Fácil personalización: Temas y escalas predefinidos
  • Leyendas automáticas: Se generan solas
  • Facetas: Paneles múltiples fácilmente
  • Comunidad: Muchas extensiones disponibles

Conceptos clave

Estructura de un gráfico ggplot2:

  • Data: El dataset
  • Aesthetics (aes): Mapeo de variables a propiedades visuales
  • Geometries (geom): Tipo de representación visual
  • Stats: Transformaciones estadísticas
  • Scales: Control de ejes y colores
  • Themes: Apariencia general

Instalación

# Instalar ggplot2 (solo una vez) install.packages("ggplot2") # Cargar biblioteca library(ggplot2) # O usar todo el tidyverse install.packages("tidyverse") library(tidyverse)

Estructura básica

# La estructura es por capas con + # Capa 1: Datos y estética ggplot(data = mi_dataframe, aes(x = variable_x, y = variable_y)) + # Capa 2: Geometría geom_point() + # Capa 3: Etiquetas labs(title = "Mi gráfico", x = "Eje X", y = "Eje Y") + # Capa 4: Tema theme_minimal()

Ejemplo completo

# Crear datos library(ggplot2) datos <- data.frame( dosis = c(10, 20, 30, 40, 50), respuesta = c(15, 28, 42, 55, 68), grupo = c("A", "A", "B", "B", "B") ) # Gráfico ggplot(datos, aes(x = dosis, y = respuesta)) + geom_point(size = 4, color = "#3498db") + geom_smooth(method = "lm", se = TRUE, color = "#e74c3c") + labs(title = "Relación dosis-respuesta", x = "Dosis (mg)", y = "Respuesta (%)") + theme_minimal() + theme(plot.title = element_text(face = "bold", size = 14))

Comparación R base vs ggplot2

# R base plot(datos$dosis, datos$respuesta) # ggplot2 (equivalente) ggplot(datos, aes(x = dosis, y = respuesta)) + geom_point() # La ventaja: fácil agregar capas ggplot(datos, aes(x = dosis, y = respuesta)) + geom_point() + geom_line() + facet_wrap(~grupo) # ¡Paneles automáticos!
13 / 18
Universidad Nacional de Costa Rica

ggplot2: geometrías comunes

geom_point() - Dispersión

ggplot(datos, aes(x = x, y = y)) + geom_point( size = 3, color = "#3498db", alpha = 0.6 ) + theme_minimal()

geom_line() - Líneas

ggplot(datos, aes(x = tiempo, y = temperatura)) + geom_line( color = "#e74c3c", size = 1.2 ) + geom_point(size = 2) + theme_minimal()

geom_bar() - Barras

# Para datos ya resumidos (stat = "identity") ggplot(datos, aes(x = categoria, y = valor)) + geom_bar( stat = "identity", fill = "#3498db", width = 0.7 ) + theme_minimal() # Para contar frecuencias automáticamente ggplot(datos, aes(x = categoria)) + geom_bar(fill = "#2ecc71") + theme_minimal()

geom_col() - Columnas

# Equivalente a geom_bar(stat = "identity") ggplot(datos, aes(x = categoria, y = valor)) + geom_col(fill = "#9b59b6") + theme_minimal()

geom_histogram() - Histograma

ggplot(datos, aes(x = variable)) + geom_histogram( bins = 30, fill = "#3498db", color = "white" ) + theme_minimal()

geom_boxplot() - Boxplot

ggplot(datos, aes(x = grupo, y = valor)) + geom_boxplot( fill = "#3498db", alpha = 0.7, outlier.color = "#e74c3c" ) + theme_minimal()

geom_violin() - Violín

ggplot(datos, aes(x = grupo, y = valor)) + geom_violin( fill = "#3498db", alpha = 0.5 ) + geom_boxplot(width = 0.1) + # Boxplot dentro theme_minimal()

geom_smooth() - Línea suavizada

ggplot(datos, aes(x = x, y = y)) + geom_point(alpha = 0.3) + geom_smooth( method = "loess", # o "lm" para lineal color = "#e74c3c", fill = "#e74c3c", alpha = 0.2 ) + theme_minimal()

geom_hline() / geom_vline() - Líneas de referencia

ggplot(datos, aes(x = x, y = y)) + geom_point() + geom_hline( yintercept = mean(datos$y), linetype = "dashed", color = "#e74c3c", size = 1 ) + geom_vline( xintercept = 50, linetype = "dotted", color = "#3498db" ) + theme_minimal()

Combinar geometrías

ggplot(datos, aes(x = dosis, y = respuesta)) + geom_point(size = 3, color = "#2c3e50") + geom_line(color = "#3498db", size = 1) + geom_smooth(method = "lm", se = FALSE, color = "#e74c3c", linetype = "dashed") + theme_minimal()
14 / 18
Universidad Nacional de Costa Rica

ggplot2: estética y color

Mapear variables a estética

# Color por grupo (automático) ggplot(datos, aes(x = x, y = y, color = grupo)) + geom_point(size = 3) + theme_minimal() # Tamaño por variable ggplot(datos, aes(x = x, y = y, size = z)) + geom_point(alpha = 0.6) + theme_minimal() # Forma por grupo ggplot(datos, aes(x = x, y = y, shape = grupo)) + geom_point(size = 3) + theme_minimal() # Combinar múltiples estéticas ggplot(datos, aes(x = x, y = y, color = grupo, size = z, shape = tipo)) + geom_point(alpha = 0.7) + theme_minimal()

Paletas de color predefinidas

# ColorBrewer ggplot(datos, aes(x = categoria, y = valor, fill = grupo)) + geom_col() + scale_fill_brewer(palette = "Set2") + theme_minimal() # Viridis (accesible) ggplot(datos, aes(x = x, y = y, color = z)) + geom_point() + scale_color_viridis_c() + # _c para continuo theme_minimal() # Manual colores_personalizados <- c("#3498db", "#e74c3c", "#2ecc71") ggplot(datos, aes(x = x, y = y, color = grupo)) + geom_point() + scale_color_manual(values = colores_personalizados) + theme_minimal()

Gradientes de color

# Gradiente de dos colores ggplot(datos, aes(x = x, y = y, color = temperatura)) + geom_point(size = 3) + scale_color_gradient( low = "#3498db", high = "#e74c3c" ) + theme_minimal() # Gradiente divergente (3 colores) ggplot(datos, aes(x = x, y = y, color = diferencia)) + geom_point(size = 3) + scale_color_gradient2( low = "#3498db", mid = "white", high = "#e74c3c", midpoint = 0 ) + theme_minimal()

Temas predefinidos

# Temas incluidos en ggplot2 p <- ggplot(datos, aes(x = x, y = y)) + geom_point() # Minimalista (recomendado) p + theme_minimal() # Blanco y negro p + theme_bw() # Clásico p + theme_classic() # Oscuro p + theme_dark() # Sin ejes p + theme_void() # Líneas de grilla suaves p + theme_light()

Personalizar temas

ggplot(datos, aes(x = x, y = y)) + geom_point(color = "#3498db", size = 3) + theme_minimal() + theme( # Título plot.title = element_text( face = "bold", size = 16, hjust = 0.5 ), # Ejes axis.title = element_text( face = "bold", size = 12 ), axis.text = element_text(size = 10), # Panel panel.grid.minor = element_blank(), panel.grid.major = element_line( color = "gray90", size = 0.5 ), # Leyenda legend.position = "bottom", legend.title = element_text(face = "bold") )

Tema personalizado reutilizable

# Crear tu propio tema tema_una <- function() { theme_minimal() + theme( plot.title = element_text( color = "#a73c3c", face = "bold", size = 14 ), axis.title = element_text( color = "#2c3e50", face = "bold" ), panel.grid.minor = element_blank() ) } # Usar en cualquier gráfico ggplot(datos, aes(x = x, y = y)) + geom_point() + tema_una()
15 / 18
Universidad Nacional de Costa Rica

ggplot2: facetas y etiquetas

Facetas (paneles múltiples)

# facet_wrap: una variable ggplot(datos, aes(x = x, y = y)) + geom_point() + facet_wrap(~grupo) + theme_minimal() # Con número de columnas ggplot(datos, aes(x = x, y = y)) + geom_point() + facet_wrap(~grupo, ncol = 2) + theme_minimal() # facet_grid: dos variables (filas × columnas) ggplot(datos, aes(x = x, y = y)) + geom_point() + facet_grid(tratamiento ~ laboratorio) + theme_minimal() # Escalas libres por panel ggplot(datos, aes(x = x, y = y)) + geom_point() + facet_wrap(~grupo, scales = "free") + theme_minimal() # scales = "free_x" # Solo X libre # scales = "free_y" # Solo Y libre # scales = "free" # Ambos libres

Etiquetas y títulos

ggplot(datos, aes(x = dosis, y = respuesta)) + geom_point() + labs( title = "Relación dosis-respuesta", subtitle = "Experimento de laboratorio 2025", x = "Dosis del compuesto (mg)", y = "Respuesta biológica (%)", caption = "Fuente: Lab A, n=50" ) + theme_minimal()

Anotaciones de texto

ggplot(datos, aes(x = x, y = y)) + geom_point() + annotate("text", x = 50, y = 80, label = "Outlier importante", color = "#e74c3c", size = 4) + annotate("rect", xmin = 40, xmax = 60, ymin = 70, ymax = 90, alpha = 0.2, fill = "#e74c3c") + theme_minimal()

Etiquetas en puntos

# geom_text() - etiquetas simples ggplot(datos, aes(x = x, y = y, label = nombre)) + geom_point() + geom_text( nudge_y = 2, # Desplazar hacia arriba size = 3 ) + theme_minimal() # geom_label() - etiquetas con fondo ggplot(datos, aes(x = x, y = y, label = nombre)) + geom_point() + geom_label( nudge_y = 2, size = 3, fill = "white", alpha = 0.7 ) + theme_minimal() # ggrepel - evita superposición library(ggrepel) ggplot(datos, aes(x = x, y = y, label = nombre)) + geom_point() + geom_text_repel( size = 3, box.padding = 0.5 ) + theme_minimal()

Formatear ejes

ggplot(datos, aes(x = fecha, y = ventas)) + geom_line() + scale_x_date( date_labels = "%b %Y", # Formato de fecha date_breaks = "1 month" ) + scale_y_continuous( labels = scales::comma, # Formato con comas breaks = seq(0, 100, 20) # Breaks personalizados ) + theme_minimal() + theme(axis.text.x = element_text(angle = 45, hjust = 1))

Límites de ejes

ggplot(datos, aes(x = x, y = y)) + geom_point() + xlim(0, 100) + ylim(0, 100) + theme_minimal() # O con coord_cartesian (mejor) ggplot(datos, aes(x = x, y = y)) + geom_point() + coord_cartesian( xlim = c(0, 100), ylim = c(0, 100) ) + theme_minimal()
16 / 18
Universidad Nacional de Costa Rica

Exportar y guardar gráficos

Guardar desde R base

# PNG (para web, presentaciones) png("mi_grafico.png", width = 800, height = 600, res = 150) # DPI (calidad) plot(x, y, main = "Mi gráfico") dev.off() # IMPORTANTE: cerrar dispositivo # PDF (para documentos, alta calidad) pdf("mi_grafico.pdf", width = 8, # pulgadas height = 6) plot(x, y) dev.off() # JPEG (comprimido, menor calidad) jpeg("grafico.jpg", width = 1200, height = 800, quality = 90) plot(x, y) dev.off() # TIFF (para publicaciones científicas) tiff("grafico.tiff", width = 3000, height = 2400, res = 300, compression = "lzw") plot(x, y) dev.off()

Guardar desde ggplot2

# Método recomendado: ggsave() p <- ggplot(datos, aes(x = x, y = y)) + geom_point() + theme_minimal() # Guardar el último gráfico ggsave("mi_grafico.png", width = 8, height = 6, dpi = 300) # Guardar gráfico específico ggsave("mi_grafico.png", plot = p, width = 8, height = 6, dpi = 300) # Diferentes formatos ggsave("grafico.pdf", width = 8, height = 6) ggsave("grafico.png", width = 8, height = 6, dpi = 300) ggsave("grafico.svg", width = 8, height = 6) ggsave("grafico.tiff", width = 8, height = 6, dpi = 300)

Configuración de calidad

Recomendaciones por uso:

  • Presentaciones: PNG, 150-300 DPI
  • Web: PNG o JPEG, 72-150 DPI
  • Impresión: PDF o TIFF, 300-600 DPI
  • Publicaciones: TIFF o EPS, 300-600 DPI
  • Vectorial (escalable): PDF o SVG

Tamaños estándar

# Tamaños comunes (en pulgadas) # Presentación 16:9 ggsave("grafico.png", width = 10, height = 5.625) # Presentación 4:3 ggsave("grafico.png", width = 8, height = 6) # Cuadrado (Instagram, etc.) ggsave("grafico.png", width = 6, height = 6) # Página completa (vertical) ggsave("grafico.pdf", width = 8.5, height = 11) # Media página (horizontal) ggsave("grafico.pdf", width = 7, height = 4)

Múltiples gráficos en un archivo

# PDF con múltiples páginas pdf("varios_graficos.pdf", width = 8, height = 6) plot(x1, y1, main = "Gráfico 1") plot(x2, y2, main = "Gráfico 2") plot(x3, y3, main = "Gráfico 3") dev.off() # Con ggplot2 - usar bibliotecas adicionales library(gridExtra) library(ggplot2) p1 <- ggplot(datos, aes(x = x, y = y)) + geom_point() p2 <- ggplot(datos, aes(x = a, y = b)) + geom_line() p3 <- ggplot(datos, aes(x = cat)) + geom_bar() # Combinar en una página grid.arrange(p1, p2, p3, ncol = 2) # Guardar ggsave("combinado.png", grid.arrange(p1, p2, p3, ncol = 2), width = 12, height = 8)

Recuerda: Siempre usa dev.off() después de abrir un dispositivo gráfico, o R seguirá enviando gráficos al archivo en lugar de la pantalla

17 / 18
Universidad Nacional de Costa Rica

Resumen y mejores prácticas

Checklist de un buen gráfico

✓ Contenido

  • Tiene un mensaje claro y único
  • Muestra datos honestos sin distorsión
  • Incluye todos los datos relevantes
  • El tipo de gráfico es apropiado para los datos

✓ Diseño

  • Título descriptivo y conciso
  • Ejes etiquetados con unidades
  • Leyenda clara (si es necesaria)
  • Escala apropiada (eje Y en cero para barras)
  • Sin elementos innecesarios (chartjunk)

✓ Color y estética

  • Paleta de colores coherente y profesional
  • Accesible para personas con daltonismo
  • Contraste suficiente
  • No más de 5-7 colores diferentes
  • Colores con significado (no arbitrarios)

✓ Legibilidad

  • Texto de tamaño legible
  • Fuentes simples y profesionales
  • Etiquetas no superpuestas
  • Espacio en blanco apropiado

Errores que NUNCA debes cometer

❌ Prohibido:

  • Gráficos de torta (usa barras)
  • Efectos 3D innecesarios
  • Eje Y que no empieza en cero (en barras)
  • Colores rojo-verde juntos
  • Demasiados colores saturados
  • Más de 10 categorías en un gráfico
  • Texto ilegible o rotado 90°
  • Leyendas con demasiadas entradas
  • Ocultar datos para "embellecer"

Flujo de trabajo recomendado

  1. Define el mensaje: ¿Qué quieres comunicar?
  2. Elige el tipo: ¿Qué gráfico es mejor?
  3. Crea versión básica: Primero funcionalidad
  4. Refina estética: Colores, etiquetas, tema
  5. Revisa con otros: ¿Es claro para tu audiencia?
  6. Exporta apropiadamente: Formato y resolución correctos

Recursos para continuar

# Bibliotecas útiles adicionales # Para gráficos interactivos install.packages("plotly") library(plotly) ggplotly(tu_grafico_ggplot) # Para mapas install.packages("ggmap") # Para diagramas de redes install.packages("ggraph") # Para extensiones de ggplot2 install.packages("ggpubr") # Gráficos de publicación install.packages("patchwork") # Combinar gráficos install.packages("cowplot") # Layouts avanzados # Galería de gráficos # https://r-graph-gallery.com/ # https://ggplot2.tidyverse.org/
"La visualización efectiva de datos es una combinación de arte y ciencia: precisión técnica con claridad comunicativa"

Recuerda: Un gráfico es exitoso cuando tu audiencia entiende el mensaje en menos de 5 segundos

18 / 18