TimStats commited on
Commit
40ad80b
·
verified ·
1 Parent(s): 0c60ca1

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +209 -204
app.R CHANGED
@@ -1,4 +1,3 @@
1
- # Load required libraries
2
  library(shiny)
3
  library(plotly)
4
  library(gridlayout)
@@ -19,27 +18,9 @@ library(grid)
19
  library(gridExtra)
20
  library(png)
21
  library(xgboost)
22
- library(httr)
23
- library(magick)
24
-
25
  pdf(file = NULL)
26
  Sys.setenv(TZ='EST')
27
 
28
- # Helper functions
29
- download_and_process_image <- function(url) {
30
- tryCatch({
31
- temp_file <- tempfile(fileext = ".jpg")
32
- download.file(url, temp_file, mode = "wb")
33
- img <- image_read(temp_file)
34
- png_file <- tempfile(fileext = ".png")
35
- image_write(img, path = png_file, format = "png")
36
- return(png_file)
37
- }, error = function(e) {
38
- warning(paste("Error processing image:", e$message))
39
- return(NULL)
40
- })
41
- }
42
-
43
  is_barrel <- function(df) {
44
  df$barrel <- with(df, ifelse(hit_angle <= 50 & hit_speed >= 97 & hit_speed * 1.5 -
45
  hit_angle >= 117 & hit_speed + hit_angle >= 123, 1, 0))
@@ -47,7 +28,7 @@ is_barrel <- function(df) {
47
  }
48
 
49
  VAA <- function(milbtotal){
50
- milbtotal <- milbtotal %>%
51
  mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
52
  ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi))
53
  }
@@ -56,9 +37,9 @@ pitcher_summary <- function(game_pk,date){
56
  gdate <- as.Date.character(date)
57
  gdate <- as.Date(gdate)
58
  tmilb <- mlb_pbp(game_pk)
59
- tmilb <- tmilb %>%
60
  filter(type == "pitch")
61
- tmilb <- tmilb %>%
62
  select(matchup.batter.fullName,matchup.batter.id,matchup.pitcher.fullName,
63
  matchup.pitcher.id,result.event,details.description,details.type.description,
64
  result.description,pitchData.startSpeed,pitchData.plateTime,pitchData.zone,
@@ -77,10 +58,10 @@ pitcher_summary <- function(game_pk,date){
77
  "IVB","HB","hit_speed","hit_angle","hit_distance","inPlay",
78
  "lastPitch","spinDirection","phand")
79
  tmilb <- is_barrel(tmilb)
80
- tmilb <- tmilb %>%
81
  mutate(is_strike_swinging = ifelse(description == "Swinging Strike" |
82
  description == "Foul Tip",TRUE,FALSE))
83
- tmilb <- tmilb %>%
84
  mutate(date = gdate)
85
  return(tmilb)
86
  }
@@ -123,46 +104,69 @@ pitch_plot <- function(game){
123
  axis.ticks.y=element_blank())
124
  }
125
 
126
- # Load models
127
- FB <- xgb.load('FB.model')
128
- Off <- xgb.load('Off.model')
129
- Break <- xgb.load('Break.model')
130
 
131
- calculate_VAA <- function(vz0, ay, az, vy0, y0) {
132
- -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
133
- ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi)
 
134
  }
135
 
 
136
  calculate_EAA <- function(extension) {
137
  extension / 6.3
138
  }
139
 
 
140
  calculate_SADiff <- function(pfxX, pfxZ, spinDirection) {
 
141
  inSA <- atan2(pfxZ, pfxX) * 180/pi + 90
 
 
142
  inSA <- ifelse(inSA < 0, inSA + 360, inSA)
 
 
143
  SADiff <- spinDirection - inSA
 
 
144
  SADiff <- ifelse(SADiff > 180, SADiff - 360, SADiff)
145
  SADiff <- ifelse(SADiff < -180, SADiff + 360, SADiff)
 
146
  return(SADiff)
147
  }
148
 
 
149
  scale_TimStuff <- function(raw_score, model_mean, model_sd) {
150
  scaled_score <- (raw_score - model_mean) / model_sd
151
  result <- 50 - (scaled_score * 10)
 
 
 
 
 
 
 
 
 
 
 
152
  return(result)
153
  }
154
-
 
 
 
155
  summary_table <- function(game) {
156
  rows <- nrow(game)
157
- sumtable <- game %>%
158
  mutate(
159
- VAA = calculate_VAA(vz0, ay,az, vy0, y0),
160
  EAA = calculate_EAA(extension),
161
  SADiff = calculate_SADiff(pfxX, pfxZ,spinDirection)
162
- ) %>%
163
  mutate(team_fielding_id = ifelse(description == "Called Strike" |
164
  description == "Swinging Strike" |
165
- description == "Swinging Strike (Blocked)", 1, 0)) %>%
166
  mutate(swing = ifelse(description == "Foul" |
167
  description == "Foul Pitchout" |
168
  description == "In play, no out" |
@@ -170,10 +174,10 @@ summary_table <- function(game) {
170
  description == "In play, run(s)" |
171
  description == "Swinging Strike" |
172
  description == "swinging Strike (Blocked)" |
173
- description == "Foul Tip", 1, 0)) %>%
174
- mutate(is_strike_swinging = ifelse(is_strike_swinging == TRUE, 1, 0)) %>%
175
- mutate(Pitch = pitch_name) %>%
176
- rowwise() %>%
177
  mutate(TimStuff = if (phand == 'L') {
178
  case_when(
179
  Pitch %in% c("Four-Seam Fastball", "Sinker", "Cutter", "Fastball") ~
@@ -212,8 +216,8 @@ summary_table <- function(game) {
212
  -0.004822031, 0.007912765)),
213
  TRUE ~ NA_real_
214
  )
215
- }) %>%
216
- group_by(Pitch) %>%
217
  summarize(
218
  Pitches = n(),
219
  'Pitch%' = round(sum(Pitches)/sum(rows) * 100, digits = 1),
@@ -223,34 +227,39 @@ summary_table <- function(game) {
223
  'IVB' = round(mean(IVB, na.rm = TRUE), digits = 1),
224
  'HB' = round(mean(HB, na.rm = TRUE), digits = 1),
225
  'VAA' = round(mean(VAA, na.rm = TRUE), digits = 1),
 
 
 
 
226
  'CSW%' = round(sum(team_fielding_id, na.rm = TRUE) / sum(!is.na(team_fielding_id)) * 100, digits = 1),
227
  'Whiff%' = round(sum(is_strike_swinging, na.rm = TRUE) / sum(swing, na.rm = TRUE) * 100, digits = 1),
228
  'TimStuff' = round(mean(TimStuff, na.rm = TRUE), digits = 0)
229
- ) %>%
230
  arrange(-Pitches)
231
 
232
  return(sumtable)
233
  }
234
 
235
- # Initialize schedule data
 
236
  mlbid <- mlb_schedule(season = 2024, level_ids = "1")
237
- mlbteamH <- mlbid %>%
238
  select(teams_home_team_name)
239
  mlbteamH <- distinct(mlbteamH)
240
- mlbteamA <- mlbid %>%
241
  select(teams_away_team_name)
242
  mlbteamA <- distinct(mlbteamA)
243
 
244
  aaaid <- mlb_schedule(season = 2024, level_ids = "11")
245
- aaateamH <- aaaid %>%
246
  select(teams_home_team_name)
247
  aaateamH <- distinct(aaateamH)
248
- aaateamA <- aaaid %>%
249
  select(teams_away_team_name)
250
  aaateamA <- distinct(aaateamA)
251
 
252
  fslid <- mlb_schedule(season = 2024, level_ids = "14")
253
- fslid <- fslid %>%
254
  filter(teams_home_team_name == "Daytona Tortugas" |
255
  teams_home_team_name == "Jupiter Hammerheads" |
256
  teams_home_team_name == "Palm Beach Cardinals" |
@@ -261,22 +270,21 @@ fslid <- fslid %>%
261
  teams_home_team_name == "Fort Myers Mighty Mussels" |
262
  teams_home_team_name == "Lakeland Flying Tigers" |
263
  teams_home_team_name == "Tampa Tarpons")
264
- fslteamH <- fslid %>%
265
  select(teams_home_team_name)
266
  fslteamH <- distinct(fslteamH)
267
- fslteamA <- fslid %>%
268
  select(teams_away_team_name)
269
  fslteamA <- distinct(fslteamA)
270
 
271
  sbid <- mlb_schedule(season = 2024, level_ids = "22")
272
- sbteamH <- sbid %>%
273
  select(teams_home_team_name)
274
  sbteamH <- distinct(sbteamH)
275
- sbteamA <- sbid %>%
276
  select(teams_away_team_name)
277
  sbteamA <- distinct(sbteamA)
278
 
279
- # UI Definition
280
  ui <- fluidPage(
281
  tags$head(
282
  tags$style(HTML("
@@ -301,6 +309,7 @@ ui <- fluidPage(
301
  actionButton("update", "Find Pitcher", icon("magnifying-glass"),
302
  style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
303
  selectizeInput("pitcher", "Pitcher Name:", c(" ")),
 
304
  textInput("title", "Card Title"),
305
  actionButton("update1", "Make Card", icon("plus"),
306
  style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
@@ -311,6 +320,7 @@ ui <- fluidPage(
311
  )
312
  )
313
  )
 
314
  server <- function(input, output, session) {
315
  observeEvent(input$level, {
316
  if(input$level == "AAA"){
@@ -332,162 +342,156 @@ server <- function(input, output, session) {
332
  })
333
 
334
  observeEvent(input$update, {
335
- tryCatch({
336
- if(input$level == "AAA"){
337
- pname <- aaaid %>%
338
- filter(date == input$date) %>%
339
- filter(teams_home_team_name == input$homeT) %>%
340
- filter(teams_away_team_name == input$awayT) %>%
341
- filter(game_number == input$gamenum)
342
- pname <- pitcher_summary(pname[,6],input$date)
343
- }
344
- if(input$level == "FSL"){
345
- pname <- fslid %>%
346
- filter(date == input$date) %>%
347
- filter(teams_home_team_name == input$homeT) %>%
348
- filter(teams_away_team_name == input$awayT) %>%
349
- filter(game_number == input$gamenum)
350
- pname <- pitcher_summary(pname[,6],input$date)
351
- }
352
- if(input$level == "MLB"){
353
- pname <- mlbid %>%
354
- filter(date == as.character.Date(input$date)) %>%
355
- filter(teams_home_team_name == input$homeT) %>%
356
- filter(teams_away_team_name == input$awayT) %>%
357
- filter(game_number == input$gamenum)
358
- pname <- pitcher_summary(pname[,6],input$date)
359
- }
360
- if(input$level == "College (Statcast Parks Only)"){
361
- pname <- sbid %>%
362
- filter(date == input$date) %>%
363
- filter(teams_home_team_name == input$homeT) %>%
364
- filter(teams_away_team_name == input$awayT) %>%
365
- filter(game_number == input$gamenum)
366
- pname <- pitcher_summary(pname[,6],input$date)
367
- }
368
-
369
- if(nrow(pname) == 0) {
370
- showNotification("No pitchers found for the selected game.", type = "warning")
371
- } else {
372
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
373
- }
374
- }, error = function(e) {
375
- showNotification(paste("Error finding pitchers:", e$message), type = "error")
376
- })
377
  })
378
 
379
  combinedPlot <- reactiveVal()
380
  observeEvent(input$update1, {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  tryCatch({
382
- if(input$level == "MLB"){
383
- id <- mlbid %>%
384
- filter(date == as.character.Date(input$date)) %>%
385
- filter(teams_home_team_name == input$homeT) %>%
386
- filter(teams_away_team_name == input$awayT) %>%
387
- filter(game_number == input$gamenum)
388
- game <- pitcher_summary(id[,6],input$date)
389
- game <- game %>%
390
- filter(`Pitcher Name` == input$pitcher)
391
- id <- as.character(game[1,4])
392
- }
393
- if(input$level == "FSL"){
394
- id <- fslid %>%
395
- filter(date == as.character.Date(input$date)) %>%
396
- filter(teams_home_team_name == input$homeT) %>%
397
- filter(teams_away_team_name == input$awayT) %>%
398
- filter(game_number == input$gamenum)
399
- game <- pitcher_summary(id[,6],input$date)
400
- game <- game %>%
401
- filter(`Pitcher Name` == input$pitcher)
402
- id <- as.character(game[1,4])
403
- }
404
- if(input$level == "AAA"){
405
- id <- aaaid %>%
406
- filter(date == as.character.Date(input$date)) %>%
407
- filter(teams_home_team_name == input$homeT) %>%
408
- filter(teams_away_team_name == input$awayT) %>%
409
- filter(game_number == input$gamenum)
410
- game <- pitcher_summary(id[,6],input$date)
411
- game <- game %>%
412
- filter(`Pitcher Name` == input$pitcher)
413
- id <- as.character(game[1,4])
414
- }
415
- if(input$level == "College (Statcast Parks Only)"){
416
- id <- sbid %>%
417
- filter(date == as.character.Date(input$date)) %>%
418
- filter(teams_home_team_name == input$homeT) %>%
419
- filter(teams_away_team_name == input$awayT) %>%
420
- filter(game_number == input$gamenum)
421
- game <- pitcher_summary(id[,6],input$date)
422
- game <- game %>%
423
- filter(`Pitcher Name` == input$pitcher)
424
- id <- as.character(game[1,4])
425
- }
426
-
427
- if(nrow(game) == 0) {
428
- showNotification("No data available for the selected pitcher.", type = "warning")
429
- return()
430
- }
431
-
432
- break_plot <- break_plot(game)
433
- pitch_plot <- pitch_plot(game)
434
-
435
- table_plot <- tableGrob(summary_table(game), theme = ttheme_default(
436
- core = list(fg_params = list(cex = 1.7)),
437
- colhead = list(fg_params = list(cex = 1.2)),
438
- rowhead = list(fg_params = list(cex = 2.5))))
439
- table_plot$widths[[1]] <- unit(0, "cm")
440
-
441
- text_grobs <- which(sapply(table_plot$grobs, function(g) {
442
- g$name == "core-fg-1" && inherits(g$children[[1]], "text")
443
- }))
444
-
445
- for (i in text_grobs) {
446
- text <- table_plot$grobs[[i]]$children[[1]]$label
447
- table_plot$grobs[[i]]$children[[1]]$label <- sub("^\\d+\\s*", "", text)
448
- }
449
-
450
- grid.newpage()
451
- grid.draw(table_plot)
452
-
453
- mlb_url <- paste0("https://midfield.mlbstatic.com/v1/people/", id, "/mlb/300?circle=false")
454
- milb_url <- paste0("https://midfield.mlbstatic.com/v1/people/", id, "/milb/300?circle=false")
455
-
456
- img_file <- tryCatch({
457
- download_and_process_image(mlb_url)
458
  }, error = function(e) {
459
- NULL
 
460
  })
461
-
462
- if (is.null(img_file)) {
463
- img_file <- tryCatch({
464
- download_and_process_image(milb_url)
465
- }, error = function(e) {
466
- NULL
467
- })
468
- }
469
-
470
- if (!is.null(img_file)) {
471
- img <- readPNG(img_file)
472
- img_grob <- rasterGrob(img, interpolate = TRUE)
473
- } else {
474
- img_grob <- textGrob("Image not available", gp = gpar(col = "red", fontsize = 20))
475
- }
476
-
477
- combined <- grid.arrange(
478
- arrangeGrob(table_plot, img_grob, ncol = 2, widths = c(2/3, 1/3)),
479
- arrangeGrob(break_plot, pitch_plot, ncol = 2),
480
- nrow = 2,
481
- top = textGrob(paste(input$title, "Made by @TimStats", sep = " "), gp = gpar(fontsize = 20, font = 2))
482
- )
483
-
484
- combinedPlot(combined)
485
-
486
- output$combinedPlot <- renderPlot({
487
- grid.draw(combinedPlot())
488
- })
489
- }, error = function(e) {
490
- showNotification(paste("Error generating card:", e$message), type = "error")
491
  })
492
  })
493
 
@@ -496,9 +500,10 @@ server <- function(input, output, session) {
496
  paste("baseball_card_", Sys.Date(), ".png", sep = "")
497
  },
498
  content = function(file) {
499
- ggsave(file, plot = combinedPlot(), width = 18, height = 12, dpi = 300)
500
  }
501
  )
502
  }
503
 
 
504
  shinyApp(ui, server)
 
 
1
  library(shiny)
2
  library(plotly)
3
  library(gridlayout)
 
18
  library(gridExtra)
19
  library(png)
20
  library(xgboost)
 
 
 
21
  pdf(file = NULL)
22
  Sys.setenv(TZ='EST')
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  is_barrel <- function(df) {
25
  df$barrel <- with(df, ifelse(hit_angle <= 50 & hit_speed >= 97 & hit_speed * 1.5 -
26
  hit_angle >= 117 & hit_speed + hit_angle >= 123, 1, 0))
 
28
  }
29
 
30
  VAA <- function(milbtotal){
31
+ milbtotal <- milbtotal |>
32
  mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
33
  ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi))
34
  }
 
37
  gdate <- as.Date.character(date)
38
  gdate <- as.Date(gdate)
39
  tmilb <- mlb_pbp(game_pk)
40
+ tmilb <- tmilb |>
41
  filter(type == "pitch")
42
+ tmilb <- tmilb |>
43
  select(matchup.batter.fullName,matchup.batter.id,matchup.pitcher.fullName,
44
  matchup.pitcher.id,result.event,details.description,details.type.description,
45
  result.description,pitchData.startSpeed,pitchData.plateTime,pitchData.zone,
 
58
  "IVB","HB","hit_speed","hit_angle","hit_distance","inPlay",
59
  "lastPitch","spinDirection","phand")
60
  tmilb <- is_barrel(tmilb)
61
+ tmilb <- tmilb |>
62
  mutate(is_strike_swinging = ifelse(description == "Swinging Strike" |
63
  description == "Foul Tip",TRUE,FALSE))
64
+ tmilb <- tmilb |>
65
  mutate(date = gdate)
66
  return(tmilb)
67
  }
 
104
  axis.ticks.y=element_blank())
105
  }
106
 
107
+ # Assume FB.model, Off.model, and Break.model are already loaded in the environment
 
 
 
108
 
109
+ # Function to calculate VAA (Vertical Approach Angle)
110
+ calculate_VAA <- function(vz0, ay, vy0, y0) {
111
+ -atan((vz0 + (ay * (-sqrt((vy0*vy0) - (2*ay*(y0-(17/12)))) - vy0) / ay)) /
112
+ (-sqrt((vy0*vy0) - (2*ay*(y0-(17/12)))))) * (180/pi)
113
  }
114
 
115
+ # Function to calculate EAA (Effective Approach Angle)
116
  calculate_EAA <- function(extension) {
117
  extension / 6.3
118
  }
119
 
120
+ # Function to calculate SADiff (Spin Axis Differential)
121
  calculate_SADiff <- function(pfxX, pfxZ, spinDirection) {
122
+ # Calculate initial inSA
123
  inSA <- atan2(pfxZ, pfxX) * 180/pi + 90
124
+
125
+ # Adjust inSA if it's negative
126
  inSA <- ifelse(inSA < 0, inSA + 360, inSA)
127
+
128
+ # Calculate SADiff
129
  SADiff <- spinDirection - inSA
130
+
131
+ # Adjust SADiff to be within -180 to 180 range
132
  SADiff <- ifelse(SADiff > 180, SADiff - 360, SADiff)
133
  SADiff <- ifelse(SADiff < -180, SADiff + 360, SADiff)
134
+
135
  return(SADiff)
136
  }
137
 
138
+ # Function to scale TimStuff
139
  scale_TimStuff <- function(raw_score, model_mean, model_sd) {
140
  scaled_score <- (raw_score - model_mean) / model_sd
141
  result <- 50 - (scaled_score * 10)
142
+
143
+ # Add logging
144
+ # cat("Raw score:", raw_score, "\n")
145
+ # cat("Model mean:", model_mean, "\n")
146
+ # cat("Model SD:", model_sd, "\n")
147
+ # cat("Scaled score:", scaled_score, "\n")
148
+ # cat("Final result:", result, "\n")
149
+
150
+ # Ensure the result is within a reasonable range
151
+ # result <- max(min(result, 100), 0)
152
+
153
  return(result)
154
  }
155
+ FB <- xgb.load('FB.model')
156
+ Off <- xgb.load('Off.model')
157
+ Break <- xgb.load('Break.model')
158
+ # Modify the summary_table function
159
  summary_table <- function(game) {
160
  rows <- nrow(game)
161
+ sumtable <- game |>
162
  mutate(
163
+ VAA = calculate_VAA(vz0, ay, vy0, y0),
164
  EAA = calculate_EAA(extension),
165
  SADiff = calculate_SADiff(pfxX, pfxZ,spinDirection)
166
+ ) |>
167
  mutate(team_fielding_id = ifelse(description == "Called Strike" |
168
  description == "Swinging Strike" |
169
+ description == "Swinging Strike (Blocked)", 1, 0)) |>
170
  mutate(swing = ifelse(description == "Foul" |
171
  description == "Foul Pitchout" |
172
  description == "In play, no out" |
 
174
  description == "In play, run(s)" |
175
  description == "Swinging Strike" |
176
  description == "swinging Strike (Blocked)" |
177
+ description == "Foul Tip", 1, 0)) |>
178
+ mutate(is_strike_swinging = ifelse(is_strike_swinging == TRUE, 1, 0)) |>
179
+ mutate(Pitch = pitch_name) |>
180
+ rowwise() |>
181
  mutate(TimStuff = if (phand == 'L') {
182
  case_when(
183
  Pitch %in% c("Four-Seam Fastball", "Sinker", "Cutter", "Fastball") ~
 
216
  -0.004822031, 0.007912765)),
217
  TRUE ~ NA_real_
218
  )
219
+ }) |>
220
+ group_by(Pitch) |>
221
  summarize(
222
  Pitches = n(),
223
  'Pitch%' = round(sum(Pitches)/sum(rows) * 100, digits = 1),
 
227
  'IVB' = round(mean(IVB, na.rm = TRUE), digits = 1),
228
  'HB' = round(mean(HB, na.rm = TRUE), digits = 1),
229
  'VAA' = round(mean(VAA, na.rm = TRUE), digits = 1),
230
+ # 'EAA' = round(mean(EAA, na.rm = TRUE), digits = 2),
231
+ # 'x0' = round(mean(x0, na.rm = TRUE), digits = 2),
232
+ # 'z0' = round(mean(z0, na.rm = TRUE), digits = 2),
233
+ # 'SADiff' = round(mean(SADiff, na.rm = TRUE), digits = 2),
234
  'CSW%' = round(sum(team_fielding_id, na.rm = TRUE) / sum(!is.na(team_fielding_id)) * 100, digits = 1),
235
  'Whiff%' = round(sum(is_strike_swinging, na.rm = TRUE) / sum(swing, na.rm = TRUE) * 100, digits = 1),
236
  'TimStuff' = round(mean(TimStuff, na.rm = TRUE), digits = 0)
237
+ ) |>
238
  arrange(-Pitches)
239
 
240
  return(sumtable)
241
  }
