- Add policy event markers to time series charts - Create methodology page (/toronto/methodology) with data sources - Add demo data module for testing without full pipeline - Update README with project documentation - Add health check endpoint (/health) - Add database initialization script - Export new figure factory functions Closes #21 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
264 lines
11 KiB
Python
264 lines
11 KiB
Python
"""Methodology page for Toronto Housing Dashboard."""
|
|
|
|
import dash
|
|
import dash_mantine_components as dmc
|
|
from dash import html
|
|
|
|
dash.register_page(
|
|
__name__,
|
|
path="/toronto/methodology",
|
|
title="Methodology | Toronto Housing Dashboard",
|
|
description="Data sources, methodology, and limitations for the Toronto Housing Dashboard",
|
|
)
|
|
|
|
|
|
def layout() -> dmc.Container:
|
|
"""Render the methodology page layout."""
|
|
return dmc.Container(
|
|
size="md",
|
|
py="xl",
|
|
children=[
|
|
# Header
|
|
dmc.Title("Methodology", order=1, mb="lg"),
|
|
dmc.Text(
|
|
"This page documents the data sources, processing methodology, "
|
|
"and known limitations of the Toronto Housing Dashboard.",
|
|
size="lg",
|
|
c="dimmed",
|
|
mb="xl",
|
|
),
|
|
# Data Sources Section
|
|
dmc.Paper(
|
|
p="lg",
|
|
radius="md",
|
|
withBorder=True,
|
|
mb="lg",
|
|
children=[
|
|
dmc.Title("Data Sources", order=2, mb="md"),
|
|
# TRREB
|
|
dmc.Title("Purchase Data: TRREB", order=3, size="h4", mb="sm"),
|
|
dmc.Text(
|
|
[
|
|
"The Toronto Regional Real Estate Board (TRREB) publishes monthly ",
|
|
html.Strong("Market Watch"),
|
|
" reports containing aggregate statistics for residential real estate "
|
|
"transactions across the Greater Toronto Area.",
|
|
],
|
|
mb="sm",
|
|
),
|
|
dmc.List(
|
|
[
|
|
dmc.ListItem("Source: TRREB Market Watch Reports (PDF)"),
|
|
dmc.ListItem("Geographic granularity: ~35 TRREB Districts"),
|
|
dmc.ListItem("Temporal granularity: Monthly"),
|
|
dmc.ListItem("Coverage: 2021-present"),
|
|
dmc.ListItem(
|
|
[
|
|
"Metrics: Sales count, average/median price, new listings, ",
|
|
"active listings, days on market, sale-to-list ratio",
|
|
]
|
|
),
|
|
],
|
|
mb="md",
|
|
),
|
|
dmc.Anchor(
|
|
"TRREB Market Watch Archive",
|
|
href="https://trreb.ca/market-data/market-watch/market-watch-archive/",
|
|
target="_blank",
|
|
mb="lg",
|
|
),
|
|
# CMHC
|
|
dmc.Title(
|
|
"Rental Data: CMHC", order=3, size="h4", mb="sm", mt="md"
|
|
),
|
|
dmc.Text(
|
|
[
|
|
"Canada Mortgage and Housing Corporation (CMHC) conducts the annual ",
|
|
html.Strong("Rental Market Survey"),
|
|
" providing rental market statistics for major urban centres.",
|
|
],
|
|
mb="sm",
|
|
),
|
|
dmc.List(
|
|
[
|
|
dmc.ListItem("Source: CMHC Rental Market Survey (Excel)"),
|
|
dmc.ListItem(
|
|
"Geographic granularity: ~20 CMHC Zones (Census Tract aligned)"
|
|
),
|
|
dmc.ListItem(
|
|
"Temporal granularity: Annual (October survey)"
|
|
),
|
|
dmc.ListItem("Coverage: 2021-present"),
|
|
dmc.ListItem(
|
|
[
|
|
"Metrics: Average/median rent, vacancy rate, universe count, ",
|
|
"turnover rate, year-over-year rent change",
|
|
]
|
|
),
|
|
],
|
|
mb="md",
|
|
),
|
|
dmc.Anchor(
|
|
"CMHC Housing Market Information Portal",
|
|
href="https://www.cmhc-schl.gc.ca/professionals/housing-markets-data-and-research/housing-data/data-tables/rental-market",
|
|
target="_blank",
|
|
),
|
|
],
|
|
),
|
|
# Geographic Considerations
|
|
dmc.Paper(
|
|
p="lg",
|
|
radius="md",
|
|
withBorder=True,
|
|
mb="lg",
|
|
children=[
|
|
dmc.Title("Geographic Considerations", order=2, mb="md"),
|
|
dmc.Alert(
|
|
title="Important: Non-Aligned Geographies",
|
|
color="yellow",
|
|
mb="md",
|
|
children=[
|
|
"TRREB Districts and CMHC Zones do ",
|
|
html.Strong("not"),
|
|
" align geographically. They are displayed as separate layers and "
|
|
"should not be directly compared at the sub-regional level.",
|
|
],
|
|
),
|
|
dmc.Text(
|
|
"The dashboard presents three geographic layers:",
|
|
mb="sm",
|
|
),
|
|
dmc.List(
|
|
[
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("TRREB Districts (~35): "),
|
|
"Used for purchase/sales data visualization. "
|
|
"Districts are defined by TRREB and labeled with codes like W01, C01, E01.",
|
|
]
|
|
),
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("CMHC Zones (~20): "),
|
|
"Used for rental data visualization. "
|
|
"Zones are aligned with Census Tract boundaries.",
|
|
]
|
|
),
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("City Neighbourhoods (158): "),
|
|
"Reference overlay only. "
|
|
"These are official City of Toronto neighbourhood boundaries.",
|
|
]
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
# Policy Events
|
|
dmc.Paper(
|
|
p="lg",
|
|
radius="md",
|
|
withBorder=True,
|
|
mb="lg",
|
|
children=[
|
|
dmc.Title("Policy Event Annotations", order=2, mb="md"),
|
|
dmc.Text(
|
|
"The time series charts include markers for significant policy events "
|
|
"that may have influenced housing market conditions. These annotations are "
|
|
"for contextual reference only.",
|
|
mb="md",
|
|
),
|
|
dmc.Alert(
|
|
title="No Causation Claims",
|
|
color="blue",
|
|
children=[
|
|
"The presence of a policy marker near a market trend change does ",
|
|
html.Strong("not"),
|
|
" imply causation. Housing markets are influenced by numerous factors "
|
|
"beyond policy interventions.",
|
|
],
|
|
),
|
|
],
|
|
),
|
|
# Limitations
|
|
dmc.Paper(
|
|
p="lg",
|
|
radius="md",
|
|
withBorder=True,
|
|
mb="lg",
|
|
children=[
|
|
dmc.Title("Limitations", order=2, mb="md"),
|
|
dmc.List(
|
|
[
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("Aggregate Data: "),
|
|
"All statistics are aggregates. Individual property characteristics, "
|
|
"condition, and micro-location are not reflected.",
|
|
]
|
|
),
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("Reporting Lag: "),
|
|
"TRREB data reflects closed transactions, which may lag market "
|
|
"conditions by 1-3 months. CMHC data is annual.",
|
|
]
|
|
),
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("Geographic Boundaries: "),
|
|
"TRREB district boundaries were manually digitized from reference maps "
|
|
"and may contain minor inaccuracies.",
|
|
]
|
|
),
|
|
dmc.ListItem(
|
|
[
|
|
html.Strong("Data Suppression: "),
|
|
"Some cells may be suppressed for confidentiality when transaction "
|
|
"counts are below thresholds.",
|
|
]
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
# Technical Implementation
|
|
dmc.Paper(
|
|
p="lg",
|
|
radius="md",
|
|
withBorder=True,
|
|
children=[
|
|
dmc.Title("Technical Implementation", order=2, mb="md"),
|
|
dmc.Text("This dashboard is built with:", mb="sm"),
|
|
dmc.List(
|
|
[
|
|
dmc.ListItem("Python 3.11+ with Dash and Plotly"),
|
|
dmc.ListItem("PostgreSQL with PostGIS for geospatial data"),
|
|
dmc.ListItem("dbt for data transformation"),
|
|
dmc.ListItem("Pydantic for data validation"),
|
|
dmc.ListItem("SQLAlchemy 2.0 for database operations"),
|
|
],
|
|
mb="md",
|
|
),
|
|
dmc.Anchor(
|
|
"View source code on GitHub",
|
|
href="https://github.com/lmiranda/personal-portfolio",
|
|
target="_blank",
|
|
),
|
|
],
|
|
),
|
|
# Back link
|
|
dmc.Group(
|
|
mt="xl",
|
|
children=[
|
|
dmc.Anchor(
|
|
"← Back to Dashboard",
|
|
href="/toronto",
|
|
size="lg",
|
|
),
|
|
],
|
|
),
|
|
],
|
|
)
|