TimStats commited on
Commit
703939d
·
verified ·
1 Parent(s): 4e8a5b1

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +63 -132
app.R CHANGED
@@ -14,6 +14,9 @@ library(ggthemes)
14
  library(ggpubr)
15
  library(jsonlite)
16
  library(utils)
 
 
 
17
  Sys.setenv(TZ='EST')
18
 
19
  is_barrel <- function(df) {
@@ -89,6 +92,7 @@ pitch_plot <- function(game){
89
  ylab(" ") +
90
  xlim(-3,3)+
91
  ylim(0.2,4)+
 
92
  ggthemes::theme_few()+
93
  guides(color = guide_legend(title = "Pitch Type"))+
94
  theme(axis.text.x=element_blank(),
@@ -120,10 +124,10 @@ summary_table <- function(game){
120
  'Pitch%' = round(sum(Pitches)/sum(rows) * 100,digits = 1),
121
  'Avg. Velo' = round(sum(start_speed)/Pitches,digits = 1),
122
  'Spin Rate' = round(sum(spin_rate)/ Pitches,digits = 1),
123
- 'Extension' = mean(extension,na.rm = TRUE),
124
- 'IVB' = mean(IVB,na.rm=TRUE),
125
- 'HB' = mean(HB,na.rm = TRUE),
126
- 'VAA' = mean(VAA,na.rm= TRUE),
127
  'CSW%' = round(sum(team_fielding_id)/
128
  sum(!is.na(team_fielding_id))*100,digits = 1),
129
  'Whiff%' = round(sum(is_strike_swinging)/
@@ -182,38 +186,29 @@ ui <- fluidPage(
182
  .selectize-input { font-size: 14px; }
183
  .form-group { margin-bottom: 10px; }
184
  .action-button { width: 100%; }
185
- .grid-card { width: 100% !important; }
186
  }
187
  "))
188
  ),
189
  titlePanel("2024 MLB/AAA/FSL Summary Cards"),
190
  sidebarLayout(
191
  sidebarPanel(
 
192
  dateInput("date", "Date:"),
193
- selectizeInput("level", "Level:", c("MLB", "AAA", "FSL", "Spring Breakout")),
194
  selectizeInput("homeT", "Home Team:", mlbteamH[,1]),
195
  selectizeInput("awayT", "Away Team:", mlbteamA[,1]),
196
  selectizeInput("gamenum", "Game Number (For Doubleheaders):", c("1", "2")),
 
 
197
  selectizeInput("pitcher", "Pitcher Name:", c(" ")),
198
  selectizeInput("league", "MLB or MiLB Photo", c("MLB", "MiLB")),
199
  textInput("title", "Card Title"),
200
  actionButton("update1", "Make Card", icon("plus"),
201
- style = "color: #FFFFFF; background-color: #0077B6; width: 100%;")
 
202
  ),
203
  mainPanel(
204
- fluidRow(
205
- column(12, textOutput(outputId = "cardTitle"))
206
- ),
207
- fluidRow(
208
- column(6, plotlyOutput(outputId = "breakgraph")),
209
- column(6, plotlyOutput(outputId = "strikezone"))
210
- ),
211
- fluidRow(
212
- column(12, DTOutput(outputId = "myTable"))
213
- ),
214
- fluidRow(
215
- column(12, imageOutput(outputId = "picture"))
216
- )
217
  )
218
  )
219
  )
@@ -232,13 +227,13 @@ server <- function(input, output, session) {
232
  updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = mlbteamH[,1])
233
  updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = mlbteamA[,1])
234
  }
235
- if(input$level == "Spring Breakout"){
236
  updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = sbteamH[,1])
237
  updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = sbteamA[,1])
238
  }
239
  })
240
 