242
 
243
+ # The rest of your code remains the same
244
+
245
  mlbid <- mlb_schedule(season = 2024, level_ids = "1")
246
+ mlbteamH <- mlbid |>
247
  select(teams_home_team_name)
248
  mlbteamH <- distinct(mlbteamH)
249
+ mlbteamA <- mlbid |>
250
  select(teams_away_team_name)
251
  mlbteamA <- distinct(mlbteamA)
252
 
253
  aaaid <- mlb_schedule(season = 2024, level_ids = "11")
254
+ aaateamH <- aaaid |>
255
  select(teams_home_team_name)
256
  aaateamH <- distinct(aaateamH)
257
+ aaateamA <- aaaid |>
258
  select(teams_away_team_name)
259
  aaateamA <- distinct(aaateamA)
260
 
261
  fslid <- mlb_schedule(season = 2024, level_ids = "14")
262
+ fslid <- fslid |>
263
  filter(teams_home_team_name == "Daytona Tortugas" |
264
  teams_home_team_name == "Jupiter Hammerheads" |
265
  teams_home_team_name == "Palm Beach Cardinals" |
 
270
  teams_home_team_name == "Fort Myers Mighty Mussels" |
271
  teams_home_team_name == "Lakeland Flying Tigers" |
272
  teams_home_team_name == "Tampa Tarpons")
