mirror of
https://github.com/wassname/geopandas.git
synced 2026-09-09 11:22:50 +08:00
Initial commit of geocoding functionality
Geocode a Series or list of strings and get back a GeoDataFrame with the Point objects and a full geocoded address.
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
from collections import defaultdict
|
||||
|
||||
import fiona
|
||||
import geopy
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from shapely.geometry import Point
|
||||
|
||||
import geopandas as gpd
|
||||
|
||||
def geocode(strings, provider='googlev3', **kwargs):
|
||||
"""
|
||||
Geocode a set of strings and get a GeoDataFrame of the resulting points
|
||||
|
||||
Parameters
|
||||
----------
|
||||
strings : list or Series of addresses to geocode
|
||||
provider : geopy geocoder to use, default 'googlev3'
|
||||
Some providers require additional arguments such as access keys
|
||||
* googlev3
|
||||
* bing
|
||||
* google
|
||||
* yahoo
|
||||
* mapquest
|
||||
* openmapquest
|
||||
|
||||
Consult the terms of service for each provider to ensure proper use
|
||||
of the results.
|
||||
|
||||
Example
|
||||
-------
|
||||
>>> df = geocode(['boston, ma', '1600 pennsylvania ave. washington, dc'])
|
||||
address geometry
|
||||
0 Boston, MA, USA POINT (-71.0597731999999951 42.3584308000000007)
|
||||
1 1600 Pennsylvania Avenue Northwest, President'... POINT (-77.0365122999999983 38.8978377999999978)
|
||||
|
||||
"""
|
||||
if not isinstance(strings, pd.Series):
|
||||
strings = pd.Series(strings)
|
||||
|
||||
coders = {'googlev3': geopy.geocoders.GoogleV3,
|
||||
'bing': geopy.geocoders.Bing,
|
||||
'google': geopy.geocoders.Google,
|
||||
'yahoo': geopy.geocoders.Yahoo,
|
||||
'mapquest': geopy.geocoders.MapQuest,
|
||||
'openmapquest': geopy.geocoders.OpenMapQuest}
|
||||
|
||||
if provider not in coders:
|
||||
raise ValueError('Unknown geocoding provider: {}'.format(provider))
|
||||
|
||||
coder = coders[provider](**kwargs)
|
||||
results = {}
|
||||
for i, s in strings.iteritems():
|
||||
# Probably want some try/catch here, but what to do on exception?
|
||||
results[i] = coder.geocode(s)
|
||||
|
||||
df = _prepare_geocode_result(results)
|
||||
return df
|
||||
|
||||
def _prepare_geocode_result(results):
|
||||
"""
|
||||
Helper function for the geocode function
|
||||
|
||||
Takes a dict where keys are index entries, values are tuples containing:
|
||||
(address, (lat, lon))
|
||||
|
||||
"""
|
||||
# Prepare the data for the DataFrame as a dict of lists
|
||||
d = defaultdict(list)
|
||||
index = []
|
||||
|
||||
for i, s in results.iteritems():
|
||||
address, loc = s
|
||||
|
||||
# loc is lat, lon and we want lon, lat
|
||||
p = Point(loc[1], loc[0])
|
||||
d['geometry'].append(p)
|
||||
d['address'].append(address)
|
||||
index.append(i)
|
||||
|
||||
df = gpd.GeoDataFrame(d, index=index)
|
||||
df.crs = fiona.crs.from_epsg(4326)
|
||||
|
||||
return df
|
||||
@@ -1 +1,2 @@
|
||||
psycopg2>=2.5.1
|
||||
geopy>=0.95.1
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import unittest
|
||||
|
||||
import fiona
|
||||
from shapely.geometry import Point
|
||||
import geopandas as gpd
|
||||
|
||||
from geopandas.geocode import geocode, _prepare_geocode_result
|
||||
|
||||
class TestGeocode(unittest.TestCase):
|
||||
def test_prepare_result(self):
|
||||
# Calls _prepare_result with sample results from the geocoder call
|
||||
# loop
|
||||
p0 = Point(12.3, -45.6) # Treat these as lat/lon
|
||||
p1 = Point(-23.4, 56.7)
|
||||
d = {'a': ('address0', p0.coords[0]),
|
||||
'b': ('address1', p1.coords[0])}
|
||||
|
||||
df = _prepare_geocode_result(d)
|
||||
assert type(df) is gpd.GeoDataFrame
|
||||
self.assertEqual(fiona.crs.from_epsg(4326), df.crs)
|
||||
self.assertEqual(len(df), 2)
|
||||
self.assertIn('address', df)
|
||||
|
||||
coords = df.loc['a']['geometry'].coords[0]
|
||||
test = p0.coords[0]
|
||||
# Output from the df should be lon/lat
|
||||
self.assertAlmostEqual(coords[0], test[1])
|
||||
self.assertAlmostEqual(coords[1], test[0])
|
||||
|
||||
coords = df.loc['b']['geometry'].coords[0]
|
||||
test = p1.coords[0]
|
||||
self.assertAlmostEqual(coords[0], test[1])
|
||||
self.assertAlmostEqual(coords[1], test[0])
|
||||
|
||||
def test_bad_provider(self):
|
||||
self.assertRaises(ValueError, geocode, ['cambridge, ma'], 'badprovider')
|
||||
Reference in New Issue
Block a user