Skip to content

Project 5 — Migration & Housing Trends

Difficulty

🟡 Intermediate. ~12–16 hours.


Goal

"Where are people moving in and out of [your metro area], and how do those flows align with housing-price changes?"

Tell a temporal story by combining migration flows (origin → destination, by county) with housing-price trends (Zillow ZHVI or similar) at the tract or county level.

Data needed

Layer Source
US counties TIGER/Line
County-to-county migration Census ACS migration flows table
Median home value over time Zillow ZHVI (county-level), https://www.zillow.com/research/data/
(Optional) Tract-level home values Census ACS B25077
Metro area boundary Census CBSA

Tools used

  • ArcGIS Pro: Add Join, Calculate Field, Spatial Join
  • Time-aware layers, animations
  • Layout multi-frame
  • Charts (in pop-ups or dashboard)

Workflow

Step 1 — Set up

  1. Project: migration_housing_<metro>.
  2. Project to NAD83 / Conus Albers (EPSG:5070) for area-correct visuals.
  3. Filter counties to your metro CBSA.

Step 2 — Compute net migration

For each county:

def net_migration(in_flow, out_flow):
    if in_flow is None: in_flow = 0
    if out_flow is None: out_flow = 0
    return in_flow - out_flow

Add field NET_MIG_2022. Repeat for several years.

Step 3 — Compute housing change

For each county:

def pct_change(now, then):
    if now is None or then is None or then == 0: return None
    return ((now - then) / then) * 100

Add field ZHVI_CHG_2018_2024 = pct_change(!ZHVI_2024!, !ZHVI_2018!).

Step 4 — Map both

Map A — Net migration (diverging)

  1. Symbology: Graduated Colors on NET_MIG_2022.
  2. Method: Manual (negative quantiles + 0 + positive quantiles).
  3. Color scheme: Diverging RdBu — losses red, gains blue.

Map B — Housing-price change

  1. Symbology: Graduated Colors on ZHVI_CHG_2018_2024.
  2. Sequential or diverging palette (depending on whether any counties saw declines).
  3. Match the 0% midpoint to neutral.

Step 5 — Detect patterns

Add a categorical field:

def category(net_mig, price_chg):
    if net_mig is None or price_chg is None: return "Unknown"
    if net_mig > 0 and price_chg > 0: return "Hot growth"
    if net_mig > 0 and price_chg <= 0: return "Bargain growth"
    if net_mig < 0 and price_chg > 0: return "Pricing out"
    if net_mig < 0 and price_chg < 0: return "Decline"
    return "Mixed"

Symbolize a third map by CATEGORY — this is the headline.

Step 6 — Time animation

If your data is a long table (year per row), create a time-aware feature class:

  1. Right-click layer → Properties → Time → Filter Layer Content based on attribute values.
  2. Set Time Field = YEAR.
  3. Open the Time ribbon → animate.
  4. Export as MP4 / GIF for your portfolio.

Step 7 — Layout / Story Map

A 4-section Story Map:

  1. Set the scene: "Where are Americans moving?"
  2. Net migration map (animated).
  3. Housing change map.
  4. Combined category map + 1-paragraph takeaway.

Skills learned

  • Time-aware data
  • Animation export
  • Diverging vs sequential palettes
  • Cross-source data joins (Zillow + Census)
  • Categorical synthesis from multiple variables

Portfolio value

A real-estate / urban-planning power move. Combines analysis with storytelling and a topical question (post-COVID migration, remote work, housing affordability).

Stretch goals

  • Add flow lines between origin and destination counties (use XY To Line + flow line styling).
  • Use migration_flows OD table to map where people came from for any one county.
  • Layer rent data alongside home values.
  • Build a dashboard with toggle between metros for comparison.

→ Next: Site Suitability Analysis.