Armá un Dashboard con R y Quarto

Betsy Cohen
RLadies Buenos Aires

Mientras esperás a que comencemos…

Asegurate de haber seguido las instrucciones de configuración y que tenés los programas y paquetes que necesitás para seguir el taller

Agradecimientos

Este taller y sus materiales se basaron en:

Build-a-Dashboard dictado por Mine Çetinkaya-Rundel


Auspisian RLadies Buenos Aires:

Codigo de conducta

Todos los espacios de participación de R-Ladies Global y RLadies Buenos Aires, incluyendo reuniones presenciales o virtuales, Twitter, Slack y listas de correo se rigen por el Código de conducta de RLadies.

Licencia

Estos materiales están publicados bajo la licencia Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA), la cual implica:

  • Atribución: Podés compartir y adaptar el material siempre que reconozcas la autoría de forma adecuada.
  • Uso no comercial: No está permitido usar el material con fines comerciales.
  • Compartir igual: Si adaptás o transformas el material, debés distribuirlo bajo la misma licencia.

Hacemos a este este bello espacio…

María Nanton

Jesica Formoso

Betsabé Cohen

Virginia García Alonso

Empecemos por el principio

La unidad fundamental en los tableros de Quarto son las tarjetas

Por default las tarjetas se ordenan en filas y columnas

Y si queremos un layout más avanzado vamos a poder agregar páginas, tabsets, y sidebars

Trabajando la disposición

Las filas y columnas se definen, a su vez, mediante encabezados de Markdown y chuncks. Por ejemplo, aquí se muestra un diseño simple con dos filas, donde la segunda fila se divide en dos columnas:

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
author: "Rladies BA"
format: dashboard
---

## Row {height=70%}

```{r}
``` 
## Row {height=30%}
```{r}
``` 
```{r}
``` 

Paginado

Podemos agregar varias páginas a nuestro dashboard usando títulos del nivel 1 de Markdown.

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
author: "Rladies BA"
format: dashboard
---

# Page 1

## Row {height=70%}

```{r}
``` 
## Row {height=30%}
```{r}
``` 
```{r}
``` 
# Page 2
```{r}
``` 
```{r}
``` 

Tabset

Otra opción muy linda es agregar solapas o tabsets indicando la clase .tabset a una columna o fila:

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
author: "Rladies BA"
format: dashboard
---

## Row 

```{r}
``` 
## Row {.tabset}
```{r}
``` 
```{r}
``` 

Como dijo Gilda: pasito a pasito

Paso 1: Armá un archivo Quarto con format: dashboard en el YAML

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

Paso 2: Cada chunck funciona como una tarjeta

Los distintos niveles de las seccioines en que se ordenen esas tarjetas también podemos irlas agregando usando ##

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

```{r}
library(ggplot2)
```

```{r}
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

Paso 2: Así queda nuestra primera tarjeta

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

```{r}
library(ggplot2)
```

```{r}
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

Paso 3: Sumamos otra tarjeta

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

```{r}
library(ggplot2)
```

```{r}
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

```{r}
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Paso 3: Y se visualiza abajo

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

```{r}
library(ggplot2)
```

```{r}
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```

```{r}
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Paso 4: A cada tarjeta podemos agregarle un título usando la opción #|title:

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

```{r}
library(ggplot2)
```
```{r}
#| title: Highway vs. city mileage
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```
```{r}
#| title: Drive types
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Paso 4: A cada tarjeta podemos agregarle un título usando la opción #|title:

dashboard-r.qmd
---
title: "Mi primer tablero en quarto"
format: dashboard
---

```{r}
library(ggplot2)
```
```{r}
#| title: Highway vs. city mileage
ggplot(mpg, aes(x = cty, y = hwy)) +
  geom_point()
```
```{r}
#| title: Drive types
ggplot(mpg, aes(x = drv)) +
  geom_bar()
```

Ahora te toca a vos

Vamos a trabajar con un ranking de los libros más vendidos que levantamos de una conocida cadena de librerías en buenos aires que empieza con C y terminda con uspide y que podes descargar desde la misma carpeta del ejercicio aquí y vamos a crear una serie de visualizaciones simples usando plotly{}:

  1. Una tabla con un ranking de libros
  2. Un gráfico de barras con el raiting promedio por género
  3. Un Boxplot de precio por género

🛟(un ayudin en la diapo siguiente)🛟

Copiar y pegar las visualizaciones

Para agilizar el trabajo los gráficos ya se encuentran listos aquí:

dashboard-r.qmd

