TimStats commited on
Commit
67fd53f
·
verified ·
1 Parent(s): 6ebd8fe

Upload 2 files

Browse files
Files changed (2) hide show
  1. Beam.csv +0 -0
  2. app.R +478 -58
Beam.csv ADDED
The diff for this file is too large to render. See raw diff
 
app.R CHANGED
@@ -1,58 +1,478 @@
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(gt)
3
+ library(dplyr)
4
+ library(shinyjs)
5
+ library(shinyauthr)
6
+ library(gtExtras)
7
+ library(bslib)
8
+
9
+ Bean <- read.csv('Beam.csv')
10
+
11
+ test <- Beam %>%
12
+ select(Date,PitchofPA,Pitcher,PitcherId,PitcherThrows,PitcherTeam,Batter,BatterId,
13
+ BatterSide,BatterTeam,Inning,`Top/Bottom`,Outs,Balls,Strikes,TaggedPitchType,
14
+ AutoPitchType,PitchCall,TaggedHitType,KorBB,PlayResult,OutsOnPlay,RunsScored,
15
+ RelSpeed,VertRelAngle,HorzRelAngle,SpinRate,SpinAxis,Tilt,RelHeight,RelSide,
16
+ Extension,InducedVertBreak,HorzBreak,PlateLocHeight,PlateLocSide,VertApprAngle,
17
+ HorzApprAngle,ExitSpeed,Angle,Direction,Distance,pfxx,pfxz,x0,z0,vx0,vy0,vz0,
18
+ ax0,ay0,az0,Level,League,ContactPositionX,ContactPositionY,ContactPositionZ,
19
+ SpinAxis3dTransverseAngle,SpinAxis3dLongitudinalAngle,SpinAxis3dTilt,
20
+ SpinAxis3dSpinEfficiency,SpinAxis3dSeamOrientationRotationX,
21
+ SpinAxis3dSeamOrientationRotationY,SpinAxis3dSeamOrientationRotationZ)
22
+ test <- test %>%
23
+ mutate("Hit" = case_when(PlayResult %in% c("Single","Double","Triple","HomeRun") ~ TRUE,TRUE ~ FALSE),
24
+ "CallStrike" = case_when(PitchCall %in% c("StrikeCalled") ~ TRUE, TRUE ~ FALSE),
25
+ "Whiff" = case_when(PitchCall %in% c("StrikeSwinging") ~ TRUE, TRUE ~ FALSE),
26
+ "CSW" = CallStrike + Whiff,
27
+ "Contact" = case_when(PitchCall %in% c("FoulBall","FouBallNotFieldable","InPlay") ~ TRUE, TRUE ~ FALSE),
28
+ "GB" = case_when(TaggedHitType %in% c('GroundBall') ~ TRUE, TRUE ~ FALSE),
29
+ "LD" = case_when(TaggedHitType %in% c('LineDrive') ~ TRUE, TRUE ~ FALSE),
30
+ "FB" = case_when(TaggedHitType %in% c ("FlyBall") ~ TRUE, TRUE ~ FALSE),
31
+ "PopU" = case_when(TaggedHitType %in% c ("Popup") ~ TRUE, TRUE ~ FALSE),
32
+ "Swing" = Whiff + Contact,
33
+ "BBE" = GB + LD + FB + PopU,
34
+ "HardHit" = ifelse(ExitSpeed >= 95,TRUE,FALSE),
35
+ "Ball" = case_when(PitchCall %in% c("BallCalled","BallinDirt") ~ TRUE, TRUE ~ FALSE),
36
+ "Single" = case_when(PlayResult %in% c("Single") ~ TRUE, TRUE ~ FALSE),
37
+ "Double" = case_when(PlayResult %in% c("Double") ~ TRUE, TRUE ~ FALSE),
38
+ "Triple" = case_when(PlayResult %in% c("Triple") ~ TRUE, TRUE ~ FALSE),
39
+ "HR" = case_when(PlayResult %in% c("HomeRun") ~ TRUE, TRUE ~ FALSE),
40
+ "Sac" = case_when(PlayResult %in% c("Sacrifice") ~ TRUE, TRUE ~ FALSE),
41
+ "HBP" = case_when(PitchCall %in% c("HitByPitch") ~ TRUE, TRUE ~ FALSE),
42
+ "Error" = case_when(PlayResult %in% c("Error") ~ TRUE, TRUE ~ FALSE),
43
+ "FC"= case_when(PlayResult %in% c("FieldersChoice") ~ TRUE, TRUE ~ FALSE),
44
+ "Out" = case_when(PlayResult %in% c ("Out") ~ TRUE, TRUE ~ FALSE),
45
+ "BIP" = Single + Double + Triple + HR + Sac + Error + Out + FC,
46
+ "Count" = paste0(Balls,"-",Strikes),
47
+ "Strikeout" = ifelse(KorBB == "Strikeout",TRUE,FALSE),
48
+ "Walk" = ifelse(KorBB == "Walk",TRUE,FALSE),
49
+ "Zone" = case_when(between(PlateLocSide,-.825,.825) & between(PlateLocHeight,1.45,3.45) ~ TRUE, TRUE ~ FALSE),
50
+ "AB" = Strikeout + BIP - Sac,
51
+ "PA" = Strikeout + BIP + Walk + HBP
52
+ )
53
+
54
+
55
+ gt_theme_tim <- function(gt_object,...) {
56
+
57
+ stopifnot(`'gt_object' must be a 'gt_tbl', have you accidentally passed raw data?` = "gt_tbl" %in%
58
+ class(gt_object))
59
+
60
+ table_id <- subset(gt_object[['_options']], parameter == 'table_id')$value[[1]]
61
+
62
+ if (is.na(table_id)) {
63
+ table_id <- gt::random_id()
64
+ opt_position <- which("table_id" %in% gt_object[["_options"]][["parameter"]])[[1]]
65
+ gt_object[["_options"]][["value"]][[opt_position]] <- table_id
66
+ }
67
+
68
+ gt_object %>%
69
+ # cell body
70
+ gt::tab_style(
71
+ locations = gt::cells_body(),
72
+ style = gt::cell_text(font = "Arial", size = px(14))
73
+ ) %>%
74
+ # col. headers
75
+ gt::tab_style(
76
+ locations = gt::cells_column_labels(),
77
+ style = gt::cell_text(weight = 'bold', font = "Arial", size = px(14))
78
+ ) %>%
79
+ # group rows
80
+ gt::tab_style(
81
+ locations = gt::cells_row_groups(),
82
+ style = list(
83
+ gt::cell_text(font = "Arial", weight = 650, size = px(14), color = "#FFFDF5"),
84
+ gt::cell_fill(color = "#000000")
85
+ )
86
+ ) %>%
87
+ # footnote
88
+ gt::tab_style(
89
+ locations = gt::cells_footnotes(),
90
+ style = gt::cell_text(font = "Arial", size = px(12))
91
+ ) %>%
92
+ # title
93
+ gt::tab_style(
94
+ locations = gt::cells_title('title'),
95
+ style = gt::cell_text(weight = 'bold', font = "Arial", size = px(18))
96
+ ) %>%
97
+ # subtitle
98
+ gt::tab_style(
99
+ locations = gt::cells_title('subtitle'),
100
+ style = gt::cell_text(font = "Arial", size = px(14))
101
+ ) %>%
102
+ # caption
103
+ gt::tab_style(
104
+ locations = gt::cells_source_notes(),
105
+ style = gt::cell_text(font = "Arial", size = px(12))
106
+ ) %>%
107
+ # spanner
108
+ gt::tab_style(
109
+ locations = gt::cells_column_spanners(),
110
+ style = gt::cell_text(font = "Arial", weight = 650, size = px(8))
111
+ ) %>%
112
+ gt::tab_options(
113
+ data_row.padding = 1,
114
+ table_body.hlines.color = "transparent",
115
+ column_labels.border.top.color = 'black',
116
+ column_labels.border.top.width = px(1),
117
+ column_labels.border.bottom.style = 'none',
118
+ #column_labels.background.color = "orange",
119
+ row_group.border.top.style = "none",
120
+ row_group.border.top.color = "black",
121
+ row_group.border.bottom.width = px(1),
122
+ row_group.border.bottom.color = "black",
123
+ row_group.border.bottom.style = 'solid',
124
+ row_group.padding = px(1.5),
125
+ heading.align = 'center',
126
+ heading.border.bottom.style = "none",
127
+ table_body.border.top.style = "none",
128
+ table_body.border.bottom.color = "white",
129
+ table.border.bottom.style = 'none',
130
+ table.border.top.style = 'none',
131
+ source_notes.border.lr.style = "none",
132
+ ...
133
+ ) %>%
134
+ gt::opt_row_striping()
135
+ }
136
+
137
+ user_base <- tibble::tibble(
138
+ user = c("TrentR", "user2"),
139
+ password = sapply(c("Caprisun", "pass2"), sodium::password_store),
140
+ permissions = c("admin", "standard"),
141
+ name = c("User One", "User Two")
142
+ )
143
+
144
+ # Define UI for application that draws a histogram
145
+ ui <- fluidPage(
146
+ div(class = "pull-right", shinyauthr::logoutUI(id = "logout")),
147
+
148
+ # login section
149
+ shinyauthr::loginUI(id = "login"),
150
+
151
+ div(
152
+ id = "bar",
153
+ # Application title
154
+ titlePanel("College Pitcher"),
155
+
156
+ # Sidebar layout
157
+ sidebarLayout(
158
+ sidebarPanel(
159
+ selectInput("player",
160
+ "Select Player",
161
+ choices = unique(test$Pitcher)),
162
+ width = 3
163
+ ),
164
+
165
+ mainPanel(
166
+ tabsetPanel(
167
+ tabPanel("Splits",
168
+ gt_output("CountFilter"),
169
+ gt_output("PitchFilter"),
170
+ gt_output("PitchSideFilter"),
171
+ gt_output("InningFilter"),
172
+ gt_output("SideFilter")
173
+ )
174
+ ),
175
+ width = 9
176
+ )
177
+ )
178
+ ) %>% shinyjs::hidden()
179
+ )
180
+
181
+ # Define server logic required to draw a histogram
182
+ server <- function(input, output) {
183
+
184
+ credentials <- shinyauthr::loginServer(
185
+ id = "login",
186
+ data = user_base,
187
+ user_col = user,
188
+ pwd_col = password,
189
+ sodium_hashed = TRUE,
190
+ log_out = reactive(logout_init())
191
+ )
192
+
193
+ # Logout to hide
194
+ logout_init <- shinyauthr::logoutServer(
195
+ id = "logout",
196
+ active = reactive(credentials()$user_auth)
197
+ )
198
+
199
+ observe({
200
+ req(credentials()$user_auth)
201
+ shinyjs::show(id = "bar")
202
+ })
203
+
204
+ output$CountFilter <- render_gt({
205
+ test <- test %>% filter(Pitcher == input$player) %>% group_by(Count) %>%
206
+ summarise(
207
+ Pitches = n(),
208
+ #BBE = sum(BBE,na.rm = TRUE),
209
+ "Whiff%" = mean(Whiff,na.rm = TRUE),
210
+ "CSW%" = mean(CSW,na.rm = TRUE),
211
+ "Zone%" = mean(Zone,na.rm = TRUE),
212
+ "ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
213
+ "ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
214
+ "OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
215
+ "OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
216
+ "Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
217
+ "EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
218
+ "Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
219
+ "Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
220
+ "GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
221
+ "LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
222
+ "FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
223
+ "AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
224
+ "OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
225
+ sum(PA,na.rm = TRUE),digits = 3),
226
+ "SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
227
+ sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
228
+ ungroup()%>%
229
+ gt() %>%
230
+ gt_theme_tim() %>%
231
+ fmt_number(columns = `Avg EV`:`Max EV`,decimals = 1) %>%
232
+ cols_width(Count:Pitches ~ px(70),
233
+ everything() ~ px(85)) %>%
234
+ cols_align(align = "center") %>%
235
+ fmt_number(columns = AVG:SLG,decimals = 3) %>%
236
+ fmt_percent(columns = ends_with("%")) %>%
237
+ sub_missing() %>%
238
+ #gt_theme_savant() %>%
239
+ opt_interactive(
240
+ use_compact_mode = TRUE,
241
+ use_pagination = FALSE
242
+ )
243
+ })
244
+ output$PitchFilter <- render_gt({
245
+ tes <- test %>%
246
+ filter(Pitcher == input$player) %>%
247
+ group_by(AutoPitchType) %>%
248
+ summarise(
249
+ Pitches = n(),
250
+ # BBE = sum(BBE,na.rm = TRUE),
251
+ "Usage%" = n() / nrow(.), # Added Usage% calculation
252
+ "Whiff%" = mean(Whiff, na.rm = TRUE),
253
+ "CSW%" = mean(CSW, na.rm = TRUE),
254
+ "Zone%" = mean(Zone, na.rm = TRUE),
255
+ "ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE], na.rm = TRUE),
256
+ "ZSwing%" = mean(Swing[Zone == TRUE], na.rm = TRUE),
257
+ "OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE], na.rm = TRUE),
258
+ "OSwing%" = mean(Swing[Zone == FALSE], na.rm = TRUE),
259
+ "Avg EV" = mean(ExitSpeed[BBE == TRUE], na.rm = TRUE),
260
+ "EV90" = quantile(ExitSpeed[BBE == TRUE], .9, na.rm = TRUE),
261
+ "Max EV" = max(ExitSpeed[BBE == TRUE], na.rm = TRUE),
262
+ "Max EV" = ifelse(is.infinite(`Max EV`), NA, `Max EV`),
263
+ "GB%" = mean(GB[BBE == TRUE], na.rm = TRUE),
264
+ "LD%" = mean(LD[BBE == TRUE], na.rm = TRUE),
265
+ "FB%" = mean(FB[BBE == TRUE], na.rm = TRUE),
266
+ "AVG" = round(sum(Hit, na.rm = TRUE) / sum(AB, na.rm = TRUE), digits = 3),
267
+ "OBP" = round((sum(Hit, na.rm = TRUE) + sum(Walk, na.rm = TRUE) + sum(HBP, na.rm = TRUE)) /
268
+ sum(PA, na.rm = TRUE), digits = 3),
269
+ "SLG" = (round(sum(Single, na.rm = TRUE) + sum(Double, na.rm = TRUE) * 2 +
270
+ sum(Triple, na.rm = TRUE) * 3 + sum(HR, na.rm = TRUE))) / sum(AB, na.rm = TRUE)
271
+ ) %>%
272
+ ungroup() %>%
273
+ arrange(desc(Pitches)) %>%
274
+ gt() %>%
275
+ gt_theme_tim() %>%
276
+ fmt_number(columns = `Avg EV`:`Max EV`, decimals = 1) %>%
277
+ cols_label(AutoPitchType = "Type") %>%
278
+ cols_width(
279
+ AutoPitchType ~ px(100),
280
+ Pitches ~ px(70),
281
+ everything() ~ px(85)
282
+ ) %>%
283
+ cols_align(align = "center") %>%
284
+ fmt_number(columns = AVG:SLG, decimals = 3) %>%
285
+ fmt_percent(columns = ends_with("%")) %>%
286
+ sub_missing() %>%
287
+ opt_interactive(
288
+ use_compact_mode = TRUE,
289
+ use_pagination = FALSE
290
+ )
291
+ })
292
+ output$PitchSideFilter <- render_gt({
293
+ test <- test %>%
294
+ filter(Pitcher == input$player) %>%
295
+ group_by(BatterSide) %>%
296
+ mutate(total_side = n()) %>%
297
+ ungroup() %>%
298
+ group_by(AutoPitchType, BatterSide) %>%
299
+ summarise(
300
+ Pitches = n(),
301
+ #BBE = sum(BBE,na.rm = TRUE),
302
+ "Usage%" = (n() / first(total_side)),
303
+ "Whiff%" = mean(Whiff, na.rm = TRUE),
304
+ "CSW%" = mean(CSW, na.rm = TRUE),
305
+ "Zone%" = mean(Zone, na.rm = TRUE),
306
+ "ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE], na.rm = TRUE),
307
+ "ZSwing%" = mean(Swing[Zone == TRUE], na.rm = TRUE),
308
+ "OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE], na.rm = TRUE),
309
+ "OSwing%" = mean(Swing[Zone == FALSE], na.rm = TRUE),
310
+ "Avg EV" = mean(ExitSpeed[BBE == TRUE], na.rm = TRUE),
311
+ "EV90" = quantile(ExitSpeed[BBE == TRUE], .9, na.rm = TRUE),
312
+ "Max EV" = max(ExitSpeed[BBE == TRUE], na.rm = TRUE),
313
+ "Max EV" = ifelse(is.infinite(`Max EV`), NA, `Max EV`),
314
+ "GB%" = mean(GB[BBE == TRUE], na.rm = TRUE),
315
+ "LD%" = mean(LD[BBE == TRUE], na.rm = TRUE),
316
+ "FB%" = mean(FB[BBE == TRUE], na.rm = TRUE),
317
+ "AVG" = round(sum(Hit, na.rm = TRUE) / sum(AB, na.rm = TRUE), digits = 3),
318
+ "OBP" = round((sum(Hit, na.rm = TRUE) + sum(Walk, na.rm = TRUE) + sum(HBP, na.rm = TRUE)) /
319
+ sum(PA, na.rm = TRUE), digits = 3),
320
+ "SLG" = (round(sum(Single, na.rm = TRUE) + sum(Double, na.rm = TRUE) * 2 +
321
+ sum(Triple, na.rm = TRUE) * 3 + sum(HR, na.rm = TRUE))) / sum(AB, na.rm = TRUE)
322
+ ) %>%
323
+ ungroup() %>%
324
+ arrange(desc(BatterSide),desc(Pitches)) %>%
325
+ gt() %>%
326
+ gt_theme_tim() %>%
327
+ fmt_number(columns = `Avg EV`:`Max EV`, decimals = 1) %>%
328
+ cols_label(AutoPitchType = "Type", BatterSide = "Side") %>%
329
+ cols_width(
330
+ AutoPitchType ~ px(100),
331
+ Pitches ~ px(70),
332
+ BatterSide ~ px(70),
333
+ everything() ~ px(85)
334
+ ) %>%
335
+ cols_align(align = "center") %>%
336
+ fmt_number(columns = AVG:SLG, decimals = 3) %>%
337
+ fmt_percent(columns = ends_with("%")) %>%
338
+ sub_missing() %>%
339
+ opt_interactive(
340
+ use_compact_mode = TRUE,
341
+ use_pagination = FALSE
342
+ )
343
+ })
344
+ output$InningFilter <- render_gt({
345
+ test <- test %>% filter(Pitcher == input$player) %>% group_by(Inning) %>%
346
+ summarise(
347
+ Pitches = n(),
348
+ #BBE = sum(BBE,na.rm = TRUE),
349
+ "Whiff%" = mean(Whiff,na.rm = TRUE),
350
+ "CSW%" = mean(CSW,na.rm = TRUE),
351
+ "Zone%" = mean(Zone,na.rm = TRUE),
352
+ "ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
353
+ "ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
354
+ "OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
355
+ "OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
356
+ "Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
357
+ "EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
358
+ "Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
359
+ "Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
360
+ "GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
361
+ "LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
362
+ "FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
363
+ "AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
364
+ "OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
365
+ sum(PA,na.rm = TRUE),digits = 3),
366
+ "SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
367
+ sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
368
+ ungroup()%>%
369
+ gt() %>%
370
+ gt_theme_tim() %>%
371
+ fmt_number(columns = `Avg EV`:`Max EV`,decimals = 1) %>%
372
+ cols_width(Inning:Pitches ~ px(70),
373
+ everything() ~ px(85)) %>%
374
+ cols_align(align = "center") %>%
375
+ fmt_number(columns = AVG:SLG,decimals = 3) %>%
376
+ fmt_percent(columns = ends_with("%")) %>%
377
+ sub_missing() %>%
378
+ #gt_theme_savant() %>%
379
+ opt_interactive(
380
+ use_compact_mode = TRUE,
381
+ use_pagination = FALSE
382
+ )
383
+ })
384
+ output$SideFilter <- render_gt({
385
+ test1 <- test %>% filter(Pitcher == input$player) %>% group_by(BatterSide) %>%
386
+ summarise(
387
+ Pitches = n(),
388
+ #BBE = sum(BBE,na.rm = TRUE),
389
+ "Whiff%" = mean(Whiff,na.rm = TRUE),
390
+ "CSW%" = mean(CSW,na.rm = TRUE),
391
+ "Zone%" = mean(Zone,na.rm = TRUE),
392
+ "ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
393
+ "ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
394
+ "OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
395
+ "OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
396
+ "Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
397
+ "EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
398
+ "Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
399
+ "Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
400
+ "GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
401
+ "LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
402
+ "FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
403
+ "AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
404
+ "OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
405
+ sum(PA,na.rm = TRUE),digits = 3),
406
+ "SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
407
+ sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
408
+ ungroup()
409
+ test2 <- test %>% mutate(BatterSide = "Both") %>%filter(Pitcher == "Beam, Drew") %>% group_by(BatterSide) %>%
410
+ summarise(
411
+ Pitches = n(),
412
+ #BBE = sum(BBE,na.rm = TRUE),
413
+ "Whiff%" = mean(Whiff,na.rm = TRUE),
414
+ "CSW%" = mean(CSW,na.rm = TRUE),
415
+ "Zone%" = mean(Zone,na.rm = TRUE),
416
+ "ZCon%" = mean(Contact[Zone == TRUE & Swing == TRUE],na.rm = TRUE),
417
+ "ZSwing%" = mean(Swing[Zone == TRUE],na.rm = TRUE),
418
+ "OCon%" = mean(Contact[Zone == FALSE & Swing == TRUE],na.rm = TRUE),
419
+ "OSwing%" = mean(Swing[Zone == FALSE],na.rm = TRUE),
420
+ "Avg EV" = mean(ExitSpeed[BBE == TRUE],na.rm = TRUE),
421
+ "EV90" = quantile(ExitSpeed[BBE == TRUE],.9,na.rm = TRUE),
422
+ "Max EV" = max(ExitSpeed[BBE == TRUE],na.rm = TRUE),
423
+ "Max EV" = ifelse(is.infinite(`Max EV`),NA,`Max EV`),
424
+ "GB%" = mean(GB[BBE == TRUE],na.rm = TRUE),
425
+ "LD%" = mean(LD[BBE == TRUE],na.rm = TRUE),
426
+ "FB%" = mean(FB[BBE == TRUE],na.rm = TRUE),
427
+ "AVG" = round(sum(Hit,na.rm = TRUE) / sum(AB,na.rm = TRUE),digits = 3),
428
+ "OBP" = round((sum(Hit,na.rm = TRUE) + sum(Walk,na.rm = TRUE) + sum(HBP,na.rm = TRUE))/
429
+ sum(PA,na.rm = TRUE),digits = 3),
430
+ "SLG" = (round(sum(Single,na.rm = TRUE) + sum(Double,na.rm = TRUE) * 2 +
431
+ sum(Triple,na.rm = TRUE) * 3 + sum(HR,na.rm = TRUE)))/sum(AB,na.rm = TRUE))%>%
432
+ ungroup()
433
+ test <- rbind(test1,test2)
434
+ test %>%
435
+ gt() %>%
436
+ gt_theme_tim() %>%
437
+ fmt_number(columns = `Avg EV`:`Max EV`,decimals = 1) %>%
438
+ cols_width(BatterSide:Pitches ~ px(70),
439
+ everything() ~ px(85)) %>%
440
+ cols_align(align = "center") %>%
441
+ cols_label(BatterSide = "Side") %>%
442
+ fmt_number(columns = AVG:SLG,decimals = 3) %>%
443
+ fmt_percent(columns = ends_with("%")) %>%
444
+ sub_missing() %>%
445
+ #gt_theme_savant() %>%
446
+ opt_interactive(
447
+ use_compact_mode = TRUE,
448
+ use_pagination = FALSE
449
+ )
450
+
451
+ })
452
+ output$slashline <- render_gt({
453
+ test <- test %>% filter(Pitcher == input$player) %>%
454
+ summarise(
455
+ Pitches = n(),
456
+ `1B` = sum(Single,na.rm = TRUE),
457
+ `2B` = sum(Double,na.rm = TRUE),
458
+ `3B` = sum(Triple,na.rm = TRUE),
459
+ HR = sum(HR,na.rm = TRUE),
460
+ SO = sum(Strikeout,na.rm = TRUE),
461
+ BB = sum(Walk,na.rm = TRUE),
462
+ Whiffs = sum(Whiff,na.rm = TRUE),
463
+ `Hard Hits` = sum(HardHit,na.rm = TRUE)
464
+ )%>%
465
+ ungroup()%>%
466
+ gt() %>%
467
+ gt_theme_tim() %>%
468
+ cols_align(align = "center") %>%
469
+ # gt_theme_savant() %>%
470
+ opt_interactive(
471
+ use_compact_mode = TRUE,
472
+ use_pagination = FALSE
473
+ )
474
+ })
475
+ }
476
+
477
+ # Run the application
478
+ shinyApp(ui = ui, server = server)