Lecture 9
September 23, 2026
Raw daily counts show individual bursts. A moving average asks about local level.
daily |>
ggplot(aes(day)) +
geom_line(aes(y = n), color = "gray75", linewidth = 0.4) +
geom_line(aes(y = ma7), color = deep_gold, linewidth = 1) +
scale_x_date(date_breaks = "2 months", date_labels = "%b") +
labs(title = "Smoothing reveals the local level and hides daily extremes", x = NULL, y = "Event records")Ask:
A smoother is a summary, not repaired data.
daily_windows <- daily |>
mutate(
ma7 = as.numeric(stats::filter(n, rep(1 / 7, 7), sides = 2)),
ma30 = as.numeric(stats::filter(n, rep(1 / 30, 30), sides = 2))
) |>
pivot_longer(c(ma7, ma30), names_to = "window", values_to = "smooth")
ggplot(daily_windows, aes(day)) +
geom_line(aes(y = n), color = "gray82", linewidth = 0.3) +
geom_line(aes(y = smooth, color = window), linewidth = 1) +
scale_color_manual(values = c(ma7 = deep_gold, ma30 = blue_gray), labels = c(ma7 = "7 days", ma30 = "30 days")) +
scale_x_date(date_breaks = "2 months", date_labels = "%b") +
labs(title = "Longer windows suppress more short-term variation", x = NULL, y = "Event records", color = "Window")For an odd window of length \(2h+1\),
\[ \widetilde{y}_t=\frac{1}{2h+1}\sum_{j=-h}^{h} y_{t+j}. \]
A centered average uses future and past observations, so it is appropriate for description but not for a real-time forecast at the current endpoint.
Choose a smoothing window for (a) daily staffing and (b) seasonal planning. Explain why the same window should not automatically serve both decisions.
A lagged value pairs today’s observation with an earlier one:
# A tibble: 6 × 4
day n yesterday last_week
<date> <int> <int> <int>
1 2024-01-08 609 101 463
2 2024-01-09 1373 609 14
3 2024-01-10 246 1373 57
4 2024-01-11 328 246 40
5 2024-01-12 912 328 80
6 2024-01-13 617 912 317
lagged <- daily |>
mutate(lag1 = lag(n), lag7 = lag(n, 7))
ggplot(lagged, aes(lag1, n)) +
geom_point(alpha = 0.3, color = deep_gold) +
geom_smooth(method = "lm", se = FALSE, color = blue_gray) +
labs(title = "Lag 1", x = "Yesterday's count", y = "Today's count")
ggplot(lagged, aes(lag7, n)) +
geom_point(alpha = 0.3, color = deep_gold) +
geom_smooth(method = "lm", se = FALSE, color = blue_gray) +
labs(title = "Lag 7", x = "Count seven days ago", y = "Today's count")

Autocorrelation measures linear similarity between a series and a lagged version of itself.
This dependence reflects multi-day weather systems, reporting, seasonality, and other processes—not one simple mechanism.
One year is enough to display a seasonal pattern but not enough to estimate a stable annual autocorrelation at lag 12.
If lag-1 autocorrelation is positive, what does that say? Write one defensible sentence and one causal sentence that the plot does not justify.
Storm Events categories, collection practices, and reporting coverage changed over time.
An upward record count can reflect:
The right display depends on which structure you have.
They are not ordinary x and y variables on a flat plane.
Earth is curved; a map projection converts the surface to a plane. Every projection distorts some combination of area, shape, distance, or direction.
For state-level choropleths, area distortion can alter the visual weight assigned to regions even when the data values are unchanged.
The event locations are themselves the observations. Questions include:
Interpreting concentration requires exposure, geography, and reporting context.
events |>
filter(event_type == "Hail", has_begin_coords, magnitude > 0,
begin_lon >= -125, begin_lon <= -66, begin_lat >= 24, begin_lat <= 50) |>
ggplot() +
geom_polygon(data = us, aes(long, lat, group = group), fill = "gray95", color = "white") +
geom_point(aes(begin_lon, begin_lat, size = magnitude), alpha = 0.35, color = deep_gold) +
coord_quickmap() +
labs(title = "A measured value is attached to each reported location", size = "Hail size", x = NULL, y = NULL) +
theme_void()Here the location is known and hail magnitude is the measured attribute.
An areal value summarizes a region such as a state or county. Examples include total events, total damage, or a normalized rate.
The region is the observational unit. A choropleth should not be interpreted as showing within-region point locations.
Nearby observations can be more similar than distant observations. That violates the independence assumption behind many familiar analyses.
Spatial inference requires choices about neighborhood, distance, trend, and covariance; a smooth map alone does not provide those choices.
At a new location, kriging forms a weighted combination of nearby observed values. The weights reflect the fitted spatial covariance and the geometry of the observed sites.
The resulting surface is a model-based prediction, not observed data between stations. Prediction uncertainty should accompany the interpolated map.
us <- ggplot2::map_data("state")
events |>
filter(has_begin_coords, begin_lon >= -125, begin_lon <= -66, begin_lat >= 24, begin_lat <= 50) |>
slice_sample(n = 8000) |>
ggplot() +
geom_polygon(data = us, aes(long, lat, group = group), fill = "gray95", color = "white") +
geom_point(aes(begin_lon, begin_lat), alpha = 0.08, size = 0.5, color = deep_gold) +
coord_quickmap() +
labs(title = "A point map mixes hazard, exposure, and reporting", x = NULL, y = NULL) +
theme_void()What does a dense cluster of points on this map mean? List three plausible explanations, then identify one denominator or additional dataset needed to distinguish them.
Next: choropleths, normalization, and high-quality composition.
MaDS Data Visualization · Fall 2026