Generando mapas estáticos con Google Map y Python

Posted by in Python

La entrada de hoy está relacionada con la resolución de un pequeño problema que me ha consultado un lector de este blog, y comparto la solución, que ha supuesto realizar un pequeño script de Python, utilizando Google Maps, para conseguir imágenes con mapas estáticos. El objetivo es utilizar estos mapas estáticos en unos informes, y qué mejor que acelerar y automatizar los mapas de ubicación de puntos. La alternativa es hacerlos en ArcGIS, previo cambio de sistema de coordenadas, localización del fondo del mapa, ….

El problema

Se dispone de una relación de puntos con su longitud y latitud a los que se ha dado un nombre, y se desea realizar un mapa de localización de cada punto. Para ello, una alternativa es utilizar Google Maps, con la opción de mapas estaticos. La solución aquí presentada es sólo para un punto, que introduciremos de forma manual, pero una vez que se conoce la estructura, el resto será sencillo: cargar la relación de puntos y acomodarlos a la estructura requerida.

El motivo de explicar este problema es porque muchas veces necesitamos informes dónde es muy interesante mostrar información geográfica de una localización, y para un sólo punto, pues vale, trabajas un poco con la URL y lo tienes, pero cuando necesitas automatizar el proyecto, nada mejor que unas líneas de Python.

Dividiremos la solución del problema en 3 partes: preparación de la URL, descarga de la URL, guardar la imágen en un archivo gráfico.

1.- Preparación de la URL

Quizás, esta parte es la más complicada, pues hay que cumplir con las reglas de Google Maps, siguiendo su documentación. Leéla bien y verás cómo no hace falta ni Javascript siquiera.

En la URL que tenemos que preparar hay varias cosas que configurar:

  • center, con la longitud y latitud a representar
  • zoom, que es el nivel de zoom que va desde 1 (más general) hasta 20 (más concreto).
  • size, que es el tamaño de la imagen que queremos. Por ejemplo, 400×400, aunque puedes poner lo que necesites.
  • maptype, es el tipo de mapa que quieres mostrar, y tienes varios: hybrid, sensor, satellite, …
  • format, es otro parámetro opcional para especificar el tipo de formato de imagen. Por defecto es png, pero puedes cambiar a jpg.
  • markers, es para poner marcadores en tu imagen. Es opcional, pero puedes poner varios. la sintaxis es indicar el color, la etiqueta y la posición.

Aunque para resolver esta cuestión no me ha hecho falta, aquí te dejo una función (la idea original es de aquí) para crear urls de forma más versátil:


def get_static_google_map(filename_wo_extension, center=None, zoom=None, imgsize="500x500", imgformat="jpeg",
maptype="roadmap", markers=None ):
"""retrieve a map (image) from the static google maps server

See: http://code.google.com/apis/maps/documentation/staticmaps/

Creates a url2 string with a URL like this:
http://maps.google.com/maps/api/staticmap?center=Brooklyn+Bridge,New+York,NY&zoom=14&size=512x512&maptype=roadmap
&markers=color:blue|label:S|40.702147,-74.015794&sensor=false"""

# assemble the URL
url2  =  "http://maps.google.com/maps/api/staticmap?" # base URL, append query params, separated by &

# if center and zoom  are not given, the map will show all marker locations
if center != None:
url2 += "center=%s&" % center
#url2 += "center=%s&" % "40.714728, -73.998672"   # latitude and longitude (up to 6-digits)
#url2 += "center=%s&" % "50011" # could also be a zipcode,
#url2 += "center=%s&" % "Brooklyn+Bridge,New+York,NY"  # or a search term
if center != None:
url2 += "zoom=%i&" % zoom  # zoom 0 (all of the world scale ) to 22 (single buildings scale)

url2 += "size=%ix%i&" % (imgsize)  # tuple of ints, up to 640 by 640
url2 += "format=%s&" % imgformat
url2 += "maptype=%s&" % maptype  # roadmap, satellite, hybrid, terrain

