Esquemas Avanzados

Introducción

Existe varios paquetes en R exclusivos para generar gráficos estadísticos, así como existen paquetes de análisis de datos en los cuales los desarrolladores personalizan sus gráficos utilizando base u otros paquetes de graficación. En este módulo veremos algunos de estos paquetes para este fin.

ggplot

El paquete ggplot2 es un sistema declarativo para construir gráficos basado en el libro The Grammar of Graphics. Hace parte de la colección tidyverse diseñado para Data Science, la cual es una modificación del legueje R con la filosofía de hacer más simple la programación y la lectura de código.

install.packages("tidyverse")
install.packages("ggplot2")

Para graficar con este paquete se requiere establecer qué es lo que se quiere graficar, es decir, cuáles argumentos y papel son los que se quiere visualizar. Luego se agregan las funciones geom que transforma los datos y genera los gráficos por capas.

library(ggplot2)
ggplot(mtcars)

Para agregar los argumentos se utiliza el comando aes que recibe las variables que se quieren graficar y el papel estético que cumple.

ggplot(mtcars,aes(x=mpg,y=disp))

Para especificar el gráfico que se quiere, se utiliza la batería geom precedido de +.

# Gráfico de dispersiones
ggplot(mtcars,aes(x=mpg,y=disp))+
  geom_point()

En la página de referencia de ggplot pueden encontrar todas las capas disponibles en el paquete.

ggplot(mtcars,aes(x=mpg,y=disp,colour=drat))+
  geom_point(aes(size=hp))+
  ggtitle("Desplazamientos vs Consumo\ndado los caballos de fuerza y eje trasero")+
  theme_bw()

ggplot(mtcars,aes(x=mpg,y=disp,colour=drat))+
  geom_point(aes(size=hp))+
  ggtitle("Desplazamientos vs Consumo\ndado los caballos de fuerza y eje trasero")+
  theme_bw()+scale_color_gradient(low=c("red","gold"),high = c("forestgreen"))

ggplot(mtcars,aes(x=mpg,y=disp,colour=drat))+
  geom_point(aes(size=hp))+geom_smooth()+
  ggtitle("Desplazamientos vs Consumo\ndado los caballos de fuerza y eje trasero")+
  theme_bw()+scale_color_gradient(low=c("red","gold"),high = c("forestgreen"))

set.seed(1234)
wdata = data.frame(
        sex = factor(rep(c("F", "M"), each=200)),
        weight = c(rnorm(200, 55), rnorm(200, 58)))
head(wdata)
# Box-plot básico desde el data.frame
qplot(sex, weight, data = wdata, 
      geom= "boxplot", fill = sex)

# Violin plot
qplot(sex, weight, data = wdata, geom = "violin")

# Dot plot
qplot(sex, weight, data = wdata, geom = "dotplot",
      stackdir = "center", binaxis = "y", dotsize = 0.5)

# Histogramas
# Color por grupo (sexo)
qplot(weight, data = wdata, geom = "histogram",
      fill = sex)

# Density plot
# Color por grupo (sexo) cambiando el tipo de linea
qplot(weight, data = wdata, geom = "density",
    color = sex, linetype = sex)

# Se puede asignar la base del gráfico a una variable
a <- ggplot(wdata, aes(x = weight))
# gráfico área
a + geom_area(stat = "bin")

# Color por grupo
a + geom_area(aes(fill = sex), stat ="bin", alpha=0.6) +
  theme_classic()

# density plot
a + geom_density()

# color de líneas por grupos
a + geom_density(aes(color = sex)) 

# Color por grupo y transparencia
a + geom_density(aes(fill = sex), alpha=0.4)

# Media por grupos
# install.packages("plyr",dependencies = T)
library(plyr)
(mu <- ddply(wdata, "sex", summarise, grp.mean=mean(weight)))
# Agregar la media como línea con color manual
a + geom_density(aes(color = sex)) +
  geom_vline(data=mu, aes(xintercept=grp.mean, color=sex),
             linetype="dashed") +
  scale_color_manual(values=c("#999999", "#E69F00"))

