Lightweight route mapping with OpenStreetMap and Nominatim

I realise Geopy is supported on Anvil but thought people might be interested in this extremely lightweight solution I cooked up for my Corona Virus app. It does 80% of what I wanted without the learning curve of getting to grips with Geopy or the ‘proper’ authenticated APIs of Nominatim (for getting address data including Longitude and Latitude) or OpenStreetMap (for displaying a route rather nicely).

The goal was to generate a URL (http GET request) in the following format:

https://www.openstreetmap.org/directions?engine=graphhopper_foot&route=51.45476%2C-0.22850%3B51.45473%2C-0.22512

It took just two short Server functions:

import anvil.http
LOCALE = "United Kingdom"

def nominatim_scrape(address_list):
    """
    Returns location & address data for supplied address list
    E.g. [street, town, county]
    """
    nominatim = 'https://nominatim.openstreetmap.org/search?q='
    nominatim += f"{','.join(address_list).replace(', ',',').replace('&','%26')},{LOCALE},&format=json".replace(" ","%20")
    # Some fiddly string formatting there due to my data model...
    return  anvil.http.request(nominatim, json=True)

def generate_route_url(street1, town1, county1, street2, town2, county2):
    """Creates an Open Street Map url showing a route between two locations"""
    address1 = [street1, town1, county1]
    address2 = [street2, town2, county2]
    # Get the address data as a json response from Nominatim
    data1 = nominatim_scrape(address1)[0]
    data2 = nominatim_scrape(address2)[0]
    # Create the http GET request and return is as a url
    data1 = data1['lat'] + "%2C" + data1['lon']
    data2 = data2['lat'] + "%2C" + data2['lon']
    url = "https://www.openstreetmap.org/directions?engine=graphhopper_foot&route="
    url += data1 + "%3B" + data2
    return url

The .url property of an Anvil link component can then simply be set to the OpenStreetMap url to open when clicked. Simples!

Unfortunately I think you need to use the full API to embed in an i-frame which would’ve looked even better, but that’s a challenge for another day…

I was just childishly excited to be able to offer users some sort of mapping functionality “Anvil style” i.e. with minimal fuss and bother, and all within their browser.

Here’s a clone of the current app if you want to see it in action or have a play:

https://anvil.works/build#clone:P33PVE5OAIUCIJY3=TH42XLEGYI2TOLUOUTEK7QAO

And here’s a link to the Nominatim API:
https://nominatim.org/release-docs/develop/api/Details/

4 Likes

Well, that is extraordinarily cool!

Tip: Instead of using .replace() to replace individual characters like '&' and ' ' with their URL-encoded versions, you use anvil.http.url_encode(), which will safely encode everything.

2 Likes

Brilliant! Another thing I didn’t know I didn’t know, thanks @meredydd.