# add markers (location and style)
if markers != None:
for marker in markers:
url2 += "%s&" % marker

#url2 += "mobile=false&"  # optional: mobile=true will assume the image is shown on a small screen (mobile device)
url2 += "sensor=false&"   # must be given, deals with getting loction from mobile device
return url2

Por ejemplo, vamos a crear una URL que puedes ver aquí, enlazando a mi ciudad Córdoba.

Mapa estático desde Google Maps

La ruta exacta es esta: http://maps.google.com/maps/api/staticmap?center=37.8654938,-4.7791247&zoom=14&size=512×512&maptype=roadmap&markers=color:blue|label:M|37.8654938,-4.7791247&sensor=false.

Para nuestra solución, creamos una función que recibe el dato a procesar y genera la URL:


tmp_url = "https://maps.googleapis.com/maps/api/staticmap?center={lat},{lon}&zoom=17&size=400x400&maptype=satellite&markers=color:green|label:|{lat},{lon}"

def crea_url(datos):
return tmp_url.format(**datos)

Estructura de datos

Para este ejercicio, los datos deben acomodarse a una estructura diccionario con los campos: lon, lat y nombre.

2.- Descarga de URL

Esta es la parte fácil, pues ya vimos anteriormente cómo descargar código HTML en Python (y también en C#). Aquí vamos a utilizar request, que es más sencillo que urllib2. Además, en caso de que necesites configurar un proxy, sólo tienes que completar la información.


import requests

proxy = "127.0.0.1:8080"
proxies = {"http": proxy, "https": proxy}
sesion = requests.Session()
sesion.proxies = proxies

Si nos vas a usar proxy, entonces proxies = { }. De esta forma, ya tenemos preparado para descargar URLs.

3.- Grabando la imágen a un fichero

El tercer y último paso es guardar los datos recibidos por la petición y guardarlos en un fichero de imagen.


def save_imagen(datos):
url = crea_url(datos)
r = sesion.get(url)
f=open('%s.png' % datos["nombre"],'wb')
f.write(r.content)
f.close()

El código completo lo teneis en GitHub. No obstante, está a tu disposición para que lo ajustes a lo que tú necesites.


# coding:utf-8
from __future__ import print_function
from __future__ import division

__UPDATED__ = '2015.06.22'
__AUTHOR__ = 'David Trillo'
__WEBSITE__ = 'http://www.manejandodatos.es'
__VERSION__ = "1.0.0"

import requests

# URLs antiguas
#
 url = 
"https://maps.googleapis.com/maps/api/staticmap?center=-38.25466,-4.971062&zoom=13&size=600x300&maptype=roadmap&markers=color:blue|label:S|40.702147,-74.015794&markers=color:green|label:G|40.711614,-74.012318&markers=color:red|label:C|40.718217,-73.998284"
tmp_url
 = 
"https://maps.googleapis.com/maps/api/staticmap?center={lat},{lon}&zoom=17&size=400x400&maptype=satellite&markers=color:green|label:|{lat},{lon}"

def crea_url(datos):
    return tmp_url.format(**datos)

def save_imagen(datos):
    url = crea_url(datos)
    r = sesion.get(url)
    f=open('%s.png' % datos["nombre"],'wb')
    f.write(r.content)
    f.close()

proxy = "10.238.8.23:8080"
proxies = {"http": proxy, "https": proxy}
sesion = requests.Session()
sesion.proxies = proxies

# Aqui se modifican los datos
datos = {"lat": 37.8654938, "lon": -4.7791247, "nombre": "gm2img"}

save_imagen(datos)

Aquí tienes lo que ocurre al ejecutarlo, que se crea el fichero en el mismo lugar donde está el script.

Fichero imagen creado

Fichero imagen creado

Mi lector se ha quedado super satisfecho con el resultado, así que espero que a tí también te haya resultado interesante.

Happy coding.

Google+ Comments - Comentarios Google+