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")), 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 = FALSE, 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)