Created
February 4, 2018 19:54
-
-
Save hhl60492/120362483890db9df622020eaea7c92e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import math | |
import requests | |
import json | |
import os | |
from .color_dicts import mpl_color_map, html_color_codes | |
def safe_iter(var): | |
try: | |
return iter(var) | |
except TypeError: | |
return [var] | |
class GoogleMapPlotter(object): | |
def __init__(self, center_lat, center_lng, zoom, apikey=''): | |
self.center = (float(center_lat), float(center_lng)) | |
self.zoom = int(zoom) | |
self.apikey = str(apikey) | |
self.grids = None | |
self.paths = [] | |
self.shapes = [] | |
self.points = [] | |
self.heatmap_points = [] | |
self.radpoints = [] | |
self.gridsetting = None | |
self.coloricon = os.path.join(os.path.dirname(__file__), 'markers\\%s.png') | |
self.color_dict = mpl_color_map | |
self.html_color_codes = html_color_codes | |
@classmethod | |
def from_geocode(cls, location_string, zoom=13): | |
lat, lng = cls.geocode(location_string) | |
return cls(lat, lng, zoom) | |
@classmethod | |
def geocode(self, location_string): | |
geocode = requests.get( | |
'http://maps.googleapis.com/maps/api/geocode/json?address="%s"' % location_string) | |
geocode = json.loads(geocode.text) | |
latlng_dict = geocode['results'][0]['geometry']['location'] | |
return latlng_dict['lat'], latlng_dict['lng'] | |
def grid(self, slat, elat, latin, slng, elng, lngin): | |
self.gridsetting = [slat, elat, latin, slng, elng, lngin] | |
def marker(self, lat, lng, color='#FF0000', c=None, title="no implementation"): | |
if c: | |
color = c | |
color = self.color_dict.get(color, color) | |
color = self.html_color_codes.get(color, color) | |
self.points.append((lat, lng, color[1:], title)) | |
def scatter(self, lats, lngs, color=None, size=None, marker=True, c=None, s=None, **kwargs): | |
color = color or c | |
size = size or s or 40 | |
kwargs["color"] = color | |
kwargs["size"] = size | |
settings = self._process_kwargs(kwargs) | |
for lat, lng in zip(lats, lngs): | |
if marker: | |
self.marker(lat, lng, settings['color']) | |
else: | |
self.circle(lat, lng, size, **settings) | |
def circle(self, lat, lng, radius, color=None, c=None, **kwargs): | |
color = color or c | |
kwargs.setdefault('face_alpha', 0.5) | |
kwargs.setdefault('face_color', "#000000") | |
kwargs.setdefault("color", color) | |
settings = self._process_kwargs(kwargs) | |
path = self.get_cycle(lat, lng, radius) | |
self.shapes.append((path, settings)) | |
def _process_kwargs(self, kwargs): | |
settings = dict() | |
settings["edge_color"] = kwargs.get("color", None) or \ | |
kwargs.get("edge_color", None) or \ | |
kwargs.get("ec", None) or \ | |
"#000000" | |
settings["edge_alpha"] = kwargs.get("alpha", None) or \ | |
kwargs.get("edge_alpha", None) or \ | |
kwargs.get("ea", None) or \ | |
1.0 | |
settings["edge_width"] = kwargs.get("edge_width", None) or \ | |
kwargs.get("ew", None) or \ | |
1.0 | |
settings["face_alpha"] = kwargs.get("alpha", None) or \ | |
kwargs.get("face_alpha", None) or \ | |
kwargs.get("fa", None) or \ | |
0.3 | |
settings["face_color"] = kwargs.get("color", None) or \ | |
kwargs.get("face_color", None) or \ | |
kwargs.get("fc", None) or \ | |
"#000000" | |
settings["color"] = kwargs.get("color", None) or \ | |
kwargs.get("c", None) or \ | |
settings["edge_color"] or \ | |
settings["face_color"] | |
# Need to replace "plum" with "#DDA0DD" and "c" with "#00FFFF" (cyan). | |
for key, color in settings.items(): | |
if 'color' in key: | |
color = self.color_dict.get(color, color) | |
color = self.html_color_codes.get(color, color) | |
settings[key] = color | |
settings["closed"] = kwargs.get("closed", None) | |
return settings | |
def plot(self, lats, lngs, color=None, c=None, **kwargs): | |
color = color or c | |
kwargs.setdefault("color", color) | |
settings = self._process_kwargs(kwargs) | |
path = zip(lats, lngs) | |
self.paths.append((path, settings)) | |
def heatmap(self, lats, lngs, threshold=10, radius=10, gradient=None, opacity=0.6, dissipating=True): | |
""" | |
:param lats: list of latitudes | |
:param lngs: list of longitudes | |
:param threshold: | |
:param radius: The hardest param. Example (string): | |
:return: | |
""" | |
settings = {} | |
settings['threshold'] = threshold | |
settings['radius'] = radius | |
settings['gradient'] = gradient | |
settings['opacity'] = opacity | |
settings['dissipating'] = dissipating | |
settings = self._process_heatmap_kwargs(settings) | |
heatmap_points = [] | |
for lat, lng in zip(lats, lngs): | |
heatmap_points.append((lat, lng)) | |
self.heatmap_points.append((heatmap_points, settings)) | |
def _process_heatmap_kwargs(self, settings_dict): | |
settings_string = '' | |
settings_string += "heatmap.set('threshold', %d);\n" % settings_dict['threshold'] | |
settings_string += "heatmap.set('radius', %d);\n" % settings_dict['radius'] | |
settings_string += "heatmap.set('opacity', %f);\n" % settings_dict['opacity'] | |
dissipation_string = 'true' if settings_dict['dissipating'] else 'false' | |
settings_string += "heatmap.set('dissipating', %s);\n" % (dissipation_string) | |
gradient = settings_dict['gradient'] | |
if gradient: | |
gradient_string = "var gradient = [\n" | |
for r, g, b, a in gradient: | |
gradient_string += "\t" + "'rgba(%d, %d, %d, %d)',\n" % (r, g, b, a) | |
gradient_string += '];' + '\n' | |
gradient_string += "heatmap.set('gradient', gradient);\n" | |
settings_string += gradient_string | |
return settings_string | |
def polygon(self, lats, lngs, color=None, c=None, **kwargs): | |
color = color or c | |
kwargs.setdefault("color", color) | |
settings = self._process_kwargs(kwargs) | |
shape = zip(lats, lngs) | |
self.shapes.append((shape, settings)) | |
# create the html file which include one google map and all points and | |
# paths | |
def draw(self, htmlfile): | |
f = open(htmlfile, 'w') | |
f.write('<html>\n') | |
f.write('<head>\n') | |
f.write( | |
'<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />\n') | |
f.write( | |
'<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>\n') | |
f.write('<title>Google Maps - pygmaps </title>\n') | |
if self.apikey: | |
f.write('<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=visualization&sensor=true_or_false&key=%s"></script>\n' % self.apikey ) | |
else: | |
f.write('<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=visualization&sensor=true_or_false"></script>\n' ) | |
f.write('<script type="text/javascript">\n') | |
f.write('\tfunction initialize() {\n') | |
self.write_map(f) | |
self.write_grids(f) | |
self.write_points(f) | |
self.write_paths(f) | |
self.write_shapes(f) | |
self.write_heatmap(f) | |
f.write('\t}\n') | |
f.write('</script>\n') | |
f.write('</head>\n') | |
f.write( | |
'<body style="margin:0px; padding:0px;" onload="initialize()">\n') | |
f.write( | |
'\t<div id="map_canvas" style="width: 100%; height: 100%;"></div>\n') | |
f.write('</body>\n') | |
f.write('</html>\n') | |
f.close() | |
############################################# | |
# # # # # # Low level Map Drawing # # # # # # | |
############################################# | |
def write_grids(self, f): | |
if self.gridsetting is None: | |
return | |
slat = self.gridsetting[0] | |
elat = self.gridsetting[1] | |
latin = self.gridsetting[2] | |
slng = self.gridsetting[3] | |
elng = self.gridsetting[4] | |
lngin = self.gridsetting[5] | |
self.grids = [] | |
r = [ | |
slat + float(x) * latin for x in range(0, int((elat - slat) / latin))] | |
for lat in r: | |
self.grids.append( | |
[(lat + latin / 2.0, slng + lngin / 2.0), (lat + latin / 2.0, elng + lngin / 2.0)]) | |
r = [ | |
slng + float(x) * lngin for x in range(0, int((elng - slng) / lngin))] | |
for lng in r: | |
self.grids.append( | |
[(slat + latin / 2.0, lng + lngin / 2.0), (elat + latin / 2.0, lng + lngin / 2.0)]) | |
for line in self.grids: | |
settings = self._process_kwargs({"color": "#000000"}) | |
self.write_polyline(f, line, settings) | |
def write_points(self, f): | |
for point in self.points: | |
self.write_point(f, point[0], point[1], point[2], point[3]) | |
def get_cycle(self, lat, lng, rad): | |
# unit of radius: meter | |
cycle = [] | |
d = (rad / 1000.0) / 6378.8 | |
lat1 = (math.pi / 180.0) * lat | |
lng1 = (math.pi / 180.0) * lng | |
r = [x * 10 for x in range(36)] | |
for a in r: | |
tc = (math.pi / 180.0) * a | |
y = math.asin( | |
math.sin(lat1) * math.cos(d) + math.cos(lat1) * math.sin(d) * math.cos(tc)) | |
dlng = math.atan2(math.sin( | |
tc) * math.sin(d) * math.cos(lat1), math.cos(d) - math.sin(lat1) * math.sin(y)) | |
x = ((lng1 - dlng + math.pi) % (2.0 * math.pi)) - math.pi | |
cycle.append( | |
(float(y * (180.0 / math.pi)), float(x * (180.0 / math.pi)))) | |
return cycle | |
def write_paths(self, f): | |
for path, settings in self.paths: | |
self.write_polyline(f, path, settings) | |
def write_shapes(self, f): | |
for shape, settings in self.shapes: | |
self.write_polygon(f, shape, settings) | |
# TODO: Add support for mapTypeId: google.maps.MapTypeId.SATELLITE | |
def write_map(self, f): | |
f.write('\t\tvar centerlatlng = new google.maps.LatLng(%f, %f);\n' % | |
(self.center[0], self.center[1])) | |
f.write('\t\tvar myOptions = {\n') | |
f.write('\t\t\tzoom: %d,\n' % (self.zoom)) | |
f.write('\t\t\tcenter: centerlatlng,\n') | |
f.write('\t\t\tmapTypeId: google.maps.MapTypeId.ROADMAP\n') | |
f.write('\t\t};\n') | |
f.write( | |
'\t\tvar map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);\n') | |
f.write('\n') | |
def write_point(self, f, lat, lon, color, title): | |
f.write('\t\tvar latlng = new google.maps.LatLng(%f, %f);\n' % | |
(lat, lon)) | |
#f.write('\t\tvar img = new google.maps.MarkerImage(\'%s\');\n' % | |
#(self.coloricon % color)) | |
f.write('\t\tvar marker = new google.maps.Marker({\n') | |
f.write('\t\tlabel: "%s",\n' % title) | |
#f.write('\t\ticon: img,\n') | |
f.write('\t\tsize: new google.maps.Size(20,20),\n') | |
f.write('\t\tposition: latlng\n') | |
f.write('\t\t});\n') | |
f.write('\t\tmarker.setMap(map);\n') | |
f.write('\n') | |
def write_polyline(self, f, path, settings): | |
clickable = False | |
geodesic = True | |
strokeColor = settings.get('color') or settings.get('edge_color') | |
strokeOpacity = settings.get('edge_alpha') | |
strokeWeight = settings.get('edge_width') | |
f.write('var PolylineCoordinates = [\n') | |
for coordinate in path: | |
f.write('new google.maps.LatLng(%f, %f),\n' % | |
(coordinate[0], coordinate[1])) | |
f.write('];\n') | |
f.write('\n') | |
f.write('var Path = new google.maps.Polyline({\n') | |
f.write('clickable: %s,\n' % (str(clickable).lower())) | |
f.write('geodesic: %s,\n' % (str(geodesic).lower())) | |
f.write('path: PolylineCoordinates,\n') | |
f.write('strokeColor: "%s",\n' % (strokeColor)) | |
f.write('strokeOpacity: %f,\n' % (strokeOpacity)) | |
f.write('strokeWeight: %d\n' % (strokeWeight)) | |
f.write('});\n') | |
f.write('\n') | |
f.write('Path.setMap(map);\n') | |
f.write('\n\n') | |
def write_polygon(self, f, path, settings): | |
clickable = False | |
geodesic = True | |
strokeColor = settings.get('edge_color') or settings.get('color') | |
strokeOpacity = settings.get('edge_alpha') | |
strokeWeight = settings.get('edge_width') | |
fillColor = settings.get('face_color') or settings.get('color') | |
fillOpacity= settings.get('face_alpha') | |
f.write('var coords = [\n') | |
for coordinate in path: | |
f.write('new google.maps.LatLng(%f, %f),\n' % | |
(coordinate[0], coordinate[1])) | |
f.write('];\n') | |
f.write('\n') | |
f.write('var polygon = new google.maps.Polygon({\n') | |
f.write('clickable: %s,\n' % (str(clickable).lower())) | |
f.write('geodesic: %s,\n' % (str(geodesic).lower())) | |
f.write('fillColor: "%s",\n' % (fillColor)) | |
f.write('fillOpacity: %f,\n' % (fillOpacity)) | |
f.write('paths: coords,\n') | |
f.write('strokeColor: "%s",\n' % (strokeColor)) | |
f.write('strokeOpacity: %f,\n' % (strokeOpacity)) | |
f.write('strokeWeight: %d\n' % (strokeWeight)) | |
f.write('});\n') | |
f.write('\n') | |
f.write('polygon.setMap(map);\n') | |
f.write('\n\n') | |
def write_heatmap(self, f): | |
for heatmap_points, settings_string in self.heatmap_points: | |
f.write('var heatmap_points = [\n') | |
for heatmap_lat, heatmap_lng in heatmap_points: | |
f.write('new google.maps.LatLng(%f, %f),\n' % | |
(heatmap_lat, heatmap_lng)) | |
f.write('];\n') | |
f.write('\n') | |
f.write('var pointArray = new google.maps.MVCArray(heatmap_points);' + '\n') | |
f.write('var heatmap;' + '\n') | |
f.write('heatmap = new google.maps.visualization.HeatmapLayer({' + '\n') | |
f.write('\n') | |
f.write('data: pointArray' + '\n') | |
f.write('});' + '\n') | |
f.write('heatmap.setMap(map);' + '\n') | |
f.write(settings_string) | |
if __name__ == "__main__": | |
mymap = GoogleMapPlotter(37.428, -122.145, 16) | |
# mymap = GoogleMapPlotter.from_geocode("Stanford University") | |
mymap.grid(37.42, 37.43, 0.001, -122.15, -122.14, 0.001) | |
mymap.marker(37.427, -122.145, "yellow") | |
mymap.marker(37.428, -122.146, "cornflowerblue") | |
mymap.marker(37.429, -122.144, "k") | |
lat, lng = mymap.geocode("Stanford University") | |
mymap.marker(lat, lng, "red") | |
mymap.circle(37.429, -122.145, 100, "#FF0000", ew=2) | |
path = [(37.429, 37.428, 37.427, 37.427, 37.427), | |
(-122.145, -122.145, -122.145, -122.146, -122.146)] | |
path2 = [[i+.01 for i in path[0]], [i+.02 for i in path[1]]] | |
path3 = [(37.433302 , 37.431257 , 37.427644 , 37.430303), (-122.14488, -122.133121, -122.137799, -122.148743)] | |
path4 = [(37.423074, 37.422700, 37.422410, 37.422188, 37.422274, 37.422495, 37.422962, 37.423552, 37.424387, 37.425920, 37.425937), | |
(-122.150288, -122.149794, -122.148936, -122.148142, -122.146747, -122.14561, -122.144773, -122.143936, -122.142992, -122.147863, -122.145953)] | |
mymap.plot(path[0], path[1], "plum", edge_width=10) | |
mymap.plot(path2[0], path2[1], "red") | |
mymap.polygon(path3[0], path3[1], edge_color="cyan", edge_width=5, face_color="blue", face_alpha=0.1) | |
mymap.heatmap(path4[0], path4[1], threshold=10, radius=40) | |
mymap.heatmap(path3[0], path3[1], threshold=10, radius=40, dissipating=False, gradient=[(30,30,30,0), (30,30,30,1), (50, 50, 50, 1)]) | |
mymap.scatter(path4[0], path4[1], c='r', marker=True) | |
mymap.scatter(path4[0], path4[1], s=90, marker=False, alpha=0.1) | |
# Get more points with: | |
# http://www.findlatitudeandlongitude.com/click-lat-lng-list/ | |
scatter_path = ([37.424435, 37.424417, 37.424417, 37.424554, 37.424775, 37.425099, 37.425235, 37.425082, 37.424656, 37.423957, 37.422952, 37.421759, 37.420447, 37.419135, 37.417822, 37.417209], | |
[-122.142048, -122.141275, -122.140503, -122.139688, -122.138872, -122.138078, -122.137241, -122.136405, -122.135568, -122.134731, -122.133894, -122.133057, -122.13222, -122.131383, -122.130557, -122.129999]) | |
mymap.scatter(scatter_path[0], scatter_path[1], c='r', marker=True) | |
mymap.draw('./mymap.html') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment