igroffman commited on
Commit
5be2ddf
·
verified ·
1 Parent(s): 60b3182

Update app.R

Browse files
Files changed (1) hide show
  1. app.R +135 -8
app.R CHANGED
@@ -128,6 +128,35 @@ app_css <- "
128
  font-weight: bold;
129
  color: #333;
130
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
  "
132
 
133
  # =====================================================================
@@ -723,26 +752,88 @@ create_report_contact_chart <- function(game_data, player_name) {
723
  }
724
 
725
  calculate_leaderboards <- function(df, team_meta_df = team_meta) {
726
-
727
- format_name <- function(name) {
 
728
  if (is.na(name)) return(name)
729
  stringr::str_replace(name, "^\\s*(\\w+)\\s*,\\s*(\\w+)\\s*$", "\\2 \\1")
730
  }
731
-
732
  get_logo <- function(team_abbr) {
733
  if (is.null(team_meta_df) || is.null(team_abbr) || is.na(team_abbr)) return("")
 
734
  logo <- team_meta_df$BTeamLogo[team_meta_df$team_abbr == team_abbr]
735
  if (length(logo) == 0 || is.na(logo[1])) return("")
736
  logo[1]
737
  }
738
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
739
  top_ev <- df %>%
740
  filter(!is.na(ExitSpeed), !is.na(Batter)) %>%
741
  group_by(Batter, BatterTeam) %>%
742
  summarise(MaxEV = max(ExitSpeed, na.rm = TRUE), .groups = "drop") %>%
743
  arrange(desc(MaxEV)) %>%
744
  head(5) %>%
745
- mutate(Logo = sapply(BatterTeam, get_logo))
 
746
 
747
  top_dist <- df %>%
748
  filter(!is.na(Distance), !is.na(Batter), Distance > 0) %>%
@@ -750,7 +841,8 @@ calculate_leaderboards <- function(df, team_meta_df = team_meta) {
750
  summarise(MaxDist = max(Distance, na.rm = TRUE), .groups = "drop") %>%
751
  arrange(desc(MaxDist)) %>%
752
  head(5) %>%
753
- mutate(Logo = sapply(BatterTeam, get_logo))
 
754
 
755
  top_velo <- df %>%
756
  filter(!is.na(RelSpeed), !is.na(Pitcher)) %>%
@@ -758,7 +850,8 @@ calculate_leaderboards <- function(df, team_meta_df = team_meta) {
758
  summarise(MaxVelo = max(RelSpeed, na.rm = TRUE), .groups = "drop") %>%
759
  arrange(desc(MaxVelo)) %>%
760
  head(5) %>%
761
- mutate(Logo = sapply(PitcherTeam, get_logo))
 
762
 
763
  top_whiffs <- df %>%
764
  filter(!is.na(Pitcher)) %>%
@@ -766,9 +859,16 @@ calculate_leaderboards <- function(df, team_meta_df = team_meta) {
766
  summarise(Whiffs = sum(PitchCall == "StrikeSwinging", na.rm = TRUE), .groups = "drop") %>%
767
  arrange(desc(Whiffs)) %>%
768
  head(5) %>%
769
- mutate(Logo = sapply(PitcherTeam, get_logo))
 
770
 
771
- list(exit_velo = top_ev, distance = top_dist, pitch_velo = top_velo, whiffs = top_whiffs)
 
 
 
 
 
 
772
  }
773
 
774
  create_simple_header <- function(player_name, game_date, bio_data = NULL) {
@@ -3610,8 +3710,15 @@ output$leaderboard_ui <- renderUI({
3610
  if (is.null(df)) return(NULL)
3611
 
3612
  leaders <- calculate_leaderboards(df)
 
3613
 
3614
  make_column <- function(title, data, name_col, value_col, unit) {
 
 
 
 
 
 
3615
  rows <- lapply(seq_len(nrow(data)), function(i) {
3616
  logo_html <- if (nzchar(data$Logo[i])) {
3617
  tags$img(src = data$Logo[i], class = "leaderboard-logo",
@@ -3628,7 +3735,27 @@ output$leaderboard_ui <- renderUI({
3628
  }
3629
 
3630
  div(class = "leaderboard-section",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3631
  h3(class = "leaderboard-title", icon("trophy"), " Game Leaders"),
 
3632
  div(class = "leaderboard-grid",
3633
  make_column("Top Exit Velocity", leaders$exit_velo, "Batter", "MaxEV", "MPH"),
3634
  make_column("Top Distances", leaders$distance, "Batter", "MaxDist", "Ft."),
 
128
  font-weight: bold;
129
  color: #333;
130
  }
131
+ .game-info-bar {
132
+ display: flex;
133
+ justify-content: space-between;
134
+ align-items: center;
135
+ background: linear-gradient(135deg, #006F71 0%, #00a8a8 100%);
136
+ color: white;
137
+ padding: 12px 20px;
138
+ border-radius: 8px;
139
+ margin-bottom: 15px;
140
+ font-size: 0.95em;
141
+ }
142
+ .game-info-item {
143
+ display: flex;
144
+ flex-direction: column;
145
+ align-items: center;
146
+ }
147
+ .game-info-label {
148
+ font-size: 0.75em;
149
+ opacity: 0.85;
150
+ text-transform: uppercase;
151
+ }
152
+ .game-info-value {
153
+ font-weight: bold;
154
+ font-size: 1.1em;
155
+ }
156
+ .game-score {
157
+ font-size: 1.2em;
158
+ font-weight: bold;
159
+ }
160
  "
161
 
162
  # =====================================================================
 
752
  }
753
 
754
  calculate_leaderboards <- function(df, team_meta_df = team_meta) {
755
+
756
+ # Helper to format names from "Last, First" to "First Last"
757
+ format_name <- function(name) {
758
  if (is.na(name)) return(name)
759
  stringr::str_replace(name, "^\\s*(\\w+)\\s*,\\s*(\\w+)\\s*$", "\\2 \\1")
760
  }
761
+
762
  get_logo <- function(team_abbr) {
763
  if (is.null(team_meta_df) || is.null(team_abbr) || is.na(team_abbr)) return("")
764
+ # Match BatterTeam/PitcherTeam to team_abbr in TMB
765
  logo <- team_meta_df$BTeamLogo[team_meta_df$team_abbr == team_abbr]
766
  if (length(logo) == 0 || is.na(logo[1])) return("")
767
  logo[1]
768
  }
769
 
770
+ # Game Info
771
+ stadium <- if ("Stadium" %in% names(df)) unique(na.omit(df$Stadium))[1] else "Unknown"
772
+ level <- if ("Level" %in% names(df)) unique(na.omit(df$Level))[1] else ""
773
+
774
+ league <- if ("League" %in% names(df)) unique(na.omit(df$League))[1] else ""
775
+
776
+ # Format date to MM/DD/YYYY
777
+ game_date <- if ("Date" %in% names(df)) {
778
+ raw_date <- unique(na.omit(df$Date))[1]
779
+ parsed <- tryCatch({
780
+ if (grepl("^\\d{4}-\\d{1,2}-\\d{1,2}", raw_date)) {
781
+ as.Date(raw_date, format = "%Y-%m-%d")
782
+ } else if (grepl("^\\d{1,2}/\\d{1,2}/\\d{4}", raw_date)) {
783
+ as.Date(raw_date, format = "%m/%d/%Y")
784
+ } else {
785
+ as.Date(raw_date)
786
+ }
787
+ }, error = function(e) Sys.Date())
788
+ format(parsed, "%m/%d/%Y")
789
+ } else format(Sys.Date(), "%m/%d/%Y")
790
+
791
+ # Calculate final score from RunsScored
792
+ teams <- unique(c(df$BatterTeam, df$PitcherTeam))
793
+ teams <- teams[!is.na(teams)]
794
+
795
+ score_info <- df %>%
796
+ filter(!is.na(RunsScored), RunsScored > 0) %>%
797
+ group_by(BatterTeam) %>%
798
+ summarise(Runs = sum(RunsScored, na.rm = TRUE), .groups = "drop") %>%
799
+ arrange(desc(Runs))
800
+
801
+ if (nrow(score_info) >= 2) {
802
+ team1 <- score_info$BatterTeam[1]
803
+ runs1 <- score_info$Runs[1]
804
+ team2 <- score_info$BatterTeam[2]
805
+ runs2 <- score_info$Runs[2]
806
+
807
+ # Get team names from TMB if available
808
+ get_team_name <- function(abbr) {
809
+ if (is.null(team_meta_df)) return(abbr)
810
+ name <- team_meta_df$BTeamName[team_meta_df$team_abbr == abbr]
811
+ if (length(name) == 0 || is.na(name[1])) return(abbr)
812
+ name[1]
813
+ }
814
+
815
+ final_score <- paste0(get_team_name(team1), " ", runs1, " - ",
816
+ get_team_name(team2), " ", runs2)
817
+ } else {
818
+ final_score <- "Score N/A"
819
+ }
820
+
821
+ game_info <- list(
822
+ stadium = stadium,
823
+ level = level,
824
+ league = league,
825
+ date = game_date,
826
+ final_score = final_score
827
+ )
828
+
829
  top_ev <- df %>%
830
  filter(!is.na(ExitSpeed), !is.na(Batter)) %>%
831
  group_by(Batter, BatterTeam) %>%
832
  summarise(MaxEV = max(ExitSpeed, na.rm = TRUE), .groups = "drop") %>%
833
  arrange(desc(MaxEV)) %>%
834
  head(5) %>%
835
+ mutate(Batter = sapply(Batter, format_name),
836
+ Logo = sapply(BatterTeam, get_logo))
837
 
838
  top_dist <- df %>%
839
  filter(!is.na(Distance), !is.na(Batter), Distance > 0) %>%
 
841
  summarise(MaxDist = max(Distance, na.rm = TRUE), .groups = "drop") %>%
842
  arrange(desc(MaxDist)) %>%
843
  head(5) %>%
844
+ mutate(Batter = sapply(Batter, format_name),
845
+ Logo = sapply(BatterTeam, get_logo))
846
 
847
  top_velo <- df %>%
848
  filter(!is.na(RelSpeed), !is.na(Pitcher)) %>%
 
850
  summarise(MaxVelo = max(RelSpeed, na.rm = TRUE), .groups = "drop") %>%
851
  arrange(desc(MaxVelo)) %>%
852
  head(5) %>%
853
+ mutate(Pitcher = sapply(Pitcher, format_name),
854
+ Logo = sapply(PitcherTeam, get_logo))
855
 
856
  top_whiffs <- df %>%
857
  filter(!is.na(Pitcher)) %>%
 
859
  summarise(Whiffs = sum(PitchCall == "StrikeSwinging", na.rm = TRUE), .groups = "drop") %>%
860
  arrange(desc(Whiffs)) %>%
861
  head(5) %>%
862
+ mutate(Pitcher = sapply(Pitcher, format_name),
863
+ Logo = sapply(PitcherTeam, get_logo))
864
 
865
+ list(
866
+ game_info = game_info,
867
+ exit_velo = top_ev,
868
+ distance = top_dist,
869
+ pitch_velo = top_velo,
870
+ whiffs = top_whiffs
871
+ )
872
  }
873
 
874
  create_simple_header <- function(player_name, game_date, bio_data = NULL) {
 
3710
  if (is.null(df)) return(NULL)
3711
 
3712
  leaders <- calculate_leaderboards(df)
3713
+ gi <- leaders$game_info
3714
 
3715
  make_column <- function(title, data, name_col, value_col, unit) {
3716
+ if (nrow(data) == 0) {
3717
+ return(div(class = "leaderboard-column",
3718
+ div(class = "leaderboard-column-header", span(title), span(unit)),
3719
+ div("No data available", style = "color: #999; padding: 10px;")))
3720
+ }
3721
+
3722
  rows <- lapply(seq_len(nrow(data)), function(i) {
3723
  logo_html <- if (nzchar(data$Logo[i])) {
3724
  tags$img(src = data$Logo[i], class = "leaderboard-logo",
 
3735
  }
3736
 
3737
  div(class = "leaderboard-section",
3738
+ # Game Info Bar
3739
+ div(class = "game-info-bar",
3740
+ div(class = "game-info-item",
3741
+ span(class = "game-info-label", "Date"),
3742
+ span(class = "game-info-value", gi$date)),
3743
+ div(class = "game-info-item",
3744
+ span(class = "game-info-label", "Stadium"),
3745
+ span(class = "game-info-value", gi$stadium)),
3746
+ div(class = "game-info-item",
3747
+ span(class = "game-info-label", "Level"),
3748
+ span(class = "game-info-value", gi$level)),
3749
+ div(class = "game-info-item",
3750
+ span(class = "game-info-label", "League"),
3751
+ span(class = "game-info-value", gi$league)),
3752
+ div(class = "game-info-item",
3753
+ span(class = "game-info-label", "Final Score"),
3754
+ span(class = "game-score", gi$final_score))
3755
+ ),
3756
+ # Leaders Title
3757
  h3(class = "leaderboard-title", icon("trophy"), " Game Leaders"),
3758
+ # Leaders Grid
3759
  div(class = "leaderboard-grid",
3760
  make_column("Top Exit Velocity", leaders$exit_velo, "Batter", "MaxEV", "MPH"),
3761
  make_column("Top Distances", leaders$distance, "Batter", "MaxDist", "Ft."),