Python: Code Snippets - Geocode
Sunday 23rd July 2017 3:25am
UPDATE:- Google are no longer offering API keys without billing information
Geocoding is the process of converting locations (a street address, postcode etc.) into coordinates; latitude and longitude.
The first script takes these coordinates and returns an image of the location.
To run this script copy the code below and save to a file called geocode_image.py
geocode_image.py:
#!/usr/bin/env python
# Geocode map image
# Return an image for a given location
# (latitude and longitude)
# Date: 07 March 2016
# Written By: Phantom Raspberry Blower
import Image
import urllib
import StringIO
import os
from math import log, exp, tan, atan, pi, ceil
# Define constants
EARTH_RADIUS = 6378137 # in metres
EQUATOR_CIRCUMFERENCE = 2 * pi * EARTH_RADIUS
INITIAL_RESOLUTION = EQUATOR_CIRCUMFERENCE / 256.0
ORIGIN_SHIFT = EQUATOR_CIRCUMFERENCE / 2.0
class GeocodeImage():
# Initialize
def __init__(self):
pass # Do nothing
def latlontopixels(self, lat, lon, zoom):
mx = (lon * ORIGIN_SHIFT) / 180.0
my = log(tan((90 + lat) * pi / 360.0))/(pi / 180.0)
my = (my * ORIGIN_SHIFT) / 180.0
res = INITIAL_RESOLUTION / (2 ** zoom)
px = (mx + ORIGIN_SHIFT) / res
py = (my + ORIGIN_SHIFT) / res
return px, py
def pixelstolatlon(self, px, py, zoom):
res = INITIAL_RESOLUTION / (2**zoom)
mx = px * res - ORIGIN_SHIFT
my = py * res - ORIGIN_SHIFT
lat = (my / ORIGIN_SHIFT) * 180.0
lat = 180 / pi * (2*atan(exp(lat*pi/180.0)) - pi/2.0)
lon = (mx / ORIGIN_SHIFT) * 180.0
return lat, lon
def geocode_image(self, lat, lon, file_path):
plat, plon = self.latlontopixels(lat, lon, 17)
nlat, nlon = self.pixelstolatlon(plat-320, plon+180, 17)
upperleft = '%f,%f' % (nlat, nlon)
plat, plon = self.latlontopixels(nlat, nlon, 17)
nlat, nlon = self.pixelstolatlon(plat+640, plon-360, 17)
lowerright = '%f,%f' % (nlat, nlon)
zoom = 18 # be careful not to get too many images!
map_type = 'hybrid'
ullat, ullon = map(float, upperleft.split(','))
lrlat, lrlon = map(float, lowerright.split(','))
# Set some important parameters
scale = 1
maxsize = 640
# convert all these coordinates to pixels
ulx, uly = self.latlontopixels(ullat, ullon, zoom)
lrx, lry = self.latlontopixels(lrlat, lrlon, zoom)
# calculate total pixel dimensions of final image
dx, dy = abs(lrx - ulx), abs(uly - lry)
# calculate rows and columns
cols, rows = int(ceil(dx/maxsize)), int(ceil(dy/maxsize))
# calculate pixel dimensions of each small image
bottom = 120
length = int(ceil(dx/cols))
height = int(ceil(dy/rows))
heightplus = height + bottom
final = Image.new("RGB", (int(dx), int(dy)))
for x in range(cols):
for y in range(rows):
dxn = length * (0.5 + x)
dyn = height * (0.5 + y)
latn, lonn = self.pixelstolatlon(ulx + dxn,
uly - dyn - bottom/2,
zoom)
position = ','.join((str(latn), str(lonn)))
print x, y, position
urlparams = urllib.urlencode({'center': position,
'zoom': str(zoom),
'size': '%dx%d' % (length,
heightplus),
'maptype': map_type,
'sensor': 'false',
'scale': scale})
url = 'http://maps.google.com/maps/api/staticmap?' + urlparams
f = urllib.urlopen(url)
im = Image.open(StringIO.StringIO(f.read()))
final.paste(im, (int(x*length), int(y*height)))
final.save(file_path)
final.show()
return final
# Check if running stand-alone or imported
if __name__ == '__main__':
import os
# Request both latitude and longitude
latitude = input('Enter Latitude: ')
longitude = input('Enter Longitude: ')
gi = GeocodeImage()
print "Fetching image ..."
gi.geocode_image(latitude,
longitude,
os.getcwd() + '/geocode_image.jpg')
print "Image saved!"
The next script accepts an address, location or postcode and returns the latitude and longitude.
Copy the code below and save to a file called geocode.py
geocode.py:
#!/usr/bin/env python
# Geocode
# Return the address and location for a given postcode
# Date: 07 March 2016
# Written By: Phantom Raspberry Blower
import requests # Used to request web pages
import Image
import urllib
import StringIO
from geocode_image import GeocodeImage
class Geocode():
# Initialize
def __init__(self):
self.addr = ''
def geocode_postcode(self, postcode):
self.geocode(postcode)
def _clear(self):
self.post_code = ''
self.addr = ''
self.addr_label = ''
self.formatted_addr = ''
self.lat = 0.0
self.lon = 0.0
def geocode(self, postcode):
self._clear()
self.post_code = postcode.upper()
url = 'https://maps.googleapis.com/maps/api/geocode/json'
params = {'sensor': 'false', 'address': postcode}
r = requests.get(url, params=params)
results = r.json()['results']
location = results[0]['geometry']['location']
self.lat = location['lat']
self.lon = location['lng']
address_components = results[0]['address_components']
for item in range(1, len(address_components)):
if item > 1:
self.addr = "%s\n" % self.addr
self.addr = "%s%s" % (self.addr, address_components[item]['long_name'])
self.formatted_addr = results[0]['formatted_address']
def image(self):
gi = GeocodeImage()
gi.geocode_image(self.lat, self.lon, os.getcwd() + '/geocode_image.jpg')
return "Image Saved"
def postcode(self):
return self.post_code
def location(self):
return [self.latitude(), self.longitude()]
def latitude(self):
return self.lat
def longitude(self):
return self.lon
def address(self):
return self.addr
def address_label(self):
return str(self.formatted_address()).replace(", ", ",\n")
def formatted_address(self):
return str(self.formatted_addr)
# Check if running stand-alone or imported
if __name__ == '__main__':
postcode = raw_input('Enter Address, Location or Postcode: ').upper()
gc = Geocode()
gc.geocode_postcode(postcode)
print "\nAddress:"
print " ", gc.address_label().replace("\n", "\n ")
print "\nLocation:"
print " Latitude: ", gc.latitude()
print " Longitude: ", gc.longitude()
print "\nSingle-line Address:"
print " ", gc.formatted_address(), "\n"
gc.image()
Ouput:
python geocode.py
Enter Address, Location or Postcode: SW1A 1AA
Address:
London SW1A 1AA,
UK
Location:
latitude: 51.501009
longitude: -0.1415876
Single-line Address:
London SW1A 1AA, UK
0 0 51.5014095689,-0.143875696751
0 1 51.5002073959,-0.143875696751
1 0 51.5014095689,-0.141585090252
1 1 51.5002073959,-0.141585090252
2 0 51.5014095689,-0.139294483753
2 1 51.5002073959,-0.139294483753
Image:

