Gravity Model
What It Does
Section titled “What It Does”The Gravity Model estimates the total potential flow of diners toward this location from population rings at increasing distances. Think of it as: how many person-visits per day could realistically arrive here given population, income, and distance?
Unlike the Huff model (which calculates our market share), the Gravity model measures the raw demand pipeline. Multiply flow by Huff captureProb to get actual covers.
Core Formula
Section titled “Core Formula”flow_zone = k × Oᵢ × Dⱼ / distM^βWhere:
Oᵢ= origin mass (zone population × income match × dining frequency)Dⱼ= destination attractiveness (effective area × cuisine score × income match)distM= midpoint distance of zone in metresk= scaling constant (varies by floor area)β= distance decay exponent (varies by service model / price band)
Current Implementation
Section titled “Current Implementation”Scaling Constant
Section titled “Scaling Constant”k = max(0.0008, 0.003 - (floorArea - 300) × 0.000002)Examples: 300 sqft → k=0.003; 800 sqft → k=0.002; 1200 sqft → k=0.0014.
Larger venues get a lower k to prevent unrealistic flow numbers — physical capacity caps actual throughput.
Destination Attractiveness (Dⱼ)
Section titled “Destination Attractiveness (Dⱼ)”effectiveArea = max(400, floorArea)cuisineScore = min(2, effectiveArea / 500)Dⱼ = effectiveArea × cuisineScore × incomeMatchThe effective area floor of 400 means even small budget restaurants (e.g. a 200 sqft cha chaan teng) get reasonable gravity pull — they attract as much foot traffic as a larger one; they just can’t serve the overflow.
Income Match Factor
Section titled “Income Match Factor”| Price band | Low income (<18–22K) | Mid income | High income |
|---|---|---|---|
| Budget | 1.2 | 1.0 | 0.8 |
| Mid | 0.8 | 1.0 | 1.0 |
| Premium | 0.7 | 1.0 | 1.2 |
| High-end | 0.5 | 1.0 | 1.3 |
Gravity Beta (Distance Decay within Zones)
Section titled “Gravity Beta (Distance Decay within Zones)”Separate from the Huff beta — this controls how steeply flow falls off within each ring:
| Service / price | gravityBeta |
|---|---|
| Delivery | 0.8 |
| Takeaway | 0.7 |
| High-end | 0.6 |
| Premium | 0.7 |
| Mid | 0.8 |
| Budget | 0.9 |
For delivery and takeaway, zones within 1400 m (delivery) or 600 m (takeaway) get an additional effectiveBeta × 0.7 boost.
Population Zones
Section titled “Population Zones”| Zone | Midpoint used | Primary data source |
|---|---|---|
| 0–400 m (5 min walk) | 200 m | STPU census zone cumulative ring |
| 400–800 m (10 min walk) | 600 m | STPU ring differential |
| 800 m–2 km (transit) | 1400 m | STPU ring differential |
| 2 km+ (destination) | 3500 m | STPU 5 km ring minus 2 km ring |
When STPU data is unavailable, falls back to density × π × r² × coverage factor.
Zero-population zones: If a ring has pop = 0, flow = 0 is returned (previously returned flow = 1).
Minimum floor: Zones with pop > 0 always return at least flow = 1.
Data Sources
Section titled “Data Sources”- Population: Census 2021 STPU (211 zones), aggregated into distance rings
- Income: STPU weighted median household income
- Dining frequency: constant 15% daily dine-out rate (HK average)
Interpretation
Section titled “Interpretation”| estimatedFlow | Meaning |
|---|---|
| 5,000+ | Dense urban core with high foot traffic potential |
| 1,000–5,000 | Typical urban neighbourhood |
| 200–1,000 | Suburban or low-density area |
| < 200 | Remote or very low-density site |
Known Limitations
Section titled “Known Limitations”- Assumes uniform population distribution within each ring (STPU zones reduce this error significantly)
- Dining frequency (15%) is a Hong Kong average — varies by day of week and season
- No distinction between lunch and dinner demand patterns
- Worker/commuter population not separately modelled here (handled in KPI estimates)
Changelog
Section titled “Changelog”| Date | Change |
|---|---|
| 2026-03-25 | Zero-population rings now return flow=0 instead of flow=1 |
| 2026-02-10 | Initial implementation with STPU ring data integration |