Sección 3 scattered bases

La ruta de dispersión es un tipo de gráfico que resulta muy útil para representar datos de baja complejidad como puntos, líneas, texto y polígonos, y es la base para una gran cantidad de funciones como add_markers(), add_lines(), add_paths(), add_segments(), add_ribbons(), add_area() y add_polygons(), así como para muchas gráficas de ggplotly(). Estas funciones ofrecen una forma más sencilla de visualizar casos específicos de diagramas de dispersión, al manipular y transformar los datos antes de asignarlos al gráfico. Por ejemplo, add_lines() permite que las líneas se dibujen de forma ordenada según el eje X, lo cual resulta útil para graficar series de tiempo.

library(plotly)
## 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
data(economics, package = "ggplot2")

# sort economics by psavert, just to 
# show difference between paths and lines
p <- economics %>%
  arrange(psavert) %>%
  plot_ly(x = ~date, y = ~psavert)

add_paths(p)
add_lines(p)

En la sección 2.1 Se han incorporado argumentos de “mapeo estético” en la visualización de datos, lo cual facilita la asignación de datos a diferentes propiedades visuales, como el color o el tipo de línea. Además, para garantizar que haya al menos una geometría por grupo, se pueden utilizar las agrupaciones de dplyr. En la figura superior se muestra un ejemplo de cómo se puede utilizar la función group_by() para agrupar eficazmente las series temporales por años, lo cual resulta útil para visualizar la estacionalidad anual de los datos. Otra forma de garantizar al menos una geometría por “grupo” es proporcionar una variable categórica relevante a una estética específica.

library(lubridate)
## 
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
## 
##     date, intersect, setdiff, union
econ <- economics %>%
  mutate(yr = year(date), mnth = month(date))

# One trace (more performant, but less interactive)
econ %>%
  group_by(yr) %>%
  plot_ly(x = ~mnth, y = ~uempmed) %>%
  add_lines(text = ~yr)
# Multiple traces (less performant, but more interactive)
plot_ly(econ, x = ~mnth, y = ~uempmed) %>%
  add_lines(color = ~ordered(yr))
# The split argument guarantees one trace per group level (regardless 
# of the variable type). This is useful if you want a consistent
# visual property over multiple traces 
# plot_ly(econ, x = ~mnth, y = ~uempmed) %>%
#   add_lines(split = ~yr, color = I("black"))

Esto se debe a que el enfoque de agrupación utiliza un solo seguimiento de plotly.js (más eficiente, menos interactivo), mientras que el enfoque de color crea un solo gráfico por programa por año. Aunque es fácil comenzar a utilizar plotly.js mediante sus características básicas, es recomendable aprender a utilizar la biblioteca directamente. A diferencia de las funciones de plotly, los atributos de plotly.js no se enumeran explícitamente como argumentos en las funciones de trazado (a menos que sean atributos especiales), sino que se pasan directamente a la definición de la figura utilizando el operador “….”. Las capas basadas en dispersión en este capítulo establecen el atributo “tipo” de plotly.js en “dispersión” y el modo de visualización (por ejemplo, add_markers() utiliza mode=‘markers’, etc.), pero es posible trabajar de manera más directa con plotly.js utilizando la función de nivel inferior “add_trace()”. También se demuestra cómo utilizar atributos anidados de plotly.js, como “textfont” y “xaxis”, los cuales contienen otros atributos, por lo que es necesario proporcionar la lista correcta de nombres de argumentos para acceder a ellos.

library(praise)
set.seed(99)
plot_ly() %>%
 add_trace(
   type = "scatter",
   mode = "markers+lines+text",
   x = 4:6, 
   y = 4:6,
   text = replicate(3, praise::praise("You are ${adjective}! 🙌")),
   textposition = "right",
   hoverinfo = "text",
   textfont = list(family = "Roboto Condensed", size = 16)
 ) %>%
 layout(xaxis = list(range = c(3, 8)))

