igroffman commited on
Commit
c44030f
·
verified ·
1 Parent(s): 2540ee6

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +114 -4
app.R CHANGED
@@ -1631,6 +1631,98 @@ create_pitcher_release_plot <- function(game_data, pitch_colors) {
1631
  theme(legend.position = "none")
1632
  }
1633
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1634
  create_pitcher_pdf <- function(game_df, pitcher_name, output_file, pitch_colors) {
1635
  ensure_cols <- function(df, cols) {
1636
  if (is.null(df)) df <- data.frame()
@@ -3091,6 +3183,15 @@ create_advanced_pitcher_pdf <- function(game_df, pitcher_name, output_file) {
3091
  create_count_usage_plot(pitcher_df, pitcher_name, pitch_colors),
3092
  error = function(e) ggplot2::ggplot() + ggplot2::theme_void() + ggplot2::ggtitle("Count Usage Error")
3093
  )
 
 
 
 
 
 
 
 
 
3094
 
3095
  # Start PDF
3096
  pdf(output_file, width = 11, height = 14)
@@ -3155,21 +3256,30 @@ create_advanced_pitcher_pdf <- function(game_df, pitcher_name, output_file) {
3155
  gp = grid::gpar(cex = 0.62))
3156
  }
3157
 
3158
- # Movement plot
3159
  grid::pushViewport(grid::viewport(x = 0.25, y = charts_y_top, width = 0.45, height = charts_height, just = c("center","top")))
3160
  tryCatch(print(movement_plot, newpage = FALSE), error = function(e) NULL)
3161
  grid::popViewport()
3162
 
3163
- # Velocity plot
3164
  grid::pushViewport(grid::viewport(x = 0.75, y = charts_y_top, width = 0.45, height = charts_height, just = c("center","top")))
3165
  tryCatch(print(velo_plot, newpage = FALSE), error = function(e) NULL)
3166
  grid::popViewport()
3167
 
3168
- # Count plot
3169
- grid::pushViewport(grid::viewport(x = 0.5, y = count_y_top, width = 0.92, height = count_height, just = c("center","top")))
 
3170
  tryCatch(print(count_plot, newpage = FALSE), error = function(e) NULL)
3171
  grid::popViewport()
3172
 
 
 
 
 
 
 
 
 
 
 
3173
  # Pitch Characteristics table
3174
  grid::grid.text("Pitch Characteristics", x = 0.5, y = y_top_char + 0.015,
3175
  gp = grid::gpar(fontface = "bold", cex = 1.1, col = "#006F71"))
 
1631
  theme(legend.position = "none")
1632
  }
1633
 
