Spaces:
Running
Running
Update app.R
Browse files
app.R
CHANGED
|
@@ -517,7 +517,6 @@ create_bp_pdf <- function(bp_data, batter_name, output_file) {
|
|
| 517 |
invisible(output_file)
|
| 518 |
}
|
| 519 |
|
| 520 |
-
|
| 521 |
parse_game_day <- function(df, tz = "America/New_York") {
|
| 522 |
stopifnot("Date" %in% names(df))
|
| 523 |
if (inherits(df$Date, "Date")) {
|
|
@@ -529,7 +528,6 @@ parse_game_day <- function(df, tz = "America/New_York") {
|
|
| 529 |
}
|
| 530 |
as.Date(df$Date[1])
|
| 531 |
}
|
| 532 |
-
|
| 533 |
create_at_bats_plot <- function(batter_data, player_name, game_key, pitch_colors,
|
| 534 |
max_lines_per_col = 16L) {
|
| 535 |
df <- dplyr::filter(batter_data, Batter == player_name)
|
|
@@ -629,7 +627,6 @@ plot_data <- df %>%
|
|
| 629 |
panel.spacing = grid::unit(8, "pt")
|
| 630 |
)
|
| 631 |
}
|
| 632 |
-
|
| 633 |
create_report_spray_chart <- function(game_data, player_name) {
|
| 634 |
spray_data <- game_data %>%
|
| 635 |
dplyr::filter(Batter == player_name) %>%
|
|
@@ -683,7 +680,6 @@ create_report_spray_chart <- function(game_data, player_name) {
|
|
| 683 |
plot.title = ggplot2::element_text(hjust = 0.5, size = 9, face = "bold")
|
| 684 |
)
|
| 685 |
}
|
| 686 |
-
|
| 687 |
create_report_contact_chart <- function(game_data, player_name) {
|
| 688 |
contact_data <- game_data %>%
|
| 689 |
filter(Batter == player_name) %>%
|
|
@@ -746,14 +742,12 @@ create_report_contact_chart <- function(game_data, player_name) {
|
|
| 746 |
legend.key.width = unit(0.3, "cm")
|
| 747 |
)
|
| 748 |
}
|
| 749 |
-
|
| 750 |
calculate_leaderboards <- function(df, team_meta_df = team_meta) {
|
| 751 |
|
| 752 |
format_name <- function(name) {
|
| 753 |
if (is.na(name)) return(name)
|
| 754 |
stringr::str_replace(name, "^\\s*(\\w+)\\s*,\\s*(\\w+)\\s*$", "\\2 \\1")
|
| 755 |
}
|
| 756 |
-
|
| 757 |
get_logo <- function(team_abbr) {
|
| 758 |
if (is.null(team_meta_df) || is.null(team_abbr) || is.na(team_abbr)) return("")
|
| 759 |
team_abbr <- trimws(as.character(team_abbr))
|
|
@@ -781,7 +775,6 @@ calculate_leaderboards <- function(df, team_meta_df = team_meta) {
|
|
| 781 |
# Game Info
|
| 782 |
stadium <- if ("Stadium" %in% names(df)) unique(na.omit(df$Stadium))[1] else "Unknown"
|
| 783 |
level <- if ("Level" %in% names(df)) unique(na.omit(df$Level))[1] else ""
|
| 784 |
-
|
| 785 |
league <- if ("League" %in% names(df)) unique(na.omit(df$League))[1] else ""
|
| 786 |
|
| 787 |
game_date <- if ("Date" %in% names(df)) {
|
|
@@ -806,7 +799,6 @@ game_date <- if ("Date" %in% names(df)) {
|
|
| 806 |
|
| 807 |
if (is.na(parsed)) "N/A" else format(parsed, "%m/%d/%Y")
|
| 808 |
} else "N/A"
|
| 809 |
-
|
| 810 |
# Calculate final score from RunsScored
|
| 811 |
teams <- unique(c(df$BatterTeam, df$PitcherTeam))
|
| 812 |
teams <- teams[!is.na(teams)]
|
|
@@ -882,7 +874,6 @@ game_date <- if ("Date" %in% names(df)) {
|
|
| 882 |
whiffs = top_whiffs
|
| 883 |
)
|
| 884 |
}
|
| 885 |
-
|
| 886 |
create_simple_header <- function(player_name, game_date, bio_data = NULL) {
|
| 887 |
if (!is.null(bio_data) && nrow(bio_data) > 0) {
|
| 888 |
player_bio <- bio_data %>% filter(Batter == player_name)
|
|
@@ -918,6 +909,21 @@ grid::textGrob(
|
|
| 918 |
)
|
| 919 |
}
|
| 920 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 921 |
create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NULL) {
|
| 922 |
if (length(dev.list()) > 0) { try(dev.off(), silent = TRUE) }
|
| 923 |
|
|
@@ -931,6 +937,9 @@ create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NU
|
|
| 931 |
game_day <- parse_game_day(batter_df, tz = "America/New_York")
|
| 932 |
game_key <- format(game_day, "%Y-%m-%d")
|
| 933 |
|
|
|
|
|
|
|
|
|
|
| 934 |
game_stats <- batter_df %>%
|
| 935 |
summarise(
|
| 936 |
PA = sum(PAindicator, na.rm = TRUE),
|
|
@@ -962,6 +971,8 @@ create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NU
|
|
| 962 |
spray_plot <- create_report_spray_chart(game_df, player_name)
|
| 963 |
contact_plot <- create_report_contact_chart(game_df, player_name)
|
| 964 |
|
|
|
|
|
|
|
| 965 |
pitch_log <- pitch_sequence %>%
|
| 966 |
filter(PitchCall == "InPlay") %>%
|
| 967 |
mutate(
|
|
@@ -969,11 +980,44 @@ create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NU
|
|
| 969 |
event = dplyr::case_when(
|
| 970 |
!is.na(PlayResult) & PlayResult != "Undefined" ~ PlayResult, TRUE ~ "Out"
|
| 971 |
),
|
| 972 |
-
|
|
|
|
|
|
|
| 973 |
Dist = ifelse(!is.na(Distance), round(Distance), NA),
|
| 974 |
-
Velo = round(RelSpeed, 1)
|
| 975 |
-
|
| 976 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 977 |
|
| 978 |
chart_y <- 0.36
|
| 979 |
chart_h <- 0.22
|
|
@@ -981,26 +1025,70 @@ create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NU
|
|
| 981 |
table_title_y <- 0.13
|
| 982 |
table_y <- 0.11
|
| 983 |
|
| 984 |
-
|
| 985 |
-
|
| 986 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 987 |
x_start <- 0.5 - sum(widths)/2
|
| 988 |
x_pos <- c(x_start, x_start + cumsum(widths[-length(widths)]))
|
|
|
|
|
|
|
| 989 |
for (i in seq_along(headers)) {
|
| 990 |
grid.rect(x = x_pos[i], y = y_top, width = widths[i]*0.985, height = row_height,
|
| 991 |
just = c("left","top"), gp = gpar(fill = "#006F71", col = "black", lwd = 0.4))
|
| 992 |
grid.text(headers[i], x = x_pos[i] + widths[i]*0.49, y = y_top - row_height*0.5,
|
| 993 |
gp = gpar(col = "white", cex = cex, fontface = "bold"))
|
| 994 |
}
|
|
|
|
|
|
|
| 995 |
for (r in seq_len(nrow(df))) {
|
| 996 |
y_row <- y_top - r*row_height
|
| 997 |
-
|
| 998 |
-
|
| 999 |
-
|
| 1000 |
-
|
| 1001 |
-
|
| 1002 |
-
|
| 1003 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1004 |
for (i in seq_along(row_vals)) {
|
| 1005 |
grid.rect(x = x_pos[i], y = y_row, width = widths[i]*0.985, height = row_height, just = c("left","top"),
|
| 1006 |
gp = gpar(fill = ifelse(r %% 2 == 0, "#f7f7f7", "white"), col = "grey80", lwd = 0.3))
|
|
@@ -1048,23 +1136,24 @@ create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NU
|
|
| 1048 |
print(contact_plot, newpage = FALSE)
|
| 1049 |
popViewport()
|
| 1050 |
|
| 1051 |
-
grid.text(paste(player_name, "-", game_key), x = 0.5, y = 0.13,
|
| 1052 |
gp = gpar(fontface = "bold", cex = 0.98))
|
| 1053 |
|
| 1054 |
rows_total <- nrow(pitch_log)
|
| 1055 |
max_rows_first <- floor((0.11 - 0.02) / 0.0130)
|
| 1056 |
rows_first <- min(rows_total, max_rows_first)
|
| 1057 |
if (rows_first > 0) {
|
| 1058 |
-
draw_pitch_table(pitch_log[1:rows_first, , drop = FALSE], y_top = 0.11, row_height = 0.0130,
|
|
|
|
| 1059 |
}
|
| 1060 |
next_row <- rows_first + 1
|
| 1061 |
if (next_row <= rows_total) {
|
| 1062 |
grid::grid.newpage()
|
| 1063 |
-
draw_pitch_table(pitch_log[next_row:rows_total, , drop = FALSE], y_top = 0.97, row_height = 0.0175,
|
|
|
|
| 1064 |
}
|
| 1065 |
}
|
| 1066 |
|
| 1067 |
-
|
| 1068 |
# ============================================================
|
| 1069 |
# PITCHER POST-GAME PDF (Tableau-style)
|
| 1070 |
# Fixes:
|
|
|
|
| 517 |
invisible(output_file)
|
| 518 |
}
|
| 519 |
|
|
|
|
| 520 |
parse_game_day <- function(df, tz = "America/New_York") {
|
| 521 |
stopifnot("Date" %in% names(df))
|
| 522 |
if (inherits(df$Date, "Date")) {
|
|
|
|
| 528 |
}
|
| 529 |
as.Date(df$Date[1])
|
| 530 |
}
|
|
|
|
| 531 |
create_at_bats_plot <- function(batter_data, player_name, game_key, pitch_colors,
|
| 532 |
max_lines_per_col = 16L) {
|
| 533 |
df <- dplyr::filter(batter_data, Batter == player_name)
|
|
|
|
| 627 |
panel.spacing = grid::unit(8, "pt")
|
| 628 |
)
|
| 629 |
}
|
|
|
|
| 630 |
create_report_spray_chart <- function(game_data, player_name) {
|
| 631 |
spray_data <- game_data %>%
|
| 632 |
dplyr::filter(Batter == player_name) %>%
|
|
|
|
| 680 |
plot.title = ggplot2::element_text(hjust = 0.5, size = 9, face = "bold")
|
| 681 |
)
|
| 682 |
}
|
|
|
|
| 683 |
create_report_contact_chart <- function(game_data, player_name) {
|
| 684 |
contact_data <- game_data %>%
|
| 685 |
filter(Batter == player_name) %>%
|
|
|
|
| 742 |
legend.key.width = unit(0.3, "cm")
|
| 743 |
)
|
| 744 |
}
|
|
|
|
| 745 |
calculate_leaderboards <- function(df, team_meta_df = team_meta) {
|
| 746 |
|
| 747 |
format_name <- function(name) {
|
| 748 |
if (is.na(name)) return(name)
|
| 749 |
stringr::str_replace(name, "^\\s*(\\w+)\\s*,\\s*(\\w+)\\s*$", "\\2 \\1")
|
| 750 |
}
|
|
|
|
| 751 |
get_logo <- function(team_abbr) {
|
| 752 |
if (is.null(team_meta_df) || is.null(team_abbr) || is.na(team_abbr)) return("")
|
| 753 |
team_abbr <- trimws(as.character(team_abbr))
|
|
|
|
| 775 |
# Game Info
|
| 776 |
stadium <- if ("Stadium" %in% names(df)) unique(na.omit(df$Stadium))[1] else "Unknown"
|
| 777 |
level <- if ("Level" %in% names(df)) unique(na.omit(df$Level))[1] else ""
|
|
|
|
| 778 |
league <- if ("League" %in% names(df)) unique(na.omit(df$League))[1] else ""
|
| 779 |
|
| 780 |
game_date <- if ("Date" %in% names(df)) {
|
|
|
|
| 799 |
|
| 800 |
if (is.na(parsed)) "N/A" else format(parsed, "%m/%d/%Y")
|
| 801 |
} else "N/A"
|
|
|
|
| 802 |
# Calculate final score from RunsScored
|
| 803 |
teams <- unique(c(df$BatterTeam, df$PitcherTeam))
|
| 804 |
teams <- teams[!is.na(teams)]
|
|
|
|
| 874 |
whiffs = top_whiffs
|
| 875 |
)
|
| 876 |
}
|
|
|
|
| 877 |
create_simple_header <- function(player_name, game_date, bio_data = NULL) {
|
| 878 |
if (!is.null(bio_data) && nrow(bio_data) > 0) {
|
| 879 |
player_bio <- bio_data %>% filter(Batter == player_name)
|
|
|
|
| 909 |
)
|
| 910 |
}
|
| 911 |
|
| 912 |
+
# Helper function to check if bat tracking data is available
|
| 913 |
+
has_bat_tracking <- function(df) {
|
| 914 |
+
bat_cols <- c("BatSpeed", "VerticalAttackAngle", "HorizontalAttackAngle")
|
| 915 |
+
cols_present <- bat_cols %in% names(df)
|
| 916 |
+
if (!all(cols_present)) return(FALSE)
|
| 917 |
+
|
| 918 |
+
# Check if there's at least some non-NA data in any of these columns
|
| 919 |
+
any_data <- any(
|
| 920 |
+
!is.na(df$BatSpeed) |
|
| 921 |
+
!is.na(df$VerticalAttackAngle) |
|
| 922 |
+
!is.na(df$HorizontalAttackAngle)
|
| 923 |
+
)
|
| 924 |
+
return(any_data)
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
create_postgame_pdf <- function(game_df, player_name, output_file, bio_data = NULL) {
|
| 928 |
if (length(dev.list()) > 0) { try(dev.off(), silent = TRUE) }
|
| 929 |
|
|
|
|
| 937 |
game_day <- parse_game_day(batter_df, tz = "America/New_York")
|
| 938 |
game_key <- format(game_day, "%Y-%m-%d")
|
| 939 |
|
| 940 |
+
# Check if bat tracking data is available
|
| 941 |
+
bat_tracking_available <- has_bat_tracking(batter_df)
|
| 942 |
+
|
| 943 |
game_stats <- batter_df %>%
|
| 944 |
summarise(
|
| 945 |
PA = sum(PAindicator, na.rm = TRUE),
|
|
|
|
| 971 |
spray_plot <- create_report_spray_chart(game_df, player_name)
|
| 972 |
contact_plot <- create_report_contact_chart(game_df, player_name)
|
| 973 |
|
| 974 |
+
# Build pitch log with conditional bat tracking columns
|
| 975 |
+
# New order: Inning, Pitcher, Count, Pitch, Velo, IVB, HB, VAA, EV, LA, Dist, Bat Speed, AA, HAA
|
| 976 |
pitch_log <- pitch_sequence %>%
|
| 977 |
filter(PitchCall == "InPlay") %>%
|
| 978 |
mutate(
|
|
|
|
| 980 |
event = dplyr::case_when(
|
| 981 |
!is.na(PlayResult) & PlayResult != "Undefined" ~ PlayResult, TRUE ~ "Out"
|
| 982 |
),
|
| 983 |
+
Count = paste0(Balls, "-", Strikes),
|
| 984 |
+
EV = round(ExitSpeed),
|
| 985 |
+
LA = round(Angle),
|
| 986 |
Dist = ifelse(!is.na(Distance), round(Distance), NA),
|
| 987 |
+
Velo = round(RelSpeed, 1),
|
| 988 |
+
# Pitch movement metrics
|
| 989 |
+
IVB = ifelse("InducedVertBreak" %in% names(.) & !is.na(InducedVertBreak),
|
| 990 |
+
round(InducedVertBreak, 1), NA),
|
| 991 |
+
HB = ifelse("HorzBreak" %in% names(.) & !is.na(HorzBreak),
|
| 992 |
+
round(HorzBreak, 1), NA),
|
| 993 |
+
# Vertical Approach Angle (pitch)
|
| 994 |
+
VAA = ifelse("VertApprAngle" %in% names(.) & !is.na(VertApprAngle),
|
| 995 |
+
round(VertApprAngle, 1), NA)
|
| 996 |
+
)
|
| 997 |
+
|
| 998 |
+
# Add bat tracking columns if available
|
| 999 |
+
if (bat_tracking_available) {
|
| 1000 |
+
pitch_log <- pitch_log %>%
|
| 1001 |
+
mutate(
|
| 1002 |
+
BatSpd = ifelse("BatSpeed" %in% names(.) & !is.na(BatSpeed),
|
| 1003 |
+
round(BatSpeed, 1), NA),
|
| 1004 |
+
AA = ifelse("VerticalAttackAngle" %in% names(.) & !is.na(VerticalAttackAngle),
|
| 1005 |
+
round(VerticalAttackAngle, 1), NA),
|
| 1006 |
+
HAA = ifelse("HorizontalAttackAngle" %in% names(.) & !is.na(HorizontalAttackAngle),
|
| 1007 |
+
round(HorizontalAttackAngle, 1), NA)
|
| 1008 |
+
)
|
| 1009 |
+
}
|
| 1010 |
+
|
| 1011 |
+
# Select columns based on availability
|
| 1012 |
+
if (bat_tracking_available) {
|
| 1013 |
+
pitch_log <- pitch_log %>%
|
| 1014 |
+
select(PitchNumber, Inning, Pitcher, Count, TaggedPitchType, Velo, IVB, HB, VAA,
|
| 1015 |
+
event, EV, LA, Dist, BatSpd, AA, HAA)
|
| 1016 |
+
} else {
|
| 1017 |
+
pitch_log <- pitch_log %>%
|
| 1018 |
+
select(PitchNumber, Inning, Pitcher, Count, TaggedPitchType, Velo, IVB, HB, VAA,
|
| 1019 |
+
event, EV, LA, Dist)
|
| 1020 |
+
}
|
| 1021 |
|
| 1022 |
chart_y <- 0.36
|
| 1023 |
chart_h <- 0.22
|
|
|
|
| 1025 |
table_title_y <- 0.13
|
| 1026 |
table_y <- 0.11
|
| 1027 |
|
| 1028 |
+
# Updated draw function with bat tracking support
|
| 1029 |
+
draw_pitch_table <- function(df, y_top, row_height = 0.0135, cex = 0.58, include_bat_tracking = FALSE) {
|
| 1030 |
+
if (include_bat_tracking) {
|
| 1031 |
+
# Headers with bat tracking: #, Inn, Pitcher, Count, Pitch, Velo, IVB, HB, VAA, Event, EV, LA, Dist, BatSpd, AA, HAA
|
| 1032 |
+
headers <- c("#", "Inn", "Pitcher", "Count", "Pitch", "Velo", "IVB", "HB", "VAA", "Event", "EV", "LA", "Dist", "BatSpd", "AA", "HAA")
|
| 1033 |
+
widths <- c(0.025, 0.03, 0.12, 0.04, 0.065, 0.04, 0.04, 0.04, 0.04, 0.065, 0.035, 0.035, 0.04, 0.045, 0.04, 0.04)
|
| 1034 |
+
} else {
|
| 1035 |
+
# Headers without bat tracking: #, Inn, Pitcher, Count, Pitch, Velo, IVB, HB, VAA, Event, EV, LA, Dist
|
| 1036 |
+
headers <- c("#", "Inn", "Pitcher", "Count", "Pitch", "Velo", "IVB", "HB", "VAA", "Event", "EV", "LA", "Dist")
|
| 1037 |
+
widths <- c(0.03, 0.035, 0.15, 0.05, 0.08, 0.05, 0.05, 0.05, 0.05, 0.08, 0.045, 0.045, 0.05)
|
| 1038 |
+
}
|
| 1039 |
+
|
| 1040 |
x_start <- 0.5 - sum(widths)/2
|
| 1041 |
x_pos <- c(x_start, x_start + cumsum(widths[-length(widths)]))
|
| 1042 |
+
|
| 1043 |
+
# Draw headers
|
| 1044 |
for (i in seq_along(headers)) {
|
| 1045 |
grid.rect(x = x_pos[i], y = y_top, width = widths[i]*0.985, height = row_height,
|
| 1046 |
just = c("left","top"), gp = gpar(fill = "#006F71", col = "black", lwd = 0.4))
|
| 1047 |
grid.text(headers[i], x = x_pos[i] + widths[i]*0.49, y = y_top - row_height*0.5,
|
| 1048 |
gp = gpar(col = "white", cex = cex, fontface = "bold"))
|
| 1049 |
}
|
| 1050 |
+
|
| 1051 |
+
# Draw rows
|
| 1052 |
for (r in seq_len(nrow(df))) {
|
| 1053 |
y_row <- y_top - r*row_height
|
| 1054 |
+
|
| 1055 |
+
if (include_bat_tracking) {
|
| 1056 |
+
row_vals <- c(
|
| 1057 |
+
df$PitchNumber[r],
|
| 1058 |
+
ifelse(is.na(df$Inning[r]), "-", df$Inning[r]),
|
| 1059 |
+
df$Pitcher[r],
|
| 1060 |
+
df$Count[r],
|
| 1061 |
+
df$TaggedPitchType[r],
|
| 1062 |
+
ifelse(is.na(df$Velo[r]), "-", df$Velo[r]),
|
| 1063 |
+
ifelse(is.na(df$IVB[r]), "-", df$IVB[r]),
|
| 1064 |
+
ifelse(is.na(df$HB[r]), "-", df$HB[r]),
|
| 1065 |
+
ifelse(is.na(df$VAA[r]), "-", df$VAA[r]),
|
| 1066 |
+
df$event[r],
|
| 1067 |
+
ifelse(is.na(df$EV[r]), "-", df$EV[r]),
|
| 1068 |
+
ifelse(is.na(df$LA[r]), "-", df$LA[r]),
|
| 1069 |
+
ifelse(is.na(df$Dist[r]), "-", df$Dist[r]),
|
| 1070 |
+
ifelse(is.na(df$BatSpd[r]), "-", df$BatSpd[r]),
|
| 1071 |
+
ifelse(is.na(df$AA[r]), "-", df$AA[r]),
|
| 1072 |
+
ifelse(is.na(df$HAA[r]), "-", df$HAA[r])
|
| 1073 |
+
)
|
| 1074 |
+
} else {
|
| 1075 |
+
row_vals <- c(
|
| 1076 |
+
df$PitchNumber[r],
|
| 1077 |
+
ifelse(is.na(df$Inning[r]), "-", df$Inning[r]),
|
| 1078 |
+
df$Pitcher[r],
|
| 1079 |
+
df$Count[r],
|
| 1080 |
+
df$TaggedPitchType[r],
|
| 1081 |
+
ifelse(is.na(df$Velo[r]), "-", df$Velo[r]),
|
| 1082 |
+
ifelse(is.na(df$IVB[r]), "-", df$IVB[r]),
|
| 1083 |
+
ifelse(is.na(df$HB[r]), "-", df$HB[r]),
|
| 1084 |
+
ifelse(is.na(df$VAA[r]), "-", df$VAA[r]),
|
| 1085 |
+
df$event[r],
|
| 1086 |
+
ifelse(is.na(df$EV[r]), "-", df$EV[r]),
|
| 1087 |
+
ifelse(is.na(df$LA[r]), "-", df$LA[r]),
|
| 1088 |
+
ifelse(is.na(df$Dist[r]), "-", df$Dist[r])
|
| 1089 |
+
)
|
| 1090 |
+
}
|
| 1091 |
+
|
| 1092 |
for (i in seq_along(row_vals)) {
|
| 1093 |
grid.rect(x = x_pos[i], y = y_row, width = widths[i]*0.985, height = row_height, just = c("left","top"),
|
| 1094 |
gp = gpar(fill = ifelse(r %% 2 == 0, "#f7f7f7", "white"), col = "grey80", lwd = 0.3))
|
|
|
|
| 1136 |
print(contact_plot, newpage = FALSE)
|
| 1137 |
popViewport()
|
| 1138 |
|
| 1139 |
+
grid.text(paste(player_name, "-", game_key, "- Batted Ball Log"), x = 0.5, y = 0.13,
|
| 1140 |
gp = gpar(fontface = "bold", cex = 0.98))
|
| 1141 |
|
| 1142 |
rows_total <- nrow(pitch_log)
|
| 1143 |
max_rows_first <- floor((0.11 - 0.02) / 0.0130)
|
| 1144 |
rows_first <- min(rows_total, max_rows_first)
|
| 1145 |
if (rows_first > 0) {
|
| 1146 |
+
draw_pitch_table(pitch_log[1:rows_first, , drop = FALSE], y_top = 0.11, row_height = 0.0130,
|
| 1147 |
+
cex = 0.52, include_bat_tracking = bat_tracking_available)
|
| 1148 |
}
|
| 1149 |
next_row <- rows_first + 1
|
| 1150 |
if (next_row <= rows_total) {
|
| 1151 |
grid::grid.newpage()
|
| 1152 |
+
draw_pitch_table(pitch_log[next_row:rows_total, , drop = FALSE], y_top = 0.97, row_height = 0.0175,
|
| 1153 |
+
cex = 0.56, include_bat_tracking = bat_tracking_available)
|
| 1154 |
}
|
| 1155 |
}
|
| 1156 |
|
|
|
|
| 1157 |
# ============================================================
|
| 1158 |
# PITCHER POST-GAME PDF (Tableau-style)
|
| 1159 |
# Fixes:
|