---
title: "Untitled"
author: "RN7"
date: "1/18/2020"
output: html_document
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

# pkgs

```{r, message=FALSE, warning=FALSE}
pacman::p_load(tidyverse, polite, scales, ggimage, 
               ggforce, ggtext,
               rvest, glue, extrafont, ggrepel, magick)
loadfonts()
```

## add_logo

```{r}
add_logo <- function(plot_path, logo_path, logo_position, 
                     logo_scale = 10){

    # Requires magick R Package https://github.com/ropensci/magick

    # Useful error message for logo position
    if (!logo_position %in% c("top right", "top left", "bottom right", "bottom left")) {
        stop("Error Message: Uh oh! Logo Position not recognized\n  Try: logo_positon = 'top left', 'top right', 'bottom left', or 'bottom right'")
    }

    # read in raw images
    plot <- magick::image_read(plot_path)
    logo_raw <- magick::image_read(logo_path)

    # get dimensions of plot for scaling
    plot_height <- magick::image_info(plot)$height
    plot_width <- magick::image_info(plot)$width

    # default scale to 1/10th width of plot
    # Can change with logo_scale
    logo <- magick::image_scale(logo_raw, as.character(plot_width/logo_scale))

    # Get width of logo
    logo_width <- magick::image_info(logo)$width
    logo_height <- magick::image_info(logo)$height

    # Set position of logo
    # Position starts at 0,0 at top left
    # Using 0.01 for 1% - aesthetic padding

    if (logo_position == "top right") {
        x_pos = plot_width - logo_width - 0.01 * plot_width
        y_pos = 0.01 * plot_height
    } else if (logo_position == "top left") {
        x_pos = 0.01 * plot_width
        y_pos = 0.01 * plot_height
    } else if (logo_position == "bottom right") {
        x_pos = plot_width - logo_width - 0.01 * plot_width
        y_pos = plot_height - logo_height - 0.01 * plot_height
    } else if (logo_position == "bottom left") {
        x_pos = 0.01 * plot_width
        y_pos = plot_height - logo_height - 0.01 * plot_height
    }

    # Compose the actual overlay
    magick::image_composite(plot, logo, offset = paste0("+", x_pos, "+", y_pos))
}
```



# Bundesliga data

- Save "Player Standard Stats" & "Squad Standard Stats" as a `.csv` file or whatever you prefer.
- https://fbref.com/en/comps/20/passing/Bundesliga-Stats

## advanced stats


```{r}
buli_player_goalkeeping_stats_hinrunde_raw <- read_csv(here::here("data/buli_player_goalkeeping_stats_hinrunde.csv"),
                                  skip = 1, col_names = TRUE) %>% 
    select(-Matches, -Rk)

buli_player_goalkeeping_stats_hinrunde <- buli_player_goalkeeping_stats_hinrunde_raw %>% 
  rename_at(vars(15:17), 
            ~ glue::glue("launch_{colnames(buli_player_goalkeeping_stats_hinrunde_raw)[15:17]}")) %>% 
  rename_at(vars(18:21), 
            ~ glue::glue("pass_{colnames(buli_player_goalkeeping_stats_hinrunde_raw)[18:21]}")) %>% 
  rename_at(vars(22:24), 
            ~ glue::glue("goalkick_{colnames(buli_player_goalkeeping_stats_hinrunde_raw)[22:24]}")) %>% 
  rename_at(vars(25:27), 
            ~ glue::glue("crosses_{colnames(buli_player_goalkeeping_stats_hinrunde_raw)[25:27]}"))


buli_player_goalkeeping_stats_hinrunde <- buli_player_goalkeeping_stats_hinrunde %>% 
  rename_all(~str_replace_all(colnames(buli_player_goalkeeping_stats_hinrunde), "_[0-9]", "")) %>% 
  rename(PSxGper90 = `/90`)

glimpse(buli_player_goalkeeping_stats_hinrunde)
```


## regular stats

