TimMedia / app.R
TimStats's picture
Upload 2 files
67fd53f verified
Raw
History Blame
20.9 kB
library(shiny)
library(gt)
library(dplyr)
library(shinyjs)
library(shinyauthr)
library(gtExtras)
library(bslib)
Bean <- read.csv('Beam.csv')
test <- Beam %>%
select(Date,PitchofPA,Pitcher,PitcherId,PitcherThrows,PitcherTeam,Batter,BatterId,
BatterSide,BatterTeam,Inning,`Top/Bottom`,Outs,Balls,Strikes,TaggedPitchType,
AutoPitchType,PitchCall,TaggedHitType,KorBB,PlayResult,OutsOnPlay,RunsScored,
RelSpeed,VertRelAngle,HorzRelAngle,SpinRate,SpinAxis,Tilt,RelHeight,RelSide,
Extension,InducedVertBreak,HorzBreak,PlateLocHeight,PlateLocSide,VertApprAngle,
HorzApprAngle,ExitSpeed,Angle,Direction,Distance,pfxx,pfxz,x0,z0,vx0,vy0,vz0,
ax0,ay0,az0,Level,League,ContactPositionX,ContactPositionY,ContactPositionZ,
SpinAxis3dTransverseAngle,SpinAxis3dLongitudinalAngle,SpinAxis3dTilt,
SpinAxis3dSpinEfficiency,SpinAxis3dSeamOrientationRotationX,
SpinAxis3dSeamOrientationRotationY,SpinAxis3dSeamOrientationRotationZ)
test <- test %>%
mutate("Hit" = case_when(PlayResult %in% c("Single","Double","Triple","HomeRun") ~ TRUE,TRUE ~ FALSE),
"CallStrike" = case_when(PitchCall %in% c("StrikeCalled") ~ TRUE, TRUE ~ FALSE),
"Whiff" = case_when(PitchCall %in% c("StrikeSwinging") ~ TRUE, TRUE ~ FALSE),
"CSW" = CallStrike + Whiff,
"Contact" = case_when(PitchCall %in% c("FoulBall","FouBallNotFieldable","InPlay") ~ TRUE, TRUE ~ FALSE),
"GB" = case_when(TaggedHitType %in% c('GroundBall') ~ TRUE, TRUE ~ FALSE),
"LD" = case_when(TaggedHitType %in% c('LineDrive') ~ TRUE, TRUE ~ FALSE),
"FB" = case_when(TaggedHitType %in% c ("FlyBall") ~ TRUE, TRUE ~ FALSE),
"PopU" = case_when(TaggedHitType %in% c ("Popup") ~ TRUE, TRUE ~ FALSE),
"Swing" = Whiff + Contact,
"BBE" = GB + LD + FB + PopU,
"HardHit" = ifelse(ExitSpeed >= 95,TRUE,FALSE),
"Ball" = case_when(PitchCall %in% c("BallCalled","BallinDirt") ~ TRUE, TRUE ~ FALSE),
"Single" = case_when(PlayResult %in% c("Single") ~ TRUE, TRUE ~ FALSE),
"Double" = case_when(PlayResult %in% c("Double") ~ TRUE, TRUE ~ FALSE),
"Triple" = case_when(PlayResult %in% c("Triple") ~ TRUE, TRUE ~ FALSE),
"HR" = case_when(PlayResult %in% c("HomeRun") ~ TRUE, TRUE ~ FALSE),
"Sac" = case_when(PlayResult %in% c("Sacrifice") ~ TRUE, TRUE ~ FALSE),
"HBP" = case_when(PitchCall %in% c("HitByPitch") ~ TRUE, TRUE ~ FALSE),
"Error" = case_when(PlayResult %in% c("Error") ~ TRUE, TRUE ~ FALSE),
"FC"= case_when(PlayResult %in% c("FieldersChoice") ~ TRUE, TRUE ~ FALSE),
"Out" = case_when(PlayResult %in% c ("Out") ~ TRUE, TRUE ~ FALSE),
"BIP" = Single + Double + Triple + HR + Sac + Error + Out + FC,
"Count" = paste0(Balls,"-",Strikes),
"Strikeout" = ifelse(KorBB == "Strikeout",TRUE,FALSE),
"Walk" = ifelse(KorBB == "Walk",TRUE,FALSE),
"Zone" = case_when(between(PlateLocSide,-.825,.825) & between(PlateLocHeight,1.45,3.45) ~ TRUE, TRUE ~ FALSE),
"AB" = Strikeout + BIP - Sac,
"PA" = Strikeout + BIP + Walk + HBP
)
gt_theme_tim <- function(gt_object,...) {
stopifnot(`'gt_object' must be a 'gt_tbl', have you accidentally passed raw data?` = "gt_tbl" %in%
class(gt_object))
table_id <- subset(gt_object[['_options']], parameter == 'table_id')$value[[1]]
if (is.na(table_id)) {
table_id <- gt::random_id()
opt_position <- which("table_id" %in% gt_object[["_options"]][["parameter"]])[[1]]
gt_object[["_options"]][["value"]][[opt_position]] <- table_id
}
gt_object %>%
# cell body
gt::tab_style(
locations = gt::cells_body(),
style = gt::cell_text(font = "Arial", size = px(14))
) %>%
# col. headers
gt::tab_style(
locations = gt::cells_column_labels(),
style = gt::cell_text(weight = 'bold', font = "Arial", size = px(14))
) %>%
# group rows
gt::tab_style(
locations = gt::cells_row_groups(),
style = list(
gt::cell_text(font = "Arial", weight = 650, size = px(14), color = "#FFFDF5"),
gt::cell_fill(color = "#000000")
)
) %>%
# footnote
gt::tab_style(
locations = gt::cells_footnotes(),
style = gt::cell_text(font = "Arial", size = px(12))
) %>%
# title
gt::tab_style(
locations = gt::cells_title('title'),
style = gt::cell_text(weight = 'bold', font = "Arial", size = px(18))
) %>%
# subtitle
gt::tab_style(
locations = gt::cells_title('subtitle'),
style = gt::cell_text(font = "Arial", size = px(14))
) %>%
# caption
gt::tab_style(
locations = gt::cells_source_notes(),
style = gt::cell_text(font = "Arial", size = px(12))
) %>%
# spanner
gt::tab_style(
locations = gt::cells_column_spanners(),
style = gt::cell_text(font = "Arial", weight = 650, size = px(8))
) %>%
gt::tab_options(
data_row.padding = 1,
table_body.hlines.color = "transparent",
column_labels.border.top.color = 'black',
column_labels.border.top.width = px(1),
column_labels.border.bottom.style = 'none',
#column_labels.background.color = "orange",
row_group.border.top.style = "none",
row_group.border.top.color = "black",
row_group.border.bottom.width = px(1),
row_group.border.bottom.color = "black",
row_group.border.bottom.style = 'solid',
row_group.padding = px(1.5),
heading.align = 'center',
heading.border.bottom.style = "none",
table_body.border.top.style = "none",
table_body.border.bottom.color = "white",
table.border.bottom.style = 'none',
table.border.top.style = 'none',
source_notes.border.lr.style = "none",
...
) %>%
gt::opt_row_striping()
}
user_base <- tibble::tibble(
user = c("TrentR", "user2"),
password = sapply(c("Caprisun", "pass2"), sodium::password_store),
permissions = c("admin", "standard"),
name = c("User One", "User Two")
)
# Define UI for application that draws a histogram
ui <- fluidPage(
div(class = "pull-right", shinyauthr::logoutUI(id = "logout")),
# login section
shinyauthr::loginUI(id = "login"),
div(
id = "bar",
# Application title
titlePanel("College Pitcher"),
# Sidebar layout
sidebarLayout(
sidebarPanel(
selectInput("player",
"Select Player",
choices = unique(test$Pitcher)),
width = 3
),
mainPanel(
tabsetPanel(
tabPanel("Splits",
gt_output("CountFilter"),
gt_output("PitchFilter"),
gt_output("PitchSideFilter"),
gt_output("InningFilter"),
gt_output("SideFilter")
)
),
width = 9
)
)
) %>% shinyjs::hidden()
)
# Define server logic required to draw a histogram
server <- function(input, output) {
credentials <- shinyauthr::loginServer(
id = "login",
data = user_base,
user_col = user,
pwd_col = password,
sodium_hashed = TRUE,
log_out = reactive(logout_init())
)
# Logout to hide
logout_init <- shinyauthr::logoutServer(
id = "logout",
active = reactive(credentials()$user_auth)
)
observe({
req(credentials()$user_auth)
shinyjs::show(id = "bar")
})
output$CountFilter <- render_gt({
test <- test %>% filter(Pitcher == input$player) %>% group_by(Count) %>%
summarise(
Pitches = n(),
#BBE = sum(BBE,na.rm = TRUE),
"Whiff%" = mean(Whiff,na.rm = TRUE),
"CSW%" = mean(CSW,na.rm = TRUE),
"Zone%" = mean(Zone,na.rm = TRUE),
"ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
"ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
"OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
"OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
"Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
"Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
"GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
"LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
"FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
"AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
"OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
sum(PA,na.rm = TRUE),digits = 3),
"SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
ungroup()%>%
gt() %>%
gt_theme_tim() %>%
fmt_number(columns = `Avg EV`:`Max EV`,decimals = 1) %>%
cols_width(Count:Pitches ~ px(70),
everything() ~ px(85)) %>%
cols_align(align = "center") %>%
fmt_number(columns = AVG:SLG,decimals = 3) %>%
fmt_percent(columns = ends_with("%")) %>%
sub_missing() %>%
#gt_theme_savant() %>%
opt_interactive(
use_compact_mode = TRUE,
use_pagination = FALSE
)
})
output$PitchFilter <- render_gt({
tes <- test %>%
filter(Pitcher == input$player) %>%
group_by(AutoPitchType) %>%
summarise(
Pitches = n(),
# BBE = sum(BBE,na.rm = TRUE),
"Usage%" = n() / nrow(.), # Added Usage% calculation
"Whiff%" = mean(Whiff, na.rm = TRUE),
"CSW%" = mean(CSW, na.rm = TRUE),
"Zone%" = mean(Zone, na.rm = TRUE),
"ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE], na.rm = TRUE),
"ZSwing%" = mean(Swing[Zone == TRUE], na.rm = TRUE),
"OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE], na.rm = TRUE),
"OSwing%" = mean(Swing[Zone == FALSE], na.rm = TRUE),
"Avg EV" = mean(ExitSpeed[BBE == TRUE], na.rm = TRUE),
"EV90" = quantile(ExitSpeed[BBE == TRUE], .9, na.rm = TRUE),
"Max EV" = max(ExitSpeed[BBE == TRUE], na.rm = TRUE),
"Max EV" = ifelse(is.infinite(`Max EV`), NA, `Max EV`),
"GB%" = mean(GB[BBE == TRUE], na.rm = TRUE),
"LD%" = mean(LD[BBE == TRUE], na.rm = TRUE),
"FB%" = mean(FB[BBE == TRUE], na.rm = TRUE),
"AVG" = round(sum(Hit, na.rm = TRUE) / sum(AB, na.rm = TRUE), digits = 3),
"OBP" = round((sum(Hit, na.rm = TRUE) + sum(Walk, na.rm = TRUE) + sum(HBP, na.rm = TRUE)) /
sum(PA, na.rm = TRUE), digits = 3),
"SLG" = (round(sum(Single, na.rm = TRUE) + sum(Double, na.rm = TRUE) * 2 +
sum(Triple, na.rm = TRUE) * 3 + sum(HR, na.rm = TRUE))) / sum(AB, na.rm = TRUE)
) %>%
ungroup() %>%
arrange(desc(Pitches)) %>%
gt() %>%
gt_theme_tim() %>%
fmt_number(columns = `Avg EV`:`Max EV`, decimals = 1) %>%
cols_label(AutoPitchType = "Type") %>%
cols_width(
AutoPitchType ~ px(100),
Pitches ~ px(70),
everything() ~ px(85)
) %>%
cols_align(align = "center") %>%
fmt_number(columns = AVG:SLG, decimals = 3) %>%
fmt_percent(columns = ends_with("%")) %>%
sub_missing() %>%
opt_interactive(
use_compact_mode = TRUE,
use_pagination = FALSE
)
})
output$PitchSideFilter <- render_gt({
test <- test %>%
filter(Pitcher == input$player) %>%
group_by(BatterSide) %>%
mutate(total_side = n()) %>%
ungroup() %>%
group_by(AutoPitchType, BatterSide) %>%
summarise(
Pitches = n(),
#BBE = sum(BBE,na.rm = TRUE),
"Usage%" = (n() / first(total_side)),
"Whiff%" = mean(Whiff, na.rm = TRUE),
"CSW%" = mean(CSW, na.rm = TRUE),
"Zone%" = mean(Zone, na.rm = TRUE),
"ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE], na.rm = TRUE),
"ZSwing%" = mean(Swing[Zone == TRUE], na.rm = TRUE),
"OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE], na.rm = TRUE),
"OSwing%" = mean(Swing[Zone == FALSE], na.rm = TRUE),
"Avg EV" = mean(ExitSpeed[BBE == TRUE], na.rm = TRUE),
"EV90" = quantile(ExitSpeed[BBE == TRUE], .9, na.rm = TRUE),
"Max EV" = max(ExitSpeed[BBE == TRUE], na.rm = TRUE),
"Max EV" = ifelse(is.infinite(`Max EV`), NA, `Max EV`),
"GB%" = mean(GB[BBE == TRUE], na.rm = TRUE),
"LD%" = mean(LD[BBE == TRUE], na.rm = TRUE),
"FB%" = mean(FB[BBE == TRUE], na.rm = TRUE),
"AVG" = round(sum(Hit, na.rm = TRUE) / sum(AB, na.rm = TRUE), digits = 3),
"OBP" = round((sum(Hit, na.rm = TRUE) + sum(Walk, na.rm = TRUE) + sum(HBP, na.rm = TRUE)) /
sum(PA, na.rm = TRUE), digits = 3),
"SLG" = (round(sum(Single, na.rm = TRUE) + sum(Double, na.rm = TRUE) * 2 +
sum(Triple, na.rm = TRUE) * 3 + sum(HR, na.rm = TRUE))) / sum(AB, na.rm = TRUE)
) %>%
ungroup() %>%
arrange(desc(BatterSide),desc(Pitches)) %>%
gt() %>%
gt_theme_tim() %>%
fmt_number(columns = `Avg EV`:`Max EV`, decimals = 1) %>%
cols_label(AutoPitchType = "Type", BatterSide = "Side") %>%
cols_width(
AutoPitchType ~ px(100),
Pitches ~ px(70),
BatterSide ~ px(70),
everything() ~ px(85)
) %>%
cols_align(align = "center") %>%
fmt_number(columns = AVG:SLG, decimals = 3) %>%
fmt_percent(columns = ends_with("%")) %>%
sub_missing() %>%
opt_interactive(
use_compact_mode = TRUE,
use_pagination = FALSE
)
})
output$InningFilter <- render_gt({
test <- test %>% filter(Pitcher == input$player) %>% group_by(Inning) %>%
summarise(
Pitches = n(),
#BBE = sum(BBE,na.rm = TRUE),
"Whiff%" = mean(Whiff,na.rm = TRUE),
"CSW%" = mean(CSW,na.rm = TRUE),
"Zone%" = mean(Zone,na.rm = TRUE),
"ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
"ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
"OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
"OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
"Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
"Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
"GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
"LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
"FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
"AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
"OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
sum(PA,na.rm = TRUE),digits = 3),
"SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
ungroup()%>%
gt() %>%
gt_theme_tim() %>%
fmt_number(columns = `Avg EV`:`Max EV`,decimals = 1) %>%
cols_width(Inning:Pitches ~ px(70),
everything() ~ px(85)) %>%
cols_align(align = "center") %>%
fmt_number(columns = AVG:SLG,decimals = 3) %>%
fmt_percent(columns = ends_with("%")) %>%
sub_missing() %>%
#gt_theme_savant() %>%
opt_interactive(
use_compact_mode = TRUE,
use_pagination = FALSE
)
})
output$SideFilter <- render_gt({
test1 <- test %>% filter(Pitcher == input$player) %>% group_by(BatterSide) %>%
summarise(
Pitches = n(),
#BBE = sum(BBE,na.rm = TRUE),
"Whiff%" = mean(Whiff,na.rm = TRUE),
"CSW%" = mean(CSW,na.rm = TRUE),
"Zone%" = mean(Zone,na.rm = TRUE),
"ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
"ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
"OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
"OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
"Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
"Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
"GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
"LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
"FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
"AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
"OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
sum(PA,na.rm = TRUE),digits = 3),
"SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
ungroup()
test2 <- test %>% mutate(BatterSide = "Both") %>%filter(Pitcher == "Beam, Drew") %>% group_by(BatterSide) %>%
summarise(
Pitches = n(),
#BBE = sum(BBE,na.rm = TRUE),
"Whiff%" = mean(Whiff,na.rm = TRUE),
"CSW%" = mean(CSW,na.rm = TRUE),
"Zone%" = mean(Zone,na.rm = TRUE),
"ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
"ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
"OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
"OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
"Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
"Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
"Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
"GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
"LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
"FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
"AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
"OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
sum(PA,na.rm = TRUE),digits = 3),
"SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
ungroup()
test <- rbind(test1,test2)
test %>%
gt() %>%
gt_theme_tim() %>%
fmt_number(columns = `Avg EV`:`Max EV`,decimals = 1) %>%
cols_width(BatterSide:Pitches ~ px(70),
everything() ~ px(85)) %>%
cols_align(align = "center") %>%
cols_label(BatterSide = "Side") %>%
fmt_number(columns = AVG:SLG,decimals = 3) %>%
fmt_percent(columns = ends_with("%")) %>%
sub_missing() %>%
#gt_theme_savant() %>%
opt_interactive(
use_compact_mode = TRUE,
use_pagination = FALSE
)
})
output$slashline <- render_gt({
test <- test %>% filter(Pitcher == input$player) %>%
summarise(
Pitches = n(),
`1B` = sum(Single,na.rm = TRUE),
`2B` = sum(Double,na.rm = TRUE),
`3B` = sum(Triple,na.rm = TRUE),
HR = sum(HR,na.rm = TRUE),
SO = sum(Strikeout,na.rm = TRUE),
BB = sum(Walk,na.rm = TRUE),
Whiffs = sum(Whiff,na.rm = TRUE),
`Hard Hits` = sum(HardHit,na.rm = TRUE)
)%>%
ungroup()%>%
gt() %>%
gt_theme_tim() %>%
cols_align(align = "center") %>%
# gt_theme_savant() %>%
opt_interactive(
use_compact_mode = TRUE,
use_pagination = FALSE
)
})
}
# Run the application
shinyApp(ui = ui, server = server)