Si acaba de comenzar a utilizar plotly.js, le sugiero que dedique un poco de tiempo a explorar los atributos disponibles de plotly.js para los diferentes tipos de gráficos de dispersión y piense en cómo podría utilizarlos. La mayoría de estos atributos también funcionan para otros tipos de gráficos, por lo que aprender sobre atributos específicos para un tipo de gráfico en particular también puede ser útil en otros contextos. Aunque puede utilizar la referencia en línea de plotly.js, https://plot.ly/r/reference/#scatter, para buscar y aprender sobre los atributos, es recomendable utilizar la función schema() por varias razones.

library(listviewer)
schema()

Las secciones que siguen en este capítulo muestran varios tipos de vistas de datos utilizando capas basadas en dispersión. ## 3.1 Markers En esta sección se describe la visualización de gráficos de dispersión utilizando el modo de “marcadores” (add_markers()). Para simplificar, muchos de los ejemplos utilizan add_markers() con ejes x e y numéricos, lo que resulta en un gráfico de dispersión, que es una forma común de visualizar la relación entre dos variables cuantitativas. Sin embargo, el contenido que sigue es igualmente aplicable a los gráficos de puntos (dot plots) que no tienen ejes numéricos x e y. ### 3.1.1 alpha combination De acuerdo con Unwin (2015), los gráficos de dispersión pueden ser valiosos para revelar otros aspectos importantes como relaciones causales, valores atípicos, grupos, vacíos, barreras y relaciones condicionales. Sin embargo, una limitación común de estos gráficos es el problema del sobretrazado, que ocurre cuando múltiples observaciones se encuentran en las mismas o similares ubicaciones x/y. La figura presentada a continuación muestra una técnica para abordar este problema mediante la utilización de la transparencia alfa. Si se está trabajando con una gran cantidad de puntos, considerar el uso de toWebGL() para representar los gráficos utilizando Canvas en lugar de SVG.

subplot(
  plot_ly(mpg, x = ~cty, y = ~hwy, name = "default"),
  plot_ly(mpg, x = ~cty, y = ~hwy) %>% 
    add_markers(alpha = 0.2, name = "alpha")
)
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

3.1.2 Colors

Asignar una variable discreta a un color en una traza resulta en múltiples trazas separadas para cada categoría, lo cual es útil para la legibilidad y la interactividad al hacer hover sobre los puntos. En contraste, asignar una variable numérica a un color resulta en una sola traza con una barra de color para decodificar visualmente los colores de vuelta a los valores numéricos de los datos. La función colorbar() se puede utilizar para personalizar la apariencia de esta barra de color generada automáticamente. La escala de colores por defecto en plotly.js es viridis, una escala perceptualmente uniforme y distinguible incluso para personas con diferentes tipos de daltonismo (Berkeley Institute for Data Science 2016).

p <- plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.5)
subplot(
  add_markers(p, color = ~cyl, showlegend = FALSE) %>% 
    colorbar(title = "Viridis"),
  add_markers(p, color = ~factor(cyl))
)

El argumento “colors” tiene varias opciones para personalizar la escala de colores, pero no acepta cualquier tipo de valor. En particular, se pueden usar uno de los siguientes tipos de valores: (1) un nombre de paleta de colores de brewer (se pueden encontrar los nombres válidos en los nombres de fila de RColorBrewer::brewer.pal.info), (2) un vector de colores para interpolación, o (3) una función de interpolación de color, como colorRamp() o scales::color_ramp().

col1 <- c("#132B43", "#56B1F7")
col2 <- viridisLite::inferno(10)
col3 <- colorRamp(c("red", "white", "blue"))
subplot(
  add_markers(p, color = ~cyl, colors = col1) %>%
    colorbar(title = "ggplot2 default"),
  add_markers(p, color = ~cyl, colors = col2) %>% 
    colorbar(title = "Inferno"),
  add_markers(p, color = ~cyl, colors = col3) %>% 
    colorbar(title = "colorRamp")
) %>% hide_legend()
col1 <- "Accent"
col2 <- colorRamp(c("red", "blue"))
col3 <- c(`4` = "red", `5` = "black", `6` = "blue", `8` = "green")
subplot(
  add_markers(p, color = ~factor(cyl), colors = col1),
  add_markers(p, color = ~factor(cyl), colors = col2),
  add_markers(p, color = ~factor(cyl), colors = col3)
) %>% hide_legend()

