Scalonetapp, la shiny del mundial

Celebrando un año de la tercera estrella

codigo
tutorial
shiny
Author

Pedro Damian Orden

Published

December 18, 2023

Introducción

Hace un año, Argentina alcanzaba una hazaña futbolística, llevándose a casa el título mundial. Para conmemorar este hito, se me ocurrió que no había mejor manera que celebrar que a través de la creación de una aplicación Shiny de código abierto. Esta herramienta no solo celebra nuestro amor por el fútbol, sino que también representa una unión entre el deporte y la tecnología.

¿Qué es una Aplicación Shiny?

Una aplicación Shiny es una herramienta interactiva desarrollada en R, una plataforma de software para estadística y gráficos. Estas aplicaciones permiten a los usuarios manipular datos y visualizaciones de forma dinámica, ofreciendo una forma poderosa y accesible de monitorear y explorar datos. La interactividad es clave: los usuarios pueden cambiar los parámetros, los filtros y otras características para personalizar su vista de los datos. Esto las convierte en herramientas esenciales para el análisis y la presentación de datos.

La Importancia de Herramientas Interactivas de Monitoreo de Datos

En un mundo donde el big data y el análisis de datos se han vuelto cruciales, herramientas como Shiny son indispensables. Proporcionan una forma visual e intuitiva de entender grandes conjuntos de datos, lo que es particularmente útil en campos como el deporte, donde la performance puede analizarse en múltiples dimensiones. Además, al ser de código abierto, Shiny permite una colaboración y mejora continua, democratizando el acceso a poderosas herramientas de análisis de datos.

Presentando el Código de la Aplicación

Para mostrar la performance de los equipos en el Mundial, utilizamos el framework de bslib junto con tablas HTML interactivas. Bslib es un paquete en R que permite a los desarrolladores de Shiny utilizar fácilmente Bootstrap, un framework de diseño web, para personalizar el aspecto de sus aplicaciones. Esto hace que la aplicación no solo sea funcional sino también visualmente atractiva y amigable para el usuario. Las tablas HTML interactivas, por otro lado, permiten a los usuarios interactuar con los datos de formas que van más allá de las capacidades de una tabla estática, como ordenar, filtrar y explorar los datos en detalle.

En los siguientes segmentos del post, desglosaremos cada parte del código, explicando cómo cada módulo contribuye a la funcionalidad general de la aplicación y cómo puedes utilizar estos componentes para tus propios proyectos de análisis de datos.

Instalación de Librerías en Nuestra Aplicación Shiny

Antes de sumergirnos en el código, es fundamental instalar y comprender el propósito de cada una de las librerías que utilizamos. Aquí te explico brevemente el rol de cada una en nuestra aplicación Shiny:

  1. library(shiny): Shiny es el núcleo de nuestra aplicación. Esta librería nos permite construir aplicaciones web interactivas directamente desde R. Utilizamos Shiny para manejar la interfaz de usuario, el servidor y la comunicación entre ambos.

  2. library(bslib): Bslib es una librería que se integra con Shiny para proporcionar más opciones de personalización visual a través de Bootstrap. Bootstrap es un popular framework de diseño web, y bslib nos permite utilizar sus funcionalidades para mejorar el aspecto de nuestra aplicación Shiny, haciéndola más atractiva y moderna.

  3. library(shinyWidgets): Esta librería amplía las capacidades de Shiny en términos de widgets. Los widgets son elementos de la interfaz de usuario, como botones, barras deslizantes y cuadros de selección. ShinyWidgets añade más opciones y estilos para estos elementos, permitiéndonos crear una interfaz de usuario más rica y personalizada.

  4. library(reactable): Reactable nos permite crear tablas interactivas en Shiny. Estas tablas pueden ser ordenadas, filtradas y paginadas, lo que las hace ideales para mostrar grandes conjuntos de datos de manera eficiente y fácil de explorar para el usuario.

  5. library(reactablefmtr): Esta librería es un complemento de Reactable. Reactablefmtr ofrece funciones adicionales para formatear y estilizar las celdas de las tablas creadas con Reactable, permitiendo una mayor personalización y mejorando la presentación de los datos.

  6. library(dplyr): Dplyr es una parte crucial del conjunto de librerías del tidyverse, ampliamente usado para la manipulación de datos en R. Nos permite realizar operaciones de limpieza y transformación de datos de manera eficiente, como filtrar filas, seleccionar columnas y realizar agrupaciones.

