TimStats commited on
Commit
f687602
·
verified ·
1 Parent(s): 725340b

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +277 -47
app.R CHANGED
@@ -1,58 +1,288 @@
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(shinydashboard)
3
+ library(shinyWidgets)
4
  library(ggplot2)
5
+ library(MASS) # For kde2d function
6
+ library(viridis) # For color palette
7
+ library(dplyr) # For data manipulation
8
+ library(httr)
9
+ library(patchwork) # For combining plots
10
 
11
+ download_private_csv <- function(repo_id, filename) {
12
+ url <- paste0("https://huggingface.co/spaces/", repo_id, "/resolve/main/", filename)
13
+ cat(url)
14
+ response <- GET(url)
15
+
16
+ if (status_code(response) == 200) {
17
+ content <- content(response, "text")
18
+ con <- textConnection(content)
19
+ data <- read.csv(con)
20
+ close(con)
21
+ return(data)
22
+ } else {
23
+ stop("Failed to download dataset")
24
+ }
25
+ }
26
+
27
+ heatMap <- function(data, gtitle, concen) {
28
+ custom_colors <- c("#333333","#46363a","#5a383f","#6d3944","#803947","#933948",
29
+ "#a63848","#b93647","#cb3445","#dd3340","#ee323b","#ff3333")
30
+
31
+ data_clean <- data %>%
32
+ filter(!is.na(px) & !is.na(pz) & is.finite(px) & is.finite(pz))
33
+
34
+ h_x <- MASS::bandwidth.nrd(data_clean$px)
35
+ h_z <- MASS::bandwidth.nrd(data_clean$pz)
36
+
37
+ bandwidth_factor <- concen
38
+
39
+ kde <- kde2d(data_clean$px, data_clean$pz, n = 200,
40
+ h = c(h_x, h_z) * bandwidth_factor,
41
+ lims = c(-3, 3, 0, 5))
42
+
43
+ df <- expand.grid(x = kde$x, y = kde$y)
44
+ df$density <- as.vector(kde$z)
45
+
46
+ ggplot(df, aes(x = x, y = y, z = density)) +
47
+ geom_contour_filled(bins = length(custom_colors) - 1) +
48
+ scale_fill_manual(values = custom_colors) +
49
+ coord_cartesian(xlim = c(-3,3), ylim = c(0,5)) +
50
+ coord_fixed(ratio = 1) +
51
+ labs(title = gtitle) +
52
+ theme_void() +
53
+ geom_segment(aes(x = -0.71, xend = 0.71, y = 1.5, yend = 1.5), colour = "black") +
54
+ geom_segment(aes(x = -0.71, xend = 0.71, y = 3.6, yend = 3.6), colour = "black") +
55
+ geom_segment(aes(x = 0.71, xend = 0.71, y = 1.5, yend = 3.6), colour = "black") +
56
+ geom_segment(aes(x = -0.71, xend = -0.71, y = 1.5, yend = 3.6), colour = "black") +
57
+ theme(
58
+ legend.position = "none",
59
+ plot.background = element_rect(fill = "#333333", color = NA),
60
+ panel.background = element_rect(fill = "#333333", color = NA),
61
+ text = element_text(color = "white"),
62
+ panel.grid = element_blank(),
63
+ plot.title = element_text(hjust = 0.5) # Center the title
64
+ )
65
+ }
66
+
67
+ mlb <- download_private_csv("TimStats/MiLBStatcast", paste0("MLB", "24T", ".csv"))
68
+ aaa <- download_private_csv("TimStats/MiLBStatcast", paste0("AAA", "24T", ".csv"))
69
+ fsl <- download_private_csv("TimStats/MiLBStatcast", paste0("FSL", "24T", ".csv"))
70
+
71
+ # ... (previous library imports and functions remain the same)
72
+
73
+ ui <- dashboardPage(
74
+ skin = "black", # Use the black skin for a darker theme
75
+ dashboardHeader(title = "Player Analysis Dashboard"),
76
+ dashboardSidebar(
77
+ sidebarMenu(
78
+ menuItem("Player Selection", tabName = "player", icon = icon("user"))
79
+ )
80
  ),
81
+ dashboardBody(
82
+ tags$head(
83
+ tags$style(HTML("
84
+ .content-wrapper, .right-side {
85
+ background-color: #333333;
86
+ }
87
+ .box {
88
+ background-color: #444444;
89
+ border-top: none;
90
+ color: #ffffff;
91
+ }
92
+ .box-header {
93
+ color: #ffffff;
94
+ }
95
+ .form-control {
96
+ background-color: #e0e0e0;
97
+ color: #333333;
98
+ border: 1px solid #777777;
99
+ }
100
+ .selectize-input {
101
+ background-color: #e0e0e0;
102
+ color: #333333;
103
+ }
104
+ .selectize-dropdown {
105
+ background-color: #e0e0e0;
106
+ color: #333333;
107
+ }
108
+ .selectize-dropdown-content {
109
+ background-color: #e0e0e0;
110
+ color: #333333;
111
+ }
112
+ .selectize-dropdown .active {
113
+ background-color: #b0b0b0;
114
+ color: #333333;
115
+ }
116
+ label {
117
+ color: #ffffff;
118
+ }
119
+ .irs-min, .irs-max, .irs-from, .irs-to, .irs-single {
120
+ color: #333333;
121
+ background-color: #e0e0e0;
122
+ }
123
+ .irs-bar {
124
+ border-top: 1px solid #428bca;
125
+ border-bottom: 1px solid #428bca;
126
+ background: #428bca;
127
+ }
128
+ .irs-line {
129
+ background: #e0e0e0;
130
+ border: 1px solid #777777;
131
+ }
132
+ .daterangepicker {
133
+ background-color: #e0e0e0;
134
+ color: #333333;
135
+ }
136
+ .daterangepicker .calendar-table {
137
+ background-color: #e0e0e0;
138
+ }
139
+ .daterangepicker td.active, .daterangepicker td.active:hover {
140
+ background-color: #007bff;
141
+ color: #ffffff;
142
+ }
143
+ .daterangepicker td.available:hover, .daterangepicker th.available:hover {
144
+ background-color: #b0b0b0;
145
+ }
146
+ .daterangepicker .calendar-table .next span, .daterangepicker .calendar-table .prev span {
147
+ color: #333333;
148
+ }
149
+ .daterangepicker .drp-selected {
150
+ color: #333333;
151
+ }
152
+ "))
153
+ ),
154
+ tabItems(
155
+ tabItem(tabName = "player",
156
+ fluidRow(
157
+ column(width = 3,
158
+ box(width = NULL, title = "Pick Player Here", status = "primary",
159
+ selectInput("league", "Select League:", choices = c("MLB","AAA","FSL")),
160
+ selectInput("player", "Select Player:", choices = c("")),
161
+ sliderInput("concen", "Heatmap Bandwidth", value = 1, step = 0.05, min = .5, max = 1.5)
162
+ )
163
+ ),
164
+ column(width = 4,
165
+ box(width = NULL, title = "Filters for Graph 1", status = "info",
166
+ selectInput("hand1", "Batter Handedness", choices = c("All Batters","LHH","RHH")),
167
+ selectInput("pitch1", "Pitch:", choices = c("")),
168
+ dateRangeInput("date1", "Date Range:", start = "2024-02-09", end = "2024-09-05")
169
+ )
170
+ ),
171
+ column(width = 4,
172
+ box(width = NULL, title = "Filters for Graph 2", status = "success",
173
+ selectInput("hand2", "Batter Handedness", choices = c("All Batters","LHH","RHH")),
174
+ selectInput("pitch2", "Pitch:", choices = c("")),
175
+ dateRangeInput("date2", "Date Range:", start = "2024-02-09", end = "2024-09-05")
176
+ )
177
+ )
178
+ ),
179
+ fluidRow(
180
+ column(width = 8,
181
+ box(width = NULL, title = "Combined Heatmap", status = "warning",
182
+ plotOutput("combined_graph", height = "600px")
183
+ )
184
+ )
185
+ )
186
+ )
187
+ )
188
+ )
189
  )
190
 
191
+
192
  server <- function(input, output, session) {
193
+
194
+ pname <- reactiveVal()
195
+
196
+ observeEvent(input$league, {
197
+ req(input$league) # Ensure league input is available
198
+ tryCatch({
199
+ if(input$league == "MLB"){
200
+ t <- mlb
201
+ } else if(input$league == "AAA"){
202
+ t <- aaa
203
+ } else if(input$league == "FSL"){
204
+ t <- fsl
205
+ }
206
+ pname(t)
207
+ updateSelectInput(
208
+ session = session,
209
+ inputId = "player",
210
+ label = "Select Player:",
211
+ choices = unique(t$`Pitcher.Name`),
212
+ selected = NULL
213
+ )
214
+ }, error = function(e) {
215
+ message("Error downloading or processing data: ", e$message)
216
+ })
217
  })
218
+
219
+ observeEvent(input$player, {
220
+ req(input$player)
221
+ tryCatch({
222
+ t <- pname()
223
+ d <- t |>
224
+ filter(`Pitcher.Name` == input$player)
225
+ updateSelectInput(
226
+ session = session,
227
+ inputId = "pitch1",
228
+ label = "Pitch:",
229
+ choices = unique(d$`pitch_name`),
230
+ selected = NULL
231
+ )
232
+ updateSelectInput(
233
+ session = session,
234
+ inputId = "pitch2",
235
+ label = "Pitch:",
236
+ choices = unique(d$`pitch_name`),
237
+ selected = NULL
238
+ )
239
+ }, error = function(e) {
240
+ message("Error processing player data: ", e$message)
241
+ })
242
+ })
243
+
244
+ output$combined_graph <- renderPlot({
245
+
246
+ t <- pname()
247
+
248
+ # Function to filter data based on inputs
249
+ filter_data <- function(hand, pitch, date_range) {
250
+ data <- if(hand == "All Batters") {
251
+ t %>% filter(`Pitcher.Name` == input$player)
252
+ } else if(hand == "LHH") {
253
+ t %>% filter(bhand == "L", `Pitcher.Name` == input$player)
254
+ } else {
255
+ t %>% filter(bhand == "R", `Pitcher.Name` == input$player)
256
  }
257
+
258
+ data %>%
259
+ filter(pitch_name == pitch) %>%
260
+ filter(between(as.Date(date), date_range[1], date_range[2]))
261
+ }
262
+
263
+ graph1_data <- filter_data(input$hand1, input$pitch1, input$date1)
264
+ graph2_data <- filter_data(input$hand2, input$pitch2, input$date2)
265
+
266
+ title1 <- paste0(input$player, " ", input$pitch1, " vs. ", input$hand1, "\n", input$date1[1], " to ", input$date1[2])
267
+ title2 <- paste0(input$player, " ", input$pitch2, " vs. ", input$hand2, "\n", input$date2[1], " to ", input$date2[2])
268
+
269
+ plot1 <- heatMap(graph1_data, title1, input$concen)
270
+ plot2 <- heatMap(graph2_data, title2, input$concen)
271
+
272
+ combined_plot <- plot1 + plot2 +
273
+ plot_layout(ncol = 2) +
274
+ plot_annotation(
275
+ title = paste0(input$player, " Pitch Comparison"),
276
+ theme = theme(
277
+ plot.title = element_text(hjust = 0.5, size = 20, color = "white"),
278
+ plot.background = element_rect(fill = "#333333", color = NA),
279
+ plot.margin = margin(0, 0, 0, 0)
280
+ )
281
+ ) &
282
+ theme(plot.margin = margin(0, 0, 0, 0))
283
+
284
+ return(combined_plot)
285
+ }, bg = "#333333", width = 800)
286
  }
287
 
288
+ shinyApp(ui = ui, server = server)