Seguiremos utilizando los mismos paquetes que la parte anterior.
Code
# ejecutar estas líneas para poder instalar {datos}# install.packages("remotes")# remotes::install_github("cienciadedatos/datos")library(datos)# datoslibrary(highcharter)# gráficoslibrary(ggplot2)# más gráficos library(dplyr)# manipulación de datoslibrary(tidyr)# más manipulación de datos
Mapa de calor. Usualmente se utiliza para visualizar relaciones entre dos variables categorícas (o 2 contínuas categorizandolas). En este ejemplo utilizaremos día y hora como una variables “numericas discretas”.
Caso de heatmaps son los visualizar distancia entre observaciones/individuos.
Code
mtautos2<-mtautos[1:20, ]matriz_distancias<-dist(mtautos2)hchart(matriz_distancias)%>%hc_title(text ="Distancia entre características de los vehículos")
Medio/Avanzado. Es la implementación de este ejemplo https://www.highcharts.com/demo/heatmap-canvas. Notar la relación de opciones en HighchartsJS y {highcharter}.
Code
# install.packages("aimsir17")library(lubridate)data(observations, package ="aimsir17")temperaturas<-observations%>%filter(station=="KNOCK AIRPORT")%>%select(fecha =date, hora =hour, temperatura =temp)%>%mutate(fecha =as.Date(fecha))# temperaturas %>% # count(fecha, hora) %>% # count(n)hc11<-hchart(temperaturas,"heatmap",hcaes(datetime_to_timestamp(fecha), hora, value =temperatura), colsize =36e5*24# 1 hour * 24 = 1 day)%>%hc_title(text ="Temperaturas del aeropuerto Knock")%>%hc_subtitle(text ="Datos obtenidos del paquete {aimsir17}.")%>%hc_chart(zoomType ="x")%>%hc_xAxis( type ="datetime", title =list(text =FALSE), showLastLabel =FALSE)%>%hc_yAxis( minPadding =0, maxPadding =0, startOnTick =FALSE, endOnTick =FALSE, tickPositions =list(0, 6, 12, 18, 24), tickWidth =1, min =0, max =23, reversed =TRUE, labels =list(format ="{value}:00"), title =list(text =FALSE))%>%hc_tooltip( headerFormat ="Temperatura<br/>", pointFormat ="{point.x:%e %b, %Y} {point.y}:00: <b>{point.value} ℃</b>")%>%hc_colorAxis( stops =color_stops(10, colors =scales::viridis_pal(option ="B")(10)),# fuerza a utilzar mejor el espectro de colores para que HJS no amplie el# eje para tener numero "redondos startOnTick =FALSE, endOnTick =FALSE)%>%hc_legend( align ="right", layout ="vertical", verticalAlign ="top")hc11
Día 12: paleta (lollipop)
Gráfico que se utiliza en forma general para describir una variable numérica para un set de individuos/registros (a diferencia de gráfico de barra que usualmente se utiliza sumando cantidades por categoría).
Los datos a utilizar son mtautos del paquete {datos} pero pasando algunas variables a las métricas que usualemente utilizamos: libras a kilos, pulgadas cúbicas a centímeotrs cúbicos, etc.
La implementación en {highcharter} es directa, solamente usar el mapeo de name para la variable categórica y low para la numérica (low dado que esta es una modificación del gráfico de dumbbell que utiliza además high).
Basico/Medio. En esta oportunidad haremos un tooltip de tipo tabla con el fin de mostrar más información que los HP de cada vehículo. Para esto usaremos la función auxiliar tooltip_table en el argumento pointFormat.
Code
x<-c("Caballos:", "Peso", "Cilindrada")y<-c("{point.y} HP","{point.peso_kg} kg","{point.cilindrada_cc} cc")hc12<-hchart(mtautos2, "lollipop", hcaes(name =auto, low =caballos), name ="caballos (HP)")%>%hc_xAxis(type ="category")%>%hc_yAxis(labels =list(format ="{value} HP"))%>%hc_tooltip( useHTML =TRUE, pointFormat =tooltip_table(x, y))%>%hc_title( text ="Caballos de fuerza para autómóviles de Motor Trend")%>%hc_subtitle( text ="Los datos fueron extraídos de la revista Motor Trend de Estados Unidos de 1974, y tiene datos de consumo de combustible y 10 aspectos de diseño y rendimiento para 32 automóviles (modelos de 1973-1974).")hc12
Día 13: visualizar datos temporales
Notar que el último gráfico del día 11 es un caso particular de de visualizar datos temporales.
Usualmente en R los datos temporales o serie de tiempo vienen en un objecto de clase ts (time series) que básicamente son valores numéricos asociado a una fecha (o índice). Notar que también datos temporales pueden perfectamente almacenarse en un data.frame, nota los datos observations del día 11.
Para grafica objectos de clase ts en {highcharter} es bastante directo dado que hchart es una función genérica. Esto significa que la función dependiendo de la clase del objeto la interpretará/graficará de la forma que corresponde. Por ejemplo ts y data.frame son clases que la función hchart reconoce, y existen muuuchas más clases que hchart puede interpretar, intenta correr methods("hchart") para listar todas las clases que actualmente esta función soporta.
Volviendo a nuestro gráfico en R existe los datos co2 que son una serie de tiempo (clase ts).
Time-Series [1:468] from 1959 to 1998: 315 316 316 318 318 ...
Code
hc13<-hchart(co2, name ="Concentración")%>%hc_title(# para poder usar el tag html "sub" para subindices useHTML =TRUE, text ="Concentración atomsférica de CO<sub>2</sub> en Mauna Loa")%>%hc_subtitle( text ="Las concentraciones atmosféricas de CO2 se expresan en partes por millón (ppm) y se informan en la escala preliminar de fracción molar manométrica SIO de 1997.")hc13
Aprovechando que estamos revisando series de tiempo, podemos hacer una descomposición usando Loess (suavizamiento). La función stl toma un serie de tiempo descomponiéndola en tendencia, componente estacional y ruido.
Como veremos, el gráfico se realiza simplemente como hchart(descomposicion):
Code
descomposicion<-stl(co2, "per")hc132<-hchart(descomposicion)%>%hc_tooltip(valueDecimals =2)%>%hc_title( useHTML =TRUE, text ="Descomposición de la Concentración atomsférica de CO<sub>2</sub> en Mauna Loa utilizando la funcion <code>stl</code>")%>%hc_subtitle( text ="<b>Descripción del comando <code>stl</code></b>: El componente estacional se encuentra al suavizar loess la sub-serie estacional (la serie de todos los valores de enero, ...); si s.window = 'periódico' suavizado se reemplaza efectivamente tomando la media. Los valores estacionales se eliminan y el resto se suaviza para encontrar la tendencia. El nivel general se elimina del componente estacional y se agrega al componente de tendencia. Este proceso se repite varias veces. El componente restante son los residuos del ajuste estacional más tendencial.")%>%hc_tooltip(table =TRUE)%>%hc_size(height ="700px")hc132
Para finalizar ejemplificaremos la integración de {highcharter} con el paquete {forecast} con el cual se puede realizar predicciones de los datos de forma simple.
Code
library(forecast)pronosticos<-forecast(ets(USAccDeaths), h =48, level =95)hc133<-hchart(pronosticos)%>%hc_title( text ="Muertes por accidentes en los EE. UU. 1973–1978 más predicciones generadas utilizando {forecast}")%>%hc_tooltip(shared =TRUE, valueDecimals =2)hc133
Día 14: treemaps
Es un buen gráfico para sustituir el gráfico de barras cuando la cantidad de categorías aumentan. También sirve como alternativa a los gráficos de torta o dunut (ñami!)
hchart(conteo_clases,"treemap",hcaes(clase, value =n, colorValue =n), borderColor =NA# elimina border y se tiene un aspecto más limpio imho)%>%hc_colorAxis(stops =color_stops())%>%hc_title(text ="Conteo de tipos de automóviles en los datos 'millas'")%>%hc_colorAxis(endOnTick =FALSE)
Avanzado. Este es una guia en español para hacer un treemap mostrando la cardinalidad de cada tipo y subtipo de pokemon. Primero descargaremos los datos desde el repositorio https://github.com/PokeAPI/pokeapi/tree/master/data/v2/csv.
pkmn_nombre_tipos<-read_csv(file.path(url_base, "type_names.csv"))%>%# inglés es 9, Japonez es 1, español 7filter(local_language_id==9)pkmn_tipo<-read_csv(file.path(url_base, "pokemon_types.csv"))pkmn_tipo<-pkmn_tipo%>%mutate(slot =paste0("type_", slot))%>%left_join(pkmn_nombre_tipos, by ="type_id")%>%select(pokemon_id, slot, name)%>%spread(slot, name)
Ahora, la gracia del treemap que haremos es que serán los colores. Esto es lo que hara llamativo nuestro gráfico.
Ahora, calcularemos todas las combinaciones entre todos los colores para luego promediarlos y generar un matiz entre el color con el del segundo tipo. Esto se hace con la función colorRampPalette.
A continuación, finalmente, uno de los treemaps del cual estoy orgulloso! :)
Code
hc14<-highchart()%>%hc_chart(type ="treemap")%>%hc_title( text ="Pokemon por tipos")%>%hc_add_series( data =dd, allowDrillToNode =TRUE, levelIsConstant =FALSE, textOverflow ="clip", dataLabels =list(color ="white"), levels =list(list( level =1, borderWidth =1, dataLabels =list( enabled =TRUE, verticalAlign ="top", align ="left", style =list(fontSize ="12px", textOutline =FALSE))),list( level =2, borderWidth =0, dataLabels =list(enabled =FALSE))))%>%# esto es para que el primer nivel, que no tiene color asigando, # sea transparente.hc_colors("trasnparent")hc14%>%hc_size(height =800)
Día 15: dendogramas
Los dendogramas son una 2da iteración a la visualización de distancia entre individuos o registros en una tabla como lo es el primer gráfico del día 11. Los dendogramás son complejos de leer pues traen mucha más información debido a que podemos ver como se van agrupando (en términos de distancia) las observaciones. Que una esté cerca de otra significa que sus carácterísticas son similares.
Para gráficar en {highcharter} haremos ya el conocido truco de extraer la información luego de generer un ggplot con la información. Un paquete para generar dendogramas usando {ggplot2} es {ggdendro}.
Los dendogramas salen como un resultado a partir de un “agrupamiento jerárquico” que viene a su vez de una matriz de distancias, por lo que calcularemos la clasterización antes de graficar el dendograma.
Code
# install.packages("ggdendro")library(ggdendro)hc<-hclust(dist(mtautos), "ave")ggd<-ggdendrogram(hc, rotate=TRUE)dd15<-as_tibble(ggplot2::layer_data(ggd, 2))dd152<-dd15%>%select(x, xend, y, yend)%>%mutate(id =row_number())%>%gather(key, value, -id)%>%mutate(key =stringr::str_remove(key, "end"))%>%group_by(id, key)%>%mutate(id2 =row_number())%>%spread(key, value)%>%ungroup()%>%select(-id2)%>%mutate_if(is.numeric, round, 3)hc15<-hchart(dd152,"line",# x - 1 pues al colocar categorúías hcaes(x-1, y, group =id), color ="red", showInLegend =FALSE)%>%# https://stackoverflow.com/questions/43638810/how-to-get-labels-from-hclust-resulthc_xAxis( categories =hc$labels[hc$order], title =list(text ="Vehículos"))%>%hc_yAxis( title =list(text ="Distancia"), endOnTick =FALSE, crosshair =TRUE)%>%hc_tooltip( headerFormat ="", pointFormat ="<b>x</b>: {point.x}<br><b>y</b>:{point.y}", valueDecimals =2)%>%hc_title( useHTML =TRUE, text ="Dendograma en el dataset <code>mtautos</code>")hc15
Día 16: gráficos de waffle
También conocidos como pie cuadrados los gráficos de waffle son una alternativa a los pie charts. Em highchartsJS -por tanto en {highcharter}- el equivalente es “item”.
# A tibble: 5 × 2
corte n
<ord> <int>
1 Regular 29
2 Bueno 101
3 Muy bueno 227
4 Premium 250
5 Ideal 393
Code
hc16<-hchart(diamantes_cortes_1000,"item", hcaes(name =corte, y =n), name ="cortes", marker =list(symbol ="square"), showInLegend =TRUE)%>%hc_title( text ="Distribución de cortes en una muestra de 1000 diamantes")hc16
También tiene se puede configurar para que en realidad parezca un “parlamento”.
Code
hchart(diamantes_cortes_1000,"item", hcaes(name =corte, y =n), name ="cortes",# marker = list(symbol = "square"), showInLegend =TRUE, size ="100%", center =list("50%", "75%"), startAngle =-100, endAngle =100)%>%hc_title( text ="Distribución de cortes en una muestra de 1000 diamantes con un layout de <i>Parlamento</i>")%>%hc_legend( labelFormat ='{name} <span style="opacity: 0.4">{y}</span>')
Día 17: diagramas de sankey
Con los sankey plots se puede estudiar las distribución de más variables y como se distribuyen las categorías con las categorías de las variables adyacentes:
Medio. Usualmente, los sankey necesitan un formato de datos donde se especifique desde, hacia y el peso. En una tabla usual, tidy de debe calcular los contedos de combinaciones de categorías. Para ello generamos un código el cual puede ser reusado en otra ocación con otros datos.
Hay muchos tipos de datos y formas de representar espaciales:
Coropletas
Puntos/burbujas
Arcos
Contornos
Y supongo que muchos más.
En esta oportunidad haremos coropletas que viene a colorear regiones de acuerdo a valores o categoría de una variable. En highcarter podemos utilizar como entrada archivos geojson los cuales representan características grográficas.
Utilizaremos un geojson del gran Santiago que está en el repositorio de @robsalasco (su twitter y github). También utilizaremos su paquete {sinimr} para acceder al sistema de información de municipalidades de Chile.
Ahora datos para rellenarlos. Como mencionamos utilizaremos el paquete {sinimr} https://github.com/robsalasco/sinimr:
Code
# remotes::install_github("robsalasco/sinimr")library(sinimr)varcode<-882nombre_variable<-sinimr::get_sinim_var_name(varcode)nombre_variable<-stringr::str_to_title(nombre_variable)dvar<-get_sinim(varcode, 2018, region =13, truevalue =TRUE)%>%as_tibble()%>%select(code, value)dvar<-dvar%>%left_join(dcomuna, by =c("code"="comuna"))%>%mutate(value =round(value/1e6))dvar
En higcharter los datos goeográficos van en el arguemnto mapData y los datos que tienen la información para pintar van en el data. Notar que necesitamos parsear los datos a lista con la función list_parse y que los datos deben venir con la columna value la cual se utilizará tanto para le color, leyenda, etc. Otra cosa importante es el joinBy que viene a ser lo que en un left_join es el arguemnto by.
Code
highchart(type ="map")%>%hc_add_series( mapData =gransantiago_geojson, data =list_parse(dvar),# "COMUNA" es la key en el geojson, "code" es la key en nuestros datos: dvar joinBy =c("COMUNA", "code"), showInLegend =FALSE, name =nombre_variable, dataLabels =list(enabled =TRUE, format ="{point.nom_comuna}"))%>%hc_colorAxis(minColor ="white", maxColor ="red", endOnTick =FALSE)%>%hc_tooltip(# estos campos son de los datos dvar pointFormat ="<b>{point.nom_comuna}</b>: ${point.value} MM")%>%hc_title( text ="Ingresos propios por comunas del gran Santiago para el año 2018")%>%hc_subtitle( text ="Datos obtenidos del paquete {sinimr} por @robsalasco")%>%hc_size(height =800)
Avanzado. Utilizaremos unas de las funcionalidades más entretenidas de {highcharter} que es poner gráficos dentro de un tooltip! Para esto es necesario tener una data parseada en lista (de nuevo list_parse) para luego utilizarla en conjunto con la función tooltip_chart en el argumento pointFormatter en la función hc_tooltip.
Los datos para este ejemplo son los del Ministerio de Ciencia que cuenta por comuna los casos registrados por COVID-19.
hc18<-highchart(type ="map")%>%hc_add_series( mapData =gransantiago_geojson, data =list_parse(dcovid),# "COMUNA" es la key en el geojson, "code" es la key en nuestros datos: dvar joinBy =c("COMUNA", "comuna"), showInLegend =FALSE, name ="Covid", borderColor ='transparent', borderWidth =0.1, dataLabels =list( enabled =TRUE, format ="{point.nom_comuna}", style =list(fontSize ="12px", color ="#F5F5F5")))%>%hc_colorAxis( stops =color_stops(n =10, viridis_pal(option ="B", end =0.95)(10)),# fuerza a utilzar mejor el espectro de colores para que HJS no amplie el# eje para tener numero "redondos endOnTick =FALSE)%>%hc_tooltip( useHTML =TRUE, headerFormat ="{point.key}", pointFormatter =tooltip_chart( accesor ="ttdata", hc_opts =list( subtitle =list(text ="point.nom_comuna"), chart =list(backgroundColor ="white"), xAxis =list(type ="datetime", showLastLabel =TRUE, endOnTick =FALSE), yAxis =list(showLastLabel =TRUE, endOnTick =FALSE), credits =list(enabled =FALSE)), height =225, width =400))%>%hc_title( text ="Casos COVID-19 en el Gran Santiago", align ="center")%>%hc_subtitle( text =paste("Datos Ministerio de Ciencia; con última actualización el", maxfecha), align ="center")%>%hc_legend(symbolWidth =500, align ="center", verticalAlign ="top")hc18%>%hc_size(height =800)
Día 19: streamgraph
El steamgraph puede crearse a partir de un gráfico de áreas apiladas cuando en el eje x se utiliza una variable temporal. ¿Recuerdan el gráfico de áreas apiladas que hicimos en la parte 1? En el ejemplo teníamos en el eje x una variable asociada al tiempo por lo que podemos reutilizar el código simplemente cambiado el tipo de gráfico de "area" a "streamgraph".
Por tanto reutilizaremos el mismo código:
Code
library(scales)# para viridis_paldata(movies, package ="ggplot2movies")colores<-viridis_pal(option ="B", end =0.8)(7)peliculas<-movies%>%select(anio =year, Action:Short)%>%gather(categoria, cantidad, -anio)%>%group_by(anio, categoria)%>%summarise(cantidad =sum(cantidad))%>%mutate( categoria =case_when(categoria=="Action"~"Acción",categoria=="Animation"~"Animación",categoria=="Comedy"~"Comedia",categoria=="Documentary"~"Documental",categoria=="Drama"~"Drama",categoria=="Romance"~"Romance",categoria=="Short"~"Cortometraje",TRUE~NA_character_))eventos<-tibble( anio =c(1930, 1941, 1990), texto =c("Comienzo era dorada<br>en Hollywood.","Aparición<br>de la televisión.","Comienzo aumento<br>del cine independiente."))data_plotLine<-eventos%>%transmute( value =anio, label =purrr::map(texto, ~list(text =.x)))%>%mutate(color ="#666", width =2, zIndex =5)hc19<-hchart(peliculas, "streamgraph", hcaes(anio, cantidad, group =categoria))%>%hc_yAxis(visible =FALSE)%>%# no tiene mucho sentido elhc_colors(colores)%>%hc_tooltip(table =TRUE, sort =TRUE)%>%hc_xAxis( plotLines =list_parse(data_plotLine))%>%hc_title( text ="Cantidad de películas por Género")%>%hc_caption( text ="Datos provenientes de <b>IMDB</b> a través del paquete ggplot2movies.<br> La Mayoria de eventos fueron obtenidos a partir de lectura flash en <b>Wikipedia</b>.")%>%# https://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/legend/verticalalign/hc_chart( marginRight =120)%>%hc_legend( align ="right", verticalAlign ="top", layout ="vertical", itemMarginBottom =10, x =0, y =150)hc19
Dia 20: redes
Tomamos el ejemplo del paquete {economiccomplexity} en donde realiza un análisis de proximidad basado en lo que exporta cada país https://pacha.dev/economiccomplexity/articles/basic-usage.html
world_trade_avg_1998_to_2000<-world_trade_avg_1998_to_2000%>%ungroup()%>%filter(!(country%in%c("ant", "rom", "scg", "fsm", "umi")))bi<-balassa_index(world_trade_avg_1998_to_2000)pro<-proximity(bi)net<-projections(pro$proximity_country, pro$proximity_product)dfaggregated_countries<-aggregate(world_trade_avg_1998_to_2000$value, by =list(country =world_trade_avg_1998_to_2000$country), FUN =sum)aggregated_countries<-setNames(dfaggregated_countries$x, dfaggregated_countries$country)V(net$network_country)$size<-aggregated_countries[match(V(net$network_country)$name, names(aggregated_countries))]red<-net$network_country
Code
library(ggraph)ggraph(red, layout ="auto")+geom_edge_link(edge_colour ="#a8a8a8")+geom_node_point(aes(size =size), color ="#86494d")+geom_node_text(aes(label =name), size =2, vjust =2.2)+ggtitle("Proximity Based Network Projection for Products")+theme_void()
Avanzado. Acá a partir del objeto igraph obtendremos un layout basado en el paquete {graphlayouts}. Luego dibujaremos independiente los vertices, las aristas y la información de las aristas.