241
- observeEvent(input$awayT, {
242
  if(input$level == "AAA"){
243
  pname <- aaaid |>
244
  filter(date == input$date) |>
@@ -246,7 +241,7 @@ server <- function(input, output, session) {
246
  filter(teams_away_team_name == input$awayT) |>
247
  filter(game_number == input$gamenum)
248
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
249
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
250
  }
251
  if(input$level == "FSL"){
252
  pname <- fslid |>
@@ -255,7 +250,7 @@ server <- function(input, output, session) {
255
  filter(teams_away_team_name == input$awayT) |>
256
  filter(game_number == input$gamenum)
257
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
258
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
259
  }
260
  if(input$level == "MLB"){
261
  pname <- mlbid |>
@@ -264,97 +259,20 @@ server <- function(input, output, session) {
264
  filter(teams_away_team_name == input$awayT) |>
265
  filter(game_number == input$gamenum)
266
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
267
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
268
  }
269
- if(input$level == "Spring Breakout"){
270
  pname <- sbid |>
271
  filter(date == input$date) |>
272
  filter(teams_home_team_name == input$homeT) |>
273
  filter(teams_away_team_name == input$awayT) |>
274
  filter(game_number == input$gamenum)
275
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
276
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
277
- }
278
- })
279
-
280
- observeEvent(input$homeT, {
281
- if(input$level == "AAA"){
282
- pname <- aaaid |>
283
- filter(date == input$date) |>
284
- filter(teams_home_team_name == input$homeT) |>
285
- filter(teams_away_team_name == input$awayT) |>
286
- filter(game_number == input$gamenum)
287
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
288
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
289
- }
290
- if(input$level == "FSL"){
291
- pname <- fslid |>
292
- filter(date == input$date) |>
293
- filter(teams_home_team_name == input$homeT) |>
294
- filter(teams_away_team_name == input$awayT) |>
295
- filter(game_number == input$gamenum)
296
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
297
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
298
- }
299
- if(input$level == "MLB"){
300
- pname <- mlbid |>
301
- filter(date == as.character.Date(input$date)) |>
302
- filter(teams_home_team_name == input$homeT) |>
303
- filter(teams_away_team_name == input$awayT) |>
304
- filter(game_number == input$gamenum)
305
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
306
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
307
- }
308
- if(input$level == "Spring Breakout"){
309
- pname <- sbid |>
310
- filter(date == input$date) |>
311
- filter(teams_home_team_name == input$homeT) |>
312
- filter(teams_away_team_name == input$awayT) |>
313
- filter(game_number == input$gamenum)
314
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
315
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
316
- }
317
- })
318
-
319
- observeEvent(input$gamenum, {
320
- if(input$level == "AAA"){
321
- pname <- aaaid |>
322
- filter(date == input$date) |>
323
- filter(teams_home_team_name == input$homeT) |>
324
- filter(teams_away_team_name == input$awayT) |>
325
- filter(game_number == input$gamenum)
326
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
327
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
328
- }
329
- if(input$level == "FSL"){
330
- pname <- fslid |>
331
- filter(date == input$date) |>
332
- filter(teams_home_team_name == input$homeT) |>
333
- filter(teams_away_team_name == input$awayT) |>
334
- filter(game_number == input$gamenum)
335
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
336
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
337
- }
338
- if(input$level == "MLB"){
339
- pname <- mlbid |>
340
- filter(date == as.character.Date(input$date)) |>
341
- filter(teams_home_team_name == input$homeT) |>
342
- filter(teams_away_team_name == input$awayT) |>
343
- filter(game_number == input$gamenum)
344
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
345
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
346
- }
347
- if(input$level == "Spring Breakout"){
348
- pname <- sbid |>
349
- filter(date == input$date) |>
350
- filter(teams_home_team_name == input$homeT) |>
351
- filter(teams_away_team_name == input$awayT) |>
352
- filter(game_number == input$gamenum)
353
- pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
354
- updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:(For Spring Breakout if pitchers not loading, try changing game number)",choices = pname[,3])
355
  }
356
  })
357
 
 
358
  observeEvent(input$update1, {
359
  if(input$level == "MLB"){
360
  id <- mlbid |>
@@ -389,7 +307,7 @@ server <- function(input, output, session) {
389
  filter(`Pitcher Name` == input$pitcher)
390
  id <- as.character(game[1,4])
391
  }
392
- if(input$level == "Spring Breakout"){
393
  id <- sbid |>
394
  filter(date == as.character.Date(input$date)) |>
395
  filter(teams_home_team_name == input$homeT) |>
@@ -401,37 +319,50 @@ server <- function(input, output, session) {
401
  id <- as.character(game[1,4])
402
  }
403
 
404
- output$breakgraph <- renderPlotly({
405
- ggplotly(break_plot(game))
406
- })
407
 
408
- output$strikezone <- renderPlotly({
409
- ggplotly(pitch_plot(game))
410
- })
 
 
411
 
412
- output$myTable <- renderDT({
413
- t <- summary_table(game)
414
- datatable(t, options = list(scrollX = TRUE))
415
- })
 
 
 
 
 
 
416
 
417
- output$picture <- renderImage({
418
- if(input$league == "MLB"){
419
- y <- paste("https://midfield.mlbstatic.com/v1/people/","/mlb/300?circle=false",sep = id)
420
- }
421
- if(input$league == "MiLB"){
422
- y <- paste("https://midfield.mlbstatic.com/v1/people/","/milb/300?circle=false",sep = id)
423
- }
424
- photo <- tempfile()
425
- download.file(y,photo,mode = 'wb')
426
- list(
427
- src = photo
428
- )
429
- }, deleteFile = TRUE)
430
 
431
- output$cardTitle <- renderText({
432
- paste(input$title, "Made by @TimStats", sep = " ")
 
 
433
  })
434
  })
435
- }
 
 
 
 
 
 
 
 
 
 
436
 
437
  shinyApp(ui, server)
 
14
  library(ggpubr)
15
  library(jsonlite)
16
  library(utils)
17
+ library(grid)
18
+ library(gridExtra)
19
+ library(png)
20
  Sys.setenv(TZ='EST')
21
 
22
  is_barrel <- function(df) {
 
92
  ylab(" ") +
93
  xlim(-3,3)+
94
  ylim(0.2,4)+
95
+ coord_fixed(ratio = 1) +
96
  ggthemes::theme_few()+
97
  guides(color = guide_legend(title = "Pitch Type"))+
98
  theme(axis.text.x=element_blank(),
 
124
  'Pitch%' = round(sum(Pitches)/sum(rows) * 100,digits = 1),
125
  'Avg. Velo' = round(sum(start_speed)/Pitches,digits = 1),
126
  'Spin Rate' = round(sum(spin_rate)/ Pitches,digits = 1),
127
+ 'Extension' = round(mean(extension,na.rm = TRUE),digits = 1),
128
+ 'IVB' = round(mean(IVB,na.rm=TRUE),digits = 1),
129
+ 'HB' = round(mean(HB,na.rm = TRUE),digits = 1),
130
+ 'VAA' = round(mean(VAA,na.rm= TRUE),digits = 1),
131
  'CSW%' = round(sum(team_fielding_id)/
132
  sum(!is.na(team_fielding_id))*100,digits = 1),
133
  'Whiff%' = round(sum(is_strike_swinging)/
 
186
  .selectize-input { font-size: 14px; }
187
  .form-group { margin-bottom: 10px; }
188
  .action-button { width: 100%; }
 
189
  }
190
  "))
191
  ),
192
  titlePanel("2024 MLB/AAA/FSL Summary Cards"),
193
  sidebarLayout(
194
  sidebarPanel(
195
+ width = 2,
196
  dateInput("date", "Date:"),
197
+ selectizeInput("level", "Level:", c("MLB", "AAA", "FSL", "College (Statcast Parks Only)")),
198
  selectizeInput("homeT", "Home Team:", mlbteamH[,1]),
199
  selectizeInput("awayT", "Away Team:", mlbteamA[,1]),
200
  selectizeInput("gamenum", "Game Number (For Doubleheaders):", c("1", "2")),
201
+ actionButton("update", "Find Pitcher", icon("magnifying-glass"),
202
+ style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
203
  selectizeInput("pitcher", "Pitcher Name:", c(" ")),
204
  selectizeInput("league", "MLB or MiLB Photo", c("MLB", "MiLB")),
205
  textInput("title", "Card Title"),
206
  actionButton("update1", "Make Card", icon("plus"),
207
+ style = "color: #FFFFFF; background-color: #0077B6; width: 100%;"),
208
+ downloadButton("downloadPlot", "Download Card")
209
  ),
210
  mainPanel(
211
+ plotOutput("combinedPlot", height = "900px",width = "1350px")
 
 
 
 
 
 
 
 
 
 
 
 
212
  )
213
  )
214
  )
 
227
  updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = mlbteamH[,1])
228
  updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = mlbteamA[,1])
229
  }
230
+ if(input$level == "College (Statcast Parks Only)"){
231
  updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = sbteamH[,1])
232
  updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = sbteamA[,1])
233
  }
