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?
setwd? I don't see it in your app. You shouldn't put it in yourapp.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 asapp.R?librarycalls 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 namedwwwunder the home folder of your app and uploaded to shinyapps.io with your app. This page makes further suggestions.