```{r}
# Tabla en DT con libros

datatable(
  libros,
  options = list(
    pageLength = 10,
    order = list(list(0, 'asc')), # ordenamos la tabla por ranking
    dom = 'ftp',                  # solo filtro arriba (f), tabla (t) y paginación (p)
    language = list(
      searchPlaceholder = "Buscar...",
      search = "" # saca el texto de 'Search:'
    )
  ),
  class = 'table table-striped table-hover table-sm', # usamos Bootstrap 
  filter = "none",   # sin filtros en columnas
  rownames = FALSE,
  colnames = c("Puesto","Título","Autoría","$AR","Stock","Puntaje","Género","Pág.","Ebook")
)

```

```{r}
# Grafico 1 barplot raiting promedio por género
plot_ly(
  data = libros,
  x    = ~genero,
  y    = ~rating,
  type = "bar",
  transforms = list(list(
    type = "aggregate",
    groups = ~genero,
    aggregations = list(
      list(target = "y", func = "avg", enabled = TRUE)
    )
  )),
  marker = list(color = colores),
  showlegend = FALSE
)
```

```{r}
# Gráfico 2 boxplot de precios por género
plot_ly(
  data = libros,
  x    = ~genero,
  y    = ~precio,
  color = ~genero,
  colors = colores,
  type  = "box",
  boxpoints = "outliers",
  showlegend = FALSE
) %>%
  layout(
    xaxis = list(title = ""),
    yaxis = list(title = "Precio $AR")
  )
```

¡Manos a la obra!

  • Crea un proyecto Quarto setendo el formato como dashboard
  • Indica un título en YAML
  • En un primer chunck de setup llamá a las librerías tidyverse, dt y plotly y carga los datos de libros.
  • A cada tarjeta asignales títulos usando la opción #| title:
  • Setea las dos últimas tarjetas como tabs usando {.tabset} en la definición del nivel de la fila.

y…🪄

Cuando termines deberias tener algo así

::: :::

Más objetos máaaaaaaaaas

Value boxes

  • Las value boxes son un tipo de tarjeta especial que sirve para llevar la ateción a alguna medida de resumen específica o valor de referencia.
  • Podes crear value boxes en alguna celda especifica o como divs en el markdown
  • Las value boxes usan íconos de Bootstrap y les podemos setaar color (por ej con códigos HEX) o si usaste un alias de color como parte de tu scss (no llegamos a ver este tema en esta presenta 😞)

Paso 1: definimos los valores

dashboard-r.qmd
---
title: "Valueboxes"
format: dashboard
---

```{r}
library(ggplot2)
library(dplyr)
```
## Value boxes {height="25%"}
```{r}
#| label: calculate-values
lowest_mileage_cty <- mpg |>
  filter(cty == min(cty)) |>
  distinct(cty) |>
  pull(cty)

highest_mileage_cty <- mpg |>
  filter(cty == max(cty)) |>
  distinct(cty) |>
  pull(cty)
  
rounded_mean_city_mileage <- mpg |>
  summarize(round(mean(cty), 2)) |>
  pull()
```

Paso 2: hacemos los value en cuestion

Usamos las opciones:

#| content: valuebox

#| icon: nombre-del-icono

#| color: nombre o hex del color

También es recomendable que seteemos la opción #| expandable: false (ya que no tiene sentido expandir estos elementos.) y que le pongamos un alto a esa fila de no más del 30%

dashboard-r.qmd
```{r}
#| content: valuebox
#| title: "Un título"
#| icon: fuel-pump-fill
#| color: danger
#| expandable: false

paste(lowest_mileage_cty, "mpg")
```

Agregar logos y themes

Como en otras publicaciones de Quarto podemos tunear los themes (usando scss) o los mismos que ya vienen cargados de Bootstrap así como agregar logos en el slider superior. Todas cosas que podemos hacer desde el YAML

dashboard-r.qmd
---
title: "Tablero de libros"
format: dashboard
theme: minty
logo: "images/logo.png"
editor: source
---

Ahora ustedes

  • Agregá tres value boxes indicando precio promedio, raiting promedio y porcentaje de libros que son ebook Usar los iconos “cash”,“star” y “phone” correspondientemente.
  • Cambia el theme del dashboard a uno de tu elección (por ej. minty) y agregá la imagen “images/logo.png” como logo desde YAML

Tip

Podes copiar el cálculo de los value boxes de aquí

dashboard-r.qmd
#| label: calculo de elementos para value-boxes

## precio promedio
precio_prom <- libros %>%
  filter(stock == "Disponible") %>%
  summarise(promedio = mean(precio, na.rm = TRUE)) %>%
  pull(promedio)

## puntaje promedio
rating_prom <- libros %>%
  filter(stock == "Disponible") %>%
  summarise(promedio = mean(rating, na.rm = TRUE)) %>%
  pull(promedio)

