Batch Geocoding¶
This guide shows how to encode large datasets of GPS coordinates to Yoro codes — useful for geocoding CSV files, database records, or GeoJSON features.
CSV Geocoding¶
Encode a CSV file¶
import csv
import yoro
with open("locations.csv") as fin, open("locations_with_yoro.csv", "w", newline="") as fout:
reader = csv.DictReader(fin)
fieldnames = reader.fieldnames + ["yoro_code", "yoro_precision", "resolution_m"]
writer = csv.DictWriter(fout, fieldnames=fieldnames)
writer.writeheader()
for row in reader:
lat = float(row["latitude"])
lon = float(row["longitude"])
code = yoro.encode(lat, lon, precision=12, domain="CI")
decoded = yoro.decode(code)
res = yoro.resolution(decoded["precision"], domain="CI")
row["yoro_code"] = code
row["yoro_precision"] = decoded["precision"]
row["resolution_m"] = round(res, 1)
writer.writerow(row)
Input (locations.csv)¶
name,latitude,longitude
Abidjan Plateau,5.322,-4.017
Bouake Centre,7.694,-5.031
Yamoussoukro,6.827,-5.276
San Pedro Port,4.748,-6.636
Output (locations_with_yoro.csv)¶
name,latitude,longitude,yoro_code,yoro_precision,resolution_m
Abidjan Plateau,5.322,-4.017,CI-PW2MK,12,172.9
Bouake Centre,7.694,-5.031,CI-NX3WB,12,172.9
Yamoussoukro,6.827,-5.276,CI-NW64D,12,172.9
San Pedro Port,4.748,-6.636,CI-KYB8G,12,172.9
Pandas DataFrame¶
import pandas as pd
import yoro
df = pd.read_csv("locations.csv")
# Vectorized encoding
df["yoro_code"] = df.apply(
lambda row: yoro.encode(row["latitude"], row["longitude"], domain="CI"), axis=1
)
# Add decoded info
decoded = df["yoro_code"].apply(yoro.decode)
df["yoro_lat"] = decoded.apply(lambda d: d["lat"])
df["yoro_lon"] = decoded.apply(lambda d: d["lon"])
df["cell_lat_min"] = decoded.apply(lambda d: d["bounds"]["lat_min"])
df["cell_lat_max"] = decoded.apply(lambda d: d["bounds"]["lat_max"])
print(df)
GeoJSON¶
Add Yoro codes to GeoJSON features¶
import json
import yoro
with open("parcels.geojson") as f:
geojson = json.load(f)
for feature in geojson["features"]:
geom = feature["geometry"]
if geom["type"] == "Point":
lon, lat = geom["coordinates"]
elif geom["type"] == "Polygon":
# Use centroid of first ring
coords = geom["coordinates"][0]
lon = sum(c[0] for c in coords) / len(coords)
lat = sum(c[1] for c in coords) / len(coords)
else:
continue
code = yoro.encode(lat, lon, domain="CI")
feature["properties"]["yoro_code"] = code
with open("parcels_with_yoro.geojson", "w") as f:
json.dump(geojson, f, indent=2)
Django Bulk Assignment¶
For existing database records without Yoro codes:
from django.contrib.gis.geos import Point
from yoro.django.services import get_or_create_altius_code
from myapp.models import Producer
# Find all producers without a Yoro code
producers = Producer.objects.filter(
location__isnull=False,
altius_code__isnull=True,
)
updated = []
for producer in producers.iterator(chunk_size=500):
lat, lon = producer.location.y, producer.location.x
code_obj = get_or_create_altius_code(lat, lon, domain="CI")
producer.altius_code = code_obj
updated.append(producer)
if len(updated) >= 500:
Producer.objects.bulk_update(updated, ["altius_code"])
updated = []
if updated:
Producer.objects.bulk_update(updated, ["altius_code"])
Performance¶
Yoro encoding is pure math — no I/O, no network calls:
import time
import yoro
# Benchmark: 100,000 encodes
start = time.perf_counter()
for i in range(100_000):
yoro.encode(5.0 + i * 0.00005, -4.0 + i * 0.00003, domain="CI")
elapsed = time.perf_counter() - start
print(f"100,000 encodes in {elapsed:.2f}s ({100_000 / elapsed:.0f} ops/sec)")
# Typical: ~200,000 ops/sec on modern hardware
No need for async or multiprocessing
At ~200K encodes/second, even a million-row dataset takes only 5 seconds. No parallelization needed for most use cases.