Spaces:
Running
Running
Update app.R
Browse files
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 |
-
|
|
|
|
| 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"))
|