27

I need to convert longitude and latitude coordinates to either country or city, is there an example of this in python?

thanks in advance!

godzilla
  • 3,005
  • 7
  • 44
  • 60

5 Answers5

35

I use Google's API.

from urllib2 import urlopen
import json
def getplace(lat, lon):
    url = "http://maps.googleapis.com/maps/api/geocode/json?"
    url += "latlng=%s,%s&sensor=false" % (lat, lon)
    v = urlopen(url).read()
    j = json.loads(v)
    components = j['results'][0]['address_components']
    country = town = None
    for c in components:
        if "country" in c['types']:
            country = c['long_name']
        if "postal_town" in c['types']:
            town = c['long_name']
    return town, country


print(getplace(51.1, 0.1))
print(getplace(51.2, 0.1))
print(getplace(51.3, 0.1))

Output:

(u'Hartfield', u'United Kingdom')
(u'Edenbridge', u'United Kingdom')
(u'Sevenoaks', u'United Kingdom')
Holy Mackerel
  • 3,259
  • 1
  • 25
  • 41
  • this is great, is there a clean way to pick up city and country without using split? – godzilla Nov 24 '13 at 00:10
  • Yes, I have revised my answer to return city and country – Holy Mackerel Nov 24 '13 at 00:21
  • this works fine, however is there a way of doing this locally? an api of some sort, the latency is a huge bottleneck for what i am trying to do – godzilla Nov 26 '13 at 16:23
  • @godzilla You could cache the result of each request locally and return the same town/country for requests that match a cached result within a certain allowed radius. Otherwise try searching for a downloadable geo co-ord database - perhaps post another question on this site to ask if anyone knows of any. – Holy Mackerel Nov 26 '13 at 19:58
  • 8
    For Python > 3.5 use `from urllib.request import urlopen` – PallavBakshi Mar 27 '18 at 06:58
  • 5
    Now google map api needs key to be able to use. I need to register for a billing account. after getting the key, I need to change the first url to `url = "https://maps.googleapis.com/maps/api/geocode/json?key=YourKey&"` (note: it needs to be https, not http) – Pengyao Jun 03 '19 at 23:03
13

Google has since removed keyless access to their API. Head over to google and register for a key, you get ~ 1,000 free queries a day. Code in accepted answer should be modified like this (can't add a comment, not enough rep).

from urllib.request import urlopen
import json

def getplace(lat, lon):
    key = "yourkeyhere"
    url = "https://maps.googleapis.com/maps/api/geocode/json?"
    url += "latlng=%s,%s&sensor=false&key=%s" % (lat, lon, key)
    v = urlopen(url).read()
    j = json.loads(v)
    components = j['results'][0]['address_components']
    country = town = None
    for c in components:
        if "country" in c['types']:
            country = c['long_name']
        if "postal_town" in c['types']:
            town = c['long_name']

    return town, country

print(getplace(51.1, 0.1))
print(getplace(51.2, 0.1))
print(getplace(51.3, 0.1))
KetZoomer
  • 2,701
  • 3
  • 15
  • 43
tibernut
  • 131
  • 1
  • 5
12

This is called reverse geocoding. There is one library I could find in Python which is focused on this: https://github.com/thampiman/reverse-geocoder

Some related questions with other ideas:

Community
  • 1
  • 1
pfctdayelise
  • 5,115
  • 3
  • 32
  • 52
8

In general the Google API is the best approach. It was not suitable for my case as I had to process a lot of entries and the api is slow.

I coded a small version that does the same but downloads a huge geometry first and computes the countries on the machine.

import requests

from shapely.geometry import mapping, shape
from shapely.prepared import prep
from shapely.geometry import Point


data = requests.get("https://raw.githubusercontent.com/datasets/geo-countries/master/data/countries.geojson").json()

countries = {}
for feature in data["features"]:
    geom = feature["geometry"]
    country = feature["properties"]["ADMIN"]
    countries[country] = prep(shape(geom))

print(len(countries))

def get_country(lon, lat):
    point = Point(lon, lat)
    for country, geom in countries.iteritems():
        if geom.contains(point):
            return country

    return "unknown"

print(get_country(10.0, 47.0))
# Austria
spedy
  • 2,200
  • 25
  • 26
linqu
  • 11,320
  • 8
  • 55
  • 67
  • this pip extension is also interesting, maybe not so accurate as it is based on some reference point and does some interpolation: https://pypi.python.org/pypi/reverse_geocode/1.0 – linqu Oct 16 '17 at 12:58
  • 4
    For Python 3 use: for country, geom in countries.items(): – DougR Jul 19 '19 at 12:01
  • If you are looking for a static solution, you can actually go a step ahead and download the file mentioned in url and read it this way: with open('countries.geojson', 'w') as fp: data = json.loads(fp.read()) – supersaiyan Oct 16 '20 at 14:52
2
# Python3 program for reverse geocoding. 

# importing necessary libraries 
import reverse_geocoder as rg 
from pandas import DataFrame
import pandas as pd

def reverseGeocode(coordinates): 
    result = rg.search(coordinates) 
    
    return result

    
# Coorinates tuple.Can contain more than one pair. 

if __name__ == "__main__":
    result = []
    path = "CSV_NAME.CSV"
    df = pd.read_csv(path, error_bad_lines=False)
    for i in range(0, len(df)):
        coordinates =(df["latitude"], df["longitude"]) 
        result.append(reverseGeocode(coordinates))
    print(result)
        
Lokesh K V
  • 56
  • 4