Describing: Statistics and Graphics

S23 · Chapter 12 · MC 451 Research Methods in Mass Media

Dr. Alex Leith

Today’s Agenda

  • The grammar of graphics, in three parts
  • A line, a bar, and a histogram
  • The choices a figure has to disclose
  • Why your mean and median disagree

What We Build Today

Describing Data, 75 points, due this week

  • Chapter 11 left analysis, about 35,000 rows
    • Nobody reads 35,000 rows, so a figure makes it visible
  • Three figures and one summary table
    • Each chart type chosen to fit a different question
    • They become the Results section of your White Paper

Your first version of each will look wrong. Fixing it is three lines.

The Grammar of Graphics

ggplot2 is not a catalog of chart types. It is one idea from Wilkinson’s The Grammar of Graphics: every plot is the same few parts.

  • Data: the table being shown
  • Aesthetic mappings: which column goes to x, y, or color
  • Geometry: the mark used to draw it

Choose those three and the plot is specified.

The Skeleton in Code

ggplot(data, aes(x = ..., y = ...)) +
  geom_line()

ggplot() names the data and, inside aes(), says which column maps to which visual property. geom_line() says what mark to draw, and + stacks layers.

Swap geom_line() for geom_col() and the same data is drawn as bars.

Your Turn

  • You have a variable to describe. What shape do you expect?
  • Would a line, a bar, or a histogram answer your question best?
  • What would surprise you if you saw it?

A Line for Change Over Time

viewers_over_time <- streams %>%
  filter(!is.na(game)) %>%
  mutate(
    timestamp = as.POSIXct(date / 1000, origin = "1970-01-01", tz = "UTC"),
    six_hour  = floor_date(timestamp, "6 hours"),
    category  = fct_lump_n(game, n = 5)
  ) %>%
  group_by(six_hour, category) %>%
  summarise(total_viewers = sum(viewers), .groups = "drop")

Bucket the snapshots into six-hour blocks, keep the top five games and lump the rest into “Other,” then sum the viewers in each bucket.

Drawing the Line

ggplot(viewers_over_time,
       aes(x = six_hour, y = total_viewers, color = category)) +
  geom_line(linewidth = 0.9) +
  labs(title = "Concurrent viewers by game category",
       x = "Date (UTC, six-hour buckets)",
       y = "Total viewers in bucket", color = "Category") +
  v2v::scale_colour_v2v() +
  v2v::theme_v2v()

Time on x, summed viewers on y, category to color. theme_v2v() gives every figure in the set one consistent look.

What the Line Chart Shows

  • “Other” dominates, spiking above 20 million viewers
    • One reading: viewership really does have a long tail
    • The other: lumping fifty categories guarantees that bucket wins
  • The design cost is real
    • The five named lines press flat against the axis

A dominant series crowds out the rest. Notice that, and say so.

A Bar for Counts

Hour of day is 24 discrete categories, and we want a count per category.

chat_by_hour <- analysis %>%
  mutate(hour = hour(timestamp)) %>%
  count(hour, name = "messages")

ggplot(chat_by_hour, aes(x = hour, y = messages)) +
  geom_col(fill = "#2f7d8a") +
  labs(x = "Hour of day (UTC)", y = "Messages in sample") +
  v2v::theme_v2v()

geom_col() draws a bar whose height you already computed.

What the Bar Chart Shows

Twitch, November 2018

  • A clear daily pulse, busiest through UTC midday
  • Peak at 13:00 with 2,201 messages
  • Floor at 03:00 with 833, a swing of over two to one
  • Not mysterious: the audience sat in the Americas and Europe

Twenty-four numbers become a rhythm you read in one glance.

A Histogram for Shape

msglen <- analysis %>%
  filter(!is.na(is_gaming)) %>%
  mutate(length_shown = pmin(message_length, 120))

ggplot(msglen, aes(x = length_shown, fill = is_gaming)) +
  geom_histogram(binwidth = 5, position = "identity", alpha = 0.55) +
  v2v::scale_fill_v2v() +
  v2v::theme_v2v()

A histogram slices a numeric variable into equal bins and draws a bar for how many values land in each. Two groups overlaid, so the shapes compare.

Two Choices You Must Disclose

  • binwidth = 5 sets each bar to five characters
    • Wider smooths, narrower roughens, so report it
  • pmin(message_length, 120) caps the display
    • Twitch’s real limit is 500, so the last bar is a pile-up
    • Capping keeps the bulk legible

An unannounced cap is a quiet distortion. Label the axis.

What the Histogram Shows

  • Both groups are heavily right-skewed
    • A tall stack of very short messages, then a long tail
    • Twitch chat is mostly brief, a word or an emote
  • A minority of long messages stretches the range

This is the most important thing the figure reveals, and it is invisible in any single summary number.

Mean and Median Disagree

Group by is_gaming, then summarise() n, mean, median, and sd:

  • Non-gaming: n 3,457, mean 33.70, median 16, sd 60.68
  • Gaming: n 31,309, mean 28.49, median 17, sd 38.47

Why They Disagree

  • The mean says non-gaming chat is longer, 33.70 to 28.49
  • The median collapses the story, 16 against 17
    • Near identical, and pointing the other way
  • The mean is pulled by a long tail, the median is not
    • Non-gaming has the heavier tail, and its sd records it

The gap in means is real arithmetic, but it is the tail’s work.

Checkpoint

You should now have:

  • A line chart, a bar chart, and a histogram, all on theme_v2v()
  • A grouped summary with n, mean, median, and sd
  • The binwidth and any cap written into your axis labels
  • One sentence per figure saying what it shows

If a figure will not render, check that every + ends the line above it.

Before Next Time

  • Due this week: Describing Data [R], 75 points
  • Thursday is a lab, building these three on your own variables
    • Bring your analysis table and your research question
  • Read Chapter 12, especially on readable figures

A figure can frame the question. It cannot answer it.

Questions?