The data visualisation specialist approach to TidyTuesday

Data Visualisation
R
In this informal and interactive session, I’ll be live coding a TidyTuesday data visualisation, and sharing some tips for better R workflows and more effective charts.
Published

May 12, 2026

Code

```{r}
# Load packages -----------------------------------------------------------

library(tidyverse)
library(showtext)
library(ggtext)
library(nrBrand)
library(glue)
library(ggview)
library(rcartocolor)
library(ggiraph)


# Load data ---------------------------------------------------------------

tuesdata <- tidytuesdayR::tt_load("2026-05-12")
cities <- tuesdata$cities
links <- tuesdata$links


# Load fonts --------------------------------------------------------------

font_add_google("Oswald")
font_add_google("Nunito")
showtext_auto()
showtext_opts(dpi = 300)
title_font <- "Oswald"
body_font <- "Nunito"


# Define colours and fonts-------------------------------------------------

bg_col <- "#F2F4F8"
text_col <- "#151C28"
highlight_col <- "#7F055F"

continents <- unique(cities$continent)
col_palette <- rcartocolor::carto_pal(n = length(continents), "Safe")
names(col_palette) <- continents


# Data wrangling ----------------------------------------------------------

chosen_city <- "Edinburgh"
city_id <- cities |> 
  filter(name == chosen_city) |> 
  pull(id)

plot_data <- links |> 
  filter(source == city_id | target == city_id) |> 
  mutate(
    id = if_else(
      source == city_id, target, source
    )
  ) |> 
  select(id) |> 
  left_join(
    cities, by = "id"
  ) |> 
  rename(city = name)


# Define text -------------------------------------------------------------

social <- nrBrand::social_caption(
  bg_colour = bg_col,
  icon_colour = highlight_col,
  font_colour = text_col,
  font_family = body_font
)
title <- "Twinned Cities Around the World"
st_cols <- purrr::map_chr(
  .x = 1:length(col_palette),
  .f = ~glue("<span style='color: {col_palette[.x]}'>**{names(col_palette)[.x]}**</span>")
) |> 
  str_flatten(collapse = ", ", last = ", and ") 
st <- paste0("Twinned cities in ", st_cols, ".")
cap <- source_caption(source = "Wikidata (via bothness.github.io/twin-cities)", graphic = social)


# Plot --------------------------------------------------------------------

region_data <- function(region) {
  output <- plot_data |> 
    group_by({{ region }}) |> 
    mutate(n = n()) |> 
    ungroup() |> 
    select({{ region }}, n, continent) |> 
    distinct()
  return(output)
}

ggplot() +
  geom_col(
    data = filter(cities, name == chosen_city),
    mapping = aes(x = nrow(plot_data), y = "0", fill = continent),
    width = 1
  ) +
  geom_col_interactive(
    data = region_data(city),
    mapping = aes(x = n, y = "1", fill = continent, tooltip = city),
    colour = text_col,
    width = 1
  ) +
  geom_col(
    data = region_data(country),
    mapping = aes(x = n, y = "2", fill = continent),
    colour = text_col,
    width = 1
  ) +
  geom_col(
    data = region_data(continent),
    mapping = aes(x = n, y = "3", fill = continent),
    colour = text_col,
    width = 1
  ) +
  annotate("text", x = 0, y = "0", label = chosen_city, vjust = 2) +
  scale_fill_manual(values = col_palette) +
  labs(subtitle = st, 
       title = title,
       caption = cap) +
  coord_radial(expand = FALSE) +
  theme_void(base_size = 12, base_family = body_font) +
  theme(
    legend.position = "none",
    plot.margin = margin(5, 10, 5, 10),
    plot.title.position = "plot",
    plot.caption.position = "plot",
    plot.background = element_rect(fill = bg_col, colour = bg_col),
    panel.background = element_rect(fill = bg_col, colour = bg_col),
    plot.title = element_textbox_simple(
      colour = text_col,
      hjust = 0,
      halign = 0,
      margin = margin(b = 5, t = 5),
      family = title_font,
      face = "bold",
      size = rel(1.5)
    ),
    plot.subtitle = element_textbox_simple(
      colour = text_col,
      hjust = 0,
      halign = 0,
      margin = margin(b = 5, t = 5),
      family = body_font
    ),
    plot.caption = element_textbox_simple(
      colour = text_col,
      hjust = 0,
      halign = 0,
      margin = margin(b = 0, t = 10),
      family = body_font
    ),
    strip.text = element_textbox_simple(
      face = "bold",
      margin = margin(t = 10),
      size = rel(0.9)
    ),
    panel.grid.minor = element_blank()
  ) +
  canvas(
    width = 5, height = 6.5,
    units = "in", bg = bg_col,
    dpi = 300
  ) -> p


# Save --------------------------------------------------------------------

save_ggplot(
  plot = p,
  file = file.path("2026", "2026-05-12", paste0("20260512", ".png"))
)

```

Sunburst chart showing twinned cities with Edinburgh mostly in Europe

Sunburst chart showing twinned cities with San Diego mostly in Asia

Sunburst chart showing twinned cities with Auckland mostly in Asia

Other contributions

Here are links to some other visualisations of the same data that I’ve spotted so far:

You can join the Posit Data Science Lab every Tuesday at 12pm ET / 9am PT at pos.it/dslab.