Part 6 - Working with Custom Geocoders
Geocoders for GIS
instances¶
As previously mentioned in Part 1, Geocoders
are tools that can find spatial coordinates of addresses, business names, places of interest and so on, and output points that can be visualized on a map, inserted as stops for a route, or loaded as input for spatial analysis. Geocoders
can also used to generate batch results for a set of addresses, as well as for reverse geocoding, the process of determining the address at a particular x/y location.
Geocoders can come from many sources, e.g. Esri, Google Maps, and Epi Info 7.2, with various advantages and disadvantages with regard to ease of use, exporting maps, and the ability to geocode addresses outside of the United States. Keep in mind that geocoders are not always precise. Approximate latitudes and longitudes can be found for most addresses, especially in urban areas, but the exact latitude and longitude can vary by a few decimal points depending on which geocoder you use.
A GIS
includes one or more geocoders. By default it provides access to the ArcGIS World Geocoding Service
, and the geocoding
module provides a Geocoder
class to interact with that service. You can also construct Geocoder
objects from your GIS's custom geocoding service items or from the URL to a geocoding service. Further, the list of geocoders registered with the GIS
can be queried using get_geocoders()
, a method that returns a list of Geocoder instances.
In the example below, there are more than one registered Geocoders with the GIS
, and the first one uses the Esri World Geocoding Service
for geocoding:
from arcgis.gis import GIS
from arcgis.geocoding import Geocoder, get_geocoders, geocode
gis = GIS(profile="your_enterprise_profile")
get_geocoders(gis)
Create a Geocoder instance from an Item or a URL¶
Creating a geocoder using a geocoding service item¶
Geocoding services can be published as items in the GIS
. An instance of the geocoder can also be constructed by passing in a reference to these items from the GIS
to the Geocoder's constructor Geocoder.fromitem()
:
from IPython.display import display
arcgis_online = GIS()
items = arcgis_online.content.search('Geocoder', 'geocoding service', max_items=3)
for item in items:
display(item)
# construct a geocoder using the 2nd geocoding service item
world_geocoder = Geocoder.fromitem(items[1])
world_geocoder
Creating a geocoder using a URL¶
Geocoders may also be created using the constructor Geocoder(location=..., gis=None)
by passing in their location, such as a url to a Geocoding Service. If the geocoding service is a secure service, pass in the GIS
to which it is federated with as the gis
parameter:
geocoder_url = 'https://services.arcgisonline.nl/arcgis/rest/services/Geocoder_BAG_RD/GeocodeServer'
esrinl_geocoder = Geocoder(geocoder_url, gis)
esrinl_geocoder
Specifying a particular Geocoder instance with a GIS
object¶
In this section, we will talk about specifying a particular Geocoder
instance when there are multiple available (geocode(geocoder=
)
)
The geocoder
paramter is optional for geocode
function, representing whichever geocoder to be used. If not specified, the active GIS
's first geocoder is used. We can see from the example below, that with different geocoders, the geocoded results for the same address might be different, due to the difference of spatial reference, geocoder coverage and precision, etc.
results = geocode('Raadhuisstraat 52, 1016 Amsterdam', geocoder=esrinl_geocoder)
results[0]['location']
esrinl_geocoder.properties.spatialReference
The geocoded result is different when using another geocoder (as shown below), mainly due to that two geocoders are in different spatial reference systems.
results = geocode('Raadhuisstraat 52, 1016 Amsterdam', geocoder=world_geocoder)
results[0]['location']
world_geocoder.properties.spatialReference
keys_list = [prop_name for prop_name in world_geocoder.properties.keys()]
display(keys_list)
Localized input field names in addressFields
¶
Developers integrating the geocoder into their application may need to know the appropriate input field names to use for
the language and country of their users. This information can be obtained using the localizedNames
parameter of the
address field. More information on this, as well as the recognizedNames
parameter, is available in the Foreign language
field names (World Geocoding Service
) documentation.
For example, the code below lists the supported address fields and the corresponding input field names in Hindi
or Simplified Chinese
:
for addrfld in world_geocoder.properties.addressFields:
print(addrfld['name'], end='')
print(": " + str(addrfld['localizedNames']['hi'] if 'hi' in addrfld['localizedNames'] else '-'))
for addrfld in world_geocoder.properties.addressFields:
print(addrfld['name'], end='')
print(": " + str(addrfld['localizedNames']['zh'] if 'zh' in addrfld['localizedNames'] else '-'))
candidateFields
property¶
The CandidateFields
property of the geocoder
contains the fields that are returned for each candidate.
for addrfld in world_geocoder.properties.candidateFields:
req_str = ""
if addrfld["required"]:
req_str = "*"
if "length" in addrfld:
print(addrfld["name"], "(", addrfld["length"], ")", req_str)
else:
print(addrfld["name"], req_str)
locatorProperties
¶
The geocoder has several important properties that are specified in the locatorProperties
.
These include the maximum number of addresses that can be geocoded in a single batch geocoding method call. The MaxBatchSize
property defines this limit. For instance, if MaxBatchSize=2000
, and 3000 addresses are passed in as input to the batch_geocode()
method, only the first 2000 will be geocoded.
The SuggestedBatchSize
property is also useful, as it specifies the optimal number of addresses to include in a single batch request.
The code below lists these useful locator properties.
world_geocoder.properties.locatorProperties
capbilities
property¶
Not all geocoders support reverse_geocode
, batch_geocode
, and etc. Before calling these methods with arcgis.geocoding
module, try to query the geocoder's capabilities
first.
world_geocoder.properties.capabilities
Geocoding with custom geocoder¶
When the geocoder
parameter is not applied, the geocode()
function adopts the first registered geocoding service with the currently active GIS
; when specified, geocode()
uses the custom geocoder input with the parameter.
results = geocode('Nieuwezijds Voorburgwal 147, 1012 RJ Amsterdam',
geocoder=esrinl_geocoder,
out_sr=4326,
lang_code="DUT")
results[0]
Batch geocoding with custom geocoder¶
With batch_geocode()
, the geocoder
parameter is still optional, representing the geocoder to be used. If not specified, the active GIS's first geocoder is used.
We can use a combination of the geocoder
and out_sr
parameters to get the geocoded results using custom geocoder and output in the desired spatial reference.
from arcgis.geocoding import batch_geocode
addresses = ["Kalverstraat 92, 1012 PH Amsterdam",
"Plantage Middenlaan 2a, 1018 DD Amsterdam",
"Meeuwenlaan 88, 1021 JK Amsterdam"]
geocoded = batch_geocode(addresses, geocoder = get_geocoders(gis)[0],
out_sr = 28992)
for res in geocoded:
print(res["location"], res["attributes"]["Match_addr"])
map1.draw(res["location"])
When drawing in a map, let's set as_featureset=True
to have the geocode
function return results as a FeatureSet which is easier to plot on a map.
map1 = gis.map("Amsterdam")
map1.zoom = 14
map1.center = {'spatialReference': {'latestWkid': 3857, 'wkid': 102100},
'x': 546847.186161375,
'y': 6868318.370682971}
map1
geocoded_fs = batch_geocode(addresses, geocoder = get_geocoders(gis)[0],
as_featureset=True)
map1.draw(geocoded_fs)
Reverse geocoding with custom geocoder¶
With reverse_geocode()
, the geocoder=<VAL>
parameter is still optional, representing the geocoder to be used. If not specified, the active GIS's first geocoder is used.
We can use a combination of the geocoder
and feature_types
parameters to convert coordinates to addresses using custom geocoder and return the nearest point of interest.
from arcgis.geocoding import reverse_geocode
reverse_geocode({'x': 4.885602819214398, 'y': 52.374067391443106},
geocoder = get_geocoders(gis)[0],
feature_types="POI")
Note that, the input location paramter (the required list/Point Geometry) has to be in the same spatial reference as stated by the `geocoder.properties.spatialReference`. When using different geocoders, the results of `reverse_geocode` can be varied.
reverse_geocode({'x': 120842.00295538307, 'y': 487472.9997233087, 'z': 0},
geocoder = esrinl_geocoder,
feature_types="POI")
Conclusions¶
In Part 6 of the geocoding series, we have inspected the Geocoder
object, browsed its important properties, and explored ways to geocode
, batch_geocode
, and reverse_geocode
with custom geocoders. Next, in Part 7, let's discuss how to use utility functions for geocoding.