A Beginners Guide to Building a Comprehensive Shiny Dashboard for GPS Data Visualization

In this guide, we'll walk through the process of creating a Shiny application to visualize sample GPS data. This app will include interactive charts and a styled data table. By following these detailed steps, you'll learn how to set up and deploy a Shiny app on Shinyapps.io.

A Beginners Guide to Building a Comprehensive Shiny Dashboard for GPS Data Visualization

Building a Comprehensive Shiny Dashboard for GPS Data Visualization

In this guide, we'll walk through the process of creating a Shiny application to visualize sample GPS data. This app will include interactive charts and a styled data table. By following these detailed steps, you'll learn how to set up and deploy a Shiny app on Shinyapps.io.

The app can be found Here. All the necessary files can be found at the end of this article.

Step 1: Setting Up Your Development Environment

1.1 Install R and RStudio

To begin, ensure you have R and RStudio installed:

These tools are essential for running and developing Shiny applications.

1.2 Install Required R Packages

Shiny and other related packages can be installed from CRAN. Open RStudio and install the necessary packages using the following command:

install.packages(c("shiny", "shinydashboard", "readr", "tidyverse", "ggplot2", "plotly", "DT"))

Explanation:

  • shiny: Provides the core functionality for building interactive web apps.
  • shinydashboard: Offers tools for creating dashboards with Shiny.
  • readr: Used for reading data from CSV files.
  • tidyverse: A collection of packages for data manipulation and visualization.
  • ggplot2: For creating static graphics.
  • plotly: Converts ggplot2 graphics to interactive plots.
  • DT: For rendering interactive data tables.

Step 2: Preparing Your Data

Ensure your data is properly formatted and accessible. Place your gps_data_pivot.csv file in your working directory or adjust the file path in your script accordingly.

Example Data Structure:
The CSV file should include columns such as:

  • pid (Player ID)
  • session_type (Type of session)
  • variable (Variable of interest)
  • value (Measured value)
  • player_position (Player position on the field)
  • player_max_speed (Maximum speed of the player)
  • player_sprint_threshold (Speed threshold for sprints)

Step 3: Writing the Shiny Application Code

3.1 Creating the Shiny App Script

In RStudio, create a new R script and name it app.R. This script will contain the entire Shiny application code. Here's a breakdown of the code sections:

3.1.1 Loading Libraries and Data

The first section of your script loads the necessary libraries and the dataset:

library(shiny)
library(shinydashboard)
library(readr)
library(tidyverse)
library(ggplot2)
library(plotly)
library(DT)

# Load your dataset
gps_data <- read_csv("gps_data_pivot.csv") # Load the GPS data from the working directory (folder with the app.R file)

Explanation:

  • library(shiny): Loads the Shiny package.
  • library(shinydashboard): Loads tools for creating dashboards.
  • library(readr): For reading CSV files.
  • library(tidyverse): Provides functions for data manipulation.
  • library(ggplot2): For plotting data.
  • library(plotly): Converts ggplot2 plots to interactive plots.
  • library(DT): For rendering interactive data tables.
  • read_csv("gps_data_pivot.csv"): Reads the CSV file into a data frame called gps_data.

3.1.2 Plot Function Definition

Define a function to create plots based on user input:

plot_gps_data <- function(data, session, metric, title, subtitle, caption) { # Add the modifiable function inputs
  
  p1 <- ggplot(data %>% filter(session_type %in% session, variable %in% metric), # Filter the data based on the user input
         aes(x = pid, y = value, fill = player_position)) +
    geom_col() +
    #geom_label(aes(label = value), position = position_stack(vjust = 1), color = "white", fill = "purple", size = 3) +
    scale_x_continuous(
      # lim=c(0, 28.5),
      breaks = seq(from = 1, to = 28, by = 1) 
    )  +    
    coord_flip() +
    theme_minimal() +
    theme( # Customize the plot theme
      legend.position = "bottom",
      legend.background = element_rect(fill = "purple"),
      legend.text = element_text(colour = "white"),
      legend.title = element_text(colour = "white"),
      plot.title = element_text(colour = "white", hjust = 0, face = "bold.italic", size = 18),
      plot.subtitle = element_text(colour = "white", hjust = 0, face = "italic", size = 10),
      plot.caption = element_text(colour = "white", hjust = 0, face = "italic", size = 8),
      strip.background = element_rect(fill = "purple", colour = "purple"),
      strip.text = element_text(colour = "white"),
      plot.background = element_rect(fill = "purple", colour = "purple"),
      panel.background = element_rect(fill = "purple", colour = "purple"),
      panel.grid.major = element_blank(),
      panel.grid.minor = element_blank(),
      axis.line = element_blank(),
      axis.text.x = element_text(angle = 45,colour = "white"),
      axis.text.y = element_text(colour = "white", size = 10),
      axis.ticks = element_line(colour = "white"),
      axis.title.x = element_blank(),
      axis.title.y = element_blank()
    ) +
    facet_wrap(vars(variable), scales = "free_x", ncol = 2) + # Facet the plot based on the selected variable
    labs( # Add plot labels
     
      x = "Player ID",
      y = "Value",
      fill = "Position",
      title = title, 
      subtitle = subtitle, 
      caption = caption)
  
  ggplotly(p1) # Convert the ggplot to plotly for interactive features
}

Explanation:

  • plot_gps_data: A function to create and style a ggplot chart based on inputs.
  • ggplot(): Initializes the plot with data and aesthetics.
  • geom_col(): Creates a bar plot.
  • scale_x_continuous(): Configures x-axis breaks.
  • coord_flip(): Flips coordinates for horizontal bars.
  • theme_minimal(): Applies a minimal theme.
  • theme(): Customizes plot appearance (e.g., colours, text).
  • facet_wrap(): Facets the plot by variable.
  • labs(): Adds labels and titles.
  • ggplotly(): Converts the static ggplot into an interactive plotly chart.

3.1.3 UI Layout

Define the user interface (UI) of the app using shinydashboard components:

# UI layout with collapsible and resizeable sidebar
ui <- dashboardPage(
  dashboardHeader(title = "GPS Data Dashboard"), # Add a title to the dashboard
  dashboardSidebar(
    width = 300,  # Sidebar initial width, can be adjusted
    sidebarMenu( # Add a sidebar menu
      menuItem("Chart 1", tabName = "chart1", icon = icon("chart-bar")), # Add a menu item for the charts tab
      menuItem("Chart 2", tabName = "chart2", icon = icon("chart-bar")),
      menuItem("Data Table", tabName = "styled_table", icon = icon("table")) # Add a menu item for the data table tab
    ),
    
    # Add input selectors directly in the sidebar
    selectInput("session_type1", "Select Session Type for Chart 1:", # Add a session type selector for the first chart
                choices = unique(gps_data$session_type), # Get unique session types from the data
                selected = unique(gps_data$session_type)[1],
                multiple = TRUE), # Allow multiple selections
    selectInput("variable1", "Select Variable for Chart 1:", # Add a variable selector for the first chart
                choices = unique(gps_data$variable), # Get unique variables from the data
                selected = unique(gps_data$variable)[1],
                multiple = TRUE),
    
    selectInput("session_type2", "Select Session Type for Chart 2:",
                choices = unique(gps_data$session_type),
                selected = unique(gps_data$session_type)[1],
                multiple = TRUE),
    selectInput("variable2", "Select Variable for Chart 2:",
                choices = unique(gps_data$variable),
                selected = unique(gps_data$variable)[1],
                multiple = TRUE),
    
    selectInput("session_type5", "Select Session Type for Table:", # Add a session type selector for the data table
                choices = unique(gps_data$session_type), # Get unique session types from the data
                selected = unique(gps_data$session_type)[1],
                multiple = TRUE),
    selectInput("variable5", "Select Variable for Table:", # Add a variable selector for the data table
                choices = unique(gps_data$variable), # Get unique variables from the data
                selected = unique(gps_data$variable)[1],
                multiple = TRUE),
    selectInput("rows_per_page", "Number of Rows to Show in Table:", # Add a selector for the number of rows per page
                choices = c(5, 10, 15, 20, 25), # Define the available options
                selected = 15)
  ),
  dashboardBody( # Add the dashboard body
    tabItems( # Add tab items for the charts and data table
      # Tab 1
      tabItem(tabName = "chart1", # Define the chart 1 tab
              fluidRow(
                box(width = 12, collapsible = TRUE, collapsed = FALSE, plotlyOutput("chart1", height = "1000px")),
              )),
      # Tab 2
      tabItem(tabName = "chart2", # Define the chart 2 tab
              fluidRow(
                box(width = 12, collapsible = TRUE, collapsed = FALSE, plotlyOutput("chart2", height = "1000px")),
              )),
      # Tab 3
      tabItem(tabName = "styled_table", # Define the data table tab
              fluidRow(
                box(width = 12, collapsible = TRUE, collapsed = FALSE,
                    dataTableOutput("styled_table"))
              ))
    )
  )
)

Explanation:

  • dashboardPage(): Defines the layout of the dashboard.
  • dashboardHeader(): Sets the header of the dashboard.
  • dashboardSidebar(): Creates the sidebar with menu items and input controls.
  • selectInput(): Provides drop-down menus for user input.
  • dashboardBody(): Contains the main content

of the dashboard, divided into tabs (tabItems).

  • fluidRow() and box(): Arrange outputs within the layout.

3.1.4 Server Logic

Define the server function that processes user inputs and generates outputs:

server <- function(input, output) { # Add the server function with input and output arguments
  
  gps_data <- read_csv("gps_data_pivot.csv") # Load the GPS data from the working directory (folder with the app.R file)
  
  
  # Generate plots based on the user input
  output$chart1 <- renderPlotly({ # Render the first chart with plotly
    plot_gps_data(gps_data, session = input$session_type1, metric = input$variable1, # Call the plot function with the user inputs
                  title = "Volume Physical Performance Metrics", # Define the chart title
                  subtitle = "Physical outputs of each player for the selected day & variable", # Define the chart subtitle
                  caption = "Use this chart to view the total outputs") # Define the chart caption
  })
  
  output$chart2 <- renderPlotly({ # Render the second chart with plotly
    plot_gps_data(gps_data, session = input$session_type2, metric = input$variable2, # Call the plot function with the user inputs
                  title = "Intensity Physical Performance Metrics", 
                  subtitle = "Physical outputs of each player for the selected day & variable", 
                  caption = "Use this chart to view the per minute outputs")  })
  
  # Generate the styled data table with sorting, filtering, and row selection enabled
  output$styled_table <- renderDataTable({
    gps_data %>%
      select(-total_time) %>%  # Remove total_time column
      # Relocate 'player_max_speed' and 'player_sprint_threshold' after the 'value' column
      relocate(player_max_speed, player_sprint_threshold, .before = player_position) %>%
      filter(session_type %in% input$session_type5, variable %in% input$variable5) %>%
      # Rename columns
      rename("Player ID" = pid, "Session Type" = session_type, "Variable" = variable, "Value" = value,
             "Player Position" = player_position, "Max Speed (m/s)" = player_max_speed, "Sprint Threshold (m/s)" = player_sprint_threshold) %>%
      datatable( # Render the data table
        options = list( # Define the data table options
          pageLength = as.numeric(input$rows_per_page),  # Number of rows per page
          autoWidth = TRUE,
          searching = TRUE,
          ordering = TRUE,
          dom = 'ftip', # Add the search bar, table, information, and pagination
          columnDefs = list(list(className = 'dt-center', targets = "_all"))  # Centre  align columns
        ),
        rownames = FALSE, # Remove row names
        class = 'display',  # Apply display class to match the theme
        style = "bootstrap4") # Apply the Bootstrap 4 style to the table
   
  })
}

# Run the application locally
shinyApp(ui = ui, server = server)

Explanation:

  • renderPlotly(): Generates plotly plots based on user input.
  • renderDataTable(): Creates an interactive data table.
  • filter(): Filters the data based on user inputs.
  • select(), relocate(), rename(): Modify the data frame for presentation.
  • datatable(): Configures and renders the data table with interactive features.
  • shinyApp(): Combines the UI and server logic to run the Shiny app.

Step 4: Deploying the Application to Shinyapps.io

4.1 Create a Shinyapps.io Account

  1. Go to shinyapps.io and create a free account.
  2. Once signed up, you will need to configure deployment.

4.2 Install and Configure rsconnect

Configure Your Account:In RStudio, load the rsconnect package and set your account information:

library(rsconnect)
rsconnect::setAccountInfo(name='YOUR_ACCOUNT_NAME', token='YOUR_TOKEN', secret='YOUR_SECRET')

Replace 'YOUR_ACCOUNT_NAME', 'YOUR_TOKEN', and 'YOUR_SECRET' with your Shinyapps.io credentials found on the dashboard.

Install rsconnect:

install.packages("rsconnect")

4.3 Deploy Your App

  1. After deployment, Shinyapps.io provides a URL where your app can be accessed.

Use the following command to deploy your application:

rsconnect::deployApp('path/to/your/app')

Ensure 'path/to/your/app' points to the directory containing your app.R file.

Step 5: Enhancing the Application

5.1 Implement Error Handling