273
+ fslteamH <- fslid |>
274
  select(teams_home_team_name)
275
  fslteamH <- distinct(fslteamH)
276
+ fslteamA <- fslid |>
277
  select(teams_away_team_name)
278
  fslteamA <- distinct(fslteamA)
279
 
280
  sbid <- mlb_schedule(season = 2024, level_ids = "22")
281
+ sbteamH <- sbid |>
282
  select(teams_home_team_name)
283
  sbteamH <- distinct(sbteamH)
284
+ sbteamA <- sbid |>
285
  select(teams_away_team_name)
286
  sbteamA <- distinct(sbteamA)
287
 
 
288
  ui <- fluidPage(
289
  tags$head(
290
  tags$style(HTML("
 
309
  actionButton("update", "Find Pitcher", icon("magnifying-glass"),
310
  style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
311
  selectizeInput("pitcher", "Pitcher Name:", c(" ")),
312
+ #selectizeInput("league", "MLB or MiLB Photo", c("MLB", "MiLB")),
313
  textInput("title", "Card Title"),
314
  actionButton("update1", "Make Card", icon("plus"),
315
  style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
 
320
  )
321
  )
322
  )
323
+
324
  server <- function(input, output, session) {
325
  observeEvent(input$level, {
326
  if(input$level == "AAA"){
 
342
  })
343
 
344
  observeEvent(input$update, {
345
+ if(input$level == "AAA"){
346
+ pname <- aaaid |>
347
+ filter(date == input$date) |>
348
+ filter(teams_home_team_name == input$homeT) |>
349
+ filter(teams_away_team_name == input$awayT) |>
350
+ filter(game_number == input$gamenum)
351
+ pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
352
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
353
+ }
354
+ if(input$level == "FSL"){
355
+ pname <- fslid |>
356
+ filter(date == input$date) |>
357
+ filter(teams_home_team_name == input$homeT) |>
358
+ filter(teams_away_team_name == input$awayT) |>
359
+ filter(game_number == input$gamenum)
360
+ pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
361
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
362
+ }
363
+ if(input$level == "MLB"){
364
+ pname <- mlbid |>
365
+ filter(date == as.character.Date(input$date)) |>
366
+ filter(teams_home_team_name == input$homeT) |>
367
+ filter(teams_away_team_name == input$awayT) |>
368
+ filter(game_number == input$gamenum)
369
+ pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
370
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
371
+ }
372
+ if(input$level == "College (Statcast Parks Only)"){
373
+ pname <- sbid |>
374
+ filter(date == input$date) |>
375
+ filter(teams_home_team_name == input$homeT) |>
376
+ filter(teams_away_team_name == input$awayT) |>
377
+ filter(game_number == input$gamenum)
378
+ pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
379
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
380
+ }
 
 
 
 
 
 
381
  })
382
 
383
  combinedPlot <- reactiveVal()
384
  observeEvent(input$update1, {
385
+ if(input$level == "MLB"){
386
+ id <- mlbid |>
387
+ filter(date == as.character.Date(input$date)) |>
388
+ filter(teams_home_team_name == input$homeT) |>
389
+ filter(teams_away_team_name == input$awayT) |>
390
+ filter(game_number == input$gamenum)
391
+ game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
392
+ game <- game |>
393
+ filter(`Pitcher Name` == input$pitcher)
394
+ id <- as.character(game[1,4])
395
+ }
396
+ if(input$level == "FSL"){
397
+ id <- fslid |>
398
+ filter(date == as.character.Date(input$date)) |>
399
+ filter(teams_home_team_name == input$homeT) |>
400
+ filter(teams_away_team_name == input$awayT) |>
401
+ filter(game_number == input$gamenum)
402
+ game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
403
+ game <- game |>
404
+ filter(`Pitcher Name` == input$pitcher)
405
+ id <- as.character(game[1,4])
406
+ }
407
+ if(input$level == "AAA"){
408
+ id <- aaaid |>
409
+ filter(date == as.character.Date(input$date)) |>
410
+ filter(teams_home_team_name == input$homeT) |>
411
+ filter(teams_away_team_name == input$awayT) |>
412
+ filter(game_number == input$gamenum)
413
+ game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
414
+ game <- game |>
415
+ filter(`Pitcher Name` == input$pitcher)
416
+ id <- as.character(game[1,4])
417
+ }
418
+ if(input$level == "College (Statcast Parks Only)"){
419
+ id <- sbid |>
420
+ filter(date == as.character.Date(input$date)) |>
421
+ filter(teams_home_team_name == input$homeT) |>
422
+ filter(teams_away_team_name == input$awayT) |>
423
+ filter(game_number == input$gamenum)
424
+ game <- tryCatch({pitcher_summary(id[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
425
+ game <- game |>
426
+ filter(`Pitcher Name` == input$pitcher)
427
+ id <- as.character(game[1,4])
428
+ }
429
+
430
+ break_plot <- break_plot(game)
431
+ pitch_plot <- pitch_plot(game)
432
+
433
+ # Create table plot
434
+ # Update the tableGrob in the observeEvent(input$update1, {...}) block
435
+ table_plot <- tableGrob(summary_table(game), theme = ttheme_default(
436
+ core = list(fg_params = list(cex = 1.7)),
437
+ colhead = list(fg_params = list(cex = 1.2)),
438
+ rowhead = list(fg_params = list(cex = 2.5))))
439
+ table_plot$widths[[1]] <- unit(0, "cm")
440
+
441
+ # Find the text grobs in the first column
442
+ text_grobs <- which(sapply(table_plot$grobs, function(g) {
443
+ g$name == "core-fg-1" && inherits(g$children[[1]], "text")
444
+ }))
445
+
446
+ # Remove the numbers from these text grobs
447
+ for (i in text_grobs) {
448
+ text <- table_plot$grobs[[i]]$children[[1]]$label
449
+ table_plot$grobs[[i]]$children[[1]]$label <- sub("^\\d+\\s*", "", text)
450
+ }
451
+
452
+ # Draw the modified table
453
+ grid.newpage()
454
+ grid.draw(table_plot)
455
+ # Download and process image
456
+ # if(input$league == "MLB"){
457
+ # y <- paste("https://midfield.mlbstatic.com/v1/people/","/mlb/300?circle=false",sep = id)
458
+ # } else {
459
+ # y <- paste("https://midfield.mlbstatic.com/v1/people/","/milb/300?circle=false",sep = id)
460
+ # }
461
  tryCatch({
462
+ # Try MLB URL first
463
+ y <- paste0("https://midfield.mlbstatic.com/v1/people/", id, "/mlb/300?circle=false")
464
+ # Attempt to use the URL (replace this with your actual usage code)
465
+ # For example: response <- httr::GET(y)
466
+ # If it succeeds, it will use this URL
467
+ }, error = function(e) {
468
+ # If MLB URL fails, try MiLB URL
469
+ tryCatch({
470
+ y <- paste0("https://midfield.mlbstatic.com/v1/people/", id, "/milb/300?circle=false")
471
+ # Attempt to use the MiLB URL
472
+ # For example: response <- httr::GET(y)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
473
  }, error = function(e) {
474
+ # If both fail, you can handle it here
475
+ stop("Both MLB and MiLB URLs failed")
476
  })
477
+ })
478
+ photo <- tempfile()
479
+ download.file(y, photo, mode = 'wb')
480
+ img <- readPNG(photo)
481
+ img_grob <- rasterGrob(img, interpolate = TRUE)
482
+
483
+ # Combine all elements into one plot
484
+ combined <- grid.arrange(
485
+ arrangeGrob(table_plot, img_grob, ncol = 2, widths = c(2/3, 1/3)),
486
+ arrangeGrob(break_plot, pitch_plot, ncol = 2),
487
+ nrow = 2,
488
+ top = textGrob(paste(input$title, "Made by @TimStats", sep = " "), gp = gpar(fontsize = 20, font = 2))
489
+ )
490
+
491
+ combinedPlot(combined)
492
+
493
+ output$combinedPlot <- renderPlot({
494
+ grid.draw(combinedPlot())
 
 
 
 
 
 
 
 
 
 
 
 
495
  })
496
  })
497
 
 
500
  paste("baseball_card_", Sys.Date(), ".png", sep = "")
501
  },
502
  content = function(file) {
503
+ ggsave(file, plot = combinedPlot(), width = 19, height = 12, dpi = 300)
504
  }
505
  )
506
  }
507
 
508
+
509
  shinyApp(ui, server)