Consumer Price Index (CPI) Across Urban Areas in the United States

Team

Riva Kranz · c.kranz@wustl.edu · ID 508687
Yijie Yang · yang.yijie@wustl.edu · ID 528629

Audience

Students, movers, budget planners, and journalists who want quick comparisons from official data.

Motivation

Prices for housing, food, energy, and transportation vary by place and change over time. The CPI is reliable and updated often, but it is hard to navigate and compare across areas. Our goal is a clear interactive view that lets users see how their city compares with the U.S. average and how categories move over time.

Questions

Benefits

Data

Source: U.S. Bureau of Labor Statistics (BLS), CPI-U.
Docs: BLS Data · BLS Public Data API

Using an official API key, we overcome daily rate limits and fetch all CPI series in batches. After fetching, we run two integrity checks: one to detect missing areas or categories, and another to automatically re-download incomplete regions. The final dataset includes every national, regional, divisional, and metro CPI series from 2018-2025.

Data Processing

  1. Call the BLS Public Data API v2 with an authenticated api_key to fetch all relevant series_id in parallel batches
  2. Cache intermediate results and support resuming from checkpoints to prevent data loss during long requests
  3. Run a second pass to re-fetch missing or incomplete areas, ensuring full geographic and category coverage
  4. Normalize raw JSON into tidy tables with year, month, value, and metadata columns
  5. Aggregate monthly and semiannual values into quarterly means (Q1-Q4)
  6. Classify all series into four levels — National, Region, Division, and Metro — and merge into one hierarchical dataset
  7. Export compact JSON (cpi_time_series.json) containing all layers and categories for client-side visualization
# simplified normalization snippet
records = []
for s in data["Results"]["series"]:
    for item in s["data"]:
        if item["period"] not in ["M13", "S03"]:
            records.append([
                s["seriesID"],
                item["year"],
                item["periodName"],
                float(item["value"])
            ])
df = pd.DataFrame(records, columns=["SeriesID", "Year", "Month", "CPI"])
    

Visualization Design

The app combines a choropleth map with time series. Users can move from national to region, division, and metro, pick a category, and set the period with a single timeline handle. The map colors show the gap relative to the selected group mean. The right side stacks a line chart and a category bar chart that update with selections.

Linked map and charts Single quarter selector Relative color scale Responsive layout Export ready

Must-Have Features

Optional Features

Five Design Sheets

Design sheet 1
Sheet 1: Year control updates a choropleth. Click a metro to open linked charts.
Design sheet 2
Sheet 2: A strip selector for year and level. Centered map with trend and category bar.
Design sheet 3
Sheet 3: Right panel with metro vs U.S. line and category bar.
Design sheet 4
Sheet 4: Category exploration with shared scales and a compare toggle.
Design sheet 5
Sheet 5 (final concept): Single handle timeline, linked map and charts, clean legend.

Milestone 1

Design sheet 1
Screenshot Current view of design.

Milestone 2

Milestone 2 Screenshot
Screenshot Instructions
Milestone 2 Screenshot
Screenshot New Dashboard

Final

Interaction Design

  1. On load, an instructions overlay appears to introduce the dashboard and basic interactions. The user can dismiss it or reopen it later with the “View instructions” button in the header.
  2. In the filter panel, the user selects one or more CPI categories and chooses a geographic level (Region, Division, Metro). A “Select All Categories” option with a hover help box explains that “All Items” behaves like any other category.
  3. The user can toggle the national comparison checkbox to overlay the U.S. average in the line chart and bar chart for context.
  4. The user can also toggle a color blind friendly mode in the filter panel. This switches the line chart to a color blind safe palette and adds redundant encodings (dash patterns and marker shapes). Turning it off returns the original simple color treatment.
  5. On the timeline, the user drags the two handles of the brush to select a range of quarters, or drags the middle of the brush to move the selected window. All linked views update together.
  6. On the map, the user hovers to see a tooltip for each area and clicks a region, division, or metro to focus it. The “Reset Highlight” pill clears the current selection.
  7. The line chart shows CPI trends over time for the selected area and categories, with optional national comparison and division average lines. If you click on a legend catagory, it will become less visable.
  8. The bar chart shows a category breakdown for the selected time or time range, with sorted bars and tooltips showing exact values and comparisons. Clicking on the bars allows users to drill down for more details or go back to a higher level.

Implementation

The dashboard is implemented in JavaScript with D3 for data binding and SVG rendering. We precompute a compact JSON file that contains all national, regional, divisional, and metro series and load it once on page initialization.

The choropleth map uses TopoJSON and a composite U.S. projection Clicking an area updates the shared state, which triggers re-rendering of the linked line chart and bar chart.

The timeline is a brushed D3 chart that supports both range and point modes. The brush selection is stored centrally and used to filter the time domain for both the line chart and the bar chart. The filter panel is implemented as a fixed overlay with scrollable content, and its settings feed into the same state store, so that category, level, and colorblind mode changes all propagate consistently to the views.

Evaluation and Findings

What we learned from the data

  • The Russia-Ukraine war caused a massive spike to Transportation and Energy.
  • Energy and Transportation categories show the sharpest spikes around key events, and the gap to the U.S. average can be much larger for certain regions.
  • Covid caused a massive low for all catagoried.

How well the visualization works

Linking the map and the line chart made it easier to connect “where” and “when” price differences occur. The on-load instructions and the Filters panel helped new users understand which controls affected which views.

Future improvements

  • Allow side-by-side comparison of two metros or two time periods.
  • Add download options for CSV or PNG exports directly from the dashboard.

Project Screencast