Add error handling to ensure the app can manage unexpected issues, such as missing data or incorrect inputs.

5.2 Optimize Performance

For large datasets, consider using reactive expressions and data caching to improve app performance. Reactive expressions help manage and optimize data processing in Shiny.

5.3 Improve User Experience

  1. Interactivity: Add more interactive elements, such as sliders or check-boxes.
  2. Guidance: Provide tool-tips or instructional text to help users understand the functionality.

5.4 Data Refresh

If your data updates frequently, set up a mechanism to refresh it periodically. You can use scheduled tasks or automated scripts to ensure your data stays up-to-date.

5.5 Customize Styling

  1. CSS: For advanced styling, consider using a custom CSS file to enhance the appearance of your app.
  2. Branding: Apply specific colour schemes or branding elements to match organizational requirements.

Conclusion

This comprehensive guide provides detailed explanations of each section of the code and additional steps to improve and deploy your Shiny application. Each step is designed to ensure you understand how to build, customize, and deploy a Shiny app effectively. By following this guide, you have learned to build a Shiny application from scratch, encompassing several key components:

1. Setting Up Your Development Environment

We began by installing R, RStudio, and the necessary R packages. Understanding the role of each package is crucial:

  • Shiny: Facilitates building interactive web applications.
  • shiny-dashboard: Provides tools for creating dashboard layouts and UI elements.
  • readr: Assists in reading data from CSV files.
  • tidyverse: A collection of packages for data manipulation and visualization.
  • ggplot2: Creates static graphics.
  • plotly: Converts static plots into interactive charts.
  • DT: Renders interactive data tables.

2. Preparing Your Data

Before diving into coding, ensure your data is well-structured and accessible. Proper data preparation is essential for accurate visualization and interaction. In our example, the dataset gps_data_pivot.csv was used, which contained various metrics related to player performance during sessions.

3. Building the Shiny Application

The core of your Shiny app involves writing the application script, which includes several sections:

3.1 Plot Function

The plot_gps_data function was developed to generate customizable plots based on user input. This function uses ggplot2 for creating static plots and plotly for interactivity. Understanding the components of this function, such as ggplot(), geom_col(), theme(), and facet_wrap(), helps you customize plots according to your data and requirements.

3.2 UI Layout

The user interface (UI) defines how users interact with the application. Using shinydashboard components like dashboardPage(), dashboardHeader(), dashboardSidebar(), and dashboardBody(), we structured the app to include tabs for charts and data tables, and drop-down menus for selecting different parameters. This set-up allows users to interact with the data dynamically.

3.3 Server Logic

The server function processes user inputs and updates outputs. We used renderPlotly() to create interactive plots and renderDataTable() to generate a styled data table. Reactive programming principles in Shiny ensure that the app responds to user inputs efficiently and updates the outputs accordingly.

4. Deploying the Application

Deploying your Shiny app on Shinyapps.io makes it accessible from anywhere via a web browser. We walked through:

  • Creating a Shinyapps.io account.
  • Installing and configuring the rsconnect package.
  • Deploying the app using deployApp().

This step is crucial for sharing your app with others and allowing it to run on a cloud server.

5. Enhancing the Application

Improvements can be made to ensure better performance, user experience, and customization:

  • Error Handling: Implement error handling to manage issues like missing data or invalid inputs gracefully.
  • Performance Optimization: Use reactive expressions to optimize performance, especially with large datasets.
  • User Experience: Add interactivity such as sliders or check-boxes to enhance user engagement. Provide tool-tips or instructions to help users understand how to interact with the app.
  • Data Refresh: Automate data updates to keep the information current.
  • Styling: Customize the app's appearance with CSS for a professional look and feel. Adjust the branding to match organizational themes.

Key Takeaways

  1. Understanding Shiny Components: Familiarize yourself with Shiny's core components (ui, server, and output) and how they interact.
  2. Customizing Visualizations: Learn to use ggplot2 and plotly to create informative and interactive visualizations.
  3. Interactive Elements: Implement user inputs and outputs effectively to build interactive applications.
  4. Deployment: Ensure your app is deployed properly for easy access and sharing.

Further Reading and Resources

To deepen your understanding and expand your Shiny app capabilities, consider exploring the following resources:

By leveraging these tools and techniques, you can create sophisticated and user-friendly Shiny applications that effectively present and analyse data. Happy learning.

If you have any questions, feel free to ask! Please also offer some feedback on how this can be improved, I have no doubt this will go through many iterations before I'm happy with the final product but this is a nice start.