TimStats commited on
Commit
0a61c43
·
verified ·
1 Parent(s): 602b749

Upload app.R

Browse files
Files changed (1) hide show
  1. app.R +367 -45
app.R CHANGED
@@ -1,58 +1,380 @@
1
  library(shiny)
 
 
2
  library(bslib)
 
 
 
3
  library(dplyr)
 
 
4
  library(ggplot2)
 
 
 
 
 
 
5
 
6
- df <- readr::read_csv("penguins.csv")
7
- # Find subset of columns that are suitable for scatter plot
8
- df_num <- df |> select(where(is.numeric), -Year)
9
-
10
- ui <- page_sidebar(
11
- theme = bs_theme(bootswatch = "minty"),
12
- title = "Penguins explorer",
13
- sidebar = sidebar(
14
- varSelectInput("xvar", "X variable", df_num, selected = "Bill Length (mm)"),
15
- varSelectInput("yvar", "Y variable", df_num, selected = "Bill Depth (mm)"),
16
- checkboxGroupInput("species", "Filter by species",
17
- choices = unique(df$Species), selected = unique(df$Species)
18
- ),
19
- hr(), # Add a horizontal rule
20
- checkboxInput("by_species", "Show species", TRUE),
21
- checkboxInput("show_margins", "Show marginal plots", TRUE),
22
- checkboxInput("smooth", "Add smoother"),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  ),
24
- plotOutput("scatter")
25
- )
26
-
27
- server <- function(input, output, session) {
28
- subsetted <- reactive({
29
- req(input$species)
30
- df |> filter(Species %in% input$species)
31
- })
32
-
33
- output$scatter <- renderPlot(
34
- {
35
- p <- ggplot(subsetted(), aes(!!input$xvar, !!input$yvar)) +
36
- theme_light() +
37
- list(
38
- theme(legend.position = "bottom"),
39
- if (input$by_species) aes(color = Species),
40
- geom_point(),
41
- if (input$smooth) geom_smooth()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  )
 
 
 
 
43
 
44
- if (input$show_margins) {
45
- margin_type <- if (input$by_species) "density" else "histogram"
46
- p <- p |> ggExtra::ggMarginal(
47
- type = margin_type, margins = "both",
48
- size = 8, groupColour = input$by_species, groupFill = input$by_species
49
- )
50
- }
51
 
52
- p
53
- },
54
- res = 100
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  )
 
56
  }
57
 
 
58
  shinyApp(ui, server)
 
1
  library(shiny)
2
+ library(plotly)
3
+ library(gridlayout)
4
  library(bslib)
5
+ library(DT)
6
+ library(rsconnect)
7
+ library(baseballr)
8
  library(dplyr)
9
+ library(tidyverse)
10
+ library(rvest)
11
  library(ggplot2)
12
+ library(janitor)
13
+ library(ggthemes)
14
+ library(ggpubr)
15
+ library(jsonlite)
16
+ library(utils)
17
+ library(magick)
18
 
19
+ VAA <- function(milbtotal){
20
+ milbtotal <- milbtotal |>
21
+ mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
22
+ ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi))
23
+ }
24
+ pitcher_summary <- function(game_pk){
25
+ tmilb <- mlb_pbp(game_pk)
26
+ tmilb <- tmilb |>
27
+ filter(type == "pitch")
28
+ tmilb <- tmilb |>
29
+ select(matchup.batter.fullName,matchup.batter.id,matchup.pitcher.fullName,
30
+ matchup.pitcher.id,result.event,details.description,details.type.description,
31
+ result.description,pitchData.startSpeed,
32
+ pitchData.plateTime,pitchData.zone,pitchData.breaks.spinRate,pitchData.extension,
33
+ pitchData.coordinates.pX,pitchData.coordinates.pZ,pitchData.coordinates.x0,
34
+ pitchData.coordinates.y0,pitchData.coordinates.z0,pitchData.coordinates.aX,
35
+ pitchData.coordinates.aY,pitchData.coordinates.aZ,pitchData.coordinates.vX0,
36
+ pitchData.coordinates.vZ0,pitchData.coordinates.vY0,pitchData.coordinates.pfxX,
37
+ pitchData.coordinates.pfxZ,pitchData.breaks.breakVerticalInduced,pitchData.breaks.breakHorizontal,
38
+ hitData.launchSpeed,hitData.launchAngle,hitData.totalDistance,details.isInPlay,last.pitch.of.ab)
39
+ colnames(tmilb) <- c("Batter Name","Batter ID","Pitcher Name","Pitcher ID",
40
+ "result","description","pitch_name",
41
+ "des","start_speed","plateTime","zone","spin_rate",
42
+ "extension","px","pz","x0","y0","z0","ax","ay","az",
43
+ "vx0","vz0","vy0","pfxX","pfxZ","IVB","HB","hit_speed",
44
+ "hit_angle","hit_distance","inPlay","lastPitch")
45
+ tmilb <- is_barrel(tmilb)
46
+ tmilb <- tmilb |>
47
+ mutate(is_strike_swinging = ifelse(description == "Swinging Strike" |
48
+ description == "Foul Tip",TRUE,FALSE))
49
+
50
+ tmilb <- tmilb |>
51
+ mutate(date = gdate)
52
+ return(tmilb)
53
+
54
+ }
55
+ break_plot <- function(game){
56
+ ggplot()+
57
+ geom_point(game,mapping =
58
+ aes(x=HB, y = IVB,color = pitch_name),size = 4) +
59
+ geom_vline(xintercept = 0, color = "lightblue",linewidth = 1,linetype = 4)+
60
+ geom_hline(yintercept = 0, color = "lightblue",linewidth = 1,linetype = 4)+
61
+ xlab("Horizontal Break from Pitcher's Perspective (in) ")+
62
+ ylab("Induced Verical Break (in)") +
63
+ xlim(-25,25) +
64
+ ylim(-25,25) +
65
+ ggthemes::theme_igray()+
66
+ theme(panel.grid.minor = element_line(color = "gray",
67
+ size = 0.25,
68
+ linetype = 1))+
69
+ guides(color = guide_legend(title = "Pitch Type"))
70
+
71
+ }
72
+ pitch_plot <- function(game){
73
+ ggplot()+
74
+ geom_point(game,mapping =
75
+ aes(x=px, y = pz,color = pitch_name),size = 3.5) +
76
+ geom_segment(aes(x=-0.71,xend = 0.71, y = 1.5,yend = 1.5))+
77
+ geom_segment(aes(x=-0.71,xend = 0.71, y = 3.6,yend = 3.6))+
78
+ geom_segment(aes(x= 0.71,xend = 0.71, y = 1.5,yend = 3.6))+
79
+ geom_segment(aes(x=-0.71,xend = -0.71, y = 1.5,yend =3.6))+
80
+ xlab(" ")+
81
+ ylab(" ") +
82
+ xlim(-3,3)+
83
+ ylim(0.2,4)+
84
+ ggthemes::theme_few()+
85
+ guides(color = guide_legend(title = "Pitch Type"))+
86
+ theme(axis.text.x=element_blank(),
87
+ axis.ticks.x=element_blank(),
88
+ axis.text.y=element_blank(),
89
+ axis.ticks.y=element_blank())
90
+ }
91
+ summary_table <- function(game){
92
+ rows <- nrow(game)
93
+ sumtable <- game |>
94
+ mutate(VAA = -atan((vz0+(az*(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))-vy0)/
95
+ ay))/(-sqrt((vy0*vy0)-(2*ay*(y0-(17/12))))))*(180/pi)) |>
96
+ mutate(team_fielding_id = ifelse(description == "Called Strike" |
97
+ description == "Swinging Strike" |
98
+ description == "Swinging Strike (Blocked)",1,0))|>
99
+ mutate(swing = ifelse(description == "Foul" |
100
+ description == "Foul Pitchout" |
101
+ description == "In play, no out" |
102
+ description == "In play, out(s)" |
103
+ description == "In play, run(s)" |
104
+ description == "Swinging Strike" |
105
+ description == "swinging Strike (Blocked)" |
106
+ description == "Foul Tip",1,0)) |>
107
+ mutate(is_strike_swinging = ifelse(is_strike_swinging == TRUE,1,0)) |>
108
+ mutate(Pitch = pitch_name) |>
109
+ group_by(Pitch)|>
110
+ summarize(Pitches = n(),
111
+ 'Pitch%' = round(sum(Pitches)/sum(rows) * 100,digits = 1),
112
+ 'Avg. Velo' = round(sum(start_speed)/Pitches,digits = 1),
113
+ 'Spin Rate' = round(sum(spin_rate)/ Pitches,digits = 1),
114
+ 'Extension' = mean(extension,na.rm = TRUE),
115
+ 'IVB' = mean(IVB,na.rm=TRUE),
116
+ 'HB' = mean(HB,na.rm = TRUE),
117
+ 'VAA' = mean(VAA,na.rm= TRUE),
118
+ 'CSW%' = round(sum(team_fielding_id)/
119
+ sum(!is.na(team_fielding_id))*100,digits = 1),
120
+ 'Whiff%' = round(sum(is_strike_swinging)/
121
+ sum(swing)*100,digits = 1))
122
+ }
123
+ #MLB ID Stuff
124
+ mlbid <- mlb_schedule(season = 2024, level_ids = "1")
125
+ mlbteamH <- mlbid |>
126
+ select(teams_home_team_name)
127
+ mlbteamH <- distinct(mlbteamH)
128
+ mlbteamA <- mlbid |>
129
+ select(teams_away_team_name)
130
+ mlbteamA <- distinct(mlbteamA)
131
+ #AAA ID Stuff
132
+ aaaid <- mlb_schedule(season = 2024, level_ids = "11")
133
+ aaateamH <- aaaid |>
134
+ select(teams_home_team_name)
135
+ aaateamH <- distinct(aaateamH)
136
+ aaateamA <- aaaid |>
137
+ select(teams_away_team_name)
138
+ aaateamA <- distinct(aaateamA)
139
+ #FSL ID Stuff
140
+ fslid <- mlb_schedule(season = 2024, level_ids = "14")
141
+ fslid <- fslid |>
142
+ filter(teams_home_team_name == "Daytona Tortugas" |
143
+ teams_home_team_name == "Jupiter Hammerheads" |
144
+ teams_home_team_name == "Palm Beach Cardinals" |
145
+ teams_home_team_name == "St. Lucie Mets" |
146
+ teams_home_team_name == "Bradenton Marauders" |
147
+ teams_home_team_name == "Clearwater Threshers" |
148
+ teams_home_team_name == "Dunedin Blue Jays" |
149
+ teams_home_team_name == "Fort Myers Mighty Mussels" |
150
+ teams_home_team_name == "Lakeland Flying Tigers" |
151
+ teams_home_team_name == "Tampa Tarpons")
152
+ fslteamH <- fslid |>
153
+ select(teams_home_team_name)
154
+ fslteamH <- distinct(fslteamH)
155
+ fslteamA <- fslid |>
156
+ select(teams_away_team_name)
157
+ fslteamA <- distinct(fslteamA)
158
+ #SB ID Stuff
159
+ sbid <- mlb_schedule(season = 2024, level_ids = "21")
160
+ sbteamH <- sbid |>
161
+ select(teams_home_team_name)
162
+ sbteamH <- distinct(sbteamH)
163
+ sbteamA <- sbid |>
164
+ select(teams_away_team_name)
165
+ sbteamA <- distinct(sbteamA)
166
+ ui <- grid_page(
167
+ layout = c(
168
+ "header header",
169
+ "sidebar area2 "
170
  ),
171
+ row_sizes = c(
172
+ "40px",
173
+ "1fr"
174
+ ),
175
+ col_sizes = c(
176
+ "280px",
177
+ "1fr"
178
+ ),
179
+ gap_size = "1rem",
180
+ sidebarPanel(
181
+ dateInput("date",
182
+ "Date:","2024-02-22"),
183
+ selectizeInput("level","Level:",c("MLB","AAA","FSL","Spring Breakout")),
184
+ selectizeInput("homeT","Home Team:",mlbteamH[,1]),
185
+ selectizeInput("awayT", "Away Team:",mlbteamA[,1]),
186
+ selectizeInput("gamenum","Game Number (For Doubleheaders):",c("1","2")),
187
+ actionButton("update","Find Pitchers",icon("magnifying-glass"),
188
+ style = "color: #FFFFFF; background-color: #0077B6"),
189
+ selectizeInput("pitcher","Pitcher (For Spring Breakout if pitchers not loading, try changing game number:",c(" ")),
190
+ selectizeInput("league","MLB or MiLB Photo",c("MLB","MiLB")),
191
+ textInput("title","Card Title"),
192
+ actionButton("update1","Make Card",icon("plus"),
193
+ style = "color: #FFFFFF; background-color: #0077B6"),
194
+ width = 15,
195
+ ),
196
+ grid_card_text(
197
+ area = "header",
198
+ content = "2024 MLB/AAA/FSL Summary Cards (BETA)",
199
+ alignment = "start",
200
+ is_title = TRUE
201
+ ),
202
+ grid_card(
203
+ area = "area2",
204
+ full_screen = TRUE,
205
+ card_header(textOutput(outputId = "cardTitle")),
206
+ card_body(
207
+ gap = "0px",
208
+ grid_container(
209
+ layout = c(
210
+ "area3 chart chart chart ",
211
+ "breakgraph breakgraph strikezone strikezone"
212
+ ),
213
+ row_sizes = c(
214
+ "1fr",
215
+ "1fr"
216
+ ),
217
+ col_sizes = c(
218
+ "1fr",
219
+ "1fr",
220
+ "1fr",
221
+ "1fr"
222
+ ),
223
+ gap_size = "0px",
224
+ grid_card_plot(area = "breakgraph"),
225
+ grid_card_plot(area = "strikezone"),
226
+ grid_card(
227
+ area = "chart",
228
+ card_body(
229
+ tableOutput(
230
+ outputId = "myTable"
231
+ ),
232
+ )
233
+ ),
234
+ grid_card(
235
+ area = "area3",
236
+ plotOutput(outputId = "picture")
237
  )
238
+ )
239
+ )
240
+ )
241
+ )
242
 
 
 
 
 
 
 
 
243
 
244
+ server <- function(input, output) {
245
+ game <- reactive(pitcher_summary(input$game_pk))
246
+ id <- reactive(as.character(game()[1,4]))
247
+ observeEvent(input$level,{
248
+ if(input$level == "AAA"){
249
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = aaateamH[,1])
250
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = aaateamA[,1])
251
+ }
252
+ if(input$level == "FSL"){
253
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = fslteamH[,1])
254
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = fslteamA[,1])
255
+ }
256
+ if(input$level == "MLB"){
257
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = mlbteamH[,1])
258
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = mlbteamA[,1])
259
+ }
260
+ if(input$level == "Spring Breakout"){
261
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"homeT","Home Team:",choices = sbteamH[,1])
262
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"awayT","Away Team:",choices = sbteamA[,1])
263
+ }
264
+ })
265
+ observeEvent(input$update,{
266
+ if(input$level == "AAA"){
267
+ pname <- aaaid |>
268
+ filter(date == input$date) |>
269
+ filter(teams_home_team_name == input$homeT) |>
270
+ filter(teams_away_team_name == input$awayT) |>
271
+ filter(game_number == input$gamenum)
272
+ pname <- tryCatch({pitcher_summary(pname[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
273
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
274
+ }
275
+ if(input$level == "FSL"){
276
+ pname <- fslid |>
277
+ filter(date == input$date) |>
278
+ filter(teams_home_team_name == input$homeT) |>
279
+ filter(teams_away_team_name == input$awayT) |>
280
+ filter(game_number == input$gamenum)
281
+ pname <- tryCatch({pitcher_summary(pname[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
282
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
283
+ }
284
+ if(input$level == "MLB"){
285
+ pname <- mlbid |>
286
+ filter(date == as.character.Date(input$date)) |>
287
+ filter(teams_home_team_name == input$homeT) |>
288
+ filter(teams_away_team_name == input$awayT) |>
289
+ filter(game_number == input$gamenum)
290
+ pname <- tryCatch({pitcher_summary(pname[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
291
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
292
+ }
293
+ if(input$level == "Spring Breakout"){
294
+ pname <- sbid |>
295
+ filter(date == input$date) |>
296
+ filter(teams_home_team_name == input$homeT) |>
297
+ filter(teams_away_team_name == input$awayT) |>
298
+ filter(game_number == input$gamenum)
299
+ pname <- tryCatch({pitcher_summary(pname[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
300
+ updateSelectizeInput(session = getDefaultReactiveDomain(),"pitcher","Pitcher:",choices = pname[,3])
301
+ }
302
+ })
303
+ observeEvent(input$update1,{
304
+ if(input$level == "MLB"){
305
+ id <- mlbid |>
306
+ filter(date == as.character.Date(input$date)) |>
307
+ filter(teams_home_team_name == input$homeT) |>
308
+ filter(teams_away_team_name == input$awayT) |>
309
+ filter(game_number == input$gamenum)
310
+ game <- tryCatch({pitcher_summary(id[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
311
+ game <- game |>
312
+ filter(`Pitcher Name` == input$pitcher)
313
+ id <- as.character(game[1,4])
314
+ }
315
+ if(input$level == "FSL"){
316
+ id <- fslid |>
317
+ filter(date == as.character.Date(input$date)) |>
318
+ filter(teams_home_team_name == input$homeT) |>
319
+ filter(teams_away_team_name == input$awayT) |>
320
+ filter(game_number == input$gamenum)
321
+ game <- tryCatch({pitcher_summary(id[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
322
+ game <- game |>
323
+ filter(`Pitcher Name` == input$pitcher)
324
+ id <- as.character(game[1,4])
325
+ }
326
+ if(input$level == "AAA"){
327
+ id <- aaaid |>
328
+ filter(date == as.character.Date(input$date)) |>
329
+ filter(teams_home_team_name == input$homeT) |>
330
+ filter(teams_away_team_name == input$awayT) |>
331
+ filter(game_number == input$gamenum)
332
+ game <- tryCatch({pitcher_summary(id[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
333
+ game <- game |>
334
+ filter(`Pitcher Name` == input$pitcher)
335
+ id <- as.character(game[1,4])
336
+ }
337
+ if(input$level == "Spring Breakout"){
338
+ id <- sbid |>
339
+ filter(date == as.character.Date(input$date)) |>
340
+ filter(teams_home_team_name == input$homeT) |>
341
+ filter(teams_away_team_name == input$awayT) |>
342
+ filter(game_number == input$gamenum)
343
+ game <- tryCatch({pitcher_summary(id[,6])},error=function(e){cat("ERROR :",conditionMessage(e), "\n")})
344
+ game <- game |>
345
+ filter(`Pitcher Name` == input$pitcher)
346
+ id <- as.character(game[1,4])
347
+ }
348
+ output$breakgraph <- renderPlot({
349
+ break_plot(game)
350
+ })
351
+
352
+ output$strikezone <- renderPlot({
353
+ pitch_plot(game)
354
+ })
355
+
356
+ output$myTable <- renderTable({
357
+ t <- summary_table(game)
358
+ return(t)
359
+ },width = '1150px',digits = 1,na = "NA",align = 'c')
360
+ output$picture <- renderImage({
361
+ if(input$league == "MLB"){
362
+ y <- paste("https://midfield.mlbstatic.com/v1/people/","/mlb/300?circle=false",sep = id)
363
+ }
364
+ if(input$league == "MiLB"){
365
+ y <- paste("https://midfield.mlbstatic.com/v1/people/","/milb/300?circle=false",sep = id)
366
+ }
367
+ photo <- tempfile()
368
+ download.file(y,photo,mode = 'wb')
369
+ list(
370
+ src = photo
371
+ )
372
+ },deleteFile = TRUE)
373
+ output$cardTitle <- renderText(
374
+ title <- paste(input$title,"Made by @TimStats", sep = " ")
375
  )
376
+ })
377
  }
378
 
379
+
380
  shinyApp(ui, server)