ETC5523: Communicating with Data

Workshop 6: Rebuilding cricket broadcast graphics

Author

Michael Lydeamore

Published

1 June 2001

library(tidyverse)
library(cricketdata)

options(timeout = 300)

# Download the men's ODI ball-by-ball archive, then retain one match.
balls <- cricketdata::fetch_cricsheet(
  type = "bbb",
  gender = "male",
  competition = "odis"
) |>
  filter(match_id == 1384439) |>
  arrange(innings, actual_delivery) |>
  mutate(
    total_runs = runs_off_bat + extras,
    over = floor(ball) + 1L,
    # cricketdata imports unused character fields as "", not NA.
    is_wicket = !is.na(player_dismissed) &
      str_trim(player_dismissed) != ""
  ) |>
  group_by(innings) |>
  mutate(
    score_after_ball = cumsum(total_runs),
    over_position = floor(ball) +
      round((ball - floor(ball)) * 10) / 6
  ) |>
  ungroup()

overs <- balls |>
  group_by(innings, batting_team, over) |>
  summarise(
    over_runs = sum(total_runs),
    over_wickets = sum(is_wicket),
    .groups = "drop"
  ) |>
  group_by(innings, batting_team) |>
  mutate(
    score = cumsum(over_runs),
    wickets = cumsum(over_wickets)
  ) |>
  ungroup()

dismissals <- balls |>
  filter(is_wicket) |>
  select(innings, batting_team, over_position,
         score_after_ball, player_dismissed)

worm <- bind_rows(
  overs |>
    select(innings, batting_team, over, score, wickets),
  tibble(
    innings = c(1, 2),
    batting_team = c("India", "Australia"),
    over = 0L,
    score = 0,
    wickets = 0L
  )
) |>
  arrange(innings, over)

team_colours <- c(
  "Australia" = "#C58A00",
  "India" = "#0072B2"
)

theme_broadcast <- function(base_size = 13) {
  theme_minimal(base_size = base_size) +
    theme(
      plot.background = element_rect(fill = "white", colour = NA),
      panel.background = element_rect(fill = "white", colour = NA),
      panel.grid.major = element_line(colour = "#D9E2E8", linewidth = 0.3),
      panel.grid.minor = element_blank(),
      text = element_text(colour = "#142B3A"),
      axis.text = element_text(colour = "#344955"),
      axis.title = element_text(colour = "#344955"),
      strip.text = element_text(colour = "#142B3A", face = "bold"),
      legend.position = "none",
      plot.title.position = "plot",
      plot.caption = element_text(colour = "#526773", hjust = 0)
    )
}

🎯 Objectives

By the end of this workshop, you will be able to:

  • choose comparisons that answer a viewer’s question during a match;
  • reconstruct Manhattan and worm charts from ball-by-ball data; and
  • show wickets without obscuring the pattern of runs.

Install the packages before class if needed:

install.packages(c("tidyverse", "cricketdata"))

The broadcast brief

It is the 2023 Men’s Cricket World Cup final in Ahmedabad. India made 240 all out. Australia is chasing 241.

You are on the broadcast graphics team. Your audience wants to know:

How does Australia’s chase compare with India’s innings at the same stage?

We will work from Cricsheet ball-by-ball data, accessed through the cricketdata package. The match ID is 1384439.

What are we recreating?

These graphics have long appeared during cricket broadcasts. Look at how they encode the match, rather than at the particular colours, logos or decoration.

Manhattan chart

A cricket broadcast Manhattan chart with a pair of narrow bars for each over and small circles marking wickets.

Each bar shows the runs scored in one over, producing a skyline-like view of changes in scoring intensity. The two teams can be shown in separate panels or as adjacent bars. Circles mark overs in which wickets fell.

Reference image: NV Play Streaming Overlay Control Panel.

Worm chart

A cricket television worm chart comparing two teams with cumulative-run lines and circular wicket markers.

Each line shows cumulative runs as the innings progresses. A steeper section means faster scoring; the relative height of the lines compares the teams at the same stage. Circles show where wickets interrupted each innings.

Reference image: 2018 Caribbean Premier League broadcast, via CricAmerica.

1. Read the moment before drawing (5 minutes)

After ten overs:

Team Score Run rate Match situation
India 80/2 8.00 setting the target
Australia 60/3 6.00 needs 181 from 240 balls (4.53 per over)

Discuss with a partner:

  1. Which comparison would a viewer care about: score, wickets, run rate, or required run rate?
  2. Is Australia “behind” after ten overs? Write a one-sentence answer.
  3. Which quantities should be encoded visually, and which belong in text?

2. Design a live checkpoint graphic (8 minutes)

Choose checkpoint <- 10, 20 or 30. The code below creates the two rows available to the graphics producer at that moment.

checkpoint <- 10

snapshot <- overs |>
  filter(over == checkpoint) |>
  mutate(label = paste(score, "/", wickets))

snapshot
# A tibble: 2 × 8
  innings batting_team  over over_runs over_wickets score wickets label 
    <int> <chr>        <dbl>     <int>        <int> <int>   <int> <chr> 
1       1 India           10        14            1    80       2 80 / 2
2       2 Australia       10         9            0    60       3 60 / 3

On paper, or in ggplot2, design a compact comparison that could appear between overs. It must:

  • make the runs easy to compare;
  • retain the wicket context;
  • say that both teams are being compared after the same number of overs; and
  • use direct labels rather than making the viewer search a legend.

Swap checkpoint values. Does the headline remain true?

3. Rebuild the Manhattan chart (12 minutes)

A Manhattan chart uses bar height to show runs scored in each over. Start with the skeleton below.

Before coding, decide:

  1. Should the two innings be overlaid, dodged or placed in separate panels?
  2. Where can a wicket marker go without being mistaken for more runs?
  3. What does this chart reveal that the ten-over checkpoint cannot?

4. Rebuild the worm chart (12 minutes)

A worm chart shows cumulative runs against overs. Use worm for the lines and dismissals for the wicket events.

Your wicket layer will need its own mappings:

aes(
  x = over,
  y = score,
  fill = batting_team,
  colour = batting_team
)

Ask another pair to read your chart. Can they identify the early danger, the crossover and the winning moment without you explaining them?

5. Broadcast review (8 minutes)

Choose either your Manhattan or worm chart. Give it a final editorial pass:

  1. Write a takeaway title of no more than 14 words.
  2. Add a subtitle that supplies essential match context rather than repeating the title.
  3. Check that colour is not the only way to identify wickets or teams.
  4. Remove one element that does not help a viewer answer the broadcast question.
  5. Write one sentence describing what your graphic still cannot tell us.
Fast finisher: freeze the broadcast

Create the worm as it would have appeared after 10, 20 or 30 overs of the chase. Filter both innings to that checkpoint and rewrite the title for what was known at that moment. Do not use knowledge of the final result.

Supplied data-preparation code

Keep this code for reference. You do not need to recreate it during the workshop.

Data: Cricsheet via the cricketdata R package. Match: India v Australia, ICC Men’s Cricket World Cup final, 19 November 2023.