# Dotplot
a + geom_dotplot()

# Color por grupo
a + geom_dotplot(aes(fill = sex)) 

# Color manual
a + geom_dotplot(aes(fill = sex)) +
  scale_fill_manual(values=c("#999999", "#E69F00"))

Pueden consultar la Guía práctica ggplot2 que tiene una colección de gráficos ggplot2 y los códigos para replicarlos.

Gráficos interactivos

Este tipo de gráficos se emplean para aplicaciones web o dispositivos móviles. Existen varios paquetes en R que integran los métodos de visualización del software con HTML y JavaScript.

plotly

Plot.ly es una empresa de computación técnica que ofrece soluciones gráficas para analítica, tienen sus propios software y productos, pero han contribuído al mundo de código abierto con implementaciones en R, Python, JavaScript, MATLAB, Julia o Scala.

Si bien Plotly tiene una versión empresarial paga, realmente lo que se paga son la herramientas desarrolladas por la empresa para construir dashboards y gráficos de manera más interactiva sin la necesidad de códigos. Por fortuna, es posible crear gráficos interactivos con el paquete plotly, los cuales se pueden guardar en .html para agregarlos posteriormente a las páginas web o aplicaciones.

install.packages("plotly",dependencies = T)

Los gráficos se construyen similar a ggplot2 agregando capas, y para guardar el archivo se emplea el comando api_create, sin embargo, el archivo se guarda en la nube de Plotly. Para guardar el archivo como HTML sin necesidad de subirlo a la nube se emplea el paquete htmlwidgets.

library(plotly)
plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length)
plot_ly(data = iris, x = ~Sepal.Length, y = ~Petal.Length,
        marker = list(size = 10,color = 'rgba(255, 182, 193, .9)',
                      line = list(color = 'rgba(152, 0, 0, .8)',
                      width = 2))) %>%
  layout(title = 'Styled Scatter',
         yaxis = list(zeroline = FALSE),
         xaxis = list(zeroline = FALSE))
d <- diamonds[sample(nrow(diamonds), 1000), ]
plot_ly(d, x = ~carat, y = ~price,
        color = ~carat, size = ~carat)
plot_ly(d, x = ~carat, y = ~price,
  # Hover text:
  text = ~paste("Price: ", price, '$<br>Cut:', cut),
  color = ~carat, size = ~carat)
dens <- with(diamonds, tapply(price, INDEX = cut, density))
df <- data.frame(x = unlist(lapply(dens, "[[", "x")),
                 y = unlist(lapply(dens, "[[", "y")),
                 cut = rep(names(dens), each = length(dens[[1]]$x)))
p <- plot_ly(df, x = ~x, y = ~y, color = ~cut) %>%
  add_lines()

# Con ggplot2
library(ggplot2)
df <- diamonds[sample(1:nrow(diamonds), size = 1000),]

# Boxplot en ggplot
p <- ggplot(df, aes(cut, price, fill = cut)) +
  geom_boxplot()+
  ggtitle("Lineas horizonales en los bigotes (ggplot2)")
ggplotly(p)
# Gráfico de contornos
head(volcano)
##      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14]
## [1,]  100  100  101  101  101  101  101  100  100   100   101   101   102   102
## [2,]  101  101  102  102  102  102  102  101  101   101   102   102   103   103
## [3,]  102  102  103  103  103  103  103  102  102   102   103   103   104   104
## [4,]  103  103  104  104  104  104  104  103  103   103   103   104   104   104
## [5,]  104  104  105  105  105  105  105  104  104   103   104   104   105   105
## [6,]  105  105  105  106  106  106  106  105  105   104   104   105   105   106
##      [,15] [,16] [,17] [,18] [,19] [,20] [,21] [,22] [,23] [,24] [,25] [,26]
## [1,]   102   102   103   104   103   102   101   101   102   103   104   104
## [2,]   103   103   104   105   104   103   102   102   103   105   106   106
## [3,]   104   104   105   106   105   104   104   105   106   107   108   110
## [4,]   105   105   106   107   106   106   106   107   108   110   111   114
## [5,]   105   106   107   108   108   108   109   110   112   114   115   118
## [6,]   106   107   109   110   110   112   113   115   116   118   119   121
##      [,27] [,28] [,29] [,30] [,31] [,32] [,33] [,34] [,35] [,36] [,37] [,38]
## [1,]   105   107   107   107   108   108   110   110   110   110   110   110
## [2,]   107   109   110   110   110   110   111   112   113   114   116   115
## [3,]   111   113   114   115   114   115   116   118   119   119   121   121
## [4,]   117   118   117   119   120   121   122   124   125   126   127   127
## [5,]   121   122   121   123   128   131   129   130   131   131   132   132
## [6,]   124   126   126   129   134   137   137   136   136   135   136   136
##      [,39] [,40] [,41] [,42] [,43] [,44] [,45] [,46] [,47] [,48] [,49] [,50]
## [1,]   110   110   108   108   108   107   107   108   108   108   108   108
## [2,]   114   112   110   110   110   109   108   109   109   109   109   108
## [3,]   120   118   116   114   112   111   110   110   110   110   109   109
## [4,]   126   124   122   120   117   116   113   111   110   110   110   109
## [5,]   131   130   128   126   122   119   115   114   112   110   110   110
## [6,]   136   135   133   129   126   122   118   116   115   113   111   110
##      [,51] [,52] [,53] [,54] [,55] [,56] [,57] [,58] [,59] [,60] [,61]
## [1,]   107   107   107   107   106   106   105   105   104   104   103
## [2,]   108   108   108   107   107   106   106   105   105   104   104
## [3,]   109   109   108   108   107   107   106   106   105   105   104
## [4,]   109   109   109   108   108   107   107   106   106   105   105
## [5,]   110   110   109   109   108   107   107   107   106   106   105
## [6,]   110   110   110   109   108   108   108   107   107   106   106
plot_ly(z = ~volcano, type = "contour")
plot_ly(z = volcano, type = "contour", contours = list(showlabels = TRUE)) %>%
  colorbar(title = "Elevation \n in meters")
# Gráficos en 3D
mtcars$am[which(mtcars$am == 0)] <- 'Automatic'
mtcars$am[which(mtcars$am == 1)] <- 'Manual'
mtcars$am <- as.factor(mtcars$am)

plot_ly(mtcars, x = ~wt, y = ~hp, z = ~qsec,
        color = ~am, colors = c('#BF382A', '#0C4B8E')) %>%
  add_markers() %>%
  layout(scene = list(xaxis = list(title = 'Weight'),
                     yaxis = list(title = 'Gross horsepower'),
                     zaxis = list(title = '1/4 mile time')))
plot_ly(mtcars, x = ~wt, y = ~hp, z = ~qsec,
        marker = list(color = ~mpg,
                      colorscale = c('#FFE1A1', '#683531'),
                      showscale = TRUE)) %>%
  add_markers() %>%
  layout(scene = list(xaxis = list(title = 'Weight'),
                      yaxis = list(title = 'Gross horsepower'),
                      zaxis = list(title = '1/4 mile time')),
         annotations = list(x = 1.13,
                            y = 1.05,
                            text = 'Miles/(US) gallon',
                            xref = 'paper',
                            yref = 'paper',
                            showarrow = FALSE)
         )
# Gráficos de superficie
plot_ly(z = ~volcano) %>% add_surface()
# Usando botones HTML
p <- plot_ly(z = ~volcano, type = "heatmap", colorscale='Rainbow')
# Botón para tipo de gráfico
chart_types <- list(
  type = "buttons",
  direction = "right",
  xanchor = 'center',
  yanchor = "top",
  pad = list('r'= 0, 't'= 10, 'b' = 10),
  x = 0.5,
  y = 1.27,
  buttons = list(
    list(method = "restyle",
         args = list("type", "heatmap"),
         label = "Heatmap"),
    list(method = "restyle",
         args = list("type", "contour"),
         label = "Contour"),
    list(method = "restyle",
         args = list("type", "surface"),
         label = "Surface")
  ))

# Botón para tipo de color
color_types <- list(
  type = "buttons",
  direction = "right",
  xanchor = 'center',
  yanchor = "top",
  pad = list('r'= 0, 't'= 10, 'b' = 10),
  x = 0.5,
  y = 1.17,
  buttons = list(
    list(method = "restyle",
         args = list("colorscale", "Rainbow"),
         label = "Rainbow"),
    list(method = "restyle",
         args = list("colorscale", "Jet"),
         label = "Jet"),
    list(method = "restyle",
         args = list("colorscale", "Earth"),
         label = "Earth"),
    list(method = "restyle",
         args = list("colorscale", "Electric"),
         label = "Electric")
  ))

annot <- list(list(text = "Chart<br>Type", x=0.2, y=1.25, xref='paper', yref='paper', showarrow=FALSE),
              list(text = "Color<br>Type", x=0.2, y=1.15, xref='paper', yref='paper', showarrow=FALSE))

# Resultado
p %>% layout(xaxis = list(domain = c(0.1, 1)),
             yaxis = list(title = "y"),
             updatemenus = list(chart_types,color_types),
             annotations = annot)
# Animados
# install.packages("gapminder")
library(gapminder)

gapminder %>%  plot_ly(x = ~gdpPercap, y = ~lifeExp,
                       size = ~pop, color = ~continent, 
                       frame = ~year, text = ~country, 
                       hoverinfo = "text", type = 'scatter',
                       mode = 'markers') %>%
  layout(xaxis = list(type = "log"))

Para guardar los gráficos en HTML se emplea el siguiente código.

install.packages("htmlwidgets",dependencies = T)

library(htmlwidgets)
saveWidget(as.widget(plotly),file="Plot_Adv.html",self)

Gifs en R

Para crea gifs animados es necesario instalar el paquete gganimate desde el repositorio de GitHub.

# paquete para acceder a las librerías de GitHub
install.packages("devtools",dependencies = T)

# instalar paquetes de GitHub
devtools::install_github('thomasp85/gganimate',force = T)

# También está en el CRAN
install.packages("gganimate",dependencies = T)

La idea de los gift es visualizar paso por paso las capas de un gráfico, el paquete gganimate es para construir este tipo de archivos para los gráficos construídos en ggplot2.

library(gapminder)
library(ggplot2)
library(gganimate)

p <- ggplot(gapminder,
            aes(x = gdpPercap, y = lifeExp,
                size = pop, color = continent,
                frame = year)) +
  geom_point() +
  scale_x_log10() +
  theme_bw()+
  transition_states(year)
 
# Realizar la animación
animate(p)

# Guardar el gif
anim_save("Mi_Animacion.gif")

Mapas interactivos

R tiene la capacidad de hacer análisis geoestadísticos y de estadística espacial de datos raster, areales o de patrones de puntos y existe una bartería amplia de paquetes para graficar mapas y resultados estáticos o interactivos.

Las librerías más utilizadas para graficar mapas estáticos son raster, rasterVis, cartogram, tmap y ggplot2, por otra parte para los mapas interactivos basandos en HMTL se cuenta con los paquetes leaflet, rbokeh, plotly, ggiraph, highcharter, gganimate, mapview, mapdeck, googleway, entre otros.

install.packages("leaflet",dependencies = T)
install.packages("spData",dependencies = T)
install.packages("tmap",dependencies = T)
install.packages("ggiraph",dependencies = T)
install.packages("sf",dependencies = T)
install.packages("sp",dependencies = T)
install.packages("maps",dependencies = T)
install.packages("rbokeh",dependencies = T)
library(spData)
library(maps)
data(world.cities)
library(rbokeh)
caps <- dplyr::filter(world.cities, capital == 1)
caps$population <- prettyNum(caps$pop, big.mark = ",")
plot <- suppressWarnings(figure(width = 800, height = 450, padding_factor = 0) %>%
  ly_map("world", col = "gray") %>%
  ly_points(long, lat, data = caps, size = 5,
            hover = c(name, country.etc, population)))

widgetframe::frameWidget(plot,width=600,height=400)
require(leaflet)
leaflet() %>%
  setView(lat = 6.1999, lng = -75.5791, zoom=15) %>%
  addTiles()
leaflet() %>%
  setView(lat = 6.1999, lng = -75.5791, zoom=15) %>%
  addTiles()%>%
  addProviderTiles(providers$Stamen.Toner)
leaflet() %>%
  setView(lat = 6.1999, lng = -75.5791, zoom=15) %>%
  addTiles()%>%
  addProviderTiles(providers$CartoDB.Positron)
leaflet() %>%
  setView(lat = 6.1999, lng = -75.5791, zoom=15) %>%
  addTiles()%>%
  addProviderTiles(providers$MtbMap) %>%
  addProviderTiles(providers$Stamen.TonerLines,
    options = providerTileOptions(opacity = 0.35)) %>%
  addProviderTiles(providers$Stamen.TonerLabels)
leaflet() %>% addTiles() %>% setView(-87.65, 38.0285, zoom = 6) %>%
  addWMSTiles(
    "http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi",
    layers = "nexrad-n0r-900913",
    options = WMSTileOptions(format = "image/png", transparent = TRUE),
    attribution = "Weather data © 2012 IEM Nexrad"
  )
leaflet(quakes) %>% addTiles() %>% addMarkers(
  clusterOptions = markerClusterOptions()
)
df <- sp::SpatialPointsDataFrame(
  cbind(
    (runif(20) - .5) - 75.5,  # lng
    (runif(20) - .5) + 6.1  # lat
  ),
  data.frame(type = factor(
    ifelse(runif(20) > 0.75, "alto", "bajo"),
    c("alto", "bajo")
  ))
)
leaflet(df) %>% addTiles() %>% addCircleMarkers()
pal <- colorFactor(c("navy", "red"), domain = c("bajo", "alto"))

leaflet(df) %>% addTiles() %>%
  addCircleMarkers(
    radius = ~ifelse(type == "alto", 6, 10),
    color = ~pal(type),
    stroke = FALSE, fillOpacity = 0.5
  )
leaflet() %>% addTiles() %>% addTerminator()
leaflet() %>%
  addTiles() %>%
  addTerminator(
    resolution=10,
    time = "2020-05-01T21:00:00Z",
    group = "daylight") %>%
  addLayersControl(
    overlayGroups = "daylight",
    options = layersControlOptions(collapsed = FALSE))
leaflet() %>% setView(-75,6,5) %>%
  addProviderTiles(providers$Esri.WorldStreetMap) %>%
  addMiniMap(
    tiles = providers$Esri.WorldStreetMap,
    toggleDisplay = TRUE)
pal = colorNumeric("RdYlBu", domain = cycle_hire$nbikes)
leaflet(data = cycle_hire) %>% 
  addProviderTiles(providers$CartoDB.Positron) %>%
  addCircles(col = ~pal(nbikes), opacity = 0.9) %>% 
  addPolygons(data = lnd, fill = FALSE) %>% 
  addLegend(pal = pal, values = ~nbikes) %>% 
  setView(lng = -0.1, 51.5, zoom = 12) %>% 
  addMiniMap()

Cristian Santa