INTRODUCCIÓN
Una serie temporal es una secuencia de observaciones registrada de forma consecutiva en instantes de tiempo. El objetivo es revelar los cambios de una o más variables cuantitativas y mostrar las relaciones entre las variables y su evolución a través del tiempo.
Esta solución permite representar bastantes variables que se mostrarán junto con un diagrama de dispersión, utilizando diferentes paneles para subconjuntos de datos (tiempo como variable condicionante) o utilizando diferentes atributos para grupos de datos.
Las siguientes secciones proporcionan una variedad de ejemplos para representar un conjunto de técnicas útiles que trabajan con tres conjuntos de datos disponibles en los datos de la carpeta del repositorio.
Este documento ha sido preparado con contenido extraído y adaptado de la segunda edición del libro “Visualización de series temporales, espaciales y datos de espacio-tiempo con R” publicado “con Chapman & Hall / CRC”.
Los paquetes a tener en cuenta son: lattice, latticeExtra y ggplot2 para gráficos estáticos; zoo y xts para leer y organizar datos como series temporales; RColorBrewer para definir el color de las paletas; para los paquetes de graficos highcharter y plotly, basados en htmlwidgets para generar animaciones o gráficos interactivos.
Ahora cargaremos los paquetes principales y configuraremos algunos parámetros gráficos de Latitice y LatticeExtra:
library(lattice)
library(ggplot2)
# Debemos cargar primero ggplot2 antes que LatticeExtra para evitar el enmascaramiento de los 'layers'
library(latticeExtra)
##
## Attaching package: 'latticeExtra'
## The following object is masked from 'package:ggplot2':
##
## layer
library(RColorBrewer)
# Configuracion de lattice y latticeExtra
myTheme <- custom.theme.2(
pch=19, cex=0.7, region=rev(brewer.pal(9, 'YlOrRd')),
symbol=brewer.pal(n=8, name="Dark2"))
myTheme$strip.background$col = myTheme$strip.shingle$col =
myTheme$strip.border$col = 'transparent'
myArgs <- list(
as.table=TRUE, between=list(x=0.5, y=0.2),
xscale.components = function(...)
modifyList(xscale.components.default(...), list(top=FALSE)),
yscale.components = function(...)
modifyList(yscale.components.default(...), list(right=FALSE)))
lattice.options(default.theme=myTheme, default.args=modifyList(
lattice.options()$default.args, myArgs))
library(zoo)
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
BASES DE DATOS
Las bases de datos a usar serán:
load('aranjuez.RData')
load('navarra.RData')
load('CO2.RData')
Tiempo en el eje horizontal
El método de visualización más frecuente de una serie temporal utiliza el eje horizontal para representar el índice de tiempo. Esta sección representa dos variantes para mostrar series temporales multivariadas: múltiples series temporales con diferentes escalas y variables con la misma escala.
Gráfico temporal de variables con diferentes escalas
Para el primer ejemplo, utilizaremos los ocho años de datos diarios de una estación meteorológica ubicada en Aranjuez (Madrid). Esta serie temporal multivariante se puede mostrar con el diagrama xyplot para objetos zoo con un panel para cada variable.
# El argumento del layout organiza los paneles en filas con el comando:
xyplot (aranjuez, layout = c (1, ncol (aranjuez)))
El paquete ggplot2 posee el método genérico de autoplot para automatizar la representacion de un cierto tipo de clases con un simple comando; el paquete zoo posee un metodo de autoplot para la clase zoo con un resultado similar para ser obtenido con xyplot.
# facet_free permite que cada panel tenga su propio rango:
autoplot(aranjuez) + facet_free()
Series temporales con variables con la misma escala
En este caso usaremos las medidas de radiación solar de diferentes estaciones de meteorología.
El primer paso para representar series temporales multivariadas seras usar el metodo xyplot.zoo; el objetivo de este grafico sera representar las series superpuestas en el mismo panel (superpose = TRUE) sin leyenda (auto.key = FALSE), usando finas lineas y parcial transparencia.
El siguiente código muestra las variaciones alrededor del tiempo promedio:
avRad <- zoo(rowMeans(navarra, na.rm = 1), index(navarra))
pNavarra <- xyplot(navarra - avRad,
superpose = TRUE, auto.key = FALSE,
lwd = 0.5, alpha = 0.3, col = 'midnightblue')
pNavarra
Este grafico es util para ver como una gran cantidad de series cambian con el paso del tiempo y permite realizar comparaciones entre series temporales individuales y analisis independiente de cada variable, ademas los patrones predominantes son facilmente distinguibles.
El siguiente código muestra las variaciones de la radiación solar a lo largo del tiempo medio con un gráfico de horizontes usando una fila para cada serie de tiempo. En el código elegimos origin=0 y dejamos el argumento horizonscale predeterminado. Con esta combinación cada panel tiene diferentes escalas y los colores en cada panel representan desviaciones del origen.
horizonplot(navarra - avRad,
layout = c(1, ncol(navarra)),
origin = 0, ## Deviations in each panel are calculated
## from this value
colorkey = TRUE,
col.regions = brewer.pal(6, "RdBu"))
Estes grafico tambien es util para revelar las diferencias entre una serie temporal univariada y otras referencias. Por ejemplo, vamos a usarlo con la serie temporal de temperaturas medias medidas en la estacion de meteorologia de Aranjuez, esto lo calcularemos con el comande ‘ave’:
Ta <- aranjuez$TempAvg
timeIndex <- index(aranjuez)
longTa <- ave(Ta, format(timeIndex, '%j'))
diffTa <- (Ta - longTa)
El siguiente codigo usa horizonplot para cortar y apilar y poder distinguir entre años:
years <- unique(format(timeIndex, '%Y'))
horizonplot(diffTa, cut = list(n = 8, overlap = 0),
colorkey = TRUE, layout = c(1, 8),
scales = list(draw = FALSE, y = list(relation = 'same')),
origin = 0, strip.left = FALSE) +
layer(grid.text(years[panel.number()], x = 0, y = 0.1,
gp = gpar(cex = 0.8),
just = "left"))
La primera alternativa será un diagrama de nivel que usa un indice de tiempo tanto como variable independiente como condicionante, en este grafico se muestra las diferencias con el dia del mes en el eje horizontal y el año en vertical:
year <- function(x)as.numeric(format(x, '%Y'))
day <- function(x)as.numeric(format(x, '%d'))
month <- function(x)as.numeric(format(x, '%m'))
myTheme <- modifyList(custom.theme(region = brewer.pal(9, 'RdBu')),
list(
strip.background = list(col = 'gray'),
panel.background = list(col = 'gray')))
maxZ <- max(abs(diffTa))
levelplot(diffTa ~ day(timeIndex) * year(timeIndex) | factor(month(timeIndex)),
at = pretty(c(-maxZ, maxZ), n = 8),
colorkey = list(height = 0.3),
layout = c(1, 12), strip = FALSE, strip.left = TRUE,
xlab = 'Day', ylab = 'Month',
par.settings = myTheme)
GRÁFICOS INTERACTIVOS
Esta seccion trae algunos graficos interactivos para las secciones anteriores con los siguientes paquetes: dygraphs , highcharter y plotly. Estos paquetes son usados para bibliotecas Javascript y en paquetes de htmlwidgets.
Diagramas
El paquete dygraphs es una interfaz para JavaScript y proporciona herramientas para trazar series temporales. Funciona automáticamente con objetos de series temporales xts o con objetos parecidos que sean de la misma clase.
El resultado es un gráfico interactivo, donde los valores se muestran de acuerdo con la posición del mouse a lo largo de la serie temporal.
library(dygraphs)
dyTemp <- dygraph(aranjuez[, c("TempMin", "TempAvg", "TempMax")],
main = "Temperature in Aranjuez",
ylab = "ºC")
widgetframe::frameWidget(dyTemp)
La salida de esta serie temporal es unicamente para Javascript
Highcharter
El paquete highcharter es una interfaz para los highcharts de JavaScript, con un amplio espectro de gráficos. Se puede lograr visualizar series temporales con este paquete con la combinación de la función genérica highchart y varias llamadas a la función hc_add_series_xts través del operador %>%
library(highcharter)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
## Highcharts (www.highcharts.com) is a Highsoft software product which is
## not free for commercial and Governmental use
library(xts)
aranjuezXTS <- as.xts(aranjuez)
highchart() %>%
hc_add_series(name = 'TempMax',
aranjuezXTS[, "TempMax"]) %>%
hc_add_series(name = 'TempMin',
aranjuezXTS[, "TempMin"]) %>%
hc_add_series(name = 'TempAvg',
aranjuezXTS[, "TempAvg"]) %>%
widgetframe::frameWidget()
#El resultado se puede observar directamente desde el Viewer, en salida html nos da error.
El tiempo como condicionante
Esta seccion esta orientada a un diagrama de dispersion que se definen segun el tiempo como una agrupacion de variables, y despues, un grafico de dispersion mejorado con el tiempo como condicionamiento.
Scatterplot matrix
Una matriz de diagrama de dispersión es una visualización de todos los diagramas de dispersión bivariados por pares dispuestos en una matriz (p veces p ) para las variables (p ) . Cada subtrama muestra la relación entre el par de variables en la intersección de la fila y columna indicada por los nombres de las variables en los paneles diagonales.
El siguiente código muestra la relación entre el conjunto de variables meteorológicas utilizando una paleta secuencial de ColorBrewer para codificar el mes. El orden de colores de esta paleta se elige para mostrar los meses de verano con colores intensos y para distinguir entre el primero y la segunda mitad del año con rojo y azul, respectivamente.
aranjuezDF <- as.data.frame(aranjuez)
aranjuezDF$Month <- format(index(aranjuez), '%m')
## Red-Blue palette with black added (12 colors)
colors <- c(brewer.pal(n = 11, 'RdBu'), '#000000')
## Rearrange according to months (darkest for summer)
colors <- colors[c(6:1, 12:7)]
splom(~ aranjuezDF[1:10], ## Do not include "Month"
groups = aranjuezDF$Month,
auto.key = list(space = 'right',
title = 'Month', cex.title = 1),
pscale = 0, varname.cex = 0.7, xlab = '',
par.settings = custom.theme(symbol = colors,
pch = 19),
cex = 0.3, alpha = 0.1)
Ahora lo que haremos será mostrar diagramas de dispersión separados con un panel para cada mes. Además, se incluye promedio, máximo, mínimo como una variable de condicionamiento adicional.
Primero, el conjunto de datos debe reformarse desde el formato ancho al formato largo. La versión con lattice necesita la función useOuterStrips del paquete latticeExtra , que imprime los nombres del condicionamiento variables en los márgenes exteriores superior e izquierdo.
library(reshape2)
aranjuezRshp <- melt(aranjuezDF, measure.vars = c('TempMax', 'TempAvg', 'TempMin'), variable.name = 'Statistic', value.name = 'Temperature')
useOuterStrips(
xyplot(Temperature ~ Radiation | Month * Statistic,
data = aranjuezRshp,
between = list(x = 0),
col = 'skyblue4', pch = 19,
cex = 0.5, alpha = 0.3)) +
layer({
panel.rug(..., col.line = 'indianred1',
end = 0.05, alpha = 0.6)
panel.loess(..., col = 'indianred1',
lwd = 1.5, alpha = 1)
})
Polilíneas
Nuestro primer enfoque es mostrar todos los datos en un panel con un diagrama de dispersión utilizando nombres de países como factor de agrupación. Los puntos de cada país están conectados con polilíneas para revelar la evolución del tiempo.
## lattice version
xyplot(GNI.capita ~ CO2.capita, data = CO2data,
xlab = "Carbon dioxide emissions (metric tons per capita)",
ylab = "GNI per capita, PPP (current international $)",
groups = Country.Name, type = 'b')
Se pueden agregar tres mejoras a este resultado gráfico:
1.- Defina una mejor paleta de colores para los países.
2.-Mostrar la información del tiempo con etiquetas para mostrar los valores del año.
3.- Etiquetar cada polilínea con el nombre del país en lugar de una leyenda.
Elegir colores
Para llevar acabo esto usaremos la variable Country.Name, aunque algunos paises usaran el mismo color, esto se solucionará etiquetando los paises y mostrandolos a una distancia suficiente.
nCountries <- nlevels(CO2data$Country.Name)
pal <- brewer.pal(n = 5, 'Set1')
pal <- rep(pal, length = nCountries)
## Rank of average values of CO2 per capita
CO2mean <- aggregate(CO2.capita ~ Country.Name,
data = CO2data, FUN = mean)
palOrdered <- pal[rank(CO2mean$CO2.capita)]
## simpleTheme encapsulates the palette in a new theme for xyplot
myTheme <- simpleTheme(pch = 19, cex = 0.6, col = palOrdered)
## lattice version
pCO2.capita <- xyplot(GNI.capita ~ CO2.capita,
data = CO2data,
xlab = "Carbon dioxide emissions (metric tons per capita)",
ylab = "GNI per capita, PPP (current international $)",
groups = Country.Name,
par.settings = myTheme,
type = 'b')
pCO2.capita
Este resultado puede mejorarse con etiquetas que muestren los años para mostrar la evolución del tiempo. La función de panel panel.text imprime las etiquetas de año con la combinación de +.trellis , glayer_ y panel.text . Usando glayer_ lugar de glayer nos aseguramos de que las etiquetas se imprimen debajo de las líneas.
## lattice version
pCO2.capita <- pCO2.capita +
glayer_(panel.text(...,
labels = CO2data$Year[subscripts],
pos = 2, cex = 0.5, col = 'gray'))
pCO2.capita
La mejor manera es etiquetar cada línea usando un texto cercano con la codificación del mismo color. Un método adecuado es colocar las etiquetas evitando la superposición entre etiquetas y líneas. El paquete ‘directlabels’ incluye un amplio repertorio de métodos de posicionamiento para hacer frente a la superposición. La función principal es ‘direct.label’.
library(directlabels)
## lattice version
direct.label(pCO2.capita,
method = 'extreme.grid')
Agradecimientos
Créditos al autor: Oscar Perpiñán Lamigueiro