شبكة الأحياء باستخدام مستطيلات الخريطة
متقدم
قسّم المدينة إلى خلايا شبكية، واستعلم عن كل خلية بمستطيل حدود، وصدّر النتائج بصيغة GeoJSON لعرضها على خريطة.
الإعداد
يستخدم هذا الدرس الأداة المساعدة jokerprice.py من درس البدء السريع. احفظها بجوار نصك البرمجي واضبط JOKERPRICE_API_KEY.
استعلامات مستطيل الحدود
تقبل /api/v1/metrics المعاملات north وsouth وeast وwest بدلًا من city. يجب ألا يتجاوز عرض المستطيل 5 درجات، وأن يكون الجنوب أدنى من الشمال والغرب أدنى من الشرق.
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"])ابنِ الشبكة
كل خلية طلب واحد؛ فالشبكة 4 × 4 تعني 16 طلبًا، وتنتظر الأداة المساعدة تلقائيًا إذا بلغت 120 طلبًا في الدقيقة.
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"]})صدّر GeoJSON
اكتب الخلايا على هيئة مضلعات. افتح الملف في geojson.io أو QGIS أو kepler.gl ولوّنه حسب الإشغال. تبقى الخلايا التي ما زالت قيد الجمع موجودة مع وسمها، لتظل المناطق الفارغة ظاهرة.
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"))العقارات داخل مستطيل
تصفّي /api/v1/listings حسب المدينة فقط، لذا صفِّ الإحداثيات بنفسك.
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")