Los códigos de color pueden especificarse manualmente (es decir, evitando asignar valores de datos a un rango visual) utilizando la función I(). La figura posterior ofrece un ejemplo sencillo utilizando add_markers(). Cualquier color entendido por la función col2rgb() del paquete grDevices puede ser usado de esta manera.

add_markers(p, color = I("black"))

El parámetro “color” se utiliza para establecer el color de relleno de un objeto geométrico, mientras que el parámetro “trazo” se utiliza para establecer el color del contorno del objeto geométrico. En el caso de la función add_markers(), el parámetro “color” se utiliza para asignar el color al atributo “marker.color” de plotly.js, mientras que el parámetro “trazo” se utiliza para asignar el color de la línea al atributo “marker.line.color”. ### 3.1.3 Symbols El argumento “symbol” permite asignar valores de datos al atributo “marker.symbol” de plotly.js. Su funcionamiento es similar al del argumento “color”:

Si se asigna un mapeo numérico, se generará una única traza. Si se asigna un mapeo discreto, se generarán múltiples trazas (una por cada categoría). Para especificar el rango visual para el mapeo, se puede utilizar el plural “symbols”. Para evitar mapeos, se puede utilizar la función “I()”.

p <- plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.3) 
subplot(
  add_markers(p, symbol = ~cyl, name = "A single trace"),
  add_markers(p, symbol = ~factor(cyl), color = I("black"))
)

Hay dos formas de especificar el rango visual de los símbolos: (1) códigos numéricos (interpretados como códigos pch) o (2) una cadena de caracteres que especifique un valor válido de marker.symbol.

subplot(
  add_markers(p, symbol = ~cyl, symbols = c(17, 18, 19)),
  add_markers(
    p, color = I("black"),
    symbol = ~factor(cyl), 
    symbols = c("triangle-up", "diamond", "circle")
  )
)

Estos símbolos (es decir, el alcance visual) también pueden suministrarse directamente a symbol a través de I().

plot_ly(mpg, x = ~cty, y = ~hwy) %>%
  add_markers(symbol = I(18), alpha = 0.5)

3.1.4 Trazo y batea

El argumento trazo sigue la misma semántica que color y símbolo cuando se trata de mapear variables y especificar rangos visuales. Normalmente no se desea asignar valores de datos a trazo, sino especificar un color de contorno fijo.

plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.5) %>%
  add_markers(symbol = I(18), stroke = I("black"), span = I(1))

size

Para los gráficos de dispersión, el argumento tamaño controla el área de los marcadores (a menos que se especifique lo contrario mediante sizemode), y debe ser una variable numérica. El argumento sizes controla el tamaño mínimo y máximo de los círculos, en píxeles:

p <- plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.3) 
subplot(
  add_markers(p, size = ~cyl, name = "default"),
  add_markers(p, size = ~cyl, sizes = c(1, 500), name = "custom")
)
## Warning: `line.width` does not currently support multiple values.

## Warning: `line.width` does not currently support multiple values.

Al igual que otros argumentos, I() puede utilizarse para especificar el tamaño directamente. En el caso de los marcadores, el tamaño controla el atributo marker.size plotly.js.

plot_ly(mpg, x = ~cty, y = ~hwy, alpha = 0.3, size = I(30))
## No trace type specified:
##   Based on info supplied, a 'scatter' trace seems appropriate.
##   Read more about this trace type -> https://plotly.com/r/reference/#scatter
## No scatter mode specifed:
##   Setting the mode to markers
##   Read more about this attribute -> https://plotly.com/r/reference/#scatter-mode

