Analítica de Personas · Semestre otoño 2026 · Semana 16 · Prof. René Gempp
Durante quince semanas tu entregable fue un reporte: un documento .qmd que documenta un análisis de principio a fin, pensado para que alguien (tu profesor, tu yo del futuro) reconstruya cada paso. Esta semana cambias de vehículo. El directorio de InnovaCo no va a leer once reportes. Necesita un dashboard.
| Vehículo | Propósito | Densidad | Cuándo |
|---|---|---|---|
| Reporte | Documentar y reproducir | Alta | Las tareas; la trazabilidad importa |
| Dashboard | Monitorear de un vistazo | Media, jerarquizada | Indicadores que se revisan periódicamente |
| Presentación | Mover a una decisión | Baja, una idea por slide | Una reunión, una decisión |
La definición canónica de dashboard es la de Stephen Few (2013): una representación visual de la información más importante necesaria para alcanzar un objetivo, consolidada en una sola pantalla para monitorearse de un vistazo. Cada palabra es una restricción: la más importante (no todo), una sola pantalla (sin scroll infinito), de un vistazo (la prueba del vistazo: si necesitas estudiarlo, falló).
format nuevo, no una herramienta nuevaLa buena noticia: no aprendes una herramienta nueva. Un Quarto Dashboard es el mismo .qmd que ya dominas, con una línea distinta en el YAML:
---
title: "InnovaCo · Dashboard Ejecutivo"
format:
dashboard: # <- esta es la magia
orientation: rows
execute:
echo: false # el directorio no ve código
warning: false
---
Con format: dashboard, Quarto deja de producir un documento que se lee de arriba abajo y produce una cuadrícula que llena la pantalla. El contenido se reparte el alto disponible (comportamiento fill): no hay scroll infinito, hay un tablero.
flexdashboard? Si googleas dashboards en R vas a encontrar flexdashboard, su antecesor. Quarto Dashboards lo reemplaza: misma idea, mejor integración, soporte nativo de parámetros. Usa Quarto Dashboards.
El layout se controla con encabezados Markdown y atributos entre llaves:
# Título crea una página (aparece en la barra de navegación).## Título crea una fila (con orientation: rows, el defecto) o una columna (con orientation: columns).{height="40%"}, {width="50%"} controlan el tamaño; {.tabset} convierte las cards de una fila en pestañas.# Página principal
## Row {height="20%"} # fila de KPIs (20% del alto)
# ...aquí van 4 value boxes...
## Row {height="40%"} # fila de gráficos
### Column {width="50%"} # media fila
### Column {width="50%"} # la otra media
## Row {height="40%"} {.tabset} # cards como pestañas
#| title: "Rotación 12 meses". Ese texto aparece como encabezado de la card. Es distinto del labs(title=) de ggplot — en un dashboard, deja el título a la card y usa subtitle en el gráfico para el matiz.
Una value box es la card estrella del dashboard ejecutivo: un número grande, un ícono, y un color que comunica el estado. La forma más limpia de crearla es un chunk con #| content: valuebox que devuelve una lista:
```{r}
#| content: valuebox
#| title: "Rotación acumulada"
list(
value = percent(rotacion_global, 0.1),
icon = "box-arrow-right", # íconos de Bootstrap
color = col_rot # "success" | "danger" | "warning"
)
```
El color acepta nombres semánticos de Bootstrap: "success" (verde), "danger" (rojo), "warning" (ámbar), "primary" (azul). La gracia es calcular el color según la lógica de negocio, de modo que un KPI que está mal se vea mal sin que nadie lo lea:
col_rot <- if (rotacion_global > 0.20) "danger" else "success"
col_enps <- if (enps_actual > 0) "success" else "danger"
Para íconos con más control, bslib::value_box() + bsicons::bs_icon() ofrecen la versión completa, útil si quieres incrustar un sparkline de fondo o personalizar el tema.
No todo lo que se mide es clave. Una métrica es cualquier número medible. Un KPI (Key Performance Indicator) es una métrica que además está vinculada a un objetivo, es accionable, tiene dueño y tiene referente. Un dashboard estratégico bien hecho tiene entre 4 y 8 KPIs: más que eso, deja de ser "lo clave".
Eckerson (2010) distingue tres tipos de dashboard según el horizonte de decisión:
| Tipo | Audiencia | Pregunta |
|---|---|---|
| Estratégico | Directorio | ¿Vamos por buen camino? |
| Operacional | Jefaturas | ¿Qué pasa ahora que requiere acción? |
| Analítico | Analistas | ¿Por qué está pasando? |
El de Montt es estratégico: pocos KPIs, alto nivel de agregación, foco en la tendencia. Por eso privilegiamos value boxes y líneas de tendencia, y mandamos el detalle al drill-down (pestañas, tablas interactivas).
Un indicador rezagado (lagging) mide algo que ya ocurrió (rotación, brecha): certero pero tardío. Un indicador adelantado (leading) predice un resultado futuro (eNPS, satisfacción): menos certero pero permite actuar antes. La rotación es el espejo retrovisor; el eNPS es el parabrisas. El dashboard potente combina ambos (Kaplan & Norton, 1996; Becker, Huselid & Ulrich, 2001).
El eNPS (employee Net Promoter Score) adapta el NPS de Reichheld (2003). Se basa en una pregunta: "De 0 a 10, ¿qué tan probable es que recomiendes InnovaCo como lugar para trabajar?"
Va de −100 a +100. Los pasivos (7–8) no suman ni restan.
satisfaccion_laboral del dataset. No lo hagas. El titular cambia por completo según dónde cortes los buckets, así que el número resultante no significa nada. El eNPS requiere su propia pregunta 0–10. En InnovaCo, el eNPS vive en innovaco_kpis_mensuales.csv (la encuesta de pulso); la satisfacción 1–5 se reporta aparte como "índice de satisfacción". Confundirlas es el error de integridad de métrica más común en RRHH — y se evalúa en la tarea.
Conviene ser preciso, porque "interactivo" significa tres cosas distintas. Lo que produce quarto render (sin servidor) es un HTML estático; sobre esa base hay tres niveles de interactividad:
| Nivel | ¿Servidor? | Qué permite | Herramientas |
|---|---|---|---|
| (a) Widget | No | Hover, zoom, ordenar, buscar, descargar dentro de cada gráfico/tabla | plotly, DT, leaflet |
| (b) Crosstalk | No | Filtrado cruzado: seleccionar en una tabla filtra un gráfico | crosstalk, ojs |
| (c) Shiny | Sí (R vivo) | Reactividad total: un input vuelve a EJECUTAR código R | server: shiny |
El dashboard de esta clase usa el nivel (a): plotly y DT traen su propia interactividad en JavaScript y funcionan perfectamente en el HTML estático, sin servidor. Puedes hacer hover, zoom, ordenar, buscar y —como veremos— descargar.
params$depto) genera un archivo distinto por departamento al renderizar; el usuario no filtra en vivo, abre el archivo de su área. (2) Los widgets plotly/DT son interactivos pero no recalculan en R: si quieres que mover un control re-ajuste un modelo o recompute un agregado, necesitas Shiny (server: shiny). Para "filtrado cruzado" ligero sin servidor, crosstalk enlaza widgets entre sí del lado del cliente.
library(plotly)
# Nivel (a): widget interactivo a partir de un ggplot
g <- kpis_mes |> filter(departamento != "Global") |>
ggplot(aes(mes, enps, color = departamento)) + geom_line()
ggplotly(g, tooltip = c("x", "y", "colour"))
gtEl paquete gt ("grammar of tables") construye tablas de calidad de publicación. Su lógica es la del ggplot: empiezas con gt() y vas agregando capas de formato con el pipe.
library(gt)
tabla |>
gt() |>
cols_label(rotacion = "Rotación", ingreso = "Ingreso medio") |>
fmt_percent(rotacion, decimals = 1) |>
fmt_currency(ingreso, currency = "CLP", decimals = 0, sep_mark = ".") |>
data_color( # color condicional
columns = rotacion,
fn = scales::col_numeric(c("#0D9488", "#B85042"), domain = NULL)
) |>
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
)
Funciones clave: fmt_number(), fmt_percent(), fmt_currency() formatean; cols_label() renombra encabezados; data_color() pinta celdas según su valor (el departamento con peor rotación se ve rojo); tab_header() y tab_source_note() agregan título y nota al pie (Iannone et al., 2024).
gt. Para tablas que van a un informe, un slide o un PDF: el output es una imagen pulida, fija. Es la tabla que tú controlas al 100%.
DTEl paquete DT envuelve la librería JavaScript DataTables: produce tablas con búsqueda, ordenamiento, paginación y filtros por columna. Ideal para que el usuario explore un detalle grande.
library(DT)
activos |>
select(nombre, departamento, cargo, antiguedad_anios) |>
datatable(
filter = "top", # filtros por columna
options = list(pageLength = 10), # filas por página
rownames = FALSE
)
gt | DT | |
|---|---|---|
| Naturaleza | Estática (imagen) | Interactiva (JS) |
| Fortaleza | Formato fino, publicación | Buscar, ordenar, filtrar |
| Destinatario | Directorio, informe, PDF | Analista, exploración |
| Tamaño | Pocas filas, curadas | Muchas filas, navegables |
Montt pidió la versión de Concepción, la de cada gerente, "que se genere sola". Eso son los parámetros de Quarto. Se declaran en el YAML:
---
format: dashboard
params:
depto: "Global" # valor por defecto
---
Dentro del documento, params$depto es un objeto R. Filtras los datos por él una vez, al inicio, y todo el dashboard se recalcula para esa área:
es_global <- params$depto == "Global"
emp_f <- if (es_global) empleados
else filter(empleados, departamento == params$depto)
Para generar todas las versiones de una vez, renderizas en lote con quarto_render() dentro de un purrr::walk():
library(quarto)
areas <- c("Global", "Ventas", "Soporte Técnico")
purrr::walk(areas, \(d) {
quarto_render(
input = "clase16_dashboard.qmd",
execute_params = list(depto = d),
output_file = paste0("dashboard_", d, ".html")
)
})
Pregunta frecuente del directorio: "¿puedo bajarme esta tabla a Excel?". La respuesta es sí, sin servidor. El truco tiene dos piezas: (1) hacer el HTML autocontenido con embed-resources: true en el YAML, de modo que los datos viajen dentro del archivo; y (2) ofrecer un mecanismo de descarga del lado del cliente.
DT + extensión Buttons)La extensión Buttons de DT agrega una barra con Copiar / CSV / Excel / PDF sobre la tabla. La descarga ocurre en el navegador (usa JSZip), con los datos ya incrustados en el widget:
tabla |>
datatable(
extensions = "Buttons",
options = list(
dom = "Bfrtip", # B = barra de botones
buttons = list(
list(extend = "excel", text = "Descargar Excel"),
list(extend = "csv", text = "CSV"),
list(extend = "copy", text = "Copiar")
)
)
)
downloadthis)Cuando quieres ofrecer "Descargar la base completa (.xlsx)" como un botón independiente (no atado a una tabla visible), downloadthis incrusta el archivo como base64 dentro del HTML:
library(downloadthis)
activos |>
download_this(
output_name = "InnovaCo_activos",
output_extension = ".xlsx", # también ".csv"
button_label = "Descargar base (Excel)",
button_type = "success", has_icon = TRUE
)
openxlsx (Apunte 36, sección 5), no lo vuelvas a armar: ofrécelo con downloadthis::download_file(path = "Reporte.xlsx", ...), que incrusta el archivo tal cual, con sus hojas y formatos. download_this() es para un objeto de R (una hoja); download_file() es para un archivo en disco (varias hojas).
download_this() y download_file() producen un botón HTML: se ven en el .html renderizado (o en el Viewer de RStudio), no al correr la línea suelta en la consola. El demo que funciona está en clase16_mini_reporte.qmd.
embed-resources: true + botones de descarga, entregas un solo archivo HTML por correo o por Canvas. El directorio lo abre sin instalar nada, mira los KPIs, explora la tabla y se baja la planilla que necesita — todo desde el mismo archivo, sin servidor, sin pedirte nada.
quarto render dashboard.qmd o quarto::quarto_render("dashboard.qmd"): se escribe el archivo dashboard.html en disco. El localhost aparece solo con quarto preview, que es la vista previa en vivo. Para compartir, usa el .html generado por render (con embed-resources: true es un único archivo).
bslib ni bsicons. Los value boxes de este dashboard se declaran con #| content: valuebox devolviendo una list(value=, icon=, color=). Quarto resuelve el ícono por su nombre de Bootstrap; no hay que cargar bslib ni bsicons. Si ves el error "no hay paquete llamado 'bsicons'", es porque un library(bsicons) quedó en el setup: bórralo.
format: dashboard en el YAML y echo: false (el directorio no ve código).gt para presentación o DT para explorar).params$depto recalcula todo.embed-resources: true y, si aplica, botón de descarga a Excel.
Becker, B. E., Huselid, M. A., & Ulrich, D. (2001). The HR scorecard: Linking people, strategy, and performance. Harvard Business School Press.
Eckerson, W. W. (2010). Performance dashboards: Measuring, monitoring, and managing your business (2.ª ed.). Wiley.
Few, S. (2013). Information dashboard design: Displaying data for at-a-glance monitoring (2.ª ed.). Analytics Press.
Iannone, R., Cheng, J., Schloerke, B., Hughes, E., Lauer, A., & Seo, J. (2024). gt: Easily create presentation-ready display tables [Paquete de R].
Kaplan, R. S., & Norton, D. P. (1996). The balanced scorecard: Translating strategy into action. Harvard Business School Press.
Reichheld, F. F. (2003). The one number you need to grow. Harvard Business Review, 81(12), 46–54.
Sievert, C. (2020). Interactive web-based data visualization with R, plotly, and shiny. Chapman & Hall/CRC.
Wickham, H. (2021). Mastering Shiny: Build interactive apps, reports, and dashboards powered by R. O'Reilly.