# Ejecuta las siguiente líneas en el caso de que no los tengas instalados
install.packages("plotly")
install.packages("htmlwidgets")
5 - Gráficos interactivos con plotly: nivel básico
¿Qué vamos a hacer?
En capítulos previos hemos visto herramientas para generar tanto visualizaciones estáticas (gráficos con ggplot) como dinámicas (mapas con leaflet).
En este y el siguiente capítulo veremos una alternativa interactiva a los gráficos de ggplot: plotly. Al igual que leaflet, plotly es una librería de gráficos basada en javascript, pero disponible a través de su paquete en R para poder crearlos directamente desde este lenguaje.
Antes de empezar, nos tendremos que asegurar de tener las librerías de plotly
y htmlwidgets
instaladas.
Gráficos básicos
Al pintar un gráfico con plotly, seguiremos la siguiente estructura:
Con la función
plot_ly
pintamos el gráfico en sí, pasando los datos como argumento y definiendo:- El tipo (y, opcionalmente, el subtipo): de puntos, líneas, barras, … Se establecen usando los parámetros
type
ymode
. - Los mapeos de valores a columnas del dataset, usando
x
,y
,color
,size
, … - Geometrías adicionales utilizando
add_xxxx
, comoadd_markers
,add_lines
,add_ribbons
, …
- El tipo (y, opcionalmente, el subtipo): de puntos, líneas, barras, … Se establecen usando los parámetros
Con la función
layout
personalizaremos elementos como el título, los ejes o la leyenda.
Gráficos de puntos
Podemos pintar un gráfico de puntos usando type='scatter'
y mode='markers'
. El mapeo de propiedades a columnas se hace utilizando ~mi_columna
.
library(dplyr)
library(plotly)
library(palmerpenguins)
plot_ly(data = penguins, type = "scatter", mode = "markers",
x = ~flipper_length_mm, y = ~body_mass_g)
Fíjate en la interactividad. Pasa el ratón por encima de los puntos, prueba a seleccionar un subconjunto de los puntos y utiliza los controles de arriba a la izquierda.
Podemos personalizarlo. La lista completa de opciones está disponible aquí. Navega hasta ella y prueba a buscar todas las posibles opciones del parámetro marker
dentro de un scatterplot (gráfico de puntos).
Vamos a mapear los colores según la especie del pingüino y a personalizar un poco el estilo de los puntos (markers).
plot_ly(data = penguins, type = "scatter", mode = "markers",
x = ~flipper_length_mm, y = ~body_mass_g, color = ~species,
marker = list(
size = 10,
line = list(width = 2),
opacity = 0.6
) )
Gráficos de líneas
El gráfico de líneas lo pintamos utilizando type='scatter'
y mode='lines'
.
Vamos a pintar un ejemplo utilizando los datos históricos de paro de EEUU.
# Calculo la tasa de desempleo
<- economics %>%
paro mutate(unemploy_ratio = unemploy / pop)
# Pinto mi gráfico de líneas
plot_ly(paro, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines")
Podemos añadir diferentes líneas utilizando add_lines
.
plot_ly(paro, type = "scatter", mode = "lines") %>%
add_lines(x = ~date, name = "Población", y = ~pop * 1000) %>%
add_lines(x = ~date, name = "Paro", y = ~unemploy * 1000)
Para pasar el gráfico a las siguientes funciones (de plot_ly a add_lines), utilizamos
%>%
, igual que endplyr
y enleaflet
. En realidad, este operador pertenece a la libreríamagrittr
y lo que hace es pasar el argumento de la izquierda del operador como primer argumento de la función de la derecha.
Si nuestros datos tienen nulos, tenemos dos alternativas para pintar las líneas:
- Dejar el hueco, rompiendo visualmente la línea.
- Conectar con una línea los puntos con información más cercanos, haciendo una línea más larga.
Para ver la diferencia, vamos a insertar nulos en la serie del paro, en las fechas desde el 1 de enero de 2002 hasta el 1 de enero del 2005.
# Insertamos nulos
<- paro %>%
tmp mutate(unemploy_ratio = ifelse(date >= as.Date("2002-01-01") & date <= as.Date("2005-01-01"),
NA, unemploy_ratio))
# Pintamos con huecos, es la opción por defecto
# resulta lo mismo que especificar connectgaps = FALSE
plot_ly(tmp, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines")
# Pintamos con huecos, es la opción por defecto
# resulta lo mismo que especificar connectgaps = FALSE
plot_ly(tmp, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines", connectgaps = TRUE)
También podemos pintar bandas alrededor de líneas, un recurso muy utilizado cuando existen intervalos de confianza. Rescatemos el ejemplo con los datos de defunciones en España.
Conseguimos pintar una banda pintando primero la línea superior (donde acaba) y luego la línea inferor (donde empieza), marcando esta última como fill = "tonexty"
.
# Lectura de los datos
<- read.csv("dat/defunciones_espana.csv")
defunciones
# Conversión de la fecha de tipo character a Date
<- defunciones %>%
defunciones mutate(fecha_defuncion = as.Date(fecha_defuncion))
# Pintamos la mortalidad observada y la estimada junto con su intervalo de confianza
plot_ly(defunciones, type = "scatter", mode = "lines") %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_observadas, name = "Observadas",
line = list(color = "black")) %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas, name = "Esperadas",
line = list(color = "rgb(22, 96, 167)")) %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q99, name = "Esperadas lim. sup.",
line = list(color = "gray", width = 0.5, dash = "dash")) %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q01, name = "Esperadas lim. inf.",
fill = "tonexty", fillcolor="rgba(22, 96, 167, 0.3)",
line = list(color = "gray", width = 0.5, dash = "dash"))
Fíjate en cómo definimos los colores: con rgb(r, g, b, a). Es una forma de definir un color en base a sus tres componentes (r = red, g = green, b = blue, a = alpha). El alpha es el grado de opacidad. También lo podríamos definir mediante un nombre (como blue) o su código hexadecimal (como #0000FF).
Gráficos de barras
Para representar un gráfico de barras, necesitamos especificar x
e y
.
Es habitual utilizarlos para hacer un conteo sobre una variable categórica.
<- penguins %>%
penguins_count group_by(species) %>%
summarise(count = n())
plot_ly(penguins_count, x = ~species, y = ~count, type = "bar")
También disponemos de los tipos de gráficos de barras habituales: agrupados y apilados.
<- penguins %>%
penguins_count_2 group_by(species, sex) %>%
summarise(count = n())
plot_ly(penguins_count_2, x = ~species, y = ~count, color = ~sex, type = "bar")
plot_ly(penguins_count_2, x = ~species, y = ~count, color = ~sex, type = "bar") %>%
layout(barmode = "stack")
Es la primera vez que utilizamos la función
layout
. La usaremos en plotly para ajustar detalles del gráfico como los ejes, títulos, leyendas y otras propiedades.
Gráficos estadísticos
Histogramas
En plotly también podemos utilizar gráficos que realizan de forma implícita transformaciones estadísticas. Uno de los más habituales es el histograma, que nos muestra la distribución de una determinada variable.
plot_ly(penguins, x = ~body_mass_g, type = "histogram")
También podemos sobrescribir la función de binning, es decir, la transformación estádistica. Es habitual utilizarla para realizar un histograma sobre una variable categórica contando sus observaciones, que produce un resultado equivalente a los ejemplos previos que hemos visto con gráficos de barras.
plot_ly(penguins, x = ~species, histfunc = "sum", type = "histogram")
La diferencia entre el gráfico de barras anterior y este histograma es que, en el de barras, hicimos nosotros la transformación estadística (agrupar y contar) con dplyr y pasamos los resultados ya preparados; en este histograma, le pasamos todos los datos, y es plot_ly el encargado de hacer la transformación. En este caso el resultado es similar, pero en otros, el caso del histograma puede derivar en un peor rendimiento (proceso más lento).
Otro caso de uso habitual es el de pintar varios histogramas superpuestos, para comparar la distribución en base a una segunda variable. Para hacerlo, utilizamos el barmode="overlay"
dentro de layout.
plot_ly(penguins, x =~body_mass_g, color =~sex, type = "histogram", alpha = 0.6) %>%
layout(barmode = "overlay")
Boxplots
Ya vimos que los boxplots son habituales al hacer un análisis exploratorio sobre nuestro dataset o para representar ante un público con ciertos conocimientos estadísticos. En plotly los podemos pintar utilizando el type="box"
.
plot_ly(penguins, x = ~species, y = ~body_mass_g, type = "box")
También tenemos en plotly una alternativa gráfica a los boxplots: los gráficos de violín. También muestran distribuciones, pero suelen ser un poco más amigables para un público con menos conocimientos de estadística.
plot_ly(penguins, x = ~species, y = ~body_mass_g, type = "violin")
Personalización
Podemos personalizar la mayor parte de los aspecto estéticos de nuestro gráfico en la función layout
.
Título y ejes
Los siguientes argumentos de layout
nos sirven para personalizar varios textos:
title
: el título principal del gráficoxaxis
: las propiedades del eje xyaxis
: las propiedades del eje x
Vamos a personalizar estos textos sobre el gráfico que teníamos mostrando las defunciones en España.
<- plot_ly(defunciones, type = "scatter", mode = "lines") %>%
p add_trace(x = ~fecha_defuncion, y = ~defunciones_observadas, name = "Observadas",
line = list(color = "black")) %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas, name = "Esperadas",
line = list(color = "rgb(22, 96, 167)")) %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q99, name = "Esperadas lim. sup.",
line = list(color = "gray", width = 0.5, dash = "dash")) %>%
add_trace(x = ~fecha_defuncion, y = ~defunciones_esperadas_q01, name = "Esperadas lim. inf.",
fill = "tonexty", fillcolor="rgba(22, 96, 167, 0.3)",
line = list(color = "gray", width = 0.5, dash = "dash")) %>%
layout(title = "Mortalidad observada y esperada en España",
xaxis = list(title = "Fecha"),
yaxis = list(title = "Defunciones"))
p
Tooltips
En los gráficos que hemos estado representando, podemos ver que el estilo del tooltip (el cuadro con información al pasar el ratón por encima en algún punto) por defecto es (valor en eje x, valor en eje y)
.
Podemos personalizar este valor de diferentes formas.
Un caso de uso habitual cuando tenemos varias líneas es unificar el tooltip, de forma que la información de todas las líneas aparezca junta en el cuadro de información, con layout(hovermode = "<x|y> unified")
%>%
p layout(hovermode = "x unified")
Para personalizar el texto y formato del tooltip podemos utilizar los hovertemplates. Se trata de plantillas en las que podemos incluir:
- Variables con
%{variable}
- Números con formato d3, en la forma
variable|formato
- Fechas con formato d3, en la forma
variable:formato
- Etiquetas html como
<br/>
para saltar de línea,<b>...</b>
para resaltar en negrita, …
Nota: d3 es una librería de visualización de datos de javascript de bajo nivel, en la que se basan muchas otras. Puedes consultar los links con la documentación necesaria de los formatos citados.
Aquí tenemos un ejemplo con todos los elementos descritos: etiquetas html, y variables con formateo especial de números y fechas.
plot_ly(paro, x = ~date, y = ~unemploy_ratio, type = "scatter", mode = "lines", name = "Paro",
hovertemplate = "<b>Fecha:</b> %{x|%B %Y}<br>Paro: %{y:.2%}") %>%
layout(title = "Paro en EEUU",
xaxis = list(title = "Fecha"),
yaxis = list(title = "Paro"))
Transformación de gráficos de ggplot a plotly
Plotly trae una función para transformar gráficos de ggplot2
a plotly
. Esta funcionalidad resulta muy útil si ya tenemos una serie de gráficos hechos con ggplot2
y queremos hacerlos interactivos de una forma rápida.
Si por el contrario, nos encontramos de cero con un proyecto de visualización de datos interactivo, es mejor empezarlo con las funciones de plot_ly
puras: la transformación vía ggplot2 tiene sus limitaciones.
La función que transforma un gráfico de de ggplot2
a plotly
es ggplotly
. Veamos un ejemplo:
library(ggplot2)
# Generamos un gráfico con ggplot
<- ggplot(data = penguins, mapping = aes(x = flipper_length_mm, y = body_mass_g)) +
p geom_point()
# Con la función ggplotly, lo volvemos interactivo: es decir, lo transformamos
# en un gráfico de plotly
ggplotly(p)
Profundiza
Para saber más sobre los conceptos que hemos visto, puedes consultar alguna de estas referencias:
- Chuleta de plotly: sintetiza las funciones más habituales para plotly. Muy útil para tener a mano a la hora de utilizar la librería.
- Referencia completa de atributos de plotly: documenta todos los posibles atributos que se pueden establecer por cada tipo de gráfico.
- Referencia de gráficos básicos en plotly: consúltalo para ver más ejemplos de gráficos básicos
- Referencia de gráficos estadísticos en plotly: documentación completa de los gráficos estadísticos en plotly
Conclusiones
Nos podemos quedar con las siguientes ideas como resumen de este tema:
- Cuando nos encontramos ante un proyecto de visualización de datos, podemos decidir si hacerlo con gráficos estáticos o dinámicos. El primer caso es más rápido y sencillo; el segundo, proporciona visualizaciones más completas y enriquecidas.
- En R, podemos utilizar ggplot2 para gráficos estáticos y plotly para gráficos dinámicos.
- Si tenemos una visualización de datos ya hecha con ggplot2 y queremos pasarla rápidamente a interactiva, podemos utilizar
ggplotly()
. Si, por el contrario, nos encontramos ante un proyecto a empezar desde cero, es preferible utilizar las funciones puras deplot_ly
. - Los mapeos de propiedades con columnas se hacen utilizando
~mi_columna
. - Las personalizaciones más estéticas como cambiar textos, fuentes, formatos, etc. se hacen con la función
layout()
.
Actividades
Vamos a pintar con plotly algunos gráficos que ya habíamos representado con ggplot. Para hacerlo, no utilices ggplotly
: utiliza las funciones puras de plotly
.
Actividad 1
Utilizando el dataset diamonds
, representa la relación en un gráfico de puntos del precio frente a los quilates.
Actividad 2
Con el dataset penguins
:
Pinta la relación entre longitud y profunidad del pico.
Añade al gráfico del punto 1 la distinción entre especies mediante el color.
Añade al gráfico del punto 1 la distinción entre el peso corporal mediante el color.
Actividad 3
- Lee los datos del economista (dat/economist.csv), con indicadores de desarrollo y corrupción por países:
- HDI: Human Development Index (1: más desarrollado)
- CPI: Corruption Perception Index (10: menos corrupto)
- Crea un gráfico que:
- Cada país sea un punto
- El eje x indique CPI, el y HDI
- El color del punto indique la región
- Su tamaño sea proporcional al ranking HDI
Actividad 4
Lee los datos de los resultados de las elecciones presidenciales de los Estados Unidos (dat/usa_president.csv).
Pinta en un gráfico de líneas la evolución del número de votos a lo largo de los años del partido republicado frente al demócrata.