Geocoding#

GeoPandas supports geocoding (i.e., converting place names to location on Earth) through geopy, an optional dependency of GeoPandas. The following example shows how to get the locations of boroughs in New York City, and plots those locations along with the detailed borough boundary file included within GeoPandas.

In [1]: import geodatasets

In [2]: boros = geopandas.read_file(geodatasets.get_path("nybb"))

In [3]: boros.BoroName
Out[3]: 
0    Staten Island
1           Queens
2         Brooklyn
3        Manhattan
4            Bronx
Name: BoroName, dtype: object

In [4]: boro_locations = geopandas.tools.geocode(boros.BoroName)
---------------------------------------------------------------------------
TimeoutError                              Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:536, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    535 try:
--> 536     response = conn.getresponse()
    537 except (BaseSSLError, OSError) as e:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connection.py:461, in HTTPConnection.getresponse(self)
    460 # Get the response from http.client.HTTPConnection
--> 461 httplib_response = super().getresponse()
    463 try:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/http/client.py:1378, in HTTPConnection.getresponse(self)
   1377 try:
-> 1378     response.begin()
   1379 except ConnectionError:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/http/client.py:318, in HTTPResponse.begin(self)
    317 while True:
--> 318     version, status, reason = self._read_status()
    319     if status != CONTINUE:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/http/client.py:279, in HTTPResponse._read_status(self)
    278 def _read_status(self):
--> 279     line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
    280     if len(line) > _MAXLINE:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/socket.py:706, in SocketIO.readinto(self, b)
    705 try:
--> 706     return self._sock.recv_into(b)
    707 except timeout:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/ssl.py:1311, in SSLSocket.recv_into(self, buffer, nbytes, flags)
   1308         raise ValueError(
   1309           "non-zero flags not allowed in calls to recv_into() on %s" %
   1310           self.__class__)
-> 1311     return self.read(nbytes, buffer)
   1312 else:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/ssl.py:1167, in SSLSocket.read(self, len, buffer)
   1166 if buffer is not None:
-> 1167     return self._sslobj.read(len, buffer)
   1168 else:

TimeoutError: The read operation timed out

The above exception was the direct cause of the following exception:

ReadTimeoutError                          Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:790, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    789 # Make the request on the HTTPConnection object
--> 790 response = self._make_request(
    791     conn,
    792     method,
    793     url,
    794     timeout=timeout_obj,
    795     body=body,
    796     headers=headers,
    797     chunked=chunked,
    798     retries=retries,
    799     response_conn=response_conn,
    800     preload_content=preload_content,
    801     decode_content=decode_content,
    802     **response_kw,
    803 )
    805 # Everything went great!

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:538, in HTTPConnectionPool._make_request(self, conn, method, url, body, headers, retries, timeout, chunked, response_conn, preload_content, decode_content, enforce_content_length)
    537 except (BaseSSLError, OSError) as e:
--> 538     self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
    539     raise

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:370, in HTTPConnectionPool._raise_timeout(self, err, url, timeout_value)
    369 if isinstance(err, SocketTimeout):
--> 370     raise ReadTimeoutError(
    371         self, url, f"Read timed out. (read timeout={timeout_value})"
    372     ) from err
    374 # See the above comment about EAGAIN in Python 3.

ReadTimeoutError: HTTPSConnectionPool(host='photon.komoot.io', port=443): Read timed out. (read timeout=1)

The above exception was the direct cause of the following exception:

MaxRetryError                             Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/requests/adapters.py:486, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    485 try:
--> 486     resp = conn.urlopen(
    487         method=request.method,
    488         url=url,
    489         body=request.body,
    490         headers=request.headers,
    491         redirect=False,
    492         assert_same_host=False,
    493         preload_content=False,
    494         decode_content=False,
    495         retries=self.max_retries,
    496         timeout=timeout,
    497         chunked=chunked,
    498     )
    500 except (ProtocolError, OSError) as err:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:874, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    871     log.warning(
    872         "Retrying (%r) after connection broken by '%r': %s", retries, err, url
    873     )
