• Steven Ponce
  • About
  • Data Visualizations
  • Projects
  • Email

On this page

  • Steps to Create this Graphic

White and Black Chess Ratings: A Distribution Analysis

How ratings vary between White and Black players across competitive chess matches

TidyTuesday
Data Visualization
R Programming
2024
Author

Steven Ponce

Published

September 25, 2024

Figure 1: The image displays two overlapping kernel density plots representing the distribution of chess player ratings for “White” and “Black” players. Both distributions peak around 1500 on the x-axis and range from 500 to 3000. The graph title is “White and Black Chess Ratings: A Distribution Analysis.”

Steps to Create this Graphic

1. Load Packages & Setup

Code
```{r}
#| label: load

## 1. LOAD PACKAGES & SETUP ----
pacman::p_load(
  tidyverse,         # Easily Install and Load the 'Tidyverse'
  ggtext,            # Improved Text Rendering Support for 'ggplot2'
  showtext,          # Using Fonts More Easily in R Graphs
  janitor,           # Simple Tools for Examining and Cleaning Dirty Data
  skimr,             # Compact and Flexible Summaries of Data
  scales,            # Scale Functions for Visualization
  lubridate,         # Make Dealing with Dates a Little Easier
  glue,              # Interpreted String Literals
  ggfx               # Pixel Filters for 'ggplot2' and 'grid' # Pixel Filters for 'ggplot2' and 'grid' 
 )  

### |- figure size ---- 
camcorder::gg_record(
  dir    = here::here("temp_plots"),
  device = "png",
  width  =  7.5,
  height =  5,
  units  = "in",
  dpi    = 320
)

### |- resolution ----
showtext_opts(dpi = 320, regular.wt = 300, bold.wt = 800)
```

2. Read in the Data

Code
```{r}
#| label: read

tt <-tidytuesdayR::tt_load(2024, week = 40) 

chess <- tt$chess |> clean_names() |> glimpse()

tidytuesdayR::readme(tt)
rm(tt)
```

3. Examing the Data

Code
```{r}
#| label: examine

glimpse(chess)
skim(chess)
```

4. Tidy Data

Code
```{r}
#| label: tidy

# Tidy
chess_data <- chess |>  
    select(white_rating, black_rating) |>
    pivot_longer(
        cols = c(white_rating, black_rating), 
        names_to = "player", 
        values_to = "rating") |>
    mutate(player = ifelse(player == "white_rating", "White", "Black"))

# Labels 
labels <- tibble(
    label = c("White", "Black"),
    player = c("White", "Black"),
    x = c(1600, 1600), 
    y = c(0.0001, 0.0001) 
)
```

5. Visualization Parameters

Code
```{r}
#| label: params

### |- plot aesthetics ----
bkg_col      <- colorspace::lighten('#f7f5e9', 0.05)    
title_col    <- "gray20"           
subtitle_col <- "gray20"     
caption_col  <- "gray30"   
text_col     <- "gray20"    
col_palette  <- paletteer::paletteer_d("peRReo::don")[c(5,9)]

### |-  titles and caption ----
# icons
tt <- str_glue("#TidyTuesday: { 2024 } Week { 40 } &bull; Source: Chess Game Dataset (Lichess)<br>")
li <- str_glue("<span style='font-family:fa6-brands'>&#xf08c;</span>")
gh <- str_glue("<span style='font-family:fa6-brands'>&#xf09b;</span>")
mn <- str_glue("<span style='font-family:fa6-brands'>&#xf4f6;</span>")

# text
title_text    <- str_glue("White and Black Chess Ratings: A Distribution Analysis")
subtitle_text <- str_glue("How ratings vary between White and Black players across competitive chess matches")
caption_text  <- str_glue("{tt} {li} stevenponce &bull; {mn} @sponce1(graphic.social) {gh} poncest &bull; #rstats #ggplot2")

### |-  fonts ----
font_add("fa6-brands", "fonts/6.4.2/Font Awesome 6 Brands-Regular-400.otf")
font_add_google("Oswald", regular.wt = 400, family = "title")
font_add_google("Merriweather Sans", regular.wt = 400, family = "subtitle")
font_add_google("Merriweather Sans", regular.wt = 400, family = "text")
font_add_google("Noto Sans", regular.wt = 400, family = "caption")
showtext_auto(enable = TRUE)

### |-  plot theme ----
theme_set(theme_minimal(base_size = 14, base_family = "text"))                

theme_update(
    plot.title.position   = "plot",
    plot.caption.position = "plot",
    legend.position       = 'plot',
    plot.background       = element_rect(fill = bkg_col, color = bkg_col),
    panel.background      = element_rect(fill = bkg_col, color = bkg_col),
    plot.margin           = margin(t = 10, r = 20, b = 10, l = 20),

    axis.title.x          = element_text(margin = margin(10, 0, 0, 0), size = rel(1.1), 
                                         color = text_col, family = "text", face = "bold", hjust = 0.5),
    axis.title.y          = element_blank(),  
    axis.text.y           = element_blank(),
    axis.text.x           = element_text(color = text_col, family = "text", size = rel(0.9)),
    axis.ticks.x          = element_line(color = text_col),  # Show x-axis ticks
    panel.grid            = element_blank(),
    strip.text            = element_blank() # Remove strip text 
)
```

