Lab 4: Time Series & Trends

STAT 80B - Data Visualization

Author

Your Name

Published

10 March 2026

Important Reminder

This Course Is NOT About Learning Software

This course teaches you to THINK about visualizations, not just use tools.

The software (Tableau/R) is a tool β€” you learn it through practice, trial and error, and experimentation. Don’t just follow instructions. Think about WHY you’re making each choice. Break things. Try different approaches. Understanding how each tool works comes from exploring on your own, not from step-by-step tutorials.

Objectives

By the end of this lab, you will:

  1. Create time series visualizations with trend lines using real-world global data
  2. Explore relationships between development indicators using scatter plots
  3. Compare multiple countries or regions over time
  4. Practice working with the same dataset in both Tableau and/or R

The Dataset: World Indicators

Both Tableau and the R package wbstats draw from World Bank open data β€” a rich longitudinal dataset covering nearly every country from the 1960s to the present, with indicators spanning health, economics, demographics, environment, and technology.

Your Guided Choice: Pick a Region OR a Theme

Rather than working with all countries at once, focus your analysis by choosing one of the following:

By Region:

Region Examples
🌎 Latin America & Caribbean Costa Rica, Brazil, Mexico, Chile, Colombia
🌍 Sub-Saharan Africa Kenya, Ghana, Nigeria, Ethiopia, South Africa
🌏 East Asia & Pacific China, Japan, South Korea, Indonesia, Vietnam
🌍 Europe & Central Asia Germany, France, Spain, Poland, Ukraine
🌏 South Asia India, Bangladesh, Pakistan, Sri Lanka, Nepal
🌎 North America & Oceania USA, Canada, Australia, New Zealand

By Theme (use all or many countries, focus on specific indicators):

Theme Key Indicators
πŸ’Š Health Life expectancy, fertility rate, mortality rates
πŸ’° Economic Development GDP per capita, income groups, poverty
🌿 Environment COβ‚‚ emissions per capita, energy use
🌐 Technology & Connectivity Internet users (% population), mobile subscriptions
πŸ‘₯ Demographics Population growth, urbanization, age structure

Write your choice at the top of your submission and stick with it throughout the lab.


Accessing the Data

In Tableau

  1. Open Tableau Desktop
  2. From the Start screen, find Sample Workbooks β†’ World Indicators in the bottom panel, OR
  3. Connect to Saved Data Sources β†’ look for World Indicators.tds
  4. The data is already structured with Country, Region, Year, and many indicator columns β€” explore it in the Data Source tab before building anything
Tip

In Tableau’s World Indicators, key fields to know:

  • Country / Region β€” geographic identifier
  • Year β€” date field (treat as continuous for trend lines)
  • Life Expectancy at Birth β€” years
  • GDP per Capita β€” USD
  • CO2 Emissions β€” metric tons per capita
  • Fertility Rate β€” average children per woman
  • Internet Users % β€” share of population
  • Population Total

In R

Install and load the wbstats package to pull World Bank data directly:

Code
# Install if needed (run once)
install.packages("wbstats")

library(wbstats)
library(dplyr)
library(ggplot2)

Search for indicators by keyword:

Code
# Find indicator codes β€” search for what you need
wb_search("life expectancy")
wb_search("GDP per capita")
wb_search("CO2")
wb_search("internet")
wb_search("fertility")

Download data for your chosen countries and indicators:

Code
# Example: Health indicators for Latin America
# Adjust countries and indicators to match YOUR chosen region/theme

data <- wb_data(
  indicator = c(
    life_exp    = "SP.DYN.LE00.IN",   # Life expectancy at birth
    gdp_pc      = "NY.GDP.PCAP.CD",   # GDP per capita (current USD)
    fertility   = "SP.DYN.TFRT.IN",   # Fertility rate
    co2         = "EN.ATM.CO2E.PC",   # CO2 emissions per capita
    internet    = "IT.NET.USER.ZS",   # Internet users (% of population)
    population  = "SP.POP.TOTL"       # Total population
  ),
  country = c("CRI", "BRA", "MEX", "CHL", "COL"),  # ISO3 codes for your countries
  start_date = 1990,
  end_date = 2022
)

# Preview the structure
glimpse(data)
head(data)
Finding Country ISO3 Codes

Use wb_countries() to find the correct 3-letter ISO codes for your chosen countries:

Code
wb_countries() |> 
  select(iso3c, country, region) |> 
  filter(region == "Latin America & Caribbean")  # change to your region

You can also filter by income group, regional codes, etc.

