SummaryCard / app.R
TimStats's picture
Update app.R
1c8a71c verified
Raw
History Blame
15.8 kB
library(shiny)
library(plotly)
library(gridlayout)
library(bslib)
library(DT)
library(rsconnect)
library(baseballr)
library(dplyr)
library(tidyverse)
library(rvest)
library(ggplot2)
library(janitor)
library(ggthemes)
library(ggpubr)
library(jsonlite)
library(utils)
Sys.setenv(TZ='EST')
is_barrel <- function(df) {
df$barrel <- with(df, ifelse(hit_angle <= 50 & hit_speed >= 97 & hit_speed * 1.5 -
hit_angle >= 117 & hit_speed + hit_angle >= 123, 1, 0))
return(df)
}
VAA <- function(milbtotal){
milbtotal <- milbtotal |>
mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi))
}
pitcher_summary <- function(game_pk,date){
gdate <- as.Date.character(date)
gdate <- as.Date(gdate)
tmilb <- mlb_pbp(game_pk)
tmilb <- tmilb |>
filter(type == "pitch")
tmilb <- tmilb |>
select(matchup.batter.fullName,matchup.batter.id,matchup.pitcher.fullName,
matchup.pitcher.id,result.event,details.description,details.type.description,
result.description,pitchData.startSpeed,
pitchData.plateTime,pitchData.zone,pitchData.breaks.spinRate,pitchData.extension,
pitchData.coordinates.pX,pitchData.coordinates.pZ,pitchData.coordinates.x0,
pitchData.coordinates.y0,pitchData.coordinates.z0,pitchData.coordinates.aX,
pitchData.coordinates.aY,pitchData.coordinates.aZ,pitchData.coordinates.vX0,
pitchData.coordinates.vZ0,pitchData.coordinates.vY0,pitchData.coordinates.pfxX,
pitchData.coordinates.pfxZ,pitchData.breaks.breakVerticalInduced,pitchData.breaks.breakHorizontal,
hitData.launchSpeed,hitData.launchAngle,hitData.totalDistance,details.isInPlay,last.pitch.of.ab)
colnames(tmilb) <- c("Batter Name","Batter ID","Pitcher Name","Pitcher ID",
"result","description","pitch_name",
"des","start_speed","plateTime","zone","spin_rate",
"extension","px","pz","x0","y0","z0","ax","ay","az",
"vx0","vz0","vy0","pfxX","pfxZ","IVB","HB","hit_speed",
"hit_angle","hit_distance","inPlay","lastPitch")
tmilb <- is_barrel(tmilb)
tmilb <- tmilb |>
mutate(is_strike_swinging = ifelse(description == "Swinging Strike" |
description == "Foul Tip",TRUE,FALSE))
tmilb <- tmilb |>
mutate(date = gdate)
return(tmilb)
}
break_plot <- function(game){
ggplot()+
geom_point(game,mapping =
aes(x=HB, y = IVB,color = pitch_name),size = 4) +
geom_vline(xintercept = 0, color = "lightblue",linewidth = 1,linetype = 4)+
geom_hline(yintercept = 0, color = "lightblue",linewidth = 1,linetype = 4)+
xlab("Horizontal Break from Pitcher's Perspective (in) ")+
ylab("Induced Verical Break (in)") +
xlim(-25,25) +
ylim(-25,25) +
ggthemes::theme_igray()+
theme(panel.grid.minor = element_line(color = "gray",
size = 0.25,
linetype = 1))+
guides(color = guide_legend(title = "Pitch Type"))
}
pitch_plot <- function(game){
ggplot()+
geom_point(game,mapping =
aes(x=px, y = pz,color = pitch_name),size = 3.5) +
geom_segment(aes(x=-0.71,xend = 0.71, y = 1.5,yend = 1.5))+
geom_segment(aes(x=-0.71,xend = 0.71, y = 3.6,yend = 3.6))+
geom_segment(aes(x= 0.71,xend = 0.71, y = 1.5,yend = 3.6))+
geom_segment(aes(x=-0.71,xend = -0.71, y = 1.5,yend =3.6))+
xlab(" ")+
ylab(" ") +
xlim(-3,3)+
ylim(0.2,4)+
ggthemes::theme_few()+
guides(color = guide_legend(title = "Pitch Type"))+
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
axis.text.y=element_blank(),
axis.ticks.y=element_blank())
}
summary_table <- function(game){
rows <- nrow(game)
sumtable <- game |>
mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi)) |>
mutate(team_fielding_id = ifelse(description == "Called Strike" |
description == "Swinging Strike" |
description == "Swinging Strike (Blocked)",1,0))|>
mutate(swing = ifelse(description == "Foul" |
description == "Foul Pitchout" |
description == "In play, no out" |
description == "In play, out(s)" |
description == "In play, run(s)" |
description == "Swinging Strike" |
description == "swinging Strike (Blocked)" |
description == "Foul Tip",1,0)) |>
mutate(is_strike_swinging = ifelse(is_strike_swinging == TRUE,1,0)) |>
mutate(Pitch = pitch_name) |>
group_by(Pitch)|>
summarize(Pitches = n(),
'Pitch%' = round(sum(Pitches)/sum(rows) * 100,digits = 1),
'Avg. Velo' = round(sum(start_speed)/Pitches,digits = 1),
'Spin Rate' = round(sum(spin_rate)/ Pitches,digits = 1),
'Extension' = mean(extension,na.rm = TRUE),
'IVB' = mean(IVB,na.rm=TRUE),
'HB' = mean(HB,na.rm = TRUE),
'VAA' = mean(VAA,na.rm= TRUE),
'CSW%' = round(sum(team_fielding_id)/
sum(!is.na(team_fielding_id))*100,digits = 1),
'Whiff%' = round(sum(is_strike_swinging)/
sum(swing)*100,digits = 1))
}
#MLB ID Stuff
mlbid <- mlb_schedule(season = 2024, level_ids = "1")
mlbteamH <- mlbid |>
select(teams_home_team_name)
mlbteamH <- distinct(mlbteamH)
mlbteamA <- mlbid |>
select(teams_away_team_name)
mlbteamA <- distinct(mlbteamA)
#AAA ID Stuff
aaaid <- mlb_schedule(season = 2024, level_ids = "11")
aaateamH <- aaaid |>
select(teams_home_team_name)
aaateamH <- distinct(aaateamH)
aaateamA <- aaaid |>
select(teams_away_team_name)
aaateamA <- distinct(aaateamA)
#FSL ID Stuff
fslid <- mlb_schedule(season = 2024, level_ids = "14")
fslid <- fslid |>
filter(teams_home_team_name == "Daytona Tortugas" |
teams_home_team_name == "Jupiter Hammerheads" |
teams_home_team_name == "Palm Beach Cardinals" |
teams_home_team_name == "St. Lucie Mets" |
teams_home_team_name == "Bradenton Marauders" |
teams_home_team_name == "Clearwater Threshers" |
teams_home_team_name == "Dunedin Blue Jays" |
teams_home_team_name == "Fort Myers Mighty Mussels" |
teams_home_team_name == "Lakeland Flying Tigers" |
teams_home_team_name == "Tampa Tarpons")
fslteamH <- fslid |>
select(teams_home_team_name)
fslteamH <- distinct(fslteamH)
fslteamA <- fslid |>
select(teams_away_team_name)
fslteamA <- distinct(fslteamA)
#SB ID Stuff
sbid <- mlb_schedule(season = 2024, level_ids = "21")
sbteamH <- sbid |>
select(teams_home_team_name)
sbteamH <- distinct(sbteamH)
sbteamA <- sbid |>
select(teams_away_team_name)
sbteamA <- distinct(sbteamA)
ui <- grid_page(
layout = c(
"header header",
"sidebar area2 "
),
row_sizes = c(
"40px",
"1fr"
),
col_sizes = c(
"280px",
"1fr"
),
gap_size = "1rem",
sidebarPanel(
dateInput("date",
"Date:"),
selectizeInput("level","Level:",c("MLB","AAA","FSL","Spring Breakout")),
selectizeInput("homeT","Home Team:",mlbteamH[,1]),
selectizeInput("awayT", "Away Team:",mlbteamA[,1]),
selectizeInput("gamenum","Game Number (For Doubleheaders):",c("1","2")),
actionButton("update","Find Pitchers",icon("magnifying-glass"),
style = "color: #FFFFFF; background-color: #0077B6"),
selectizeInput("pitcher","Pitcher (For Spring Breakout if pitchers not loading, try changing game number)",c(" ")),
selectizeInput("league","MLB or MiLB Photo",c("MLB","MiLB")),
textInput("title","Card Title"),
actionButton("update1","Make Card",icon("plus"),
style = "color: #FFFFFF; background-color: #0077B6"),
width = 15,
),
grid_card_text(
area = "header",
content = "2024 MLB/AAA/FSL Summary Cards (BETA: Meant for Computers, Set Zoom to 100% for best use)",
alignment = "start",
is_title = FALSE
),
grid_card(
area = "area2",
full_screen = TRUE,
card_header(textOutput(outputId = "cardTitle")),
card_body(
gap = "0px",
grid_container(
layout = c(
"area3 chart chart chart ",
"breakgraph breakgraph strikezone strikezone"
),
row_sizes = c(
"1fr",
"1fr"
),
col_sizes = c(
"1fr",
"1fr",
"1fr",
"1fr"
),
gap_size = "0px",
grid_card_plot(area = "breakgraph"),
grid_card_plot(area = "strikezone"),
grid_card(
area = "chart",
card_body(
tableOutput(
outputId = "myTable"
),
)
),
grid_card(
area = "area3",
plotOutput(outputId = "picture")
)
)
)
)
)
server <- function(input, output) {
# game <- reactive(pitcher_summary(input$game_pk))
# id <- reactive(as.character(game()[1,4]))
observeEvent(input$level,{
if(input$level == "AAA"){
updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = aaateamH[,1])
updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = aaateamA[,1])
}
if(input$level == "FSL"){
updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = fslteamH[,1])
updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = fslteamA[,1])
}
if(input$level == "MLB"){
updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = mlbteamH[,1])
updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = mlbteamA[,1])
}
if(input$level == "Spring Breakout"){
updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = sbteamH[,1])
updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = sbteamA[,1])
}
})
observeEvent(input$update,{
if(input$level == "AAA"){
pname <- aaaid |>
filter(date == input$date) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
}
if(input$level == "FSL"){
pname <- fslid |>
filter(date == input$date) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
}
if(input$level == "MLB"){
pname <- mlbid |>
filter(date == as.character.Date(input$date)) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
}
if(input$level == "Spring Breakout"){
pname <- sbid |>
filter(date == input$date) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
}
})
observeEvent(input$update1,{
if(input$level == "MLB"){
id <- mlbid |>
filter(date == as.character.Date(input$date)) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
game <- game |>
filter(`Pitcher Name` == input$pitcher)
id <- as.character(game[1,4])
}
if(input$level == "FSL"){
id <- fslid |>
filter(date == as.character.Date(input$date)) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
game <- game |>
filter(`Pitcher Name` == input$pitcher)
id <- as.character(game[1,4])
}
if(input$level == "AAA"){
id <- aaaid |>
filter(date == as.character.Date(input$date)) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
game <- game |>
filter(`Pitcher Name` == input$pitcher)
id <- as.character(game[1,4])
}
if(input$level == "Spring Breakout"){
id <- sbid |>
filter(date == as.character.Date(input$date)) |>
filter(teams_home_team_name == input$homeT) |>
filter(teams_away_team_name == input$awayT) |>
filter(game_number == input$gamenum)
game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
game <- game |>
filter(`Pitcher Name` == input$pitcher)
id <- as.character(game[1,4])
}
output$breakgraph <- renderPlot({
break_plot(game)
})
output$strikezone <- renderPlot({
pitch_plot(game)
})
output$myTable <- renderTable({
t <- summary_table(game)
return(t)
},width = '1150px',digits = 1,na = "NA",align = 'left')
output$picture <- renderImage({
if(input$league == "MLB"){
y <- paste("https://midfield.mlbstatic.com/v1/people/","/mlb/300?circle=false",sep = id)
}
if(input$league == "MiLB"){
y <- paste("https://midfield.mlbstatic.com/v1/people/","/milb/300?circle=false",sep = id)
}
photo <- tempfile()
download.file(y,photo,mode = 'wb')
list(
src = photo
)
},deleteFile = TRUE)
output$cardTitle <- renderText(
title <- paste(input$title,"Made by @TimStats", sep = " ")
)
})
}
shinyApp(ui, server)