Cada una de estas librerías juega un papel clave en la creación de una aplicación Shiny efectiva y atractiva. Nos permiten no solo presentar los datos de manera interactiva y visualmente agradable sino también manipular y preparar estos datos de manera eficiente.

library(shiny)
library(bslib)
library(shinyWidgets)
library(reactable)
library(reactablefmtr)
library(dplyr)

Carga de Datos y Preprocesamiento

La carga de datos es un paso crucial en la creación de cualquier aplicación de análisis. En nuestro caso, utilizamos datos extraídos de FBref, uno de los principales recursos para estadísticas de fútbol. Estos datos representan métricas agregadas por equipo del Mundial de Fútbol. A continuación, veamos cómo manejamos estos datos en R.

Carga de datos

team_data <- read.csv("https://raw.githubusercontent.com/pedroorden/scalonetapp/main/datawc.csv", check.names = FALSE)

Aquí cargamos nuestro conjunto de datos datawc.csv, que contiene las métricas del Mundial por equipo. Utilizamos check.names = FALSE para evitar que R altere los nombres de las columnas, manteniendo la consistencia con los nombres originales del archivo.

Preprocesamiento y Organización de Métricas:

Creamos una lista metricas_por_dimension, que agrupa las métricas en diferentes dimensiones como Equipo, Juego, Ataque, Disciplina, Defensa y Arquero. Cada una de estas categorías contiene un conjunto específico de métricas relevantes, lo que nos permite organizar los datos de manera más intuitiva y facilita su manipulación y visualización posterior.

metricas_por_dimension <- list(
  Equipo = c("posesión", "jugadores usados", "promedio de edad", "partidos", "minutos jugados"),
  Juego = c("pases", "pases completados", "% pases completados", "pases cortos", "passes_pct_short", "pases medios completados", "pases medios", "% pases medios completados", "pases largos completados", "pases largos", "% de pases largos completados", "pases al tercio final", "pases al area chica", "centros al area chica", "centros", "laterales", "cornens", "corner adentro", "corner afuera", "pases fuera de juego"),
  Ataque = c("goles", "asistencias", "goles sin penales", "penales convertidos", "penales pateados", "goles esperados", "asistencias esperadas", "tiros", "tiros al arco", "% de tiros al arco", "gol x tiro", "gol por tiro directo", "distancia media de tiro", "tiros libres al arco", "acciones de gol"),
  Disciplina = c("tarjetas amarillas", "tarjetas rojas", "faltas cometidas", "faltas recibidas", "offsides"),
  Defensa = c("entradas ganadas", "entradas", "bloqueos", "tiros bloqueados", "pases bloqueados", "intercepciones", "despejes", "perdidas de balón", "recuperaciones de pelota"),
  Arquero = c("salvadas del arquero", "goles recibidos", "tiros recibidos", "porcentaje de salvadas", "partidos sin recibir goles", "penales atajados")
)

URL de Imagen:

image_url <- "https://i.pinimg.com/originals/94/3e/64/943e645efaa71b690108be75bff08ac6.png"

Aquí definimos una URL para una imagen que se utilizará en la interfaz de usuario de nuestra aplicación Shiny. Esta imagen puede ser un logotipo, un gráfico representativo o cualquier otro recurso visual que mejore la estética de nuestra aplicación.

