Skip to content

Instantly share code, notes, and snippets.

@sujinleeme
Last active June 24, 2024 17:48
Show Gist options
  • Save sujinleeme/a63b64ade1609f9641e29b7d7479dd6b to your computer and use it in GitHub Desktop.
Save sujinleeme/a63b64ade1609f9641e29b7d7479dd6b to your computer and use it in GitHub Desktop.
Get street Geojson using Openstreet's Nominaim API

Get Street Geojson using Openstreet's Nominaim API

  1. Update street names in all-streets.txt.
  2. Update your COUNTRY_CODE = 'sg' in geojson_generator.py.
  3. Run geojson_generator.py
  4. Check *.csv and geojson.json file.

Nominatim is a search engine for OpenStreetMap data. This is the debugging interface. You may search for a name or address (forward search) or look up data by its geographic coordinate (reverse search). Each result comes with a link to a details page where you can inspect what data about the object is saved in the database and investigate how the address of the object has been computed. To enhance understand of Nominatim, recommend to visit https://nominatim.openstreetmap.org/ and play for a while.

Abingdon Road
Adam Drive
Adam Park
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
import urllib.request
import json
import csv
import os
# file path setting
OPEN_STREETS_NAMES_FILE = 'all-streets.txt'
OUTPUT_DIR = 'output'
OUTPUT_CSV_FILENAME = 'street-coordinates.csv'
OUTPUT_JSON_FILENAME = 'geojson.json'
# nominatim api address
BASE_URL = 'https://nominatim.openstreetmap.org/?format=json&polygon_geojson=1&addressdetails=1&q='
# init
CSV_DATA = [['id', 'name', 'coordinates']]
GEOJSON = {
"type": "FeatureCollection",
"features": []
}
ID = 0
COUNTRY_CODE = 'sg'
def flatten(something):
if isinstance(something, (list, tuple, set, range)):
for sub in something:
yield from flatten(sub)
else:
yield something
def split(arr, count):
return [ arr[i:i+count] for i in range(0, len(arr), count) ]
with open(OPEN_STREETS_NAMES_FILE) as f:
lines = f.read().splitlines()
for street in lines:
search_street_name = street.replace(" ", "+")
url = f'{BASE_URL}{search_street_name}+Singapore'
print(url)
res_body = urllib.request.urlopen(url).read()
content = json.loads(res_body.decode("utf-8"))
streets = [x for x in content if x['address']['country_code'] == COUNTRY_CODE]
streets = [d for d in streets if d.get('geojson', -1) != -1]
coordinates = [street['geojson']['coordinates'] for street in streets if street['geojson']['type'] == 'LineString']
all_coordinates = []
row = []
if len(streets) > 0:
all_coordinates = split(list(flatten(coordinates)), 2)
ID = ID + 1
row = [ID, street, all_coordinates]
# add to csv
CSV_DATA.append(row)
street_geojson = {
"id": ID,
"type": "Feature",
"geometry": {
"type": "LineString",
"coordinates": all_coordinates},
"properties": {
"name": street
}
}
# add to geojson
GEOJSON['features'].append(street_geojson)
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)
with open(f'{OUTPUT_DIR}/{OUTPUT_CSV_FILENAME}', 'w') as csvFile:
writer = csv.writer(csvFile)
writer.writerows(CSV_DATA)
print("writing completed")
csvFile.close()
with open(f'{OUTPUT_DIR}/{OUTPUT_JSON_FILENAME}', 'w') as f:
f.write(json.dumps(GEOJSON, sort_keys=True,
indent=4, separators=(',', ': ')))
We can make this file beautiful and searchable if this error is corrected: It looks like row 5 should actually have 3 columns, instead of 1. in line 4.
id,name,coordinates
1,Abingdon Road,"[[103.9787969, 1.3692413], [103.9787469, 1.3692966], [103.9794143, 1.3684698], [103.9794005, 1.3685049], [103.979376, 1.3685506], [103.9787969, 1.3692413]]"
2,Adam Drive,"[[103.8176052, 1.3339948], [103.8176107, 1.3340427], [103.8176123, 1.33409], [103.8176081, 1.3341221], [103.8175954, 1.3341525], [103.817576, 1.3341744], [103.8175498, 1.3341896], [103.8175177, 1.3342015], [103.8174696, 1.3342135], [103.8116705, 1.3365496], [103.8119119, 1.3365496], [103.8121614, 1.3366166], [103.8122767, 1.3367507], [103.812376, 1.3369867], [103.8125208, 1.3372978]]"
3,Adam Park,"[[103.8140937, 1.3287749], [103.8140378, 1.3288127], [103.8139981, 1.3288462], [103.8139745, 1.3288971], [103.8139726, 1.3289442], [103.8141061, 1.3291786], [103.8141291, 1.3292492], [103.8141346, 1.3293362], [103.8141172, 1.3294503], [103.8140529, 1.3296554], [103.8137841, 1.3300845], [103.8137425, 1.3302173], [103.813713, 1.3303406], [103.81374, 1.3310596], [103.81363, 1.3313742], [103.813454, 1.3315882], [103.8131354, 1.3317404], [103.8125838, 1.331864], [103.8123316, 1.331977]]"
s
@dmitribogonos
Copy link

Hi! Thank you for this awesome script! Just wanted to say that in addition to changing COUNTRY_CODE one need to change country on line 41: url = f'{BASE_URL}{search_street_name}+Singapore'

@sujinleeme
Copy link
Author

@dmitribogonos oops! Thanks for letting me know :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment