"Crime is up 40%." Up 40% since when? A percent change needs a baseline, and whoever picks the baseline picks the story. This machine lets you do it on purpose — so you'll recognize it when a press release does it to you.
Monthly incident totals, with your baseline shaded blue and your comparison period shaded red. Try: baseline 2020 (the pandemic year) versus any normal year — instant "crime wave." Baseline 2016 versus 2020 — instant "historic decline." Same dataset, opposite stories.
The Activity Log page auto-generates "story leads" like
"Theft up 25% this July." That code refuses to print some comparisons. Its rules, straight
from app.py:
For your story: before publishing any percent change, ask the three questions those rules encode: Is the comparison window fair? Are the raw counts big enough to matter? Is the change bigger than the data's normal wobble? (The spike detector makes that last question precise.)
library(tidyverse)
library(lubridate)
activity <- read_csv("https://raw.githubusercontent.com/dwillis/umpd-logs/master/data/all-police-activity.csv")
monthly <- activity |>
mutate(month = floor_date(as_date(`Date Occurred`), "month")) |>
filter(month >= ymd("2015-01-01")) |>
count(month)
# Change these four dates and watch the story flip.
baseline <- monthly |> filter(month >= ymd("2019-01-01"), month <= ymd("2019-12-01"))
compared <- monthly |> filter(month >= ymd("2021-01-01"), month <= ymd("2021-12-01"))
round((sum(compared$n) - sum(baseline$n)) / sum(baseline$n) * 100, 1)