3.1.6 Dot & Bar Plots of Errors

En este contexto, se prefieren los diagramas de puntos a los gráficos circulares, porque comparar posiciones a lo largo de una escala común es mucho más fácil que comparar ángulos o áreas (Cleveland y McGill 1984; Bostock 2010). Además, cuando se presentan estimaciones puntuales y las incertidumbres asociadas con esas estimaciones, los gráficos de barras tienden a exagerar las diferencias entre las estimaciones puntuales y se olvidan de las incertidumbres (Messing 2012).

Una aplicación popular de los gráficos de puntos (con barras de error) es el llamado “gráfico de coeficientes” para mostrar estimaciones puntuales de los coeficientes y sus errores estándar. Dado que este paquete usa puntos y segmentos para graficar los coeficientes, la información flotante no es la mejor y sería mejor usar un objeto de error. La Figura siguiente usa la función “trapy()” del paquete broom (Robinson 2016) para obtener un marco de datos con coeficientes de una fila por modelo y genera un gráfico de los coeficientes con barras de error a lo largo del eje x.

library(broom)
library(forcats)
# Fit a full-factorial linear model
m <- lm(
  Sepal.Length ~ Sepal.Width * Petal.Length * Petal.Width, 
  data = iris
)

# (1) get a tidy() data structure of covariate-level info 
# (e.g., point estimate, standard error, etc)
# (2) make sure term column is a factor ordered by the estimate
# (3) plot estimate by term with an error bar for the standard error
broom::tidy(m) %>% 
  mutate(term = forcats::fct_reorder(term, estimate)) %>%
  plot_ly(x = ~estimate, y = ~term) %>%
  add_markers(
    error_x = ~list(value = std.error), 
    color = I("black"),
    hoverinfo = "x"
  )

3.2 Lines

Muchos de los mismos principios que aprendimos sobre la estética de los marcadores (Sección 3.1) se aplican a las líneas. asegúrese de que cada grupo tenga al menos una geometría (en este caso, una línea). También aprendimos la diferencia entre add_paths() y add_lines(): el primero dibuja líneas en orden de línea, mientras que el segundo dibuja líneas en x.

3.2.1 line types

Aquí usamos el paquete dplyr para encontrar las 5 ciudades principales en términos de ventas mensuales promedio (top5) y luego filtramos los datos de origen para que solo contengan esas ciudades usando semi_join(). Como se muestra en la fig. 3.17, después de filtrar los datos, es fácil asignar un color o tipo de línea a una ciudad. La paleta de tipos de línea se puede modificar con el argumento tipos de línea y acepta valores lty de R o valores de guión de plotly.js.

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(ggplot2)
library(rockchalk)
## 
## Attaching package: 'rockchalk'
## The following object is masked from 'package:dplyr':
## 
##     summarize
library(plotly)
top5 <- txhousing %>%
  group_by(city) %>%
  summarise(m = mean(sales, na.rm = TRUE)) %>%
  arrange(desc(m)) %>%
  top_n(5)
## Selecting by m
tx5 <- semi_join(txhousing, top5, by = "city")

plot_ly(tx5, x = ~date, y = ~median) %>%
  add_lines(linetype = ~city)

Si desea controlar exactamente qué tipo de línea se utiliza para codificar un determinado valor de datos, puede proporcionar un vector de caracteres con nombres.

ltys <- c(
  Austin = "dashdot",
  `Collin County` = "longdash",
  Dallas = "dash",
  Houston = "solid",
  `San Antonio` = "dot"
)

plot_ly(tx5, x = ~date, y = ~median) %>%
  add_lines(linetype = ~city, linetypes = ltys)

3.2.2 Segments