6. Plot

Code
```{r}
#| label: plot

### |-  final plot ----
p <- ggplot(chess_data, aes(x = rating)) +

  # Geoms
  # Reference text layer
  as_reference(
    geom_text(
      data = labels, aes(x = x, y = y, label = label),
      family = "title", colour = "gray10", size = rel(35), hjust = 0.5, vjust = 0
    ),
    id = "text"
  ) +

  # Blending the text with the density plot
  with_inner_glow(
    with_blend(
      geom_density(aes(fill = player, color = player),
        alpha = 1, show.legend = FALSE,
        bw = 25,
        kernel = "epanechnikov"
      ),
      bg_layer = "text", blend_type = "xor"
    ),
    color = "gray10", sigma = 15
  ) +

  # Labs
  labs(
    x = "Player Rating",
    y = NULL,
    title = title_text,
    subtitle = subtitle_text,
    caption = caption_text
  ) +

  # Scales
  scale_x_continuous() +
  scale_y_continuous() +
  scale_fill_manual(values = col_palette) +
  scale_color_manual(values = col_palette) +
  coord_cartesian(clip = "off") +

  # Facet
  facet_wrap(~player, ncol = 1) +

  # Theme
  theme(
    plot.title = element_text(
      size = rel(1.55),
      family = "title",
      face = "bold",
      color = title_col,
      lineheight = 1.1,
      margin = margin(t = 5, b = 5)
    ),
    plot.subtitle = element_text(
      size = rel(0.85),
      family = "subtitle",
      color = subtitle_col,
      lineheight = 1.1,
      margin = margin(t = 5, b = 5)
    ),
    plot.caption = element_markdown(
      size = rel(0.50),
      family = "caption",
      color = caption_col,
      lineheight = 1.1,
      hjust = 0.5,
      halign = 1,
      margin = margin(t = 5, b = 5)
    )
  )
```

7. Save

Code
```{r}
#| label: save

### |-  plot image ----  

# Save the plot again
ggsave(
    filename = here::here("data_visualizations/TidyTuesday/2024/tt_2024_40.png"),
    plot = p,
    width  = 7.5,
    height = 5,
    units  = "in",
    dpi    = 320
)

### |-  plot thumbnail----  
magick::image_read(here::here("data_visualizations/TidyTuesday/2024/tt_2024_40.png")) |> 
  magick::image_resize(geometry = "400") |> 
  magick::image_write(here::here("data_visualizations/TidyTuesday/2024/thumbnails/tt_2024_40.png"))
```

8. Session Info

Code
```{r, eval=TRUE}
info <- capture.output(sessioninfo::session_info())
# Remove lines that contain "[1]" and "[2]" (the file paths)
filtered_info <- grep("\\[1\\]|\\[2\\]", info, value = TRUE, invert = TRUE)
cat(filtered_info, sep = "\n")
```
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.4.1 (2024-06-14 ucrt)
 os       Windows 11 x64 (build 22631)
 system   x86_64, mingw32
 ui       RTerm
 language (EN)
 collate  English_United States.utf8
 ctype    English_United States.utf8
 tz       America/New_York
 date     2025-05-22
 pandoc   3.4 @ C:/Program Files/RStudio/resources/app/bin/quarto/bin/tools/ (via rmarkdown)

─ Packages ───────────────────────────────────────────────────────────────────
 ! package     * version date (UTC) lib source
 P digest        0.6.37  2024-08-19 [?] RSPM (R 4.4.0)
 P evaluate      1.0.1   2024-10-10 [?] RSPM (R 4.4.0)
 P fastmap       1.2.0   2024-05-15 [?] RSPM (R 4.4.0)
 P htmltools     0.5.8.1 2024-04-04 [?] RSPM (R 4.4.0)
 P htmlwidgets   1.6.4   2023-12-06 [?] CRAN (R 4.4.0)
 P jsonlite      1.8.9   2024-09-20 [?] RSPM (R 4.4.0)
 P knitr         1.49    2024-11-08 [?] RSPM (R 4.4.0)
 P rmarkdown     2.29    2024-11-04 [?] RSPM (R 4.4.0)
 P rstudioapi    0.17.1  2024-10-22 [?] RSPM (R 4.4.0)
 P sessioninfo   1.2.2   2021-12-06 [?] RSPM (R 4.4.0)
 P xfun          0.49    2024-10-31 [?] RSPM (R 4.4.0)
 P yaml          2.3.10  2024-07-26 [?] RSPM (R 4.4.0)


 P ── Loaded and on-disk path mismatch.

──────────────────────────────────────────────────────────────────────────────
Back to top

© 2024 Steven Ponce

Source Issues