## porcentaje de libros en digital
pct_ebook <- libros %>%
  summarise(pct = mean(ebook == "Sí", na.rm = TRUE)*100) %>%
  pull(pct)

Cuando termines debería quedar algo como esto

BONUS: Crosstalk para un poquito de interactividad

¿Qué es crostalk?

  • Crosstalk facilita la vinculación de múltiples widgets HTML dentro de una página R Markdown, un tablero de Quarto o una aplicación Shiny.

  • La API principal de Crosstalk es un tipo de objeto llamado SharedData que encapsula el dataframe y lo pasa al widget que querramos usar.

  • Con Crosstalk vamos a poder laburar con widgets como plotly(), leaflet() o dt()

  • Además algunos autores han agregado otros paquetes compatibles como SummaryWidget() de Kent Johnson o kpiwidget() de Arnold Kakas (que vamos a ver en seguida).

Filtros en crosstalk

Crosstalk también admite el uso de filtros (parecidos a los que tenemos en shiny), pero con la ventaja de que estamos trabajando con un html estático.

library(crosstalk)
library(plotly)

# Creamos un nuveo objeto compartido
shared_mtcars <- SharedData$new(mtcars)

bscols( # lo ordeno en columnas
  widths = c(3, NA, NA),
  
  # Filtros interactivos en fomrato lista
  list(
    filter_checkbox("cyl", "Cilindros", shared_mtcars, ~cyl, inline = TRUE),
    filter_slider("hp", "Caballos", shared_mtcars, ~hp, width = "100%"),
    filter_select("auto", "Automatico", shared_mtcars, ~ifelse(am == 0, "Yes", "No"))
  ),
  
  # Primer gráfico plotly 
  plot_ly(shared_mtcars, x = ~wt, y = ~mpg, color = ~factor(cyl),
          type = "scatter", mode = "markers") %>%
    layout(xaxis = list(title = "Peso"),
           yaxis = list(title = "Millas por galón")),
  
  # Segundo gráfico plotly 
  plot_ly(shared_mtcars, x = ~hp, y = ~qsec, color = ~factor(cyl),
          type = "scatter", mode = "markers") %>%
    layout(xaxis = list(title = "Caballos"),
           yaxis = list(title = "1/4 milla"))
)

Filtros en crosstalk

El paquete kpiwidget

  • kpiwidget() (y su función homonima) nos permite crear indicadores clave de rendimiento (KPI) en los paneles de Quarto con crosstalk.

  • Podemos hacer una serie de datos resumen símples como sumas, promedios, minimos y máximos así ratios o el share de un determinado segmento.

Veamos un uso básico …

dashboard-r.qmd

# cargamos las librerías
library(crosstalk)
library(kpiwidget)

# Envolvemos nuestra base en SharedData:
sd <- SharedData$new(mtcars)

# Mostramos el promnedio de la variable mpg (millas por galón) para autos de 4 cilindros.
kpiwidget(sd, 
          kpi = "mean", 
          column = "mpg",
          selection = ~ cyl == 4
          )

Aplicando esto a nuestro dashboard de libros…

  • Paso 1: Vamos a cambiar un poco el layout pasando a dos columnas: una la vamos a usar como sidebar para los filtros y otra la vamos a mentener como cuerpo de nuestro

  • Paso 2: Creamos el objeto compartido shared_libros con ShareData$new de CrossTalk a partir de nuestra tabla de libros

  • Paso 3: En el sidebar de filtros creamos tres tarjetas con los filtros usando las funciones así:

dashboard-r.qmd
## Filters {.sidebar}

```{r}
#| label: filtro-generos
filter_select("filtro_genero", "Género", shared_libros, ~genero, multiple = TRUE)
```
<br>
```{r}
#| label: filtro-precio
filter_slider("filtro_precio", "Precio (ARS)", shared_libros, ~precio, width = "100%")
```
<br>
```{r}
#| label: filtro-ebook
filter_checkbox("filtro_ebook", "Disponible en Ebook", shared_libros, ~ebook, inline = TRUE)
```
  • Paso4:: En los gráficos vamos a reemplazar la tabla libros por shared_libros

y entonces…

Tablero con crosstalk

Antes de que te vayas..

Seguinos

@rladiesba
@RLadiesBA
RLadies Buenos Aires
@RLadiesBuenosAires
https://rladiesba.netlify.app/

¡No te pierdas las novedades!

¡En 2025 hicimos!

  • Club de lectura del libro Mastering Shiny de Hadley Wickham.
  • Meetup sobre Quarto y tableros con Quarto💜
  • Debugging! Muy pronto

¡Muchas gracias!