La función add_segments() permite conectar dos puntos [(x, y) a (xend, yend)] con una línea. Los segmentos forman los bloques de construcción de numerosos tipos de gráficos útiles, incluidos los gráficos inclinados, los gráficos de campana, los gráficos de velas y otros. Los gráficos inclinados y los gráficos de mancuernas son útiles para comparar valores numéricos en numerosas categorías. Los gráficos de velas suelen utilizarse para visualizar los cambios de un activo financiero a lo largo del tiempo. ### 3.2.2.1 slope graph !range@} l gráfico de pendiente, popularizado por Tufte (2001b), es una excelente forma de comparar el cambio en una medición a través de numerosos grupos. Este cambio puede producirse a lo largo de un eje discreto o continuo. Para un eje continuo, el slopegraph podría considerarse como una descomposición de un gráfico lineal en múltiples segmentos. El paquete slopegraph R proporciona una interfaz sucinta para crear slopegraphs con gráficos base o ggplot2 y también algunos conjuntos de datos convenientes que utilizaremos aquí (Leeper 2017).

library("vembedr")
## 
## Attaching package: 'vembedr'
## The following object is masked from 'package:lubridate':
## 
##     hms
embed_url("https://vimeo.com/327585190?embedded=true&source=vimeo_logo&owner=29107273")

3.2.2.2 Dumbell

Los denominados gráficos de mancuernas son similares en concepto a los gráficos de pendientes, pero no tan generales. Suelen utilizarse para comparar dos clases diferentes de valores numéricos entre numerosos grupos.

mpg %>%
  group_by(model) %>%
  summarise(c = mean(cty), h = mean(hwy)) %>%
  mutate(model = forcats::fct_reorder(model, c)) %>%
  plot_ly() %>%
  add_segments(
    x = ~c, y = ~model,
    xend = ~h, yend = ~model, 
    color = I("gray"), showlegend = FALSE
  ) %>%
  add_markers(
    x = ~c, y = ~model, 
    color = I("blue"), 
    name = "mpg city"
  ) %>%
  add_markers(
    x = ~h, y = ~model, 
    color = I("red"),
    name  = "mpg highway"
  ) %>%
  layout(xaxis = list(title = "Miles per gallon"))

3.2.2.3 Candlestick

Se utiliza el paquete quantmod (Ryan 2016) para obtener datos sobre el precio de las acciones de Microsoft y traza dos segmentos para cada día: uno para codificar los valores de apertura/cierre y otro para codificar los máximos/mínimos diarios.

library(quantmod)
## Loading required package: xts
## Loading required package: zoo
## 
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
## 
##     as.Date, as.Date.numeric
## 
## ################################### WARNING ###################################
## # We noticed you have dplyr installed. The dplyr lag() function breaks how    #
## # base R's lag() function is supposed to work, which breaks lag(my_xts).      #
## #                                                                             #
## # Calls to lag(my_xts) that you enter or source() into this session won't     #
## # work correctly.                                                             #
## #                                                                             #
## # All package code is unaffected because it is protected by the R namespace   #
## # mechanism.                                                                  #
## #                                                                             #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning.  #
## #                                                                             #
## # You can use stats::lag() to make sure you're not using dplyr::lag(), or you #
## # can add conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop   #
## # dplyr from breaking base R's lag() function.                                #
## ################################### WARNING ###################################
## 
## Attaching package: 'xts'
## The following objects are masked from 'package:dplyr':
## 
##     first, last
## Loading required package: TTR
## Registered S3 method overwritten by 'quantmod':
##   method            from
##   as.zoo.data.frame zoo
## 
## Attaching package: 'quantmod'
## The following object is masked from 'package:rockchalk':
## 
##     addLines
msft <- getSymbols("MSFT", auto.assign = F)
dat <- as.data.frame(msft)
dat$date <- index(msft)
dat <- subset(dat, date >= "2016-01-01")

names(dat) <- sub("^MSFT\\.", "", names(dat))