--> 874     return self.urlopen(
    875         method,
    876         url,
    877         body,
    878         headers,
    879         retries,
    880         redirect,
    881         assert_same_host,
    882         timeout=timeout,
    883         pool_timeout=pool_timeout,
    884         release_conn=release_conn,
    885         chunked=chunked,
    886         body_pos=body_pos,
    887         preload_content=preload_content,
    888         decode_content=decode_content,
    889         **response_kw,
    890     )
    892 # Handle redirect?

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:874, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    871     log.warning(
    872         "Retrying (%r) after connection broken by '%r': %s", retries, err, url
    873     )
--> 874     return self.urlopen(
    875         method,
    876         url,
    877         body,
    878         headers,
    879         retries,
    880         redirect,
    881         assert_same_host,
    882         timeout=timeout,
    883         pool_timeout=pool_timeout,
    884         release_conn=release_conn,
    885         chunked=chunked,
    886         body_pos=body_pos,
    887         preload_content=preload_content,
    888         decode_content=decode_content,
    889         **response_kw,
    890     )
    892 # Handle redirect?

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/connectionpool.py:844, in HTTPConnectionPool.urlopen(self, method, url, body, headers, retries, redirect, assert_same_host, timeout, pool_timeout, release_conn, chunked, body_pos, preload_content, decode_content, **response_kw)
    842     new_e = ProtocolError("Connection aborted.", new_e)
--> 844 retries = retries.increment(
    845     method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
    846 )
    847 retries.sleep()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/urllib3/util/retry.py:515, in Retry.increment(self, method, url, response, error, _pool, _stacktrace)
    514     reason = error or ResponseError(cause)
--> 515     raise MaxRetryError(_pool, url, reason) from reason  # type: ignore[arg-type]
    517 log.debug("Incremented Retry for (url='%s'): %r", url, new_retry)

MaxRetryError: HTTPSConnectionPool(host='photon.komoot.io', port=443): Max retries exceeded with url: /api?q=Staten+Island&limit=1 (Caused by ReadTimeoutError("HTTPSConnectionPool(host='photon.komoot.io', port=443): Read timed out. (read timeout=1)"))

During handling of the above exception, another exception occurred:

ConnectionError                           Traceback (most recent call last)
File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/geopy/adapters.py:482, in RequestsAdapter._request(self, url, timeout, headers)
    481 try:
--> 482     resp = self.session.get(url, timeout=timeout, headers=headers)
    483 except Exception as error:

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/requests/sessions.py:602, in Session.get(self, url, **kwargs)
    601 kwargs.setdefault("allow_redirects", True)
