Neighbourhood grid with map rectangles
Advanced
Split a city into grid cells, query each with a bounding box and export GeoJSON for a map.
Setup
This tutorial uses the jokerprice.py helper from the quickstart. Save it next to your script and set JOKERPRICE_API_KEY.
Bounding-box queries
/api/v1/metrics accepts north, south, east and west instead of city. The rectangle must be at most 5 degrees across, with south below north and west below east.
from jokerprice import api
box = {"north": 24.85, "south": 24.70, "east": 46.80, "west": 46.60} # central and north Riyadh
m = api("GET", "/api/v1/metrics", params={**box, "past_days": 60})["metrics"]
print(m["listings"]["tracked"], "tracked listings |", m["maturity"], "| occupancy", m["past"]["occupancy"])Build a grid
Each cell is one request. A 4 × 4 grid is 16 requests; the helper waits automatically if you reach 120 per minute.
def grid(box, rows, cols):
lat_step = (box["north"] - box["south"]) / rows
lng_step = (box["east"] - box["west"]) / cols
for r in range(rows):
for c in range(cols):
south, west = box["south"] + r * lat_step, box["west"] + c * lng_step
yield {"south": round(south, 5), "north": round(south + lat_step, 5), "west": round(west, 5), "east": round(west + lng_step, 5)}
cells = []
for cell in grid(box, 4, 4):
m = api("GET", "/api/v1/metrics", params={**cell, "past_days": 60})["metrics"]
cells.append({**cell, "tracked": m["listings"]["tracked"], "maturity": m["maturity"],
"occupancy": m["past"]["occupancy"], "adr": m["past"]["adr"]})Export GeoJSON
Write the cells as polygons. Open the file in geojson.io, QGIS or kepler.gl and colour by occupancy. Cells that are still collecting are kept but marked, so empty areas stay visible.
import json
features = []
for c in cells:
ring = [[c["west"], c["south"]], [c["east"], c["south"]], [c["east"], c["north"]], [c["west"], c["north"]], [c["west"], c["south"]]]
ok = c["maturity"] == "estimating"
features.append({"type": "Feature", "geometry": {"type": "Polygon", "coordinates": [ring]},
"properties": {"tracked": c["tracked"], "maturity": c["maturity"],
"occupancy": round(c["occupancy"], 3) if ok else None,
"adr": round(c["adr"]) if ok and c["adr"] else None}})
json.dump({"type": "FeatureCollection", "features": features}, open("riyadh-grid.geojson", "w"))Listings inside a rectangle
/api/v1/listings filters by city only, so filter coordinates yourself.
from jokerprice import all_listings
inside = lambda l, b: l.get("latitude") is not None and b["south"] <= l["latitude"] <= b["north"] and b["west"] <= l["longitude"] <= b["east"]
listings = [l for l in all_listings("riyadh") if inside(l, box)]
print(len(listings), "listings in the box")