1634
+ create_extension_height_plot <- function(data, player_name, pitch_colors) {
1635
+ data <- normalize_columns(data)
1636
+
1637
+ pitcher_data <- data %>%
1638
+ filter(Pitcher == player_name,
1639
+ !is.na(TaggedPitchType),
1640
+ TaggedPitchType != "Other",
1641
+ !is.na(Extension),
1642
+ !is.na(RelHeight))
1643
+
1644
+ if (nrow(pitcher_data) == 0) {
1645
+ return(ggplot() + theme_void() + ggtitle("Extension vs Release Height") +
1646
+ theme(plot.title = element_text(size = 12, face = "bold", hjust = 0.5)))
1647
+ }
1648
+
1649
+ avg_release <- pitcher_data %>%
1650
+ group_by(TaggedPitchType) %>%
1651
+ summarise(
1652
+ Extension = mean(Extension, na.rm = TRUE),
1653
+ RelHeight = mean(RelHeight, na.rm = TRUE),
1654
+ .groups = "drop"
1655
+ )
1656
+
1657
+ ggplot(pitcher_data, aes(Extension, RelHeight)) +
1658
+ geom_point(aes(fill = TaggedPitchType),
1659
+ size = 4, shape = 21, color = "black", alpha = 0.85, stroke = 0.25) +
1660
+ geom_point(data = avg_release,
1661
+ aes(Extension, RelHeight, fill = TaggedPitchType),
1662
+ size = 4.5, shape = 21, color = "black", stroke = 0.3, alpha = 1) +
1663
+ annotate("text", x = 1, y = 8, label = "\u2190 2B", size = 3, hjust = 0) +
1664
+ annotate("text", x = 8, y = 8, label = "Home \u2192", size = 3, hjust = 1) +
1665
+ geom_rect(aes(xmin = 0, xmax = 2.7, ymin = 0, ymax = 0.83),
1666
+ fill = "#632b11", inherit.aes = FALSE) +
1667
+ geom_rect(aes(xmin = -0.5, xmax = 1, ymin = 0.8, ymax = 0.95),
1668
+ fill = "white", color = "black", linewidth = 0.4, inherit.aes = FALSE) +
1669
+ geom_vline(xintercept = 5.6, linetype = "dashed", linewidth = 0.4, color = "grey20") +
1670
+ geom_hline(yintercept = 5.8, linetype = "dashed", linewidth = 0.4, color = "grey20") +
1671
+ scale_fill_manual(values = pitch_colors, name = "Pitch Type") +
1672
+ coord_cartesian(xlim = c(1, 8), ylim = c(0, 8)) +
1673
+ labs(title = "Release Height + Extension (Dashed = SEC Avg)",
1674
+ x = "Extension (ft)", y = "Release Height (ft)") +
1675
+ theme_minimal() +
1676
+ theme(plot.title = element_text(hjust = 0.5, size = 10, face = "bold"),
1677
+ legend.position = "none")
1678
+ }
1679
+
1680
+ create_relside_height_plot <- function(data, player_name, pitch_colors) {
1681
+ data <- normalize_columns(data)
1682
+
1683
+ pitcher_data <- data %>%
1684
+ filter(Pitcher == player_name,
1685
+ !is.na(TaggedPitchType),
1686
+ TaggedPitchType != "Other",
1687
+ !is.na(RelSide),
1688
+ !is.na(RelHeight))
1689
+
1690
+ if (nrow(pitcher_data) == 0) {
1691
+ return(ggplot() + theme_void() + ggtitle("Release Side vs Release Height") +
1692
+ theme(plot.title = element_text(size = 12, face = "bold", hjust = 0.5)))
1693
+ }
1694
+
1695
+ avg_release <- pitcher_data %>%
1696
+ group_by(TaggedPitchType) %>%
1697
+ summarise(
1698
+ RelSide = mean(RelSide, na.rm = TRUE),
1699
+ RelHeight = mean(RelHeight, na.rm = TRUE),
1700
+ .groups = "drop"
1701
+ )
1702
+
1703
+ ggplot(pitcher_data, aes(RelSide, RelHeight)) +
1704
+ geom_point(aes(fill = TaggedPitchType),
1705
+ size = 4, shape = 21, color = "black", alpha = 0.85, stroke = 0.25) +
1706
+ geom_point(data = avg_release,
1707
+ aes(RelSide, RelHeight, fill = TaggedPitchType),
1708
+ size = 4.5, shape = 21, color = "black", stroke = 0.3, alpha = 1) +
1709
+ annotate("text", x = -4.7, y = 8, label = "\u2190 3B", size = 3, hjust = 0) +
1710
+ annotate("text", x = 4.7, y = 8, label = "1B \u2192", size = 3, hjust = 1) +
1711
+ geom_rect(aes(xmin = -3.5, xmax = 3.5, ymin = 0, ymax = 0.83),
1712
+ fill = "#632b11", inherit.aes = FALSE) +
1713
+ geom_rect(aes(xmin = -0.7, xmax = 0.7, ymin = 0.8, ymax = 0.95),
1714
+ fill = "white", color = "black", linewidth = 0.4, inherit.aes = FALSE) +
1715
+ geom_vline(xintercept = 1.9, linetype = "dashed", linewidth = 0.4, color = "grey20") +
1716
+ geom_hline(yintercept = 5.7, linetype = "dashed", linewidth = 0.4, color = "grey20") +
1717
+ scale_fill_manual(values = pitch_colors, name = "Pitch Type") +
1718
+ coord_cartesian(xlim = c(-5, 5), ylim = c(0, 8)) +
1719
+ labs(title = "Release Height + Release Side (Dashed = SEC Avg)",
1720
+ x = "Release Side (ft)", y = "Release Height (ft)") +
1721
+ theme_minimal() +
1722
+ theme(plot.title = element_text(hjust = 0.5, size = 10, face = "bold"),
1723
+ legend.position = "none")
1724
+ }
1725
+
1726
  create_pitcher_pdf <- function(game_df, pitcher_name, output_file, pitch_colors) {
1727
  ensure_cols <- function(df, cols) {
1728
  if (is.null(df)) df <- data.frame()
 
3183
  create_count_usage_plot(pitcher_df, pitcher_name, pitch_colors),
3184
  error = function(e) ggplot2::ggplot() + ggplot2::theme_void() + ggplot2::ggtitle("Count Usage Error")
3185
  )
3186
+ extension_height_plot <- tryCatch(
3187
+ create_extension_height_plot(pitcher_df, pitcher_name, pitch_colors),
3188
+ error = function(e) ggplot2::ggplot() + ggplot2::theme_void() + ggplot2::ggtitle("Extension/Height Error")
3189
+ )
3190
+
3191
+ relside_height_plot <- tryCatch(
3192
+ create_relside_height_plot(pitcher_df, pitcher_name, pitch_colors),
3193
+ error = function(e) ggplot2::ggplot() + ggplot2::theme_void() + ggplot2::ggtitle("RelSide/Height Error")
3194
+ )
3195
 
3196
  # Start PDF
3197
  pdf(output_file, width = 11, height = 14)
 
3256
  gp = grid::gpar(cex = 0.62))
