Digital Geography

15. May 2019

Geocoding with Microsoft’s Azure Maps

API’s are getting more and more important as some (maybe the majority?) of GIS users don’t want to handle large datasets, don’t want to care about addresses and geo-coordinates, don’t want to create an own routing algorithm… As most of you might use Google, OSM or HERE for geocoding purposes I would like to introduce Azure Maps for this as well.

Azure Maps

We need to admit: No one is using Bing, am I right? No, seriously: Microsoft definitely missed the cloud computing and mapping developments in the past. Personally, I don’t know anyone using Bing Maps / Azure Maps at all. Yet, the recent changes in the pricing scheme for Google Maps Services might reshape the market a bit. So how do we use Azure Maps for, let’s say, geocoding.

The API Subscription

To use the geocoding service from Azure Maps you first need to create an Azure Maps account after you created an Microsoft Azure account. And yes, you will need a credit card already. And no, you can’t use the same payment details for two different subscriptions ;-).

Azure Maps Account creation in Azure Portal

For simple geocoding you will be fine with a S0 subscription which will give cost you €0.422 per 1,000 transactions (/geocodes). This price is well above the included transactions of a Freemium subscription at HERE. Once you have registered for the API you can use you subscription-key:

subscription keys at Azure Maps

The Python Code

I don’t want to go too far with processing and plugins but want to share the simple code for requesting the API, getting the found address as well as some quality indicator and the latitude/longitude of course:
import requests, json
from qgis.core import QgsField, QgsFeature
from PyQt5.QtCore import QVariant
query = r'Mörikestraße 2, 06862 Dessau-Roßlau'
key = "put you fancy Primary Key here"
r = requests.get('https://atlas.microsoft.com/search/fuzzy/json?api-version=1.0&subscription-key=' + key + '&query=' + query)
Now, as the query is set and send, we will deal with the response. But first, let’s create a layer for the result:
layer = QgsVectorLayer(
            "Point?crs=EPSG:4326",
            "AddressLayer",
            "memory"
)
layer.dataProvider().addAttributes([
            QgsField("id",QVariant.Int),
            QgsField("oldAddress",QVariant.String),
            QgsField("newAddress",QVariant.String),
            QgsField("score",QVariant.Double),
            QgsField("lat",QVariant.Double),
            QgsField("lon",QVariant.Double)
])
layer.updateFields()
Our result will have some more “hits” as well as additional attributes but we will only use the one with the largest score and most important attributes:
fet = QgsFeature()
fet.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(r.json()["results"][0]["position"]["lon"],r.json()["results"][0]["position"]["lat"])))
fet.setAttributes([
  0,
  query,
  r.json()["results"][0]["address"]["freeformAddress"],
  r.json()["results"][0]["score"],
  r.json()["results"][0]["position"]["lat"],
  r.json()["results"][0]["position"]["lon"]
])

pr = layer.dataProvider()
pr.addFeatures([fet])
QgsProject.instance().addMapLayer(layer)
As you can see, we got some results here:

geocoding results for the Azure Maps API

In this example we used the “fuzzy search” approach. if you have a defined address structure, you might also want to try out the structured search or only “address search”. Fortunately, especially the address search uses a similar result schema, so you could easily change the above script and use:
r = requests.get('https://atlas.microsoft.com/search/address/json?api-version=1.0&subscription-key=' + key + '&query=' + query)
Happy geocoding, everyone!