```{r}
buli_player_regular_goalkeeping_stats_hinrunde_raw <- read_csv(here::here("data/buli_player_regular_goalkeeping_stats_hinrunde.csv"), skip = 1, col_names = TRUE) %>% 
    select(-Matches, -Rk)

buli_player_regular_goalkeeping_stats_hinrunde <- buli_player_regular_goalkeeping_stats_hinrunde_raw %>% 
  separate(Player, into = c("fullname", "allname"), 
           sep = "\\\\") %>% 
  separate(fullname, into = c("firstname", "lastname"),
           sep = "\\s", extra = "merge", remove = FALSE) %>%
  mutate(fname = str_extract(firstname, "[A-Z]{1}")) %>% 
  ## players like Fabinho listed without Tavares last name
  mutate(player = if_else(is.na(lastname), firstname, lastname)) %>% 
  mutate(player = case_when(
    !is.na(lastname) ~ glue("{fname}. {lastname}"),
    TRUE ~ firstname)) %>% 
  select(-firstname, -fname, -lastname, -allname)


glimpse(buli_player_regular_goalkeeping_stats_hinrunde)
```


## clean

```{r}
buli_player_goalkeeping_hinrunde_clean <- buli_player_goalkeeping_stats_hinrunde %>% 
  separate(Player, into = c("fullname", "allname"), sep = "\\\\") %>%   separate(fullname, into = c("firstname", "lastname"),
           sep = "\\s", extra = "merge",
           remove = FALSE) %>%
  mutate(fname = str_extract(firstname, "[A-Z]{1}")) %>% 
  ## players like Fabinho listed without Tavares last name
  mutate(player = if_else(is.na(lastname), firstname, lastname)) %>% 
  mutate(player = case_when(
    !is.na(lastname) ~ glue("{fname}. {lastname}"),
    TRUE ~ firstname)) %>% 
  left_join(buli_player_regular_goalkeeping_stats_hinrunde) %>% 
  mutate(
    min = `90s` * 90,
    GSAA = PSxG - GA,
    GSAAper90 = (GSAA / min) * 90,
    `xSave%` = (SoTA - PSxG) / SoTA,
    GSAA_perc = `Save%` - `xSave%`,
    minPerSave = min / Saves) %>% 
  ## GSAA %: (SoTA - PSxG) / SoTA
  rename(team_name = Squad) %>% 
  ## keep fullname so can differentiate A. Gomes (Andre/Angel), etc.
  select(-`90s`, -firstname, -fname, -lastname, -allname)

glimpse(buli_player_goalkeeping_hinrunde_clean)
```


```{r}
## save
saveRDS(buli_player_goalkeeping_hinrunde_clean, 
        file = glue("{here::here()}/data/buli_player_goalkeeping_hinrunde_clean.RDS"))

buli_player_goalkeeping_hinrunde_clean <- readRDS(
  file = glue("{here::here()}/data/buli_player_goalkeeping_hinrunde_clean.RDS"))
```




# plot



```{r}
buli_player_goalkeeping_hinrunde_clean %>% 
  filter(min >= 900) %>% 
  summarize(avg_psxgper90 = median(PSxGper90),
            avg_GA = median(GA),
            avg_GSAA = median(GSAA),
            avg_SV_perc = median(`Save%`),
            avg_xSV_perc = median(`xSave%`),
            avg_minperSave = median(minPerSave),
            avg_GSAA_perc = median(GSAA_perc))

buli_player_goalkeeping_hinrunde_clean %>% 
  filter(min >= 900) %>% 
  summarize(avg_psxgper90 = mean(PSxGper90),
            avg_GA = mean(GA),
            avg_GSAA = mean(GSAA))
```


```{r}
bad_box <- data.frame(
  xmin = -Inf, xmax = 0, 
  ymin = -Inf, ymax = 28.86)

chance_creation_box <- data.frame(
  xmin = -Inf, xmax = 0, 
  ymin = 28.86, ymax = Inf)

midfield_progress_box <- data.frame(
  xmin = 0, xmax = Inf, 
  ymin = -Inf, ymax = 28.86)

dual_box <- data.frame(
  xmin = 0, xmax = Inf, 
  ymin = 28.86, ymax = Inf)
```





```{r}
buli_player_goalkeeping_hinrunde_clean %>% 
  filter(min >= 900) %>% 
  ggplot(aes(x = GA, y = PSxGper90)) +
  geom_point() +
  geom_label_repel(aes(label = player))
```



