geom_line()Fecha de la última revisión
## [1] "2026-04-15"


geom_line()Los gráficos de línea son ideales cuando:
No uses gráficos de línea cuando:
geom_point()).geom_line()Los gráficos de línea se usan frecuentemente cuando hay una variable de datos continuos ordenada secuencialmente, como las series en tiempo (años, hora, minutos, u otras secuencias). En los ejemplos que veremos a continuación se muestra la relación entre la detección del cáncer de tiroides en EE. UU. entre los años 1975 y 2012, su aumento y el nivel de mortandad.
En la Figura se muestra el cambio en número de casos de cáncer de tiroides por cada 100,000 habitantes. La columna Year, año, es una variable numérica, y típicamente no se gráfica correctamente porque no se toma como numérica automáticamente. Es necesario identificarla como que contiene valores enteros usando la opción as.integer.
En primer lugar, crearemos un nuevo data.frame para
agrupar solamente los nuevos casos de cáncer. Para crear un
data.frame solamente con esos datos se usa la función
filter() o la opción which():
## Year Cases Rate
## 1 1975 New Cases 4.8
## 2 1976 New Cases 4.8
## 3 1977 New Cases 5.4
## 4 1978 New Cases 5.1
## 5 1979 New Cases 4.5
## 6 1980 New Cases 4.3
## 7 1981 New Cases 4.4
## 8 1982 New Cases 4.6
## 9 1983 New Cases 4.7
## 10 1984 New Cases 4.8
## 11 1985 New Cases 5.1
## 12 1986 New Cases 5.3
## 13 1987 New Cases 5.0
## 14 1988 New Cases 4.9
## 15 1989 New Cases 5.4
## 16 1990 New Cases 5.5
## 17 1991 New Cases 5.5
## 18 1992 New Cases 5.9
## 19 1993 New Cases 5.6
## 20 1994 New Cases 6.1
## 21 1995 New Cases 6.2
## 22 1996 New Cases 6.5
## 23 1997 New Cases 6.8
## 24 1998 New Cases 7.0
## 25 1999 New Cases 7.3
## 26 2000 New Cases 7.6
## 27 2001 New Cases 8.3
## 28 2002 New Cases 9.2
## 29 2003 New Cases 9.6
## 30 2004 New Cases 10.1
## 31 2005 New Cases 11.0
## 32 2006 New Cases 11.3
## 33 2007 New Cases 12.4
## 34 2008 New Cases 13.2
## 35 2009 New Cases 14.4
## 36 2010 New Cases 13.9
## 37 2011 New Cases 14.8
## 38 2012 New Cases 14.9
## 39 1975 Deaths_US 0.5
## 40 1976 Deaths_US 0.6
## 41 1977 Deaths_US 0.6
## 42 1978 Deaths_US 0.5
## 43 1979 Deaths_US 0.5
## 44 1980 Deaths_US 0.5
## 45 1981 Deaths_US 0.5
## 46 1982 Deaths_US 0.5
## 47 1983 Deaths_US 0.4
## 48 1984 Deaths_US 0.5
## 49 1985 Deaths_US 0.4
## 50 1986 Deaths_US 0.5
## 51 1987 Deaths_US 0.5
## 52 1988 Deaths_US 0.4
## 53 1989 Deaths_US 0.4
## 54 1990 Deaths_US 0.4
## 55 1991 Deaths_US 0.4
## 56 1992 Deaths_US 0.5
## 57 1993 Deaths_US 0.5
## 58 1994 Deaths_US 0.4
## 59 1995 Deaths_US 0.4
## 60 1996 Deaths_US 0.5
## 61 1997 Deaths_US 0.5
## 62 1998 Deaths_US 0.4
## 63 1999 Deaths_US 0.5
## 64 2000 Deaths_US 0.5
## 65 2001 Deaths_US 0.5
## 66 2002 Deaths_US 0.5
## 67 2003 Deaths_US 0.4
## 68 2004 Deaths_US 0.5
## 69 2005 Deaths_US 0.5
## 70 2006 Deaths_US 0.5
## 71 2007 Deaths_US 0.5
## 72 2008 Deaths_US 0.5
## 73 2009 Deaths_US 0.5
## 74 2010 Deaths_US 0.5
## 75 2011 Deaths_US 0.5
## 76 2012 Deaths_US 0.5
## [1] New Cases Deaths_US
## Levels: Deaths_US New Cases
| Year | Cases | Rate |
|---|---|---|
| 1975 | New Cases | 4.8 |
| 1976 | New Cases | 4.8 |
| 1977 | New Cases | 5.4 |
| 1978 | New Cases | 5.1 |
| 1979 | New Cases | 4.5 |
| 1980 | New Cases | 4.3 |
El procedimiento para preparar el gráfico de tiroides se presenta a continuación:
ggplot(subTiroide, aes(x = as.integer(Year), y = Rate)) +
geom_line(linewidth = 1, colour = "red") +
annotate("text", x = 1985, y = 9, size = 3,
label = "Nuevos casos de \n cáncer \n de Tiroides",
color = "black") +
guides(color = "none") +
ylab("Números de nuevos casos\n de cáncer de Tiroides \n por 100,000 habitantes") +
xlab("Años") +
theme(axis.title = element_text(size = 8, face = "italic"),
axis.title.y.left = element_text(size = 10, face = "bold"))
Note que se utilizó la función annotate para escribir información sobre el gráfico. Esta función será discutida con más detalle más adelante.
A veces es importante comparar dos o más secuencias de datos. Usando
la función group = se identifica cuáles son los grupos — si
hubiese más de dos grupos, habría una línea para cada grupo. Lo que se
observa es que aunque hay mucha más gente diagnosticada con cáncer de la
tiroides, la proporción de gente que muere de este tipo de cáncer es
consistente a través del tiempo.
ggplot(Tiroide, aes(x = as.integer(Year), y = Rate,
group = Cases, color = Cases)) +
geom_line(linewidth = 2) +
annotate("text", x = 1990, y = 8, size = 4,
label = "Nuevos casos") +
annotate("text", x = 2000, y = 1, size = 4,
label = "Mortandad") +
guides(color = "none") +
ylab("Números de nuevos casos\n por 100,000 habitantes") +
xlab("Años") +
theme(axis.title = element_text(size = 10, face = "bold"))
Muchas veces el intervalo de la escala de los ejes no es el óptimo.
Para modificar el eje de X e incluir el último año, se
usa xlim() o scale_x_continuous(). También se
puede cambiar el color de las líneas manualmente con
scale_color_manual():
ggplot(Tiroide, aes(x = as.integer(Year), y = Rate,
group = Cases, color = Cases)) +
geom_line(linewidth = 2) +
annotate("text", x = 1990, y = 10, size = 4, label = "Nuevos casos") +
annotate("text", x = 1995, y = 1, size = 4, label = "Mortandad") +
scale_color_manual(values = c("New Cases" = "#00674F",
"Deaths_US" = "pink")) +
guides(color = "none") +
ylab("Razón") +
xlab("Años") +
xlim(min(Tiroide$Year - 5), max(Tiroide$Year + 6)) +
theme(axis.title = element_text(size = 14, face = "bold"))
A veces nos interesa que la línea muestre los puntos que la componen.
Se añade geom_point() después de
geom_line() para que los puntos aparezcan encima de la
línea:
ggplot(Tiroide, aes(x = as.integer(Year), y = Rate,
group = Cases, color = Cases)) +
geom_line(linewidth = 1) +
geom_point(color = "black", size = 1.5) +
annotate("text", x = 1990, y = 8, size = 4, label = "Nuevos casos") +
annotate("text", x = 2000, y = 2, size = 4, label = "Mortandad") +
guides(color = "none") +
ylab("Razón") +
xlab("Años") +
theme(axis.title = element_text(size = 10, face = "bold"))
Los puntos tienen formas variadas representadas por un número (0 al
25) o un símbolo. La opción fill (para rellenar el punto
con un color específico) es aplicable solamente a las formas 21 a
25.
Los símbolos para las gráficas de puntos
Si las líneas y los puntos son de diferentes colores, se tienen que
especificar los puntos con geom_point()
después de geom_line() ya que ggplot
funciona con capas de información. Lo que se especifica primero, sale
primero (queda debajo).
Ejemplo: puntos encima de la línea (correcto):
ggplot(Tiroide, aes(x = as.integer(Year), y = Rate,
group = Cases, color = Cases)) +
geom_line(linewidth = 3) +
geom_point(shape = 21, size = 3, color = "black", fill = "white") +
guides(color = "none") +
ylab("Razón") + xlab("Años") +
scale_x_continuous(limits = c(2000, 2012)) +
theme(axis.title = element_text(size = 10, face = "bold"))
Ejemplo: puntos debajo de la línea (incorrecto):
ggplot(Tiroide, aes(x = as.integer(Year), y = Rate,
group = Cases, color = Cases)) +
geom_point(shape = 21, size = 4, color = "black", fill = "white") +
geom_line(linewidth = 3) +
guides(color = "none") +
ylab("Razón") + xlab("Años") +
scale_x_continuous(limits = c(2000, 2012)) +
theme(axis.title = element_text(size = 10, face = "bold"))
geom_line()| Parámetro | Descripción | Ejemplo |
|---|---|---|
alpha |
Transparencia (0 = invisible, 1 = opaco) | alpha = 0.5 |
color |
Color de la línea | color = "red" |
linewidth |
Ancho de la línea | linewidth = 1.5 |
linetype |
Tipo de línea | linetype = "dashed" |
group |
Variable que define los grupos | group = Species |
Tipos de línea disponibles:
| Valor | Nombre | Apariencia |
|---|---|---|
| 1 | "solid" |
———— |
| 2 | "dashed" |
– – – – |
| 3 | "dotted" |
· · · · |
| 4 | "dotdash" |
· – · – |
| 5 | "longdash" |
—— —— |
| 6 | "twodash" |
— — — |
geom_ribbon()geom_ribbon() permite añadir una banda sombreada
alrededor de la línea para mostrar incertidumbre (intervalos de
confianza, error estándar, o rango). Esto es muy útil para mostrar la
variabilidad en datos de series temporales.
# Crear datos simulados de temperatura mensual en dos localidades de PR
set.seed(2026)
meses <- rep(1:12, 2)
localidad <- rep(c("Maricao (montaña)", "Lajas (costa sur)"), each = 12)
temp_media <- c(
# Maricao: más fresco, menos variación
19.5, 19.8, 20.5, 21.2, 22.0, 22.8, 23.0, 23.1, 22.7, 22.0, 21.0, 20.0,
# Lajas: más cálido, más variación
25.0, 25.2, 25.8, 26.5, 27.2, 28.0, 28.5, 28.6, 28.2, 27.5, 26.5, 25.5
)
temp_se <- c(
rep(0.8, 12),
rep(1.2, 12)
)
temp_df <- data.frame(
Mes = meses,
Localidad = localidad,
Temp_Mean = temp_media,
Temp_SE = temp_se
) %>%
mutate(
CI_low = Temp_Mean - 1.96 * Temp_SE,
CI_high = Temp_Mean + 1.96 * Temp_SE
)
ggplot(temp_df, aes(x = Mes, y = Temp_Mean,
color = Localidad, fill = Localidad)) +
geom_ribbon(aes(ymin = CI_low, ymax = CI_high),
alpha = 0.2, color = NA) +
geom_line(linewidth = 1.2) +
geom_point(size = 2) +
scale_x_continuous(breaks = 1:12,
labels = c("Ene","Feb","Mar","Abr","May","Jun",
"Jul","Ago","Sep","Oct","Nov","Dic")) +
scale_color_manual(values = c("Maricao (montaña)" = "#2E86AB",
"Lajas (costa sur)" = "#D73027")) +
scale_fill_manual(values = c("Maricao (montaña)" = "#2E86AB",
"Lajas (costa sur)" = "#D73027")) +
labs(x = "Mes", y = "Temperatura media (°C)",
title = "Temperatura mensual en dos localidades de Puerto Rico",
subtitle = "Línea = media, banda = intervalo de confianza al 95%") +
theme_minimal(base_size = 13) +
theme(legend.position = "bottom")
Conceptos clave:
geom_ribbon() necesita ymin y
ymax para definir la banda.geom_line() para
que la línea quede encima.alpha = 0.2 hace la banda semi-transparente.color = NA en el ribbon elimina el borde de la
banda.geom_smooth()Cuando los datos tienen mucho ruido, podemos superponer una línea de
tendencia suavizada. geom_smooth() añade un modelo local
(LOESS o GAM) sobre los datos:
# Datos simulados: conteo de coquíes por noche durante un año
set.seed(99)
dias <- 1:365
# Patrón estacional + ruido
conteo_coqui <- round(30 + 15 * sin(2 * pi * dias / 365 - pi/2) +
rnorm(365, 0, 8))
conteo_coqui <- pmax(0, conteo_coqui)
coqui_df <- data.frame(
Dia = dias,
Fecha = as.Date("2025-01-01") + dias - 1,
Conteo = conteo_coqui
)
ggplot(coqui_df, aes(x = Fecha, y = Conteo)) +
geom_line(alpha = 0.3, color = "grey50") +
geom_smooth(method = "loess", span = 0.15,
color = "#00674F", fill = "#00674F",
alpha = 0.2, linewidth = 1.2) +
labs(x = "Fecha", y = "Coquíes detectados por noche",
title = "Actividad vocal de Eleutherodactylus coqui",
subtitle = "Línea gris = datos diarios, línea verde = tendencia LOESS") +
theme_minimal(base_size = 13)
Conceptos clave:
method = "loess" ajusta un modelo local. Para datos
grandes, usa method = "gam".span controla cuánto se suaviza (valores pequeños = más
detalle, valores grandes = más suave).alpha = 0.3)
muestra el ruido real.geom_step()Cuando los cambios ocurren en puntos discretos (no gradualmente),
geom_step() es más apropiado que geom_line().
Esto es útil para datos de supervivencia, precios, o políticas que
cambian en fechas específicas.
Aquí usamos datos reales del precio promedio anual del petróleo crudo WTI (West Texas Intermediate) en dólares por barril, la referencia principal del mercado petrolero de América del Norte. Fuente: U.S. Energy Information Administration (EIA) y Trading Economics.
# Precio promedio anual del petróleo crudo WTI (USD/barril)
# Fuente: EIA Annual Average + estimaciones 2025-2026
# 2020 incluye el colapso por COVID (WTI llegó a -$37.63 en abril 2020)
# 2022 refleja la invasión rusa de Ucrania
# 2025-2026 reflejan la crisis del Estrecho de Ormuz (conflicto US-Irán)
oil_df <- data.frame(
Year = 2015:2026,
WTI_avg = c(
48.66, # 2015 — glut, oversupply
43.29, # 2016 — OPEC cuts begin
50.80, # 2017 — recovery
65.23, # 2018 — steady growth
56.99, # 2019 — trade war fears
39.16, # 2020 — COVID crash (April: -$37.63!)
67.99, # 2021 — recovery + reopening
94.53, # 2022 — Russia-Ukraine war
77.61, # 2023 — stabilization
75.96, # 2024 — oversupply concerns
68.17, # 2025 — pre-conflict (Jan-Feb avg)
93.00 # 2026 — Strait of Hormuz crisis (Apr est.)
)
)
ggplot(oil_df, aes(x = Year, y = WTI_avg)) +
# Highlight crisis periods
annotate("rect", xmin = 2019.5, xmax = 2020.5,
ymin = -Inf, ymax = Inf,
fill = "#FF9999", alpha = 0.2) +
annotate("rect", xmin = 2021.5, xmax = 2022.5,
ymin = -Inf, ymax = Inf,
fill = "#FFD700", alpha = 0.2) +
annotate("rect", xmin = 2025.5, xmax = 2026.5,
ymin = -Inf, ymax = Inf,
fill = "#FF6B6B", alpha = 0.2) +
geom_step(linewidth = 1.2, color = "#2C3E50") +
geom_point(size = 3, color = "#2C3E50", fill = "white", shape = 21,
stroke = 1.2) +
# Annotate key events
annotate("text", x = 2020, y = 32, label = "COVID-19\ncrash",
size = 2.8, color = "#C0392B", fontface = "italic") +
annotate("text", x = 2022, y = 100, label = "Rusia–\nUcrania",
size = 2.8, color = "#8B6914", fontface = "italic") +
annotate("text", x = 2026, y = 100, label = "Estrecho de\nOrmuz",
size = 2.8, color = "#C0392B", fontface = "italic") +
scale_x_continuous(breaks = 2015:2026) +
scale_y_continuous(labels = scales::dollar_format(suffix = ""),
breaks = seq(30, 100, 10)) +
labs(x = "Año", y = "Precio promedio WTI (USD/barril)",
title = "Precio del petróleo crudo WTI — promedios anuales (2015–2026)",
subtitle = "geom_step() muestra cambios discretos anuales | Fuente: EIA, Trading Economics",
caption = "Nota: 2025 = promedio Ene-Feb pre-conflicto; 2026 = estimado abril (crisis Ormuz)") +
theme_minimal(base_size = 13) +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
plot.caption = element_text(size = 8, color = "grey50"))
Conceptos clave:
geom_step() es más apropiado que
geom_line() aquí porque el precio promedio anual es un
valor discreto — no cambió gradualmente durante el año.annotate("rect") resaltan los
eventos geopolíticos clave que impactaron los precios.geom_segment()geom_segment() permite dibujar segmentos individuales
entre dos puntos. Combinado con arrow(), es útil para
mostrar direcciones de cambio o conectar eventos:
# Cambio en población de tres especies antes y después del huracán María
huracan_df <- data.frame(
Especie = c("Amazona vittata", "Buteo platypterus", "Falco sparverius"),
Antes = c(56, 450, 320),
Despues = c(28, 380, 285),
y_pos = c(3, 2, 1)
)
ggplot(huracan_df) +
geom_segment(aes(x = Antes, xend = Despues,
y = Especie, yend = Especie,
color = Despues < Antes),
linewidth = 2,
arrow = arrow(length = unit(0.3, "cm"), type = "closed")) +
geom_point(aes(x = Antes, y = Especie), size = 4, color = "grey30") +
geom_point(aes(x = Despues, y = Especie), size = 4, color = "red") +
scale_color_manual(values = c("TRUE" = "#D73027", "FALSE" = "#4575B4"),
labels = c("TRUE" = "Disminución", "FALSE" = "Aumento"),
name = "Cambio") +
annotate("text", x = 55, y = 3.3, label = "● Antes ● Después",
size = 3, hjust = 0) +
labs(x = "Población estimada (individuos)",
y = NULL,
title = "Cambio poblacional después del Huracán María (2017)",
subtitle = "Punto gris = antes, punto rojo = después, flecha = dirección") +
theme_minimal(base_size = 13) +
theme(legend.position = "none")
facet_wrap()Cuando hay muchos grupos, poner todas las líneas en un solo gráfico
puede ser confuso. facet_wrap() divide el gráfico en
paneles separados.
Aquí usamos datos reales de precipitación promedio mensual para cuatro ciudades de Puerto Rico. Los datos provienen de las normales climáticas 1991–2020 del NOAA (National Oceanic and Atmospheric Administration), publicadas por U.S. Climate Data. Las unidades originales (pulgadas) se convierten a milímetros.
# Precipitación mensual promedio (pulgadas) — Normales NOAA 1991–2020
# Fuente: https://www.usclimatedata.com/climate/puerto-rico/united-states/7335
lluvia_df <- tribble(
~Ciudad, ~Ene, ~Feb, ~Mar, ~Abr, ~May, ~Jun, ~Jul, ~Ago, ~Sep, ~Oct, ~Nov, ~Dic,
"San Juan (Norte)", 4.07, 2.58, 2.18, 4.60, 5.54, 4.66, 6.02, 6.29, 6.50, 5.21, 7.37, 4.85,
"Ponce (Sur)", 0.73, 1.21, 1.87, 2.26, 4.18, 2.16, 2.84, 4.56, 6.94, 5.38, 3.94, 1.45,
"Fajardo (Este)", 4.42, 3.07, 2.70, 3.41, 8.36, 5.44, 5.91, 5.40, 6.84, 8.00, 7.99, 5.75,
"Mayagüez (Oeste)", 1.57, 2.52, 3.03, 4.06, 7.24, 6.34, 8.66, 9.17, 10.59, 8.94, 4.69, 1.81
)
# Convertir a formato largo y de pulgadas a milímetros
lluvia_long <- lluvia_df %>%
pivot_longer(
cols = Ene:Dic,
names_to = "Mes_nombre",
values_to = "Precip_in"
) %>%
mutate(
Precip_mm = round(Precip_in * 25.4, 1),
Mes = match(Mes_nombre, c("Ene","Feb","Mar","Abr","May","Jun",
"Jul","Ago","Sep","Oct","Nov","Dic")),
Mes_label = factor(Mes_nombre,
levels = c("Ene","Feb","Mar","Abr","May","Jun",
"Jul","Ago","Sep","Oct","Nov","Dic"))
)
# Gráfico con facet_wrap
ggplot(lluvia_long, aes(x = Mes, y = Precip_mm, color = Ciudad)) +
geom_line(linewidth = 1.1) +
geom_point(size = 2.2) +
facet_wrap(~ Ciudad, ncol = 2) +
scale_x_continuous(breaks = 1:12,
labels = c("E","F","M","A","M","J",
"J","A","S","O","N","D")) +
scale_color_manual(values = c(
"San Juan (Norte)" = "#2E86AB",
"Ponce (Sur)" = "#D73027",
"Fajardo (Este)" = "#4DAF4A",
"Mayagüez (Oeste)" = "#984EA3"
)) +
labs(x = "Mes", y = "Precipitación (mm)",
title = "Precipitación mensual promedio por región — Puerto Rico",
subtitle = "Normales climáticas NOAA 1991–2020 | Fuente: U.S. Climate Data",
caption = "Datos convertidos de pulgadas a mm (×25.4)") +
theme_minimal(base_size = 12) +
theme(legend.position = "none",
strip.text = element_text(face = "bold"),
plot.caption = element_text(size = 8, color = "grey50"))
¿Qué patrones se observan?
Versión alternativa — todas las ciudades en un solo panel para comparar directamente:
ggplot(lluvia_long, aes(x = Mes, y = Precip_mm, color = Ciudad)) +
geom_line(linewidth = 1) +
geom_point(size = 2) +
scale_x_continuous(breaks = 1:12,
labels = c("E","F","M","A","M","J",
"J","A","S","O","N","D")) +
scale_color_manual(values = c(
"San Juan (Norte)" = "#2E86AB",
"Ponce (Sur)" = "#D73027",
"Fajardo (Este)" = "#4DAF4A",
"Mayagüez (Oeste)" = "#984EA3"
)) +
labs(x = "Mes", y = "Precipitación (mm)",
title = "Comparación directa de lluvia mensual — 4 regiones de PR",
subtitle = "Normales NOAA 1991–2020",
color = "Ciudad") +
theme_minimal(base_size = 13) +
theme(legend.position = "bottom")
sec_axis()A veces queremos mostrar dos variables con escalas diferentes en el mismo gráfico. Precaución: los ejes duales pueden ser engañosos si no se usan cuidadosamente.
# Datos: temperatura y humedad durante un día en el Yunque
horas <- 0:23
temp_yunque <- 22 + 5 * sin(2 * pi * (horas - 6) / 24) + rnorm(24, 0, 0.5)
humedad_yunque <- 90 - 15 * sin(2 * pi * (horas - 6) / 24) + rnorm(24, 0, 2)
dia_yunque <- data.frame(
Hora = horas,
Temp = round(temp_yunque, 1),
Humedad = round(humedad_yunque, 1)
)
# Factor de escala para el eje secundario
factor_escala <- 3
ggplot(dia_yunque, aes(x = Hora)) +
geom_line(aes(y = Temp), color = "#D73027", linewidth = 1.2) +
geom_line(aes(y = Humedad / factor_escala), color = "#4575B4",
linewidth = 1.2, linetype = "dashed") +
scale_y_continuous(
name = "Temperatura (°C)",
sec.axis = sec_axis(~ . * factor_escala, name = "Humedad relativa (%)")
) +
scale_x_continuous(breaks = seq(0, 23, 3)) +
labs(x = "Hora del día",
title = "Temperatura y humedad — El Yunque, un día típico",
subtitle = "Rojo sólido = temperatura, azul punteado = humedad") +
theme_minimal(base_size = 13) +
theme(
axis.title.y.left = element_text(color = "#D73027", face = "bold"),
axis.title.y.right = element_text(color = "#4575B4", face = "bold")
)
Nota: El eje secundario en ggplot2 es una transformación del eje primario. Se necesita un factor de escala para convertir entre las dos unidades.
annotate("rect")Para destacar un período de interés (un evento, una temporada, una intervención), se puede añadir un rectángulo sombreado:
# Volver al ejemplo de tiroides con período destacado
ggplot(Tiroide, aes(x = as.integer(Year), y = Rate,
group = Cases, color = Cases)) +
# Rectángulo sombreado para el período 2000-2010
annotate("rect", xmin = 2000, xmax = 2010,
ymin = -Inf, ymax = Inf,
alpha = 0.15, fill = "gold") +
annotate("text", x = 2005, y = 14, size = 3,
label = "Período de mayor\n aumento diagnóstico",
fontface = "italic") +
geom_line(linewidth = 1.5) +
geom_point(size = 1.5) +
scale_color_manual(values = c("New Cases" = "#00674F",
"Deaths_US" = "#D73027"),
labels = c("Nuevos casos", "Mortandad")) +
labs(x = "Años", y = "Razón por 100,000",
title = "Cáncer de tiroides en EE.UU.",
color = NULL) +
theme_minimal(base_size = 13) +
theme(legend.position = "bottom")
Comparar las tendencias temporales de observaciones de dos especies del mismo género en Puerto Rico usando datos de iNaturalist.
rinatlibrary(lubridate)
library(leaflet)
library(rinat)
# Definir el bounding box de Puerto Rico
cajaPR <- c(17.75, -67.4, 18.75, -65.15)
# Descargar datos para la primera especie
sp1 <- get_inat_obs(
taxon_name = "Gymnasio nudipes",
quality = "research",
geo = TRUE,
maxresults = 1000,
bounds = cajaPR
)
# Extraer el año de la fecha
sp1$date <- ymd_hms(sp1$datetime)
sp1$Year <- as.integer(format(sp1$date, "%Y"))
# Contar observaciones por año
sp1_conteo <- sp1 %>%
filter(!is.na(Year)) %>%
group_by(Year) %>%
summarize(n = n(), .groups = "drop") %>%
mutate(Especie = "Gymnasio nudipes")
gt(head(sp1_conteo))bind_rows().# Combinar las dos especies
ambas <- bind_rows(sp1_conteo, sp2_conteo)
# Gráfico
ggplot(ambas, aes(x = Year, y = n, color = Especie)) +
geom_line(linewidth = 1.2) +
geom_point(size = 3, shape = 21, fill = "white", stroke = 1.2) +
labs(
x = "Año",
y = "Número de observaciones",
title = "Tendencia de observaciones en iNaturalist — Puerto Rico",
color = "Especie"
) +
theme_minimal(base_size = 13) +
theme(legend.position = "bottom")Especies sugeridas para explorar:
| Grupo | Especie 1 | Especie 2 |
|---|---|---|
| Aves (lechuzas) | Gymnasio nudipes | Megascops nudipes |
| Mamíferos | Rattus norvegicus | Rattus rattus |
| Plantas (orquídeas) | Ionopsis utricularioides | Ionopsis satyrioides |
| Colibríes | Chlorostilbon maugaeus | Anthracothorax viridis |
Usando los datos de coqui_df (creados anteriormente),
calcula la media mensual y el error
estándar del conteo de coquíes, y crea un gráfico con
geom_ribbon() + geom_line().
# Paso 1: Extraer el mes
coqui_mensual <- coqui_df %>%
mutate(Mes = month(Fecha)) %>%
group_by(Mes) %>%
summarize(
Media = mean(Conteo),
SE = sd(Conteo) / sqrt(n()),
.groups = "drop"
) %>%
mutate(
CI_low = Media - 1.96 * SE,
CI_high = Media + 1.96 * SE
)
# Paso 2: Completa el gráfico
ggplot(coqui_mensual, aes(x = ___, y = ___)) +
geom_ribbon(aes(ymin = ___, ymax = ___),
fill = "___", alpha = ___) +
geom_line(linewidth = ___, color = "___") +
geom_point(size = ___, color = "___") +
scale_x_continuous(breaks = 1:12,
labels = c("E","F","M","A","M","J",
"J","A","S","O","N","D")) +
labs(x = "Mes", y = "Coquíes por noche (media ± IC 95%)",
title = "Patrón estacional de actividad de coquí") +
theme_minimal()linetype y
geom_step()Usando los datos de tiroides, crea un gráfico donde:
linetype = "solid" y
geom_line()linetype = "dashed" y
geom_line()geom_step() en lugar de
geom_line().Pregunta: ¿Cuál representación es más apropiada para datos que se miden una vez por año? ¿Por qué?
Descarga datos de iNaturalist para 4 especies de un
mismo orden o familia en Puerto Rico. Crea un gráfico con
facet_wrap() mostrando la tendencia temporal de cada
especie en un panel separado.
Usando cualquier conjunto de datos temporal, crea un gráfico de líneas que:
annotate("rect") para resaltar un período
importante (por ejemplo, el paso del Huracán María en septiembre
2017).annotate("text")
explicando el evento.geom_vline() para marcar la fecha exacta del
evento.# Pista: geom_vline para una línea vertical en una fecha específica
geom_vline(xintercept = as.numeric(as.Date("2017-09-20")),
linetype = "dashed", color = "red", linewidth = 0.8)| Función | Propósito |
|---|---|
geom_line() |
Línea que conecta puntos en orden |
geom_step() |
Línea escalonada para cambios discretos |
geom_smooth() |
Línea de tendencia suavizada (LOESS/GAM) |
geom_ribbon() |
Banda de confianza/incertidumbre |
geom_segment() |
Segmento entre dos puntos (con flechas opcionales) |
geom_point() |
Puntos sobre la línea |
geom_vline() / geom_hline() |
Líneas de referencia vertical/horizontal |
annotate("text") |
Texto libre en el gráfico |
annotate("rect") |
Rectángulo sombreado para resaltar períodos |
facet_wrap() |
Paneles separados por grupo |
scale_color_manual() |
Colores personalizados por grupo |
scale_linetype_manual() |
Tipos de línea personalizados por grupo |
sec_axis() |
Eje secundario (transformación del primario) |