martes, 28 de julio de 2015

¿Dónde poder tomar algo en estos días de verano?


En estos días tan calurosos, es bueno aprovechar las tardes y noches para salir a tomar algo o comer alguna tapa por las diferentes zonas que tiene Madrid. Es por ello que en ocasiones nos preguntamos, en qué barrio hay mayor posibilidad de encontrar algo abierto para dicho fin.

Bien, el post de hoy, gracias a nuestra API nos ayudará a encontrar la mayor concentración de locales de una categoría dada, en este caso bares y restaurantes, en un barrio determinado y posteriormente visualizarlo. Cabe destacar, al igual que en antiguos post, lo primero que necesitáis es solicitar vuestra api_key para poder replicar lo que estamos haciendo aquí. ¡Empecemos!

Suponiendo que ya tenemos nuestra api_key, lo primero es buscar en el portal de desarrollador la llamada que nos permite buscar todos los barrios de Madrid: 


Petición a la API que muestra todos los barrios de Madrid

En segundo lugar, debemos obtener los datos representativos que necesitamos (label y representación geográfica) y para ello utilizaremos la opción _view=coordenadas. Además, usaremos la extensión .geojson para mostrarla en Google Maps y CartoDB, como ya hemos descrito en algunos posts anteriores.




Guardaremos toda esta información en un recurso o zona donde podremos actualizarla posteriormente con el campo que nos falta. Puede ser un CSV, el propio GeoJSON con la suma de la información de todos los barrios o la programación de una variable que en memoria aloje la información en nuestro lenguaje de programación preferido.

A continuación, tenemos un ejemplo en el lenguaje de programación Python para este propósito:

# Importar librerías necesarias

import requests
import json
import time

# Establecer API_KEY para Localidata
api_key = 'TU_API_KEY'

# Crear una estructura de datos compatible con GeoJSON


geojson_result_barrio = {
    'features': [],
    'type': 'FeatureCollection'
}

# Código que realiza las llamadas y suma los datos de r en geojson_result_barrio.

length_barrios = [0, 1, 2]
for i in length_barrios:
     r = requests.get(b + '?_sort=label&_view=coordenadas&_page=' + str(i) + '&_pageSize=50&api_key=' + api_key)
     r = r.json().get('features')
     geojson_result_barrio['features'] += r

Por último, necesitaremos filtrar los locales comerciales que se encuentran en un barrio determinado y tienen en común la misma categoría:


donde:
  • <CodDistrito> y <CodBarrio> nos delimita el barrio dónde buscar..
  • <CodCNAE> será el código de la categoría a buscar, en este ejemplo utilizaremos el código 56 que según la lista de códigos CNAE corresponde a “Servicios de comidas y bebidas”.

Por ejemplo, para el barrio de Abrantes, la URL que pondríamos en nuestro navegador sería:

http://datos.localidata.com/recurso/comercio/Provincia/Madrid/Municipio/madrid/Local/CNAE/Division/56/Distrito/11/Barrio/7?api_key=TU_API_KEY

Petición a la API que muestra bares y restaurantes en Abrantes
 
En este caso, no es necesaria la vista coordenadas, ya que no vamos a dibujar los locales comerciales, ni tampoco es necesario ceñirnos a un formato concreto, aunque es recomendable utilizar algún formato fácil de parsear. Solamente necesitamos contabilizar el número de elementos que se nos muestra por pantalla y enlazarlo con el barrio en cuestión. Por tanto utilizaremos la opción _pageSize para conseguir 50 elementos en cada petición y la _view simple.

A continuación podemos ver cómo introducir dicho dato en nuestra variable geojson_result_barrio que teníamos previamente en el ejemplo de Python e imprimirlo en un fichero con la extensión geojson para nuestro posterior uso:


# Función sencilla para conseguir el número de elementos de una uri concreta


def get_number(uri):                             # Le pasamos como parámetro la uri a resolver
     cont = 0                                           # Contador global de elementos
     page = 0                                          # Página que estamos contabilizando
     opt_uri = '?_sort=label&_view=simple&_page=' + str(page) + '&_pageSize=50'
     r_amp = requests.get(uri + '.json' + opt_uri + '&api_key=' + api_key).json().get('result')
     cont += len(r_amp.get('items'))         # Sumar contador
     while len(r_amp.get('items')):           # Iterador para todas las páginas restantes
           page += 1
           opt_uri = '?_sort=label&_view=simple&_page=' + str(page) + '&_pageSize=50'
           r_amp = requests.get(uri + '.json' + opt_uri + '&api_key=' + api_key).json().get('result')
           cont += len(r_amp.get('items'))
     return cont                                        # Devolver contador global de elementos


# Código para conseguir los elementos de la categoria CNAE dada en todos los barrios


pos = 0                                                        # Barrio a buscar en la estructura de datos de Barrios
for i in geojson_result_barrio['features']:      # Iterador para todos los barrios
     uri = i.get('properties').get('_about')        # Conseguir la URI del barrio
     uri = uri.replace(                                    # Generar nueva URI para filtrado por CNAE
           "http://datos.localidata.com/recurso/territorio/Provincia/Madrid/Municipio/madrid/",
           "http://datos.localidata.com/recurso/comercio/Provincia/Madrid/Municipio/madrid/Local/CNAE/Division/56/"
     )
     n = get_number(uri)                               # Conseguir elementos para la nueva URI generada
     geojson_result_barrio['features'][pos]['properties']['numberData'] = n       # Guardar resultado
     pos += 1                                                 # Siguiente barrio a revisar


with open('barrios_number.geojson', 'w') as data_w_file:       # Abrir fichero en modo escritura
     json.dump(geojson_result_barrio, data_w_file)                # Escribir datos en fichero


Al final obtendremos un fichero con una gran cantidad de datos (barrio y el número que nos interesa).

Desde este momento podemos usarlo en nuestra herramienta de visualización preferida, para este ejemplo se ha usado CartoDB que importando el fichero generará una tabla y el mapa correspondiente de forma correcta sin modificación alguna por nuestra parte.

Aun así, solo nos interesaba para el ejemplo, la etiqueta o nombre del barrio, el número de locales totales que hay sin categorizar y el número que hemos sacado de las peticiones anteriores, por tanto hemos eliminado todas las columnas restantes (eran unas pocas) y este ha sido el resultado:

Vista Tabla en CartoDB al importar el fichero GeoJSON creado

Finalmente, en las opciones del mapa hemos elegido la opción de cloropeta (cloropeth) con el filtrado por la columna numberData para que así veamos la diferencia entre un barrio y otro de forma colorida, además de un cuadro de texto con los datos del ranking introducidos a mano para no perder más tiempo en la programación del mapa.

Vista Mapa en CartoDB al usar cloropeta con filtro sobre numberData

Las posibilidades como vemos son infinitas y en aproximadamente una o dos horas podemos tener una bonita visualización, ya sea con variedad en el filtrado (en vez de barrios, distritos o zonas determinadas en un bounding box) o en datos (otras categorías, unión de varias, locales de una franquicia en cuestión, etc).

Link de la visualización conseguida: 


Parece ser que el centro y algunas zonas, no son mal plan donde poder tomar algo :)