Este preprocesamiento de datos es esencial antes de pasar a la construcción de la interfaz de usuario (UI) de la aplicación. Al tener los datos cargados y organizados correctamente, podemos asegurarnos de que la UI sea interactiva, informativa y fácil de usar. La clave aquí es tener una buena comprensión de los datos con los que estamos trabajando y cómo queremos presentarlos a los usuarios finales.

En la próxima sección, nos enfocaremos en cómo estos datos se integran y visualizan en la interfaz de usuario de nuestra aplicación Shiny.

Creando de la interfaz de Usuario (UI)

En el corazón de “La Scalonetapp”, nuestra aplicación Shiny, se encuentra una interfaz de usuario diseñada para ser intuitiva y atractiva. Aquí detallamos su construcción:

# Interfaz de usuario utilizando page_sidebar de bslib
ui <- page_sidebar(
  theme = bs_theme(bootswatch = "spacelab"),
  title = "Scalonetapp",
  fillable = TRUE,
  fillable_mobile = TRUE,
  sidebar = sidebar(
    bg = "white",
    width = 270,
    tags$style(HTML("
      .sidebar { font-size: 14px; }
      .sidebar .selectize-input.items.not-full { font-size: 13px; }
      .sidebar .selectize-dropdown-content { font-size: 13px; }
      .sidebar #select_all { font-size: 13px; }")),
    div(
      img(src = image_url, style = "width: 100%; display: block; margin-left: auto; margin-right: auto;"),
      style = "text-align: center;"
    ),
    selectizeInput("teams", "Seleccione los equipos:", 
                   choices = team_data$team, 
                   multiple = TRUE, 
                   selected = c("Argentina", "Uruguay", "Francia", 
                                "Japón", "Marruecos", "España", 
                                "Portugal", "Estados Unidos",  
                                "Mexico", "Senegal")),
    actionButton("select_all", "Seleccionar Todos los Equipos"),
    p("Módulo para sumar o quitar variables al tablero:"),
    bslib::accordion(
      id = "metricAccordion",
      open = FALSE,
      .multiple = FALSE,
      # Acordeón ordenado según tus especificaciones
      accordion_panel(
        title = HTML("<strong style='color: #7F1431; font-size: 13px;'>Ver métricas</strong>"),
                      selectInput("metric_Equipo", "Equipo", choices = metricas_por_dimension[["Equipo"]], multiple = TRUE, selected = "posesión"),
                      selectInput("metric_Juego", "Juego", choices = metricas_por_dimension[["Juego"]], multiple = TRUE, selected = "pases"),
                      selectInput("metric_Ataque", "Ataque", choices = metricas_por_dimension[["Ataque"]], multiple = TRUE, selected = "goles"),
                      selectInput("metric_Disciplina", "Disciplina", choices = metricas_por_dimension[["Disciplina"]], multiple = TRUE, selected = "tarjetas amarillas"),
                      selectInput("metric_Defensa", "Defensa", choices = metricas_por_dimension[["Defensa"]], multiple = TRUE, selected = "entradas ganadas"),
                      selectInput("metric_Arquero", "Arquero", choices = metricas_por_dimension[["Arquero"]], multiple = TRUE, selected = "goles recibidos")
      )
    )
  ),
 
  card(
    full_screen = TRUE,
    card_header(
      "La Shiny del Mundial"
    ),
    card_body(
      fill = FALSE, gap = 0,
      p(class = "text-muted", style = "font-size: 14px;", 
        "Este tablero presenta datos agregados por país del Mundial de Fútbol Qatar 2022. 
        Aquí se destacan estadísticas y métricas clave que resumen el rendimiento de los equipos en el torneo de manera comparativa. 
        Este análisis conmemora el primer aniversario de la obtención del título mundial y la tercera estrella de la selección Argentina.")
    ),
    reactableOutput("teamDataTable", width = "100%"),
    tags$p(style = "font-size: 12px; margin-top: 20px; margin-bottom: 20px;", 
           HTML("Fuente: elaboración propia en base a datos extraídos de "), 
           tags$a(href = "https://www.fbref.com", "www.fbref.com"), 
           HTML(". Consulta el documento eletrónico de Tecnología y Sociedad"), 
           tags$a(href = "https://tecysoc.netlify.app/posts/la_shiny_del_mundial/", 
                  "Scalonetapp: la shiny del mundial. Celebrando un año de la tercera estrella"), 
           HTML(" para acceder al código de la app y conocer los detalles del desarrollo del tablero."))
  )
)

Configuración de Página y Sidebar: La página utiliza page_sidebar de bslib, configurada con un tema spacelab para una estética moderna. La sidebar acoge una imagen conmemorativa y controles interactivos. Los usuarios pueden seleccionar equipos a través de selectizeInput y optar por seleccionar todos los equipos con un actionButton.

Panel Acordeón para Métricas: Incorporamos un acordeón para presentar opciones de métricas de manera organizada. Los usuarios pueden explorar y seleccionar diferentes métricas para cada dimensión del juego, como “Equipo”, “Juego”, “Ataque”, entre otras.

Tarjeta de Presentación de Datos: El cuerpo principal de la UI es una tarjeta que aloja la tabla de datos. Antes de mostrar la tabla, hay un párrafo introductorio que contextualiza la aplicación, resaltando su propósito de conmemorar el aniversario del título mundial y destacando el análisis de datos agregados del Mundial Qatar 2022.

Fuente de Datos y Enlace a Documentación Adicional: En la parte inferior de la tarjeta, proporcionamos la fuente de los datos (fbref.com) y un enlace a documentación adicional, que ofrece más contexto sobre el análisis de datos en el fútbol.

Desarrollo e inntegración del servidor (server)

En una aplicación Shiny, el servidor es el corazón que impulsa la funcionalidad interactiva. En nuestra aplicación “La Scalonetapp”, el servidor realiza varias tareas cruciales que permiten al usuario explorar y analizar datos de manera dinámica y visualmente atractiva. Veamos cómo funciona nuestro servidor:

server <- function(input, output, session) {
  observeEvent(input$select_all, {
    updateSelectizeInput(session, "teams", selected = team_data$team)
  })
  
  selected_metrics <- reactive({
    unlist(lapply(names(metricas_por_dimension), function(dim) {
      input[[paste("metric", dim, sep = "_")]]
    }))
  })
  
  filtered_data <- reactive({
    if (length(selected_metrics()) == 0) return(NULL)
    selected_cols <- c("team", "img_url", selected_metrics())
    team_data[team_data$team %in% input$teams, selected_cols, drop = FALSE]
  })
  
  output$teamDataTable <- renderReactable({
    if (is.null(filtered_data())) return(NULL)
    
    # Identifica columnas numéricas
    numeric_cols <- sapply(filtered_data(), is.numeric)
    
    # Crea una lista de definiciones de columna con estilo personalizado
    columns_list <- list(
      team = colDef(name = "Equipo", style = list(fontSize = "18px"), 
                    headerStyle = list(fontSize = "15px")),
      img_url = colDef(name = " ", cell = function(value) { 
        tags$img(src = value, height = 18, width = 25) 
      })
    )
    
    # Añade columnas adicionales para las métricas seleccionadas
    for (metric in selected_metrics()) {
      if (numeric_cols[metric]) {
        # Aplicar data_bars a las columnas numéricas
        columns_list[[metric]] <- colDef(
          name = metric,
          headerStyle = list(fontSize = "15px"),  # Aumenta el tamaño del título de la columna
          cell = data_bars(
            data = filtered_data(),
            text_position = "inside-end",
            fill_color = c("yellow","lightblue"),
            background = "#EEEEEE",
            brighten_text_color = "white",  
            fill_gradient = TRUE,
            round_edges = TRUE, 
            tooltip = TRUE,
            text_size = 14,
            bold_text = TRUE,
            number_fmt = scales::comma,
            animation = "width 1s ease"
          )
        )
      } else {
        columns_list[[metric]] <- colDef(name = metric, headerStyle = list(fontSize = "10px"))
      }
    }
    
    # Crea finalmente la tabla reactable
    reactable(filtered_data(), columns = columns_list, 
              theme = espn(), highlight = TRUE, 
              defaultPageSize = 15)
  })
}

Reacción a la interacción del usuario

observeEvent(input$select_all, {...}): Esta línea es responsable de escuchar un evento específico: en este caso, cuando el usuario hace clic en el botón “Seleccionar Todos los Equipos”. Al ocurrir esto, el servidor actualiza automáticamente el input de selección de equipos para incluir todos los equipos disponibles.

La gestión de entradas del usuario:

selected_metrics <- reactive({...}): Aquí, estamos creando un objeto reactivo llamado selected_metrics. Este objeto se actualiza cada vez que el usuario cambia su selección de métricas en la interfaz. Utiliza lapply y input[[...]] para recopilar las métricas seleccionadas por el usuario.

Filtrado de los datos:

filtered_data <- reactive({...}): Este objeto reactivo crea un subconjunto de datos basado en las selecciones del usuario. Si el usuario no ha seleccionado ninguna métrica, devuelve NULL. De lo contrario, selecciona las columnas relevantes de team_data basándose en las métricas elegidas.

Renderizado de la tabla final:

output$teamDataTable <- renderReactable({...}): Esta función renderiza la tabla interactiva en la interfaz de usuario. Se actualiza dinámicamente según los datos filtrados (filtered_data). Dentro de esta función, se realizan varias operaciones:

  • Identificación de columnas numéricas para aplicar estilos específicos.

  • Creación de una lista de definiciones de columna, personalizando el estilo para mejorar la experiencia visual.

  • Aplicación de data_bars a las columnas numéricas para presentar visualmente las métricas en forma de barras.

  • Configuración de estilos adicionales como el tamaño del texto, colores de fondo, gradientes, bordes redondeados, y más.

Ejecución de la Aplicación:

shinyApp(ui = ui, server = server)

shinyApp(ui = ui, server = server): última fracción de código, pero no menos importante, esta línea de código ejecuta la aplicación, uniendo la interfaz de usuario (ui) definida previamente con la lógica del servidor.

Conclusión

Crear nuestras propias herramientas, como lo demuestra “La Scalonetapp”, es más que una muestra de habilidad técnica. Es una expresión de pasión, curiosidad y deseo de compartir conocimiento. En el corazón de esta aplicación, yace la fusión del amor por el fútbol y el poder del análisis de datos.

Shiny, en este contexto, se revela como una herramienta revolucionaria. No se limita a ser un simple marco de trabajo para crear aplicaciones; es un medio para democratizar el acceso a la información compleja. Permite transformar datos crudos en historias interactivas y visuales, haciéndolos accesibles y comprensibles para un público más amplio, sin importar su nivel de conocimiento técnico.

Esta aplicación es una forma de recordar y celebrar el éxito del equipo argentino en el fútbol, pero va más allá de ser un simple tributo. Al ser de código abierto, invita a otros a aprender, explorar y contribuir, fomentando un sentido de comunidad y colaboración en el mundo del análisis de datos.

Querés conocer la app? Podés hacerlo acá.

Hasta otra oportunidad.

Reuse

Citation

BibTeX citation:
@online{damian orden2023,
  author = {Damian Orden, Pedro},
  title = {Scalonetapp, La Shiny Del Mundial},
  date = {2023-12-18},
  url = {https://tecysoc.netlify.app/posts/la_shiny_del_mundial},
  langid = {en}
}
For attribution, please cite this work as:
Damian Orden, Pedro. 2023. “Scalonetapp, La Shiny Del Mundial.” December 18, 2023. https://tecysoc.netlify.app/posts/la_shiny_del_mundial.