--> 602 return self.request("GET", url, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/requests/sessions.py:589, in Session.request(self, method, url, params, data, headers, cookies, files, auth, timeout, allow_redirects, proxies, hooks, stream, verify, cert, json)
    588 send_kwargs.update(settings)
--> 589 resp = self.send(prep, **send_kwargs)
    591 return resp

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/requests/sessions.py:703, in Session.send(self, request, **kwargs)
    702 # Send the request
--> 703 r = adapter.send(request, **kwargs)
    705 # Total elapsed time of the request (approximately)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/requests/adapters.py:519, in HTTPAdapter.send(self, request, stream, timeout, verify, cert, proxies)
    517         raise SSLError(e, request=request)
--> 519     raise ConnectionError(e, request=request)
    521 except ClosedPoolError as e:

ConnectionError: HTTPSConnectionPool(host='photon.komoot.io', port=443): Max retries exceeded with url: /api?q=Staten+Island&limit=1 (Caused by ReadTimeoutError("HTTPSConnectionPool(host='photon.komoot.io', port=443): Read timed out. (read timeout=1)"))

During handling of the above exception, another exception occurred:

GeocoderUnavailable                       Traceback (most recent call last)
Cell In[4], line 1
----> 1 boro_locations = geopandas.tools.geocode(boros.BoroName)

File ~/checkouts/readthedocs.org/user_builds/geopandas/checkouts/v0.14.0/geopandas/tools/geocoding.py:67, in geocode(strings, provider, **kwargs)
     64     provider = "photon"
     65 throttle_time = _get_throttle_time(provider)
---> 67 return _query(strings, True, provider, throttle_time, **kwargs)

File ~/checkouts/readthedocs.org/user_builds/geopandas/checkouts/v0.14.0/geopandas/tools/geocoding.py:141, in _query(data, forward, provider, throttle_time, **kwargs)
    139 try:
    140     if forward:
--> 141         results[i] = coder.geocode(s)
    142     else:
    143         results[i] = coder.reverse((s.y, s.x), exactly_one=True)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/geopy/geocoders/photon.py:166, in Photon.geocode(self, query, exactly_one, timeout, location_bias, language, limit, osm_tag, bbox)
    164 logger.debug("%s.geocode: %s", self.__class__.__name__, url)
    165 callback = partial(self._parse_json, exactly_one=exactly_one)
--> 166 return self._call_geocoder(url, callback, timeout=timeout)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/geopy/geocoders/base.py:368, in Geocoder._call_geocoder(self, url, callback, timeout, is_json, headers)
    366 try:
    367     if is_json:
--> 368         result = self.adapter.get_json(url, timeout=timeout, headers=req_headers)
    369     else:
    370         result = self.adapter.get_text(url, timeout=timeout, headers=req_headers)

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/geopy/adapters.py:472, in RequestsAdapter.get_json(self, url, timeout, headers)
    471 def get_json(self, url, *, timeout, headers):
--> 472     resp = self._request(url, timeout=timeout, headers=headers)
    473     try:
    474         return resp.json()

File ~/checkouts/readthedocs.org/user_builds/geopandas/conda/v0.14.0/lib/python3.11/site-packages/geopy/adapters.py:494, in RequestsAdapter._request(self, url, timeout, headers)
    492         raise GeocoderServiceError(message)
    493     else:
--> 494         raise GeocoderUnavailable(message)
    495 elif isinstance(error, requests.Timeout):
    496     raise GeocoderTimedOut("Service timed out")

GeocoderUnavailable: HTTPSConnectionPool(host='photon.komoot.io', port=443): Max retries exceeded with url: /api?q=Staten+Island&limit=1 (Caused by ReadTimeoutError("HTTPSConnectionPool(host='photon.komoot.io', port=443): Read timed out. (read timeout=1)"))

In [5]: boro_locations
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[5], line 1
----> 1 boro_locations

NameError: name 'boro_locations' is not defined

In [6]: import matplotlib.pyplot as plt

In [7]: fig, ax = plt.subplots()

In [8]: boros.to_crs("EPSG:4326").plot(ax=ax, color="white", edgecolor="black");

In [9]: boro_locations.plot(ax=ax, color="red");
../../_images/boro_centers_over_bounds.png

By default, the geocode() function uses the Photon geocoding API. But a different geocoding service can be specified with the provider keyword.

The argument to provider can either be a string referencing geocoding services, such as 'google', 'bing', 'yahoo', and 'openmapquest', or an instance of a Geocoder from geopy. See geopy.geocoders.SERVICE_TO_GEOCODER for the full list. For many providers, parameters such as API keys need to be passed as **kwargs in the geocode() call.

For example, to use the OpenStreetMap Nominatim geocoder, you need to specify a user agent:

geopandas.tools.geocode(boros.BoroName, provider='nominatim', user_agent="my-application")

Attention

Please consult the Terms of Service for the chosen provider. The example above uses 'photon' (the default), which expects fair usage - extensive usage will be throttled. (Photon’s Terms of Use).