3257
  }
3258
 
 
3259
  grid::pushViewport(grid::viewport(x = 0.25, y = charts_y_top, width = 0.45, height = charts_height, just = c("center","top")))
3260
  tryCatch(print(movement_plot, newpage = FALSE), error = function(e) NULL)
3261
  grid::popViewport()
3262
 
 
3263
  grid::pushViewport(grid::viewport(x = 0.75, y = charts_y_top, width = 0.45, height = charts_height, just = c("center","top")))
3264
  tryCatch(print(velo_plot, newpage = FALSE), error = function(e) NULL)
3265
  grid::popViewport()
3266
 
3267
+ # Row 2: Count plot (left) | Release charts stacked (right)
3268
+ # Count plot - moved to left side, narrower
3269
+ grid::pushViewport(grid::viewport(x = 0.27, y = count_y_top, width = 0.50, height = count_height, just = c("center","top")))
3270
  tryCatch(print(count_plot, newpage = FALSE), error = function(e) NULL)
3271
  grid::popViewport()
3272
 
3273
+ # Extension vs Height (top right of row 2)
3274
+ grid::pushViewport(grid::viewport(x = 0.77, y = count_y_top, width = 0.42, height = count_height * 0.5, just = c("center","top")))
3275
+ tryCatch(print(extension_height_plot, newpage = FALSE), error = function(e) NULL)
3276
+ grid::popViewport()
3277
+
3278
+ # RelSide vs Height (bottom right of row 2)
3279
+ grid::pushViewport(grid::viewport(x = 0.77, y = count_y_top - count_height * 0.5, width = 0.42, height = count_height * 0.5, just = c("center","top")))
3280
+ tryCatch(print(relside_height_plot, newpage = FALSE), error = function(e) NULL)
3281
+ grid::popViewport()
3282
+
3283
  # Pitch Characteristics table
3284
  grid::grid.text("Pitch Characteristics", x = 0.5, y = y_top_char + 0.015,
3285
  gp = grid::gpar(fontface = "bold", cex = 1.1, col = "#006F71"))