---
title: "Untitled"
author: "RN7"
date: "1/23/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}
serieA_player_goalkeeping_stats_MD20_raw <- read_csv(here::here("data/serieA_player_goalkeeping_stats_1-23-20.csv"),
                                  skip = 1, col_names = TRUE) %>% 
    select(-Matches, -Rk)

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


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

glimpse(serieA_player_goalkeeping_stats_MD20)
```


## regular stats

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

serieA_player_regular_goalkeeping_stats_MD20 <- serieA_player_regular_goalkeeping_stats_MD20_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(serieA_player_regular_goalkeeping_stats_MD20)
```


## clean

```{r}
serieA_player_goalkeeping_MD20_clean <- serieA_player_goalkeeping_stats_MD20 %>% 
  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(serieA_player_regular_goalkeeping_stats_MD20) %>% 
  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(serieA_player_goalkeeping_MD20_clean)
```


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

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





# plot



```{r}
serieA_player_goalkeeping_MD20_clean %>% 
  filter(min >= 1080) %>% 
  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))

serieA_player_goalkeeping_MD20_clean %>% 
  filter(min >= 1080) %>% 
  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 = 29.03)

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

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

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







## Minutes / Save  vs. GSAA

```{r}
serieA_gk <- serieA_player_goalkeeping_MD20_clean %>% 
  filter(min >= 1080) %>% 
  mutate(fillcol = case_when(
    GSAA_perc < 0 & minPerSave < 29.03 ~ "red",
    GSAA_perc > 0 & minPerSave < 29.03 ~ "yellow",
    GSAA_perc < 0 & minPerSave > 29.03 ~ "orange",
    GSAA_perc > 0 & minPerSave > 29.03 ~ "green",
    TRUE ~ NA_character_),
    player = as.character(player)) %>% 
  mutate(player = case_when(
    GSAA == 6.0 ~ "W. Szczesny",
    GA90 == 1.60 ~ "L. Skorupski",
    GSAA == -5.9 ~ "I. Radu",
    TRUE ~ player))
```

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


```{r}
wojciech_desc <- "As Juventus aim for a 9th consecutive Scudetto their Polish shot-stopper Wojciech Szczęsny has a 80% Save %, +6 GSAA, & +10 GSAA % (all the highest in the league). With a 0.92 Goals Against per 90 (2nd in Serie A) the entire defense's efforts allow Juventus to get results even when their attack is not doing well."

gollini_desc <- "Atalanta have been lauded for their ability to dominate games, indeed, they have conceded the least amount of shots on target. However, with a 56.1 Save % (worst in the league), Pierluigi Gollini is doing extremely poorly whenever troubled. The Italian has the 5th worst GSAA having conceded 4.1 goals from shots that the average goalkeeper would have expected to have saved."

gabriel_desc <- "Gabriel is the busiest keeper in Serie A being forced to make a league high 91 saves (A save every 19.9 minutes). With a +4.24 GSAA % (3rd best in the league) the Brazilian is proving his worth by keeping an otherwise woeful Lecce team just above the relegation spots."

radu_desc <- "Genoa are rooted to the bottom of the table & their Romanian shot-stopper has not helped in the slightest. With a 60.7 Save % (3rd worst in the league) Ionut Radu has been leaking goals at a rate of 2.06 per 90 (league worst). His post-shot model stats, -5.9 GSAA (2nd worst) & -6.6 GSAA %, suggest that he is doing much worse than the average goalkeeper."
```




```{r fig.width = 14, fig.height = 10}
serieA_goalkeeping_MD20_plot <- serieA_gk %>% 
  ggplot(aes(x = GSAA_perc, y = minPerSave)) +
  geom_vline(xintercept = 0, alpha = 0.4) +
  geom_hline(yintercept = 29.03, alpha = 0.4) +
  ## 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.1, y = 8, 
           hjust = 0, color = "red", size = 6,
           label = "Busy & Saving Less Than Average GK") +
  annotate("text", family = "Roboto Condensed", fontface = "bold",
           x = -0.1, y = 52, 
           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 = 52, 
    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 = 8, 
    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.115, y = 28.6, 
    hjust = 0, color = "grey20", size = 4,
    label = "Average: 29.03 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 = serieA_gk %>% 
      filter(!player %in% c("P. Gollini", "W. Szczesny",
                            "Gabriel", "I. Radu")),
    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") +
  # Gabriel
  geom_mark_hull(
    aes(filter = player == "Gabriel",
        label = "Gabriel (U.S. Lecce)",
        description = gabriel_desc),
    expand = unit(2.5, "mm"), con.cap = unit(0, "mm"),
    con.colour = "grey20", color = "grey20",
    label.width = unit(110, 'mm'), label.buffer = unit(4.95, "mm"),
    label.family = "Roboto Condensed", label.fontsize = c(14, 12),
    label.colour = "grey20", label.fill = "#FFFF66") +
  # Gollini
  geom_mark_hull(
    aes(filter = player == "P. Gollini",
        label = "Pierluigi Gollini (Atalanta B.C.)",
        description = gollini_desc),
    expand = unit(2.5, "mm"), con.cap = unit(0, "mm"),
    con.colour = "orange", color = "orange", 
    label.width = unit(170, 'mm'), label.buffer = unit(0.5, "mm"),
    label.family = "Roboto Condensed", label.fontsize = c(14, 12),
    label.colour = "grey20", label.fill = "#ffe5cc") +
  # Radu
  geom_mark_hull(
    aes(filter = player == "I. Radu",
        label = "Ionut Radu (Genoa C.F.C.)",
        description = radu_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") +
  # wojciech
  geom_mark_hull(
    aes(filter = player == "W. Szczesny",
        label = "Wojciech Szczęsny (Juventus F.C.)",
        description = wojciech_desc),
    expand = unit(2.5, "mm"), con.cap = unit(0, "mm"),
    con.colour = "grey20", color = "grey20",
    label.width = unit(120, 'mm'), label.buffer = unit(70, "mm"),
    label.family = "Roboto Condensed", label.fontsize = c(14, 12),
    label.colour = "grey20", label.fill = "#FFFF66") +
  scale_x_continuous(labels = scales::percent,
                     breaks = seq(-0.1, 0.15, 0.05),
                     limits = c(-0.125, 0.11),
                     expand = c(0.01, 0)) +
  scale_y_continuous(breaks = seq(0, 50, 10),
                     limits = c(5, 55),
                     expand = c(0.01, 0)) +
  labs(title = "Goalkeeper Shot-Stopping & Workload: <b style='color: red'>Serie A (2019-2020)</b>",
       subtitle = glue::glue("
                             January 24th, 2020 | Matchday 20 | Minimum 1080 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 = glue::glue("
                            Data: FBref | StatsBomb
                            Ryo Nakagawara, Twitter: @R_by_Ryo")) +
  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))

serieA_goalkeeping_MD20_plot
```




## save

```{r}
ggsave(plot = serieA_goalkeeping_MD20_plot, 
       here::here("Serie A 2019-2020/output/serieA_goalkeeping_1920_MD20.png"),
       height = 10, width = 14)
```

```{r}
plot_logo <- add_logo(
  plot_path = here::here("Serie A 2019-2020/output/serieA_goalkeeping_1920_MD20.png"),
  logo_path = "https://upload.wikimedia.org/wikipedia/en/e/e1/Serie_A_logo_%282019%29.svg",
  logo_position = "top right",
  logo_scale = 32)

plot_logo
```

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







