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: