SECCIÓN 5 - Barras e histogramas

Las funciones “add_bars()” y “add_histogram()” envuelven los tipos de trazos bar’ e histogram “plotly.js”. La principal diferencia entre ellos es que los trazos de bar’ requieren alturas de barra (tanto x como y), mientras que los trazos de histogram requieren solo una variable y plotly.js maneja la agrupación en el navegador. Y quizás de manera confusa, ambas funciones se pueden usar para visualizar la distribución de una variable numérica o discreta. Entonces, esencialmente, la única diferencia entre ellos es dónde ocurre la agrupación.

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

library(plotly)
## Warning: package 'plotly' was built under R version 4.3.3
## Loading required package: ggplot2
## 
## 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
# Crea un histograma usando plot_ly
pl <- plot_ly(diamonds, x = ~price) %>%
  add_histogram(name = "plotly.js")

# Define una función para crear histogramas de precios
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)
}

# Crea histogramas usando diferentes métodos
p1 <- price_hist()
p2 <- price_hist("Sturges")
p3 <- price_hist("Scott")

# Crea subgráficos
subplot(p1, p2, p3, nrows = 3, shareX = TRUE)

FIGURA 5.1: El algoritmo de agrupamiento predeterminado de plotly.js versus el predeterminado hist() de R.

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 permite que plotly.js realice la agrupación.

Se necesita más esfuerzo humano para realizar la agrupación en R, pero hacerlo tiene la ventaja de enviar menos datos y requerir menos trabajo de cálculo por parte del navegador web. En este caso, solo tenemos unos 50.000 registros, por lo que no hay mucha diferencia en los tiempos de carga de la página o el tamaño de la página. Sin embargo, con 1 millón de registros, el tiempo de carga de la página se duplica y el tamaño de la página casi se duplica.

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
library(plotly)

# Crear el primer gráfico de histograma
p1 <- plot_ly(diamonds, x = ~cut) %>%
  add_histogram()

# Crear el segundo gráfico de barras
p2 <- diamonds %>%
  count(cut) %>%
  plot_ly(x = ~cut, y = ~n) %>%
  add_bars()

# Crear un subplot y ocultar la leyenda
subplot(p1, p2) %>% hide_legend()

FIGURE 5.2: Number of diamonds by cut.

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

library(dplyr)
library(plotly)

# Definir la función para crear un gráfico
one_plot <- function(d) {
  plot_ly(d, x = ~price) %>%
    add_annotations(
      text = unique(d$clarity), x = 0.5, y = 1, xref = "paper", yref = "paper", showarrow = FALSE
    )
}

# Aplicar la función a cada grupo de datos dividido por claridad
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 múltiples distribuciones discretas es difícil. La sutil complejidad se debe al hecho de que tanto los recuentos como las proporciones son importantes para comprender distribuciones discretas multivariadas. La Figura 5.4 presenta el recuento de diamantes, dividido tanto por talla como por claridad, utilizando un gráfico de barras agrupadas.

library(plotly)

# Crear el histograma con diferentes colores para cada nivel de claridad
plot_ly(diamonds, x = ~cut, color = ~clarity) %>%
  add_histogram()

FIGURA 5.4: Gráfico de barras agrupadas de recuentos de diamantes por talla y claridad.

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 “ideales”, la talla “VS1” es la más popular, la “VS2” es la segunda más popular y la “11” la menos popular. La distribución de la claridad dentro de los diamantes “ideales” parece ser bastante similar a la de otros diamantes, pero es difícil hacer esta comparación utilizando recuentos brutos. La figura 5.5 facilita esta comparación al mostrar la frecuencia relativa de los diamantes por claridad, dada una talla.

library(dplyr)
library(plotly)

# Número de diamantes por corte y claridad (n)
cc <- diamonds %>%
  count(cut, clarity)

# Número de diamantes por corte (nn)
cc2 <- cc %>%
  left_join(count(cc, cut, wt = n, name = 'nn'))
## Joining with `by = join_by(cut)`
# Calcular la proporción
cc2 <- cc2 %>%
  mutate(prop = n / nn)

# Crear el gráfico de barras
plot_ly(cc2, x = ~cut, y = ~prop, color = ~clarity, type = "bar") %>%
  layout(barmode = "stack")

FIGURA 5.5: Un gráfico de barras apiladas que muestra la proporción de claridad del diamante dentro del corte.

Este tipo de trama, también conocida como trama espinal, es un caso especial de trama en mosaico. En un gráfico de mosaico, puede escalar tanto el ancho como la altura de las barras según distribuciones discretas. Para gráficos de mosaico, recomiendo usar el paquete ggmosaic (Jeppson et al., 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 diagrama de mosaico de corte por claridad. Observe cómo los anchos de las barras se escalan proporcionalmente a la frecuencia de corte.

library(ggmosaic)
## Warning: package 'ggmosaic' was built under R version 4.3.3
library(plotly)

# Crear el gráfico de mosaico
p <- ggplot(data = cc) +
  geom_mosaic(aes(weight = n, x = product(cut), fill = clarity))

# Convertir el gráfico de ggplot a plotly
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 <https://github.com/haleyjeppson/ggmosaic>.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

FIGURA 5.6: Uso de ggmosaic y ggplotly() para crear visualizaciones interactivas avanzadas de datos categóricos.

SECCIÓN 6 - Diagramas de caja

Los diagramas de caja codifican el resumen de cinco números de una variable numérica y proporcionan una forma decente de comparar muchas distribuciones numéricas. La tarea visual de comparar múltiples diagramas de caja es relativamente fácil (es decir, comparar la posición a lo largo de una escala común) en comparación con algunas alternativas comunes (por ejemplo, una visualización enrejada de histogramas, como la Figura 5.1), pero el diagrama de caja a veces es inadecuado para capturar distribuciones complejas (por ejemplo, multimodales) (en este caso, un polígono de frecuencia, como el de la Figura 2.9, proporciona una buena alternativa). La función add_boxplot() requiere una variable numérica y garantiza que los diagramas de caja estén orientados correctamente, independientemente de si la variable numérica se coloca en la escala x o y. Como muestra la Figura 6.1, en el eje ortogonal al eje numérico, puede proporcionar una variable discreta (para acondicionamiento) o proporcionar un valor único (para nombrar la categoría del eje).

library(plotly)

# Crear un diagrama de caja con puntos de datos transparentes
p <- plot_ly(diamonds, y = ~price, color = I("black"),
             alpha = 0.1, boxpoints = "suspectedoutliers")

# Añadir un diagrama de caja a 'p' con la variable "Overall" en el eje x
pl <- p %>% add_boxplot(x = "Overall")

# Añadir otro diagrama de caja a 'p' con la variable "cut" en el eje x
p2 <- p %>% add_boxplot(x = ~cut)

# Crear los subgráficos
subplot(
  pl, p2, shareY = TRUE,
  widths = c(0.2, 0.8), margin = 0
) %>% hide_legend()

FIGURA 6.1: Precio general del diamante y precio por talla.

Si desea dividir por más de una variable discreta, puede usar la interacción de esas variables con el eje discreto y colorear por la variable anidada, como lo hace la Figura 6.2 con la claridad y el corte del diamante. Otro enfoque sería utilizar una pantalla enrejada, similar a la Figura 13.9.

library(plotly)

# Crear un diagrama de caja con la variable 'price' en el eje x y la interacción entre 'clarity' y 'cut' en el eje y
plot_ly(diamonds, x = ~price, y = ~interaction(clarity, cut)) %>%
  add_boxplot(color = ~clarity) %>%
  layout(yaxis = list(title = ""))

FIGURA 6.2: Precios de los diamantes por talla y claridad.

También resulta útil ordenar los diagramas de caja según algo significativo, como el precio medio. La Figura 6.3 presenta la misma información que la Figura 6.2, pero ordena los diagramas de caja por su mediana y deja inmediatamente claro que los diamantes con una talla “SI2” tienen el precio más alto, en promedio.

library(dplyr)
library(plotly)

# Añadir la interacción entre 'clarity' y 'cut' como una nueva variable 'cc'
d <- diamonds %>%
  mutate(cc = interaction(clarity, cut))

# Obtener los niveles de interacción ordenados por la mediana del precio
lvls <- d %>%
  group_by(cc) %>%
  summarise(m = median(price)) %>%
  arrange(m) %>%
  pull(cc)

# Crear el gráfico de diagrama de caja
plot_ly(d, x = ~price, y = ~factor(cc, levels = lvls)) %>%
  add_boxplot(color = ~clarity) %>%
  layout(yaxis = list(title = ""))

FIGURA 6.3: Precios de los diamantes por talla y claridad, ordenados por mediana de precios.

Similar a add_histogram(), add_boxplot() envía los datos sin procesar al navegador y permite que plotly.js calcule estadísticas resumidas. Desafortunadamente, plotly.js aún no permite estadísticas precalculadas para diagramas de caja.

SECCIÓN 7 - Frecuencias 2D

##7.1 Agrupación rectangular en plotly.js El paquete plotly proporciona dos funciones para mostrar contenedores rectangulares: add_heatmap() y add_histogram2d(). Para datos numéricos, la función add_heatmap() es un análogo 2D de add_bars() (los bins deben calcularse previamente), y la función add_histogram2d() es un análogo 2D de add_histogram() (los bins se pueden calcular en el navegador). Por lo tanto, recomiendo add_histogram2d() con fines exploratorios, ya que no es necesario pensar en cómo realizar la agrupación. También proporciona un útil atributo zs-mooth¹ para aumentar efectivamente el número de contenedores (actualmente, “best” realiza una interpolación bilineal², un tipo de algoritmo de vecinos más cercanos) y atributos nbinsx³/nbinsy para establecer el número de contenedores en el direcciones x y/o y. La Figura 7.1 compara tres usos diferentes de add_histogram(): (1) el algoritmo de agrupamiento predeterminado de plotly.js, (2) el suavizado predeterminado más, (3) establecer el número de bins en las direcciones x e y. También vale la pena señalar que los contornos rellenos, en lugar de contenedores, se pueden usar en cualquiera de estos casos usando add_histogram2dcontour() en lugar de add_histogram2d().

library(plotly)

# Crear un gráfico scatter plot con el eje x como 'carat' y el eje y como logaritmo de 'price'
p <- plot_ly(diamonds, x = ~carat, y = ~log(price), type = "scatter", mode = "markers")

# Crear subplots con histogramas 2D y configuraciones específicas
subplot(
  p %>% add_histogram2d() %>% colorbar(title = "default") %>% layout(xaxis = list(title = "default")),
  p %>% add_histogram2d(zsmooth = "best") %>% colorbar(title = "zsmooth") %>% layout(xaxis = list(title = "zsmooth")),
  p %>% add_histogram2d(nbinsx = 60, nbinsy = 68) %>% colorbar(title = "nbins") %>% layout(xaxis = list(title = "nbins")),
  shareY = TRUE, titleX = TRUE
)
## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

## Warning: 'histogram2d' objects don't have these attributes: 'mode'
## Valid attributes include:
## 'autobinx', 'autobiny', 'autocolorscale', 'bingroup', 'coloraxis', 'colorbar', 'colorscale', 'customdata', 'customdatasrc', 'histfunc', 'histnorm', 'hoverinfo', 'hoverinfosrc', 'hoverlabel', 'hovertemplate', 'hovertemplatesrc', 'ids', 'idssrc', 'legendgroup', 'legendgrouptitle', 'legendrank', 'marker', 'meta', 'metasrc', 'name', 'nbinsx', 'nbinsy', 'opacity', 'reversescale', 'showlegend', 'showscale', 'stream', 'textfont', 'texttemplate', 'transforms', 'type', 'uid', 'uirevision', 'visible', 'x', 'xaxis', 'xbingroup', 'xbins', 'xcalendar', 'xgap', 'xhoverformat', 'xsrc', 'y', 'yaxis', 'ybingroup', 'ybins', 'ycalendar', 'ygap', 'yhoverformat', 'ysrc', 'z', 'zauto', 'zhoverformat', 'zmax', 'zmid', 'zmin', 'zsmooth', 'zsrc', 'key', 'set', 'frame', 'transforms', '_isNestedKey', '_isSimpleKey', '_isGraticule', '_bbox'

##7.2 Agrupación rectangular en R En el Capítulo 5, aprovechamos una serie de algoritmos en R para calcular el número “óptimo” de contenedores para un histograma, a través de hist(), y enrutar esos resultados a add_bars (). Hay una sorprendente falta de investigación y herramientas computacionales para el análogo 2D, y entre las investigaciones que existen, las soluciones generalmente dependen de las características desconocidas de la distribución subyacente, por lo que el enfoque típico es asumir una forma gaussiana (Scott, 1992). En la práctica, esa suposición no es muy útil, pero la estimación de la densidad del kernel 2D proporciona una alternativa útil que tiende a ser más robusta ante los cambios en la forma distributiva. Aunque la estimación de la densidad del núcleo requiere la elección del núcleo y un parámetro de ancho de banda, la función kde2d() del paquete MASS proporciona una regla general bien respaldada para estimar el ancho de banda de una densidad del núcleo gaussiano (Venables y Ripley, 2002). La Figura 7.2 usa kde2d() para estimar una densidad 2D, escala la frecuencia relativa a una frecuencia absoluta y luego usa la función add_heatmap() para mostrar los resultados como un mapa de calor.

library(plotly)
library(MASS)
## Warning: package 'MASS' was built under R version 4.3.3
## 
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
## 
##     select
## The following object is masked from 'package:plotly':
## 
##     select
# Definir la función kde_count
kde_count <- function(x, y, ...) {
  kde <- MASS::kde2d(x, y, ...)
  df <- with(kde, setNames(expand.grid(x, y), c("x", "y")))
  # Escalar 'z' a un recuento
  count <- with(kde, c(z) * length(x) * diff(x)[1] * diff(y)[1])
  data.frame(df, count)
}

# Aplicar la función kde_count a los datos de diamantes
kd <- with(diamonds, kde_count(log(carat), log(price), n = 30))

# Crear un heatmap con los resultados del KDE
plot_ly(kd, x = ~x, y = ~y, z = ~count) %>%
  add_heatmap() %>%
  colorbar(title = "Número de diamantes")

FIGURA 7.2: Estimación de densidad 2D mediante la función kde2d().

##7.3 Ejes categóricos Las funciones add_histogram2d(), add_histogram2dcontour () y add_heatmap() admiten ejes categóricos. Por lo tanto, add_histogram2d() se puede utilizar para mostrar fácilmente tablas de contingencia bidireccionales, pero como es más fácil comparar valores a lo largo de una escala común que comparar colores (Cleveland y McGill, 1984), recomiendo crear gráficos de barras agrupadas. Sin embargo, la función add_heatmap() aún puede ser útil para ejes categóricos, ya que nos permite mostrar cualquier cantidad que queramos a lo largo del eje z (color).

La Figura 7.3 usa add_heatmap() para mostrar una matriz de correlación. Observe cómo los argumentos de límites en la función colorbar() se pueden usar para expandir los límites de la escala de colores para reflejar el rango de posibles correlaciones (algo que no se hace fácilmente en plotly.js).

library(plotly)
library(dplyr)

# Calcular la matriz de correlación de las variables numéricas
corr <- cor(dplyr::select_if(diamonds, is.numeric))

# Crear el heatmap de la matriz de correlación
plot_ly(colors = "RdBu") %>%
  add_heatmap(x = rownames(corr), y = colnames(corr), z = corr) %>%
  colorbar(limits = c(-1, 1))

FIGURA 7.3: Visualización de una matriz de correlación con add_heatmap() y control de los límites de escala con colorbar ().

#SECCIÓN 8 - Gráficos 3D ##8.1 Marcadores Resulta que simplemente agregando un atributo z, plot_ly() automáticamente representa marcadores, líneas y rutas en tres dimensiones. Eso significa que todas las técnicas que aprendimos en las Secciones 3.1 y 3.2 se pueden reutilizar para gráficos 3D:

library(plotly)

# Crear un gráfico 3D de dispersión con las variables 'cty', 'hwy' y 'cyl'
plot_ly(mpg, x = ~cty, y = ~hwy, z = ~cyl) %>% 
  add_markers(color = ~cyl)

FIGURA 8.1: Un diagrama de dispersión 3D.

##8.2 Caminos Para crear un camino en 3D, use add_paths() de la misma manera que lo haría para un camino 2D, pero agregue una tercera variable z, como lo hace la Figura 8.2.

library(plotly)

# Crear un gráfico 3D de líneas con las variables 'cty', 'hwy' y 'cyl'
plot_ly(mpg, x = ~cty, y = ~hwy, z = ~cyl) %>%
  add_paths(color = ~displ)

FIGURA 8.2: Un camino con interpolación de color en 3D.

##8.3 Líneas La Figura 8.3 usa add_lines() en lugar de add_paths () para garantizar que los puntos estén conectados por el eje x en lugar del orden de las filas.

library(plotly)

# Crear un gráfico 3D de líneas con las variables 'cty', '-hwy' y 'cyl'
plot_ly(mpg, x = ~cty, y = ~hwy, z = ~cyl) %>%
  add_lines(color = ~displ)

FIGURA 8.3: Una línea con interpolación de color en 3D.

Al igual que con las líneas que no son 3D, puede crear varias líneas especificando una variable de agrupación.

library(plotly)
library(dplyr)

# Crear un gráfico 3D de líneas con las variables 'cty', '-hwy' y 'cyl', agrupado por 'cyl'
plot_ly(mpg, x = ~cty, y = ~hwy, z = ~cyl) %>%
  group_by(cyl) %>%
  add_lines(color = ~displ)

FIGURA 8.4: Uso de group_by () para crear múltiples líneas 3D.

##8.4 Ejes Para gráficos 3D, tenga en cuenta que los objetos del eje son parte de la definición de escena¹, que es parte del diseño(). Es decir, si desea establecer títulos de ejes (por ejemplo, Figura 8.5), o algo más específico para la definición de ejes, la relación entre ejes (es decir, relación de aspecto²) o la configuración predeterminada de la cámara (es decir, cámara³); lo harías a través de la escena.

library(plotly)

# Crear un gráfico 3D de líneas con las variables 'cty', 'hwy' y 'cyl'
plot_ly(mpg, x = ~cty, y = ~hwy, z = ~cyl) %>%
  add_lines(color = ~displ) %>%
  layout(
    scene = list(
      xaxis = list(title = "MPG city"),
      yaxis = list(title = "MPG highway"),
      zaxis = list(title = "Number of cylinders")
    )
  )

FIGURA 8.5: Configuración de títulos de ejes en un gráfico 3D.

##8.5 Superficies Crear superficies 3D con add_surface() es muy parecido a crear mapas de calor con add_heatmap(). De hecho, incluso puedes crear superficies 3D sobre x/y categóricas (intenta cambiar add_heatmap() por add_surface() en la Figura 7.3). Dicho esto, debería haber un orden sensato para los ejes x/y en un gráfico de superficie, ya que plotly.js interpola los valores z. Normalmente la superficie 3D se encuentra sobre una región continua, como se hace en la Figura 8.6 para mostrar la altura de un volcán. Si se proporciona una matriz numérica para z como en la Figura 8.6, no es necesario proporcionar los atributos x e y, pero si lo son,la longitud de x debe coincidir con el número de columnas de la matriz y y debe coincidir con el número de filas.

library(plotly)

x <- seq_len(nrow(volcano)) + 100
y <- seq_len(ncol(volcano)) + 500

plot_ly() %>%
  add_surface(x = x, y = y, z = ~volcano)

FIGURA 8.6: Una superficie 3D de la altura del volcán.