igroffman commited on
Commit
436bf34
·
verified ·
1 Parent(s): 03a2add

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +62 -57
app.R CHANGED
@@ -772,63 +772,68 @@ server <- function(input, output, session) {
772
  }
773
  })
774
 
775
- # Movement stats table
776
- output$movement_stats <- DT::renderDataTable({
777
- req(plot_data(), input$pitcher_select)
778
-
779
- data <- plot_data()
780
-
781
- movement_stats <- data %>%
782
- filter(Pitcher == input$pitcher_select) %>%
783
- filter(!is.na(HorzBreak), !is.na(InducedVertBreak), !is.na(TaggedPitchType)) %>%
784
- mutate(
785
- pitch_group = case_when(
786
- TaggedPitchType %in% c("Fastball", "FourSeamFastBall", "FourSeamFastB", "Four-Seam", "4-Seam") ~ "Fastball",
787
- TaggedPitchType %in% c("OneSeamFastBall", "TwoSeamFastBall", "Sinker", "Two-Seam", "One-Seam") ~ "Sinker",
788
- TaggedPitchType %in% c("ChangeUp", "Changeup") ~ "Changeup",
789
- TRUE ~ TaggedPitchType
790
- ),
791
- # Create necessary indicator variables if they don't exist
792
- in_zone = if ("StrikeZoneIndicator" %in% names(.)) StrikeZoneIndicator else
793
- ifelse(!is.na(PlateLocSide) & !is.na(PlateLocHeight) &
794
- PlateLocSide >= -0.95 & PlateLocSide <= 0.95 &
795
- PlateLocHeight >= 1.6 & PlateLocHeight <= 3.5, 1, 0),
796
- is_whiff = if ("WhiffIndicator" %in% names(.)) WhiffIndicator else
797
- ifelse(!is.na(PitchCall) & PitchCall == "StrikeSwinging", 1, 0),
798
- chase = if ("Chaseindicator" %in% names(.)) Chaseindicator else
799
- ifelse(!is.na(PitchCall) & !is.na(PlateLocSide) & !is.na(PlateLocHeight) &
800
- PitchCall %in% c("StrikeSwinging", "FoulBallNotFieldable", "FoulBall", "InPlay") &
801
- (PlateLocSide < -0.95 | PlateLocSide > 0.95 | PlateLocHeight < 1.6 | PlateLocHeight > 3.5), 1, 0)
802
- )
803
-
804
- # Calculate total pitches for usage percentage
805
- total_pitches <- nrow(movement_stats)
806
-
807
- summary_stats <- movement_stats %>%
808
- group_by(`Pitch Type` = pitch_group) %>%
809
- summarise(
810
- Count = n(),
811
- `Usage%` = sprintf("%.1f%%", (n() / total_pitches) * 100),
812
- `Ext.` = if ("Extension" %in% names(.)) sprintf("%.1f", mean(Extension, na.rm = TRUE)) else "—",
813
- `Avg Velo` = sprintf("%.1f mph", mean(RelSpeed, na.rm = TRUE)),
814
- `90th Velo` = sprintf("%.1f mph", quantile(RelSpeed, 0.9, na.rm = TRUE)),
815
- `Max Velo` = sprintf("%.1f mph", max(RelSpeed, na.rm = TRUE)),
816
- `Avg IVB` = sprintf("%.1f in", mean(InducedVertBreak, na.rm = TRUE)),
817
- `Avg HB` = sprintf("%.1f in", mean(HorzBreak, na.rm = TRUE)),
818
- `Avg Spin` = if ("SpinRate" %in% names(.)) sprintf("%.0f rpm", mean(SpinRate, na.rm = TRUE)) else "—",
819
- `Rel Height` = if ("RelHeight" %in% names(.)) sprintf("%.1f", mean(RelHeight, na.rm = TRUE)) else "—",
820
- `Zone%` = sprintf("%.1f%%", round(mean(in_zone, na.rm = TRUE) * 100, 1)),
821
- `Whiff%` = sprintf("%.1f%%", round(mean(is_whiff, na.rm = TRUE) * 100, 1)),
822
- `Chase%` = sprintf("%.1f%%", round(mean(chase, na.rm = TRUE) * 100, 1)),
823
- .groups = "drop"
824
- ) %>%
825
- arrange(desc(Count))
826
-
827
- DT::datatable(summary_stats,
828
- options = list(pageLength = 15, dom = 't', scrollX = TRUE),
829
- rownames = FALSE) %>%
830
- DT::formatStyle(columns = names(summary_stats), fontSize = '12px')
831
- })
 
 
 
 
 
832
 
833
  output$selected_pitch_info <- renderText({
834
  pitch_info <- selected_pitch()
 
772
  }
773
  })