plot_ly(dat, x = ~date, xend = ~date, color = ~Close > Open, 
        colors = c("red", "forestgreen"), hoverinfo = "none") %>%
  add_segments(y = ~Low, yend = ~High, size = I(1)) %>%
  add_segments(y = ~Open, yend = ~Close, size = I(3)) %>%
  layout(showlegend = FALSE, yaxis = list(title = "Price")) %>%
  rangeslider()

3.2.3 density charts

Aprovechamos una serie de algoritmos en R para calcular el número “óptimo” de intervalos para un histograma, a través de hist(), y dirigir esos resultados a add_bars(). Podemos aprovechar la función density() para calcular las estimaciones de densidad del núcleo de forma similar, y dirigir los resultados a add_lines().

kerns <- c("gaussian", "epanechnikov", "rectangular", 
          "triangular", "biweight", "cosine", "optcosine")
p <- plot_ly()
for (k in kerns) {
  d <- density(economics$pce, kernel = k, na.rm = TRUE)
  p <- add_lines(p, x = d$x, y = d$y, name = k)
}
p

3.2.4 parallel coordinates

Una técnica de visualización muy útil, pero que a menudo se pasa por alto, es el gráfico de coordenadas paralelas. Las coordenadas paralelas permiten comparar valores a lo largo de una(s) escala(s) posicional(es) común(es) (o no alineada(s)) -la más básica de todas las tareas perceptivas- en más de 3 dimensiones (Cleveland y McGill 1984). Normalmente, cada línea representa cada medida de una fila (u observación) determinada de un conjunto de datos. Es cierto que plotly.js proporciona un tipo de trazado, parcoords, específico para coordenadas paralelas que ofrece capacidades interactivas deseables (por ejemplo, resaltar y reordenar los ejes).

iris$obs <- seq_len(nrow(iris))
iris_pcp <- function(transform = identity) {
  iris[] <- purrr::map_if(iris, is.numeric, transform)
  tidyr::gather(iris, variable, value, -Species, -obs) %>% 
    group_by(obs) %>% 
    plot_ly(x = ~variable, y = ~value, color = ~Species) %>% 
    add_lines(alpha = 0.3)
}
subplot(
  iris_pcp(), 
  iris_pcp(scale),
  iris_pcp(scales::rescale),
  nrows = 3, shareX = TRUE
) %>% hide_legend()
## Warning: attributes are not identical across measure variables; they will be
## dropped

Gracias al marco de resaltado vinculado, las coordenadas paralelas creadas de esta manera podrían vincularse a gráficos de datos relacionados de menor dimensión (pero a veces de mayor resolución) para guiar el estudio de datos multivariados. El paquete Pedestrian proporciona algunos ejemplos de vinculación de coordenadas paralelas a otras vistas, p. B. un gran recorrido para descubrir características inusuales en un espacio de alta dimensión (Sievert 2019a).

3.3 polygons

Los polígonos forman la base para otras capas basadas en dispersión de nivel superior (por ejemplo, add_ribbons() y add_sf()) que no tienen un tipo de gráfico dedicado en plotly.js. Los polígonos se pueden usar para dibujar muchas cosas, pero quizás la aplicación más conocida en la que querrá usar add_polygons() es cuando se dibujan objetos geoespaciales. Cuando use add_polygons() para trazar un mapa, asegúrese de establecer la relación de aspecto (por ejemplo, xaxis.scaleanchor) y también considere usar plotly_empty() sobre plot_ly() para agregar etiquetas de ejes, marcas y ocultar la cuadrícula de fondo.

base <- map_data("world", "canada") %>%
  group_by(group) %>%
  plotly_empty(x = ~long, y = ~lat, alpha = 0.2) %>%
  layout(showlegend = FALSE, xaxis = list(scaleanchor = "y"))
  
base %>%
  add_polygons(hoverinfo = "none", color = I("black")) %>%
  add_markers(text = ~paste(name, "<br />", pop), hoverinfo = "text", 
              color = I("red"), data = maps::canada.cities)