Useful Reference: Common Indicator Codes
Indicator Code
Life expectancy at birth SP.DYN.LE00.IN
GDP per capita (USD) NY.GDP.PCAP.CD
Fertility rate SP.DYN.TFRT.IN
COβ‚‚ emissions per capita EN.ATM.CO2E.PC
Internet users (%) IT.NET.USER.ZS
Population total SP.POP.TOTL
Urban population (%) SP.URB.TOTL.IN.ZS
Infant mortality rate SP.DYN.IMRT.IN
School enrollment, secondary SE.SEC.ENRR

Tasks

Complete at least 3 of these 5 tasks. Focus on quality over quantity. For each task, attempt it in your software of choice and take note of how the experience differs.


Task 1: Basic Time Series Line Graph

Create a line graph showing how one indicator has changed over time for your chosen countries.

Choose a single indicator that tells an interesting story across your selected region or countries.

In Tableau:

  • Open the World Indicators data source
  • Drag Year to Columns and your chosen measure to Rows
  • Drag Contry/Region to Color and Region to Label
  • Experiment with continuous vs. discrete date handling β€” what changes?
  • Try switching between line and area mark types

In R:

Code
# Basic time series β€” replace with your indicator and countries
ggplot(data, aes(x = date, y = life_exp, color = country)) +
  geom_line(linewidth = 1) +
  labs(
    title = "Life Expectancy Over Time",
    subtitle = "Selected Latin American Countries, 1990–2022",
    x = NULL,
    y = "Life Expectancy at Birth (years)",
    color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

Think about:

  • How many countries can you show before the chart becomes unreadable?
  • What does the y-axis range imply? Does it start at 0? Should it?
  • Are your line labels or a legend clearer here?

Task 2: Add a Trend Line

Enhance your time series with a trend line to highlight the overall trajectory.

In Tableau:

  • With your time series open, go to the Analytics pane (next to Data)
  • Drag Trend Line onto your visualization β€” choose placement carefully
  • Right-click the trend line to: edit model type (linear, polynomial, exponential), toggle confidence bands, display the equation
  • Try at least two different model types and compare β€” which fits better and why?

In R:

Code
# Linear trend with confidence interval
ggplot(data, aes(x = date, y = life_exp, color = country)) +
  geom_point(alpha = 0.3, size = 1) +
  geom_smooth(method = "lm", se = TRUE, linewidth = 1) +
  labs(
    title = "Life Expectancy Trend (Linear)",
    x = NULL,
    y = "Life Expectancy at Birth (years)"
  ) +
  theme_minimal()
Code
# LOESS smoothing for nonlinear patterns β€” try adjusting span
ggplot(data, aes(x = date, y = life_exp, color = country)) +
  geom_point(alpha = 0.3, size = 1) +
  geom_smooth(method = "loess", span = 0.5, se = TRUE, linewidth = 1) +
  labs(
    title = "Life Expectancy Trend (LOESS)",
    x = NULL,
    y = "Life Expectancy at Birth (years)"
  ) +
  theme_minimal()

Think about:

  • Does a linear trend actually fit your data well? What would a poor fit tell you?
  • Do the confidence intervals overlap between countries? What does that mean?

Task 3: Scatter Plot β€” Relationship Between Two Indicators

The classic β€œGapminder” style scatter plot: explore the relationship between two development indicators, ideally for one year.

In Tableau:

  • Drag one indicator to Columns, another to Rows
  • Change mark type to Circle
  • Drag Country / Region to Label (show on hover or always)
  • Drag Population Total to Size β€” does this change what you see?
  • Add a trend line from the Analytics pane
  • Try filtering to a single year (use a Year filter) β€” then try animating across years using Pages

In R:

Code
# Filter to a single year for a snapshot
data_2019 <- data |> filter(date == 2019)

ggplot(data_2019, aes(x = gdp_pc, y = life_exp, size = population, label = country)) +
  geom_point(alpha = 0.6, color = "steelblue") +
  geom_text(size = 2.5, vjust = -0.8, check_overlap = TRUE) +
  scale_x_log10(labels = scales::label_dollar(suffix = "K", scale = 1/1000)) +
  scale_size_continuous(range = c(2, 14), guide = "none") +
  labs(
    title = "GDP per Capita vs. Life Expectancy (2019)",
    subtitle = "Bubble size = population",
    x = "GDP per Capita (log scale, USD)",
    y = "Life Expectancy at Birth (years)"
  ) +
  theme_minimal()

Think about:

  • Why might a log scale on GDP per capita make sense here?
  • Does population size (bubble) reveal anything interesting?
  • What is the trend line fitting β€” and what are its assumptions?
  • Is this scatter plot better for comparing countries or for showing trends over time?

Task 4: Multiple Time Series β€” Small Multiples vs. Overlay

Compare multiple countries across the same time period using two different approaches β€” overlaid lines and small multiples (facets). Decide which works better for your data.

Approach A: Overlay

In Tableau:

  • Drag Country / Region to Color
  • Adjust line thickness and use direct labels where possible
  • How many countries is β€œtoo many”?

In R:

Code
ggplot(data, aes(x = date, y = life_exp, color = country)) +
  geom_line(linewidth = 1) +
  scale_color_brewer(palette = "Set2") +
  labs(
    title = "Life Expectancy: Overlaid Comparison",
    x = NULL, y = "Life Expectancy (years)", color = NULL
  ) +
  theme_minimal() +
  theme(legend.position = "bottom")

Approach B: Small Multiples (Facets)

In Tableau:

  • Drag Country / Region to Columns or Rows to create panels
  • Keep axes consistent across panels for fair comparison
  • Which layout direction works better for time series: rows or columns?

In R:

Code
ggplot(data, aes(x = date, y = life_exp)) +
  geom_line(color = "steelblue", linewidth = 1) +
  geom_smooth(method = "lm", se = FALSE, color = "darkred", linetype = "dashed", linewidth = 0.7) +
  facet_wrap(~ country, ncol = 3) +
  labs(
    title = "Life Expectancy by Country (Small Multiples)",
    x = NULL, y = "Life Expectancy (years)"
  ) +
  theme_minimal() +
  theme(strip.text = element_text(face = "bold"))

Think about:

  • When does overlay make comparisons easier? When do small multiples work better?
  • Should the y-axis be the same across panels (fixed) or free to each panel? Try both: scales = "fixed" vs. scales = "free_y" in facet_wrap()
  • Which approach does Tableau make easier? Which does R handle better?

Task 5: Annotated Visualization β€” Tell a Story

Take one of your visualizations from Tasks 1–4 and add annotations to highlight a specific story, event, or pattern in the data.

This could be:

  • A country that dramatically improved (or declined) on an indicator
  • A visible inflection point β€” can you trace it to a historical event?
  • A comparison that reveals surprising inequality or convergence

In Tableau:

  • Use Reference Lines (right-click axis) to mark a specific year
  • Use Annotations (right-click a data point β†’ Annotate β†’ Mark or Point) to call out a country or year
  • Adjust fonts, colors, and borders to make the annotation clean

In R:

Code
library(ggrepel)  # For non-overlapping text labels β€” install if needed

# Identify a country/year to highlight
highlight <- data |> filter(country == "Costa Rica", date == 2020)

ggplot(data, aes(x = date, y = life_exp, color = country)) +
  geom_line(linewidth = 1, alpha = 0.7) +
  # Add a vertical reference line for an event year
  geom_vline(xintercept = 2020, linetype = "dashed", color = "gray40") +
  annotate("text", x = 2020.3, y = min(data$life_exp, na.rm = TRUE) + 1,
           label = "COVID-19\npandemic", hjust = 0, size = 3, color = "gray40") +
  # Highlight a specific point
  geom_point(data = highlight, aes(x = date, y = life_exp),
             color = "red", size = 4, shape = 21, fill = "white", stroke = 2) +
  labs(
    title = "Life Expectancy with Annotation",
    x = NULL, y = "Life Expectancy (years)", color = NULL
  ) +
  theme_minimal()

Think about:

  • What story are you trying to tell, and does the annotation help or clutter?
  • Did you need to look up any historical context to explain a pattern you found?
  • Is the annotation directing the viewer’s attention, or just adding noise?

Deliverable

Submit ONE well-designed, polished visualization. It can come from either Tableau or R β€” choose whichever produced the stronger result for your chosen story.

Your submission should include:

  1. The visualization (exported image or screenshot)

    • From Tableau: Worksheet β†’ Export β†’ Image
    • From R: ggsave("myplot.png", width = 10, height = 6, dpi = 300)
  2. Your region/theme choice and which countries/indicators you used

  3. A brief write-up (3–5 sentences) addressing:

    • What pattern or story you found in the data
    • Why you chose this chart type and these design decisions
    • What you noticed about working in Tableau vs. R for this type of visualization

Grading Criteria

Component Weight What we’re looking for
Technical execution 30% Code/Tableau runs, axes labeled, data handled correctly
Design quality 40% Appropriate chart type, readable layout, thoughtful color and annotation
Reflection 30% Evidence of experimentation and genuine comparison of the two tools

Resources

Tableau:

R:

Inspiration:

  • Gapminder β€” the original animated bubble chart using World Bank data
  • Our World in Data β€” excellent examples of annotated, story-driven global indicator charts

Remember: The goal is not to master Tableau or R in one lab. The goal is to practice thinking about how to visualize change over time and relationships between variables β€” and to start developing your own sense of when each tool serves you better. Learn by doing, trying, breaking, and fixing!