```{r fig.width = 14, fig.height = 10}
buli_player_goalkeeping_hinrunde_clean %>% 
  filter(min >= 900) %>% 
  ggplot(aes(x = GA, y = GSAA)) +
  geom_point(aes(size = `xSave%`), color = "red") +
  geom_text_repel(aes(label = player)) +
  geom_vline(xintercept = 23) +
  geom_hline(yintercept = -1.2) +
  scale_x_reverse() +
  theme_minimal()
```





## Minutes / Save  vs. GSAA

```{r}
buli_gk <- buli_player_goalkeeping_hinrunde_clean %>% 
  filter(min >= 900) %>% 
  mutate(fillcol = case_when(
    GSAA_perc < 0 & minPerSave < 28.86 ~ "red",
    GSAA_perc > 0 & minPerSave < 28.86 ~ "yellow",
    GSAA_perc < 0 & minPerSave > 28.86 ~ "orange",
    GSAA_perc > 0 & minPerSave > 28.86 ~ "green",
    TRUE ~ NA_character_))
```

```{r}
point_cols <- c("yellow" = "yellow", "red" = "red",
                "orange" = "orange", "green" = "#228B22")
```


```{r}
sommer_desc <- "Yann Sommer has been in excellent form and has helped push Die Fohlen to become genuine title challengers this season. The Swiss is tied 1st for least goals conceded, 1st in Goals Against per 90 (1.06), & boasts a 6.4 GSAA (best in the league by a considerable margin, over 4 goals compared to 2nd placed Gikiewicz)."

burki_desc <- "Roman Burki is having a tough time in goal with the worst Save % in the league(47.7%) and a dreadful -16 GSAA % showing how he has leaked a lot of goals that the post-shot model expected him to save. BVB's defense may also share the blame with 3 own goals and Bürki's league-worst 0.38 PSxG/Shot on Target can also be attributed to opponent strikers being very clinical."

pavlenka_desc <- "Jiri Pavlenka is giving up a league-worst 2.41 Goals Against per 90 but he is not helped by a defense that forces him into a save every 27 minutes on average. Although the post-shot model has him saving the highest percentage of shots faced in the league (67.7% xSaves) the Czech has a -10.8 GSAA %."
```




