TimStats commited on
Commit
a190191
·
verified ·
1 Parent(s): a83c190

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +168 -44
app.R CHANGED
@@ -17,6 +17,7 @@ library(utils)
17
  library(grid)
18
  library(gridExtra)
19
  library(png)
 
20
  pdf(file = NULL)
21
  Sys.setenv(TZ='EST')
22
 
@@ -41,20 +42,21 @@ pitcher_summary <- function(game_pk,date){
41
  tmilb <- tmilb |>
42
  select(matchup.batter.fullName,matchup.batter.id,matchup.pitcher.fullName,
43
  matchup.pitcher.id,result.event,details.description,details.type.description,
44
- result.description,pitchData.startSpeed,
45
- pitchData.plateTime,pitchData.zone,pitchData.breaks.spinRate,pitchData.extension,
46
- pitchData.coordinates.pX,pitchData.coordinates.pZ,pitchData.coordinates.x0,
47
- pitchData.coordinates.y0,pitchData.coordinates.z0,pitchData.coordinates.aX,
48
- pitchData.coordinates.aY,pitchData.coordinates.aZ,pitchData.coordinates.vX0,
49
- pitchData.coordinates.vZ0,pitchData.coordinates.vY0,pitchData.coordinates.pfxX,
50
- pitchData.coordinates.pfxZ,pitchData.breaks.breakVerticalInduced,pitchData.breaks.breakHorizontal,
51
- hitData.launchSpeed,hitData.launchAngle,hitData.totalDistance,details.isInPlay,last.pitch.of.ab)
 
52
  colnames(tmilb) <- c("Batter Name","Batter ID","Pitcher Name","Pitcher ID",
53
- "result","description","pitch_name",
54
- "des","start_speed","plateTime","zone","spin_rate",
55
- "extension","px","pz","x0","y0","z0","ax","ay","az",
56
- "vx0","vz0","vy0","pfxX","pfxZ","IVB","HB","hit_speed",
57
- "hit_angle","hit_distance","inPlay","lastPitch")
58
  tmilb <- is_barrel(tmilb)
59
  tmilb <- tmilb |>
60
  mutate(is_strike_swinging = ifelse(description == "Swinging Strike" |
@@ -102,14 +104,69 @@ pitch_plot <- function(game){
102
  axis.ticks.y=element_blank())
103
  }
104
 
105
- summary_table <- function(game){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  rows <- nrow(game)
107
  sumtable <- game |>
108
- mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
109
- ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi)) |>
 
 
 
110
  mutate(team_fielding_id = ifelse(description == "Called Strike" |
111
  description == "Swinging Strike" |
112
- description == "Swinging Strike (Blocked)",1,0))|>
113
  mutate(swing = ifelse(description == "Foul" |
114
  description == "Foul Pitchout" |
115
  description == "In play, no out" |
@@ -117,25 +174,74 @@ summary_table <- function(game){
117
  description == "In play, run(s)" |
118
  description == "Swinging Strike" |
119
  description == "swinging Strike (Blocked)" |
120
- description == "Foul Tip",1,0)) |>
121
- mutate(is_strike_swinging = ifelse(is_strike_swinging == TRUE,1,0)) |>
122
  mutate(Pitch = pitch_name) |>
123
- group_by(Pitch)|>
124
- summarize(Pitches = n(),
125
- 'Pitch%' = round(sum(Pitches)/sum(rows) * 100,digits = 1),
126
- 'Avg. Velo' = round(sum(start_speed)/Pitches,digits = 1),
127
- 'Spin Rate' = round(sum(spin_rate)/ Pitches,digits = 1),
128
- 'Extension' = round(mean(extension,na.rm = TRUE),digits = 1),
129
- 'IVB' = round(mean(IVB,na.rm=TRUE),digits = 1),
130
- 'HB' = round(mean(HB,na.rm = TRUE),digits = 1),
131
- 'VAA' = round(mean(VAA,na.rm= TRUE),digits = 1),
132
- 'CSW%' = round(sum(team_fielding_id)/
133
- sum(!is.na(team_fielding_id))*100,digits = 1),
134
- 'Whiff%' = round(sum(is_strike_swinging)/
135
- sum(swing)*100,digits = 1))|>
136
- arrange(-Pitches)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  }
138
 
 
 
139
  mlbid <- mlb_schedule(season = 2024, level_ids = "1")
140
  mlbteamH <- mlbid |>
141
  select(teams_home_team_name)
@@ -203,7 +309,7 @@ ui <- fluidPage(
203
  actionButton("update", "Find Pitcher", icon("magnifying-glass"),
204
  style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
205
  selectizeInput("pitcher", "Pitcher Name:", c(" ")),
206
- selectizeInput("league", "MLB or MiLB Photo", c("MLB", "MiLB")),
207
  textInput("title", "Card Title"),
208
  actionButton("update1", "Make Card", icon("plus"),
209
  style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
@@ -325,9 +431,10 @@ server <- function(input, output, session) {
325
  pitch_plot <- pitch_plot(game)
326
 
327
  # Create table plot
328
- table_plot <- tableGrob(summary_table(game),theme = ttheme_default(
329
- core = list(fg_params = list(cex = 1.5)), # Increase text size
330
- colhead = list(fg_params = list(cex = 1.5)),
 
331
  rowhead = list(fg_params = list(cex = 2.5))))
332
  table_plot$widths[[1]] <- unit(0, "cm")
333
 
@@ -346,11 +453,28 @@ server <- function(input, output, session) {
346
  grid.newpage()
347
  grid.draw(table_plot)
348
  # Download and process image
349
- if(input$league == "MLB"){
350
- y <- paste("https://midfield.mlbstatic.com/v1/people/","/mlb/300?circle=false",sep = id)
351
- } else {
352
- y <- paste("https://midfield.mlbstatic.com/v1/people/","/milb/300?circle=false",sep = id)
353
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
354
  photo <- tempfile()
355
  download.file(y, photo, mode = 'wb')
356
  img <- readPNG(photo)
@@ -376,10 +500,10 @@ server <- function(input, output, session) {
376
  paste("baseball_card_", Sys.Date(), ".png", sep = "")
377
  },
378
  content = function(file) {
379
- ggsave(file, plot = combinedPlot(), width = 18, height = 12, dpi = 300)
380
  }
381
  )
382
- }
383
 
384
 
385
  shinyApp(ui, server)
 
17
  library(grid)
18
  library(gridExtra)
19
  library(png)
20
+ library(xgboost)
21
  pdf(file = NULL)
22
  Sys.setenv(TZ='EST')
23
 
 
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,
46
+ pitchData.breaks.spinRate,pitchData.extension, pitchData.coordinates.pX,
47
+ pitchData.coordinates.pZ,pitchData.coordinates.x0, pitchData.coordinates.y0,
48
+ pitchData.coordinates.z0,pitchData.coordinates.aX,pitchData.coordinates.aY,
49
+ pitchData.coordinates.aZ,pitchData.coordinates.vX0,pitchData.coordinates.vZ0,
50
+ pitchData.coordinates.vY0,pitchData.coordinates.pfxX,pitchData.coordinates.pfxZ,
51
+ pitchData.breaks.breakVerticalInduced,pitchData.breaks.breakHorizontal,
52
+ hitData.launchSpeed,hitData.launchAngle,hitData.totalDistance,details.isInPlay,
53
+ last.pitch.of.ab,pitchData.breaks.spinDirection,matchup.pitchHand.code)
54
  colnames(tmilb) <- c("Batter Name","Batter ID","Pitcher Name","Pitcher ID",
55
+ "result","description","pitch_name","des","start_speed",
56
+ "plateTime","zone","spin_rate","extension","px","pz","x0",
57
+ "y0","z0","ax","ay","az","vx0","vz0","vy0","pfxX","pfxZ",
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" |
 
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") ~
184
+ ifelse(any(is.na(c(start_speed, IVB, -HB, EAA, -x0, z0, spin_rate, SADiff))),
185
+ NA_real_,
186
+ scale_TimStuff(predict(FB, matrix(c(start_speed, IVB, -HB, EAA, -x0, z0, spin_rate, SADiff), nrow = 1, ncol = 8)),
187
+ -0.0011801, 0.007989927)),
188
+ Pitch %in% c("Changeup", "Splitter", "Screwball", "Forkball") ~
189
+ ifelse(any(is.na(c(start_speed, IVB, -HB, EAA, -x0, z0, spin_rate, SADiff))),
190
+ NA_real_,
191
+ scale_TimStuff(predict(Off, matrix(c(start_speed, IVB, -HB, EAA, -x0, z0, spin_rate, SADiff), nrow = 1, ncol = 8)),
192
+ -0.002239657, 0.01043216)),
193
+ Pitch %in% c("Slider", "Slurve", "Sweeper", "Curveball", "Knuckle Curve", "Slow Curve", "Knuckleball") ~
194
+ ifelse(any(is.na(c(start_speed, IVB, -HB, EAA, -x0, z0, spin_rate, SADiff))),
195
+ NA_real_,
196
+ scale_TimStuff(predict(Break, matrix(c(start_speed, IVB, -HB, EAA, -x0, z0, spin_rate, SADiff), nrow = 1, ncol = 8)),
197
+ -0.004822031, 0.007912765)),
198
+ TRUE ~ NA_real_
199
+ )
200
+ } else {
201
+ case_when(
202
+ Pitch %in% c("Four-Seam Fastball", "Sinker", "Cutter", "Fastball") ~
203
+ ifelse(any(is.na(c(start_speed, IVB, HB, EAA, x0, z0, spin_rate, SADiff))),
204
+ NA_real_,
205
+ scale_TimStuff(predict(FB, matrix(c(start_speed, IVB, HB, EAA, x0, z0, spin_rate, SADiff), nrow = 1, ncol = 8)),
206
+ -0.0011801, 0.007989927)),
207
+ Pitch %in% c("Changeup", "Splitter", "Screwball", "Forkball") ~
208
+ ifelse(any(is.na(c(start_speed, IVB, HB, EAA, x0, z0, spin_rate, SADiff))),
209
+ NA_real_,
210
+ scale_TimStuff(predict(Off, matrix(c(start_speed, IVB, HB, EAA, x0, z0, spin_rate, SADiff), nrow = 1, ncol = 8)),
211
+ -0.002239657, 0.01043216)),
212
+ Pitch %in% c("Slider", "Slurve", "Sweeper", "Curveball", "Knuckle Curve", "Slow Curve", "Knuckleball") ~
213
+ ifelse(any(is.na(c(start_speed, IVB, HB, EAA, x0, z0, spin_rate, SADiff))),
214
+ NA_real_,
215
+ scale_TimStuff(predict(Break, matrix(c(start_speed, IVB, HB, EAA, x0, z0, spin_rate, SADiff), nrow = 1, ncol = 8)),
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),
224
+ 'Avg. Velo' = round(mean(start_speed, na.rm = TRUE), digits = 1),
225
+ 'Spin Rate' = round(mean(spin_rate, na.rm = TRUE), digits = 0),
226
+ 'Extension' = round(mean(extension, na.rm = TRUE), 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)
 
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%;"),
 
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
 
 
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)
 
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)