774
 
775
+ output$movement_stats <- DT::renderDataTable({
776
+ req(plot_data(), input$pitcher_select)
777
+
778
+ data <- plot_data()
779
+
780
+ movement_stats <- data %>%
781
+ filter(Pitcher == input$pitcher_select) %>%
782
+ filter(!is.na(HorzBreak), !is.na(InducedVertBreak), !is.na(TaggedPitchType)) %>%
783
+ mutate(
784
+ pitch_group = case_when(
785
+ TaggedPitchType %in% c("Fastball", "FourSeamFastBall", "FourSeamFastB", "Four-Seam", "4-Seam") ~ "Fastball",
786
+ TaggedPitchType %in% c("OneSeamFastBall", "TwoSeamFastBall", "Sinker", "Two-Seam", "One-Seam") ~ "Sinker",
787
+ TaggedPitchType %in% c("ChangeUp", "Changeup") ~ "Changeup",
788
+ TRUE ~ TaggedPitchType
789
+ ),
790
+ # Create necessary indicator variables if they don't exist
791
+ in_zone = ifelse("StrikeZoneIndicator" %in% names(.), StrikeZoneIndicator,
792
+ ifelse(!is.na(PlateLocSide) & !is.na(PlateLocHeight) &
793
+ PlateLocSide >= -0.95 & PlateLocSide <= 0.95 &
794
+ PlateLocHeight >= 1.6 & PlateLocHeight <= 3.5, 1, 0)),
795
+ is_whiff = ifelse("WhiffIndicator" %in% names(.), WhiffIndicator,
796
+ ifelse(!is.na(PitchCall) & PitchCall == "StrikeSwinging", 1, 0)),
797
+ chase = ifelse("Chaseindicator" %in% names(.), Chaseindicator,
798
+ ifelse(!is.na(PitchCall) & !is.na(PlateLocSide) & !is.na(PlateLocHeight) &
799
+ PitchCall %in% c("StrikeSwinging", "FoulBallNotFieldable", "FoulBall", "InPlay") &
800
+ (PlateLocSide < -0.95 | PlateLocSide > 0.95 | PlateLocHeight < 1.6 | PlateLocHeight > 3.5), 1, 0))
801
+ )
802
+
803
+ # Calculate total pitches for usage percentage
804
+ total_pitches <- nrow(movement_stats)
805
+
806
+ summary_stats <- movement_stats %>%
807
+ group_by(`Pitch Type` = pitch_group) %>%
808
+ summarise(
809
+ Count = n(),
810
+ `Usage%` = sprintf("%.1f%%", (n() / total_pitches) * 100),
811
+ `Ext.` = ifelse("Extension" %in% names(movement_stats),
812
+ sprintf("%.1f", mean(Extension, na.rm = TRUE)),
813
+ ""),
814
+ `Avg Velo` = sprintf("%.1f mph", mean(RelSpeed, na.rm = TRUE)),
815
+ `90th Velo` = sprintf("%.1f mph", quantile(RelSpeed, 0.9, na.rm = TRUE)),
816
+ `Max Velo` = sprintf("%.1f mph", max(RelSpeed, na.rm = TRUE)),
817
+ `Avg IVB` = sprintf("%.1f in", mean(InducedVertBreak, na.rm = TRUE)),
818
+ `Avg HB` = sprintf("%.1f in", mean(HorzBreak, na.rm = TRUE)),
819
+ `Avg Spin` = ifelse("SpinRate" %in% names(movement_stats),
820
+ sprintf("%.0f rpm", mean(SpinRate, na.rm = TRUE)),
821
+ ""),
822
+ `Rel Height` = ifelse("RelHeight" %in% names(movement_stats),
823
+ sprintf("%.1f", mean(RelHeight, na.rm = TRUE)),
824
+ "—"),
825
+ `Zone%` = sprintf("%.1f%%", round(mean(in_zone, na.rm = TRUE) * 100, 1)),
826
+ `Whiff%` = sprintf("%.1f%%", round(mean(is_whiff, na.rm = TRUE) * 100, 1)),
827
+ `Chase%` = sprintf("%.1f%%", round(mean(chase, na.rm = TRUE) * 100, 1)),
828
+ .groups = "drop"
829
+ ) %>%
830
+ arrange(desc(Count))
831
+
832
+ DT::datatable(summary_stats,
833
+ options = list(pageLength = 15, dom = 't', scrollX = TRUE),
834
+ rownames = FALSE) %>%
835
+ DT::formatStyle(columns = names(summary_stats), fontSize = '12px')
836
+ })
837
 
838
  output$selected_pitch_info <- renderText({
839
  pitch_info <- selected_pitch()