las capas poligonales basadas en dispersión (es decir, add_polygons(), add_ribbons(), etc) renderizan todos los polígonos utilizando un trazado plotly.js por defecto. Este enfoque es computacionalmente eficiente, pero no siempre es deseable (por ejemplo, no puede tener múltiples rellenos por trazo, la interactividad es relativamente limitada). Para evitar estas limitaciones, considere el uso de split (o color con una variable discreta) para dividir los datos del polígono en múltiples trazos.

add_polygons(base, split = ~subregion, hoveron = "fills")

3.3.1 Lazos

Las cintas son útiles para mostrar los límites de incertidumbre como una función de x. La función add_ribbons() crea cintas y requiere los argumentos: x, ymin, y ymax.

library(plotly)
library(broom)
library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ purrr   1.0.1     ✔ tibble  3.2.1
## ✔ readr   2.1.4     ✔ tidyr   1.3.0
## ✔ stringr 1.5.0     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter()        masks plotly::filter(), stats::filter()
## ✖ xts::first()           masks dplyr::first()
## ✖ vembedr::hms()         masks lubridate::hms()
## ✖ dplyr::lag()           masks stats::lag()
## ✖ xts::last()            masks dplyr::last()
## ✖ rockchalk::summarize() masks dplyr::summarize()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
m <- lm(mpg ~ wt, data = mtcars)
broom::augment(m) %>%
  plot_ly(x = ~wt, showlegend = FALSE) %>%
  add_markers(y = ~mpg, color = I("black")) %>%
  add_ribbons(ymin = ~.fitted - qt(0.975, df = 1), 
              ymax = ~.fitted + qt(0.975, df = 1), 
              color = I("gray80")) %>%
  add_lines(y = ~.fitted, color = I("steelblue"))

References

Berkeley Institute for Data Science. 2016. “Mpl Colormaps.” 2016. http://web.archive.org/web/20160601125258/http://bids.github.io/colormap/.

Bostock, Jeffrey Heer AND Michael. 2010. “Crowdsourcing Graphical Perception: Using Mechanical Turk to Assess Visualization Design.” In ACM Human Factors in Computing Systems (Chi), 203–12. http://vis.stanford.edu/papers/crowdsourcing-graphical-perception.

Cleveland, William S, and Robert McGill. 1984. “Graphical Perception: Theory, Experimentation, and Application to the Development of Graphical Methods.” Journal of the American Statistical Association 79 (September): 531–54.

Few, Stephen. 2006. “Data Visualization: Rules for Encoding Values in Graph.” 2006. https://web.archive.org/web/20160404214629/http://www.perceptualedge.com/articles/b-eye/encoding_values_in_graph.pdf.

Lander, Jared P. 2016. Coefplot: Plots Coefficients from Fitted Models. https://CRAN.R-project.org/package=coefplot.

Leeper, Thomas J. 2017. Slopegraph: Edward Tufte-Inspired Slopegraphs.

Messing, Solomon. 2012. “Visualization Series: Insight from Cleveland and Tufte on Plotting Numeric Data by Groups.” 2012. http://web.archive.org/web/20160602202734/https://solomonmessing.wordpress.com/2012/03/04/visualization-series-insight-from-cleveland-and-tufte-on-plotting-numeric-data-by-groups/.

Robinson, David. 2016. Broom: Convert Statistical Analysis Objects into Tidy Data Frames. https://CRAN.R-project.org/package=broom.

Ryan, Jeffrey A. 2016. Quantmod: Quantitative Financial Modelling Framework. https://CRAN.R-project.org/package=quantmod.

Sievert, Carson. 2019a. Pedestrians: Tools for Exploring Melbourne’s Pedestrian Data. https://github.com/cpsievert/pedestrians.

Tufte, Edward. 2001b. The Visual Display of Quantitative Information. Cheshire, Conn: Graphics Press.

Unwin, Antony. 2015. Graphical Data Analysis with R. CRC Press. http://www.gradaanwr.net.