0

I am working on developing a shiny app where users can select a desired player and stadium overlay to create an animated home run plot. My code for the plot, user interface, and server are below.

library(tidyverse)
library(gganimate)
library(ggtext)
library(data.table)
library(mlbplotR)
library(GeomMLBStadiums)
library(shiny)

HRPlot_data <- read_csv("HRPlot_data.csv") %>%
  select(player_name, batter, des, launch_speed, launch_angle, hit_distance_sc, hc_x_adj, hc_y_adj, HR, 
         home_team, Opponent, pitcher, fielder_2, fielder_3, fielder_4, fielder_6, fielder_5, fielder_7, 
         fielder_8, fielder_9) %>%
  mutate(x_coord = hc_x_adj * 2.495671, y_coord = hc_y_adj * 2.495671)
  
HRPlot_ID <- read_csv("HRPlot_ID.csv")

HRPlot_Colors <- load_mlb_teams()

HRPlot_Colors2 <- HRPlot_Colors %>%
  mutate(stadium = gsub(" ", "_", tolower(HRPlot_Colors$team_mascot)),
         venue = case_when(stadium == "blue_jays" ~ "bluejays",
                           stadium == "white_sox" ~ "whitesox",
                           stadium == "red_sox" ~ "redsox", .default = stadium))

HRPlot_data1 <- list(
  HRPlot_dataex1 <- list(
    HRPlot_dataex2 <- HRPlot_data,
    HRPlot_HomeStadium <- HRPlot_Colors2 %>%
      select(stadium, team_abbr) %>%
      rename(home_team = team_abbr)
  ) %>% reduce(merge, by = "home_team"),
  HRPlot_Colorsex <- HRPlot_Colors2 %>%
    select(team_abbr, team_color, team_color2, team_name) %>%
    rename(Opponent = team_abbr, color1 = team_color, color2 = team_color2)
) %>% reduce(merge, by = "Opponent")

home_run_animate <- function(name, venue) {
  
  library(GeomMLBStadiums)
  library(mlbplotR)
  library(gganimate)
  library(ggtext)
  library(data.table)
  library(gifski)
  
  HRPlot_MLBID <- HRPlot_data1 %>% # Player ID
    filter(player_name == name) %>%
    pull(batter) %>%
    unique()
  
  HRPlot_HomeRun <- HRPlot_data1 %>% # Player Home Run Total
    filter(player_name == name) %>%
    group_by(player_name) %>%
    reframe(HR = n()) %>%
    pull(HR)
  
  HRPlot_playerdata <- list(
    MorelHR1 <- HRPlot_data1 %>%
      filter(player_name == name) %>%
      rename(key_mlbam = pitcher),
    Pitcher <- HRPlot_ID
  ) %>% reduce(merge, by = "key_mlbam")
  
  HRPlot_Positions <- list(
    z_Catcher <- list(
      Catcher <- HRPlot_playerdata %>% select(HR, fielder_2, Opponent, color1, color2) %>% rename(key_mlbam = fielder_2), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "catcher"),
    z_FirstBase <-list(
      FirstBase <- HRPlot_playerdata %>% select(HR, fielder_3, Opponent, color1, color2) %>% rename(key_mlbam = fielder_3), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "first_base"),
    z_SecondBase <- list(
      SecondBase <- HRPlot_playerdata %>% select(HR, fielder_4, Opponent, color1, color2) %>% rename(key_mlbam = fielder_4), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "second_base"),
    z_Shortstop <- list(
      Shortstop <- HRPlot_playerdata %>% select(HR, fielder_6, Opponent, color1, color2) %>% rename(key_mlbam = fielder_6), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "shortstop"),
    z_ThirdBase <- list(
      ThirdBase <- HRPlot_playerdata %>% select(HR, fielder_5, Opponent, color1, color2) %>% rename(key_mlbam = fielder_5), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "third_base"),
    z_LeftField <- list(
      LeftField <- HRPlot_playerdata %>% select(HR, fielder_7, Opponent, color1, color2) %>% rename(key_mlbam = fielder_7), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "left_field"),
    z_CenterField <- list(
      CenterField <- HRPlot_playerdata %>% select(HR, fielder_8, Opponent, color1, color2) %>% rename(key_mlbam = fielder_8), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "center_field"),
    z_RightField <- list(
      RightField <- HRPlot_playerdata %>% select(HR, fielder_9, Opponent, color1, color2) %>% rename(key_mlbam = fielder_9), 
      HRPlot_ID) %>% reduce(merge, by = "key_mlbam") %>% mutate(position = "right_field")
  ) %>% rbindlist() %>%
    mutate(fielder_x = case_when(position == "catcher" ~ 0, position == "first_base" ~ 57.5,
                                 position == "second_base" ~ 50, position == "shortstop" ~ -50,
                                 position == "third_base" ~ -57.5, position == "left_field" ~ -130,
                                 position == "center_field" ~ 0, position == "right_field" ~ 130),
           fielder_y = case_when(position == "catcher" ~ -20, position == "first_base" ~ 60,
                                 position == "second_base" ~ 120, position == "shortstop" ~ 120,
                                 position == "third_base" ~ 60, position == "left_field" ~ 220,
                                 position == "center_field" ~ 310, position == "right_field" ~ 220))
  
  HRPlot_plot <- HRPlot_playerdata %>%
    ggplot(aes(x = x_coord, y = y_coord)) +
    geom_segment(aes(x = 0, y = 0, xend = x_coord, yend = y_coord)) +
    geom_spraychart(stadium_ids = venue, stadium_transform_coords = T, stadium_segments = "all") +
    geom_point(color = "red", size = 3) +
    geom_label(data = HRPlot_Positions, aes(x = fielder_x, y = fielder_y, label = player_name2,
                                            color = "white", fill = "black"), fontface = "bold") +
    geom_mlb_dot_logos(aes(team_abbr = Opponent), x = 0, y = 210, width = 0.09) +
    scale_x_continuous(limits = c(-325, 325)) +
    annotate(GeomMLBheads, player_id = HRPlot_MLBID, width = 0.5, x = -225, y = 10) +
    geom_rect(aes(xmin = -Inf, xmax = Inf, ymin = -Inf, ymax = Inf), color = "black", fill = NA) +
    labs(title = "Home Run Count: {current_frame}",
         subtitle = paste("v.", "**{filter(HRPlot_playerdata, HR == current_frame) %>% pull(player_name2) %>% .[[1]]}**", "|",
                          "**{filter(HRPlot_playerdata, HR == current_frame) %>% pull(launch_speed) %>% .[[1]]}**", "mph |",
                          "**{filter(HRPlot_playerdata, HR == current_frame) %>% pull(launch_angle) %>% .[[1]]}**", "degrees |",
                          "**{filter(HRPlot_playerdata, HR == current_frame) %>% pull(hit_distance_sc) %>% .[[1]]}**", "ft"),
         caption = "Data courtesy of MLB Advanced Media | **Steven Pappas**", x = NULL, y = NULL) +
    theme_void() +
    theme(plot.title = element_text(face = "bold", hjust = 0.5, size = 20), 
          plot.subtitle = element_markdown(hjust = 0.5, size = 18), 
          plot.caption = element_markdown(size = 11, hjust = 0.99)) +
    scale_color_identity() +
    scale_fill_identity() +
    guides(color = "none", fill = "none") +
    transition_manual(HR) +
    enter_fade() +
    ease_aes("linear")
  
  gganimate::animate(HRPlot_plot, fps = 5)
  
}

HRPlot_datashiny1 <- HRPlot_data1 %>% 
  group_by(player_name) %>%
  reframe(N = n())

HRPlot_datashiny2 <- HRPlot_Colors2 %>%
  group_by(venue) %>%
  reframe(N = n())

HRPlot_players <- HRPlot_datashiny1$player_name

HRPlot_venues <- HRPlot_datashiny2$venue

HRPlot_ui <- fluidPage(
  titlePanel("Home Run Animation"),
  sidebarLayout(
    sidebarPanel(
      selectInput("hitter", "Select Hitter:", choices = HRPlot_players),
      selectInput("venue", "Select Venue:", choices = HRPlot_venues),
      actionButton("plotButton", "Create Plot")
    ),
    mainPanel(
      imageOutput("homeRunPlot")
    )
  )
)

HRPlot_server <- function(input, output, session) {
  observeEvent(input$plotButton, {
    req(input$hitter, input$venue)
    
    file_path = tempfile(fileext = ".gif")
    anim = home_run_animate(name = input$hitter, venue = input$venue)
    anim_save(file_path, anim)
    
    output$homeRunPlot = renderImage({
      list(src = file_path, contentType = "image/gif")
    }, deleteFile = T)
  })
}

shinyApp(ui = HRPlot_ui, server = HRPlot_server)

This code provides my desired shiny app on my local R, but I run into issues when I try to publish it to shinyapps.io. It gives me this error message "An error has occurred. The application failed to start. exit status 1." I believe this error is a contributing factor, but I am not sure why it exists. I set my working directory to pull from the folder containing my shiny app.

setwd("C:/Users/sppap/OneDrive/Documents/Home Run Plot")

showLogs()

Error: 'HRPlot_data.csv' does not exist in current working directory ('/srv/connect/apps/homerunshiny').

Does anyone have any ideas to help me resolve this issue?

4
  • 1
    Where do you use the setwd? I don't see it in your app. You shouldn't put it in your app.R, but I'm trying to understand where you run it. Did you upload the csv files along with your app? Are they in the same folder as app.R? Commented Oct 31, 2024 at 4:51
  • 1
    You should try to make a minimal shiny app that only loads csv data and perhaps shows it. Get this working on shinyapps.io and then you'll know how to solve your problem here. Commented Oct 31, 2024 at 4:52
  • Also, putting library calls inside a function is generally not a good idea. @MichaelDewar makes two very good points. Please answer his questions. To try to pre-empt those answers, local resoucres that your app needs should generally be saved to a fiolder named www under the home folder of your app and uploaded to shinyapps.io with your app. This page makes further suggestions. Commented Oct 31, 2024 at 8:21
  • @Limey that only applies to files which need to be included in the UI - you're fine putting data in the root directory and indeed that is preferable for data so it isn't sent to the browser unnecessarily and prevents users being able to access the data directly. Commented Oct 31, 2024 at 10:15

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.