234
  })
235
 
236
+ observeEvent(input$update, {
237
  if(input$level == "AAA"){
238
  pname <- aaaid |>
239
  filter(date == input$date) |>
 
241
  filter(teams_away_team_name == input$awayT) |>
242
  filter(game_number == input$gamenum)
243
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
244
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
245
  }
246
  if(input$level == "FSL"){
247
  pname <- fslid |>
 
250
  filter(teams_away_team_name == input$awayT) |>
251
  filter(game_number == input$gamenum)
252
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
253
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
254
  }
255
  if(input$level == "MLB"){
256
  pname <- mlbid |>
 
259
  filter(teams_away_team_name == input$awayT) |>
260
  filter(game_number == input$gamenum)
261
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
262
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
263
  }
264
+ if(input$level == "College (Statcast Parks Only)"){
265
  pname <- sbid |>
266
  filter(date == input$date) |>
267
  filter(teams_home_team_name == input$homeT) |>
268
  filter(teams_away_team_name == input$awayT) |>
269
  filter(game_number == input$gamenum)
270
  pname <- tryCatch({pitcher_summary(pname[,6],input$date)},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
271
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
272
  }
273
  })
274
 
275
+ combinedPlot <- reactiveVal()
276
  observeEvent(input$update1, {
277
  if(input$level == "MLB"){
278
  id <- mlbid |>
 
307
  filter(`Pitcher Name` == input$pitcher)
308
  id <- as.character(game[1,4])
309
  }
310
+ if(input$level == "College (Statcast Parks Only)"){
311
  id <- sbid |>
312
  filter(date == as.character.Date(input$date)) |>
313
  filter(teams_home_team_name == input$homeT) |>
 
319
  id <- as.character(game[1,4])
320
  }
321
 
322
+ break_plot <- break_plot(game)
323
+ pitch_plot <- pitch_plot(game)
 
324
 
325
+ # Create table plot
326
+ table_plot <- tableGrob(summary_table(game),theme = ttheme_default(
327
+ core = list(fg_params = list(cex = 1.5)), # Increase text size
328
+ colhead = list(fg_params = list(cex = 1.5)),
329
+ rowhead = list(fg_params = list(cex = 1.5))))
330
 
331
+ # Download and process image
332
+ if(input$league == "MLB"){
333
+ y <- paste("https://midfield.mlbstatic.com/v1/people/","/mlb/300?circle=false",sep = id)
334
+ } else {
335
+ y <- paste("https://midfield.mlbstatic.com/v1/people/","/milb/300?circle=false",sep = id)
336
+ }
337
+ photo <- tempfile()
338
+ download.file(y, photo, mode = 'wb')
339
+ img <- readPNG(photo)
340
+ img_grob <- rasterGrob(img, interpolate = TRUE)
341
 
342
+ # Combine all elements into one plot
343
+ combined <- grid.arrange(
344
+ arrangeGrob(table_plot, img_grob, ncol = 2, widths = c(2/3, 1/3)),
345
+ arrangeGrob(break_plot, pitch_plot, ncol = 2),
346
+ nrow = 2,
347
+ top = textGrob(paste(input$title, "Made by @TimStats", sep = " "), gp = gpar(fontsize = 20, font = 2))
348
+ )
 
 
 
 
 
 
349
 
350
+ combinedPlot(combined)
351
+
352
+ output$combinedPlot <- renderPlot({
353
+ grid.draw(combinedPlot())
354
  })
355
  })
356
+
357
+ output$downloadPlot <- downloadHandler(
358
+ filename = function() {
359
+ paste("baseball_card_", Sys.Date(), ".png", sep = "")
360
+ },
361
+ content = function(file) {
362
+ ggsave(file, plot = combinedPlot(), width = 18, height = 12, dpi = 300)
363
+ }
364
+ )
365
+ }
366
+
367
 
368
  shinyApp(ui, server)