library(ggplot2) 
library(plotly) 
## 
## Attaching package: 'plotly'
## The following object is masked from 'package:ggplot2':
## 
##     last_plot
## The following object is masked from 'package:stats':
## 
##     filter
## The following object is masked from 'package:graphics':
## 
##     layout
library(ggforce) 
library(remotes)
library(htmltools)
library(ggmosaic)

Las funciones add_bars() y add_histogram() envuelven los tipos de trazas de barras e histogramas de plotly.js. La principal diferencia entre ellos es que los trazados de barras requieren alturas de barras (tanto x como y), mientras que los trazados de histograma requieren sólo una variable, y plotly.js maneja el agrupamiento en el navegador.15 Y quizás confusamente, ambas funciones pueden utilizarse para visualizar la distribución de una variable numérica o discreta. Así que, esencialmente, la única diferencia entre ellas es dónde se produce el binning.

La Figura 5.1 compara el algoritmo de binning por defecto en plotly.js con algunos algoritmos diferentes disponibles en R a través de la función hist(). Aunque plotly.js tiene la capacidad de personalizar los bins del histograma a través de xbins/ybins, R tiene diversas facilidades para estimar el número óptimo de bins en un histograma que podemos aprovechar fácilmente.16 La función hist() por sí sola nos permite hacer referencia a 3 algoritmos famosos por su nombre (Sturges 1926; Freedman y Diaconis 1981; Scott 1979), pero también hay paquetes (por ejemplo, el paquete histograma) que amplían esta interfaz para incorporar más metodología (Mildenberger, Rozenholc y Zasada. 2009). La función price_hist() a continuación envuelve la función hist() para obtener los resultados de binning, y mapear esos bins a una versión plotly del histograma usando add_bars().

p1 <- plot_ly(diamonds, x = ~price) %>%
  add_histogram(name = "plotly.js")

price_hist <- function(method = "FD") {
  h <- hist(diamonds$price, breaks = method, plot = FALSE)
  plot_ly(x = h$mids, y = h$counts) %>% add_bars(name = method)
}

subplot(
  p1, price_hist(), price_hist("Sturges"),  price_hist("Scott"),
  nrows = 4, shareX = TRUE
)

La figura 5.2 muestra dos formas de crear un gráfico de barras básico. Aunque los resultados visuales son los mismos, vale la pena señalar la diferencia en la implementación. La función add_histogram() envía todos los valores observados al navegador y deja que plotly.js realice el binning. Se necesita más esfuerzo humano para realizar el binning en R, pero hacerlo tiene la ventaja de enviar menos datos, y que requiere menos trabajo de cálculo del navegador web. En este caso, sólo tenemos unos 50.000 registros, por lo que no hay mucha diferencia en los tiempos de carga o en el tamaño de la página. Sin embargo, con 1 millón de registros, el tiempo de carga de la página es más del doble y el tamaño de la página casi el doble.

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
p1 <- plot_ly(diamonds, x = ~cut) %>%
  add_histogram()

p2 <- diamonds %>%
  count(cut) %>%
  plot_ly(x = ~cut, y = ~n) %>% 
  add_bars()

subplot(p1, p2) %>% hide_legend()

5.1 Distribuciones numéricas múltiples

A menudo es útil ver cómo cambia la distribución numérica con respecto a una variable discreta. Cuando se utilizan barras para visualizar distribuciones numéricas múltiples, recomiendo trazar cada distribución en su propio eje utilizando una visualización de múltiplos pequeños, en lugar de intentar superponerlas en un solo eje.18. En el Capítulo 13, y específicamente en la Sección 13.1.2.3, se tratan los múltiplos pequeños con más detalle, pero la Figura 13.9 muestra cómo hacerlo con plot_ly() y subplot(). Observe cómo la función one_plot() define qué mostrar en cada panel y, a continuación, se emplea una estrategia de dividir-aplicar-recombinar (es decir, split(), lapply(), subplot()) para generar la visualización enrejada.

one_plot <- function(d) {
  plot_ly(d, x = ~price) %>%
    add_annotations(
      ~unique(clarity), x = 0.5, y = 1, 
      xref = "paper", yref = "paper", showarrow = FALSE
    )
}

diamonds %>%
  split(.$clarity) %>%
  lapply(one_plot) %>% 
  subplot(nrows = 2, shareX = TRUE, titleX = FALSE) %>%
  hide_legend()
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram
## No trace type specified:
##   Based on info supplied, a 'histogram' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#histogram

5.2 Distribuciones discretas múltiples

Visualizar distribuciones discretas múltiples es difícil. Esta sutil complejidad se debe a que tanto los recuentos como las proporciones son importantes para comprender las distribuciones discretas multivariantes. La figura 5.4 presenta los recuentos de diamantes, divididos por talla y claridad, mediante un gráfico de barras agrupadas.

plot_ly(diamonds, x = ~cut, color = ~clarity) %>%
  add_histogram()

La figura 5.4 es útil para comparar el número de diamantes por claridad, dado un tipo de talla. Por ejemplo, dentro de los diamantes “Ideal”, la talla “VS1” es la más popular, la “VS2” la segunda más popular y la “I1” la menos popular. La distribución de la claridad en los diamantes “Ideal” parece bastante similar a la de otros diamantes, pero es difícil hacer esta comparación utilizando los recuentos brutos. La figura 5.5 facilita esta comparación mostrando la frecuencia relativa de diamantes según su claridad, dada una talla.

# number of diamonds by cut and clarity (n)
cc <- count(diamonds, cut, clarity)
# number of diamonds by cut (nn)
cc2 <- left_join(cc, count(cc, cut, wt = n, name = 'nn'))
## Joining with `by = join_by(cut)`
cc2 %>%
  mutate(prop = n / nn) %>%
  plot_ly(x = ~cut, y = ~prop, color = ~clarity) %>%
  add_bars() %>%
  layout(barmode = "stack")

Este tipo de gráfico, también conocido como gráfico de lomo, es un caso especial del gráfico de mosaico. En un gráfico de mosaico, puede escalar la anchura y la altura de las barras según distribuciones discretas. Para los gráficos de mosaico, recomiendo utilizar el paquete ggmosaic (Jeppson, Hofmann y Cook 2016), que implementa un geom ggplot2 personalizado diseñado para gráficos de mosaico, que podemos convertir a plotly mediante ggplotly(). La figura 5.6 muestra un gráfico de mosaico de corte por claridad. Observe cómo la anchura de las barras es proporcional a la frecuencia de corte.

p <- ggplot(data = cc) +
  geom_mosaic(aes(weight = n, x = product(cut), fill = clarity))
ggplotly(p) 
## Warning: `unite_()` was deprecated in tidyr 1.2.0.
## ℹ Please use `unite()` instead.
## ℹ The deprecated feature was likely used in the ggmosaic package.
##   Please report the issue at <]8;;https://github.com/haleyjeppson/ggmosaichttps://github.com/haleyjeppson/ggmosaic]8;;>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

Referencias

Freedman, D., and P. Diaconis. 1981. “On the Histogram as a Density Estimator: L2 Theory.” Zeitschrift Für Wahrscheinlichkeitstheorie Und Verwandte Gebiete 57: 453–76.

Jeppson, Haley, Heike Hofmann, and Di Cook. 2016. Ggmosaic: Mosaic Plots in the ’Ggplot2’ Framework. http://github.com/haleyjeppson/ggmosaic.

Mildenberger, Thoralf, Yves Rozenholc, and David Zasada. 2009. Histogram: Construction of Regular and Irregular Histograms with Different Options for Automatic Choice of Bins. https://CRAN.R-project.org/package=histogram.

Scott, David W. 1979. “On Optimal and Data-Based Histograms.” Biometrika 66: 605–10.

Sturges, Herbert A. 1926. “The Choice of a Class Interval.” Journal of the American Statistical Association 21 (153): 65–66. https://doi.org/10.1080/01621459.1926.10502161.