```{r fig.width = 14, fig.height = 10}
buli_goalkeeping_hinrunde_plot <- buli_gk %>% 
  ggplot(aes(x = GSAA_perc, y = minPerSave)) +
  geom_vline(xintercept = 0) +
  geom_hline(yintercept = 28.86) +
  ## area fills
  geom_rect(data = chance_creation_box,
            aes(x = NULL, y = NULL,
                xmin = xmin, xmax = xmax,
                ymin = ymin, ymax = ymax),
            fill = "orange", alpha = 0.1) +
  geom_rect(data = bad_box,
            aes(x = NULL, y = NULL,
                xmin = xmin, xmax = xmax,
                ymin = ymin, ymax = ymax),
            fill = "red", alpha = 0.1) +
  geom_rect(data = midfield_progress_box,
            aes(x = NULL, y = NULL,
                xmin = xmin, xmax = xmax,
                ymin = ymin, ymax = ymax),
            fill = "yellow", alpha = 0.2) +
  geom_rect(data = dual_box,
            aes(x = NULL, y = NULL,
                xmin = xmin, xmax = xmax,
                ymin = ymin, ymax = ymax),
            fill = "green", alpha = 0.1) +
    ## area labels
  annotate("text", family = "Roboto Condensed", fontface = "bold",
           x = -0.2, y = 19, 
           hjust = 0, color = "red", size = 6,
           label = "Busy & Saving Less Than Average GK") +
  annotate("text", family = "Roboto Condensed", fontface = "bold",
           x = -0.2, y = 54, 
           hjust = 0, color = "orange", size = 6,
           label = "Not Busy & Saving Less Than Average GK") +
  annotate( # #7f7f00  #228B22 #CCCC00
    "text", family = "Roboto Condensed", fontface = "bold",
    x = 0.02, y = 54, 
    hjust = 0, color = "#228B22", size = 6,
    label = "Not Busy & Saving More Than Average GK") +
  annotate(
    "text", family = "Roboto Condensed", fontface = "bold",
    x = 0.02, y = 19, 
    hjust = 0, color = "#7f7f00", size = 6,
    label = "Busy & Saving More Than Average GK") +
  ## avg minutes per save
  annotate(
    "text", family = "Roboto Condensed", fontface = "bold",
    x = -0.2, y = 29.5, 
    hjust = 0, color = "grey20", size = 4,
    label = "Average: 28.6 Minutes per Save") +
  ## player data
  geom_point(aes(fill = factor(fillcol)), 
             shape = 21, size = 3) +
  scale_fill_manual(values = point_cols,
                    guide = NULL) +
  geom_text_repel(
    data = buli_gk %>% 
      filter(!player %in% c("J. Pavlenka", "R. Bürki",
                            "Y. Sommer")),
    aes(label = player, family = "Roboto Condensed", 
        fontface = "bold", 
        segment.color = factor(fillcol)),
    min.segment.length = 0.3, seed = 15, size = 5,
    point.padding = 0.6, color = "grey20") +
  # Bürki
  geom_mark_hull(
    aes(filter = player == "R. Bürki",
        label = "Roman Bürki (Borussia Dortmund)",
        description = burki_desc),
    expand = unit(2.5, "mm"), con.cap = unit(0, "mm"),
    con.colour = "orange", color = "orange",
    label.width = unit(140, 'mm'), label.buffer = unit(4.95, "mm"),
    label.family = "Roboto Condensed", label.fontsize = c(14, 12),
    label.colour = "grey20", label.fill = "#ffe5cc") +
  # Pavlenka
  geom_mark_hull(
    aes(filter = player == "J. Pavlenka",
        label = "Jiri Pavlenka (Werder Bremen)",
        description = pavlenka_desc),
    expand = unit(2.5, "mm"), con.cap = unit(0, "mm"),
    con.colour = "red", color = "red", 
    label.width = unit(140, 'mm'), label.buffer = unit(0.5, "mm"),
    label.family = "Roboto Condensed", label.fontsize = c(14, 12),
    label.colour = "grey20", label.fill = "#FFCCCC") +
  # Sommer
  geom_mark_hull(
    aes(filter = player == "Y. Sommer",
        label = "Yann Sommer (Borussia Mönchengladbach)",
        description = sommer_desc),
    expand = unit(2.5, "mm"), con.cap = unit(0, "mm"),
    label.width = unit(120, 'mm'), label.buffer = unit(57, "mm"),
    label.family = "Roboto Condensed", label.fontsize = c(14, 12),
    label.colour = "grey20", label.fill = "#cce5cc") +
  scale_x_continuous(labels = scales::percent,
                     breaks = seq(-0.25, 0.15, 0.05),
                     limits = c(-0.2, 0.12),
                     expand = c(0.01, 0)) +
  scale_y_continuous(breaks = seq(20, 56, 10),
                     limits = c(18, 56),
                     expand = c(0.01, 0)) +
  labs(title = "Goalkeeper Performance & Workload: <b style='color: red'>Bundesliga (2019-2020)</b>",
       subtitle = glue::glue("
                             January 18th, 2020 | Hinrunde | Minimum 900 Minutes Played
                             <p>GSAA %: Whether a GK has saved more/less than the post-shot model expected an average GK to save (Actual Save % - Expected Save %)"),
       x = "Goals Saved Above Average Percentage (GSAA %)", 
       y = "Average Minutes per Save",
       caption = "Data: FBref | StatsBomb") +
  theme_minimal() +
  theme(text = element_text(family = "Roboto Condensed"),
        plot.title = element_markdown(size = 20),
        plot.subtitle = element_markdown(size = 16),
        plot.caption = element_text(size = 14),
        axis.title = element_text(size = 14),
        axis.text = element_text(size = 12))

buli_goalkeeping_hinrunde_plot
```




## save

```{r}
ggsave(plot = buli_goalkeeping_hinrunde_plot, 
       here::here("Bundesliga 2019-2020/output/buli_goalkeeping_1920_hinrunde.png"),
       height = 10, width = 14)
```

```{r}
plot_logo <- add_logo(
  plot_path = here::here("Bundesliga 2019-2020/output/buli_goalkeeping_1920_hinrunde.png"),
  logo_path = here::here("../soccer_match_reports/img/Bundesliga_logo_(2017).svg"),
  logo_position = "top right",
  logo_scale = 18)

plot_logo
```

```{r}
image_write(image = plot_logo, 
            here::here("Bundesliga 2019-2020/output/buli_goalkeeping_1920_hinrunde_logo.png"))
```






