lunes, 17 de julio de 2017

Cómo actualizar recursos de CKAN a través de Pentaho Data Integration



Hace unos días Esther(@eminguelac)  encontró un plugin para Pentaho (Kettle) que permitia escribir directamente en el Datastore de CKAN (https://github.com/OpenGov-OpenData/CKAN-DataStore-Writer-for-Pentaho-Data-Integration). Esta funcionalidad no se ajustaba a nuestras necesidades y hemos decidido modificarlo un poco y compartirlo con la comunidad.

Nuestra idea es conseguir que el nuevo plugin actualice el recurso de un Dataset en CKAN a partir de los datos de entrada que recibe.

 El repositorio con el plugin y el código se encuentra en esta URL: https://github.com/localidata/CKAN-Resource-Updater-for-Pentaho-Data-Integration

La instalación es muy sencilla, sólo hay que copiar al directorio "../data-integration/plugins/steps" la carpeta "ckan-updater-plugin". Si el subdirectorio "steps" no existe, hay que crearlo. Después reiniciamos Pentaho y si al hacer un Trabajo ("Job") buscamos en Pasos ("Steps") la palabra "resource", nuestro componente debe aparecer.


Vamos a hacer una prueba completa para crear un recurso y actualizarlo en un portal de demos de CKAN.

Me he dado de alta en http://demo.ckan.org:

En la página de mi perfil he obtenido mi API-KEY:

Ahora dentro del portal he creado el dataset "Pentaho Upload Test": https://demo.ckan.org/dataset/pentaho-upload-test

Ya tenemos todo lo que necesitamos para hacer la primera prueba: creación de recurso.

Nos vamos a Pentaho y utilizamos los pasos: "Data Grid", nuestro "CKAN Resource Upload" y los unimos.



Después de conectarlos, añadimos en el Data Grid un tabla con algunos datos.

Ahora configuramos el CKAN Resource Upload:



Configuramos el dominio, nuestra API KEY, el ID de nuestro dataset en Package ID, el título del recurso y su descripción. No escribimos nada en Resource ID para que cree el recurso.

Ejecutamos y veremos cómo aparece el recurso Gastos en nuestro Dataset:

Además vemos que el Datapusher ha hecho su trabajo y ha añadido el contenido en el Datastore.

Si ahora repetimos la prueba utilizando el Idenficador del recurso que se ha creado escribiendolo en Resource ID:

Y añadimos un registro más en el Data Grid:



Volvemos a lanzar el proceso:



Y vemos que se actualiza el recurso.




Esperamos que el componente os sea de utilidad. Si tenéis algun problema no dudeis en escribirnos una issue en Github: https://github.com/localidata/CKAN-Resource-Updater-for-Pentaho-Data-Integration

jueves, 13 de julio de 2017

martes, 4 de julio de 2017

Localidata crece

Esta semana Carlos Martinez de la Casa se ha incorporado a Localidata.

En esta foto nos podéis ver a los dos en el evento de APIs de Red Hat de hoy.



miércoles, 13 de julio de 2016

Another choice for CKAN Maps instead of Mapquest

This week the visualization of maps inside of CKAN has been broken.

The default provider of layers (MapQuest) has changed its policy, and we haven't much time to react.

This is an example of map with the change:


To solve this, we need to change the default layer provider in the CKAN configuration file (geoview and spatial plugins) and in the default viewer (reclineView plugin).

We have choose http://www.thunderforest.com/. Specifically this visualization: http://www.thunderforest.com/maps/neighbourhood/

These are the steps to follow to do this change:

a) CKAN Configuration

In CKAN configuration file we must add these lines after the entry ckan.plugins:

ckanext.spatial.common_map.type = custom
ckanext.spatial.common_map.custom.url = http://tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png
ckanext.spatial.common_map.attribution = Maps &copy; <ahref="http://www.thunderforest.com">Thunderforest</a>, Data &copy; <aa href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>

b) Default viewer

Edit the file recline.js, which is stored in the path:

/usr/lib/ckan/default/src/ckan/ckanext/reclineview/theme/public/vendor/recline/recline.js is CKAN 2.5

o

/usr/lib/ckan/default/src/ckan/ckanext/reclinepreview/theme/public/vendor/recline/recline.js in CKAN 2.2

In this file there are two variables with this values:

var mapUrl = "//otile{s}-s.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png";   
var osmAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Tiles Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> <img src="//developer.mapquest.com/content/osm/mq_logo.png">';

We must change the two values for these:

mapUrl = "//tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png";
osmAttribution = 'Maps &copy; <a href="http://www.thunderforest.com">Thunderforest</a>, Data &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>';

c) Restart Apache2 and Nginx

With that steps the visualization of maps will be fine again.



We hope this information helps you.

Alternativa a MapQuest en CKAN

Esta semana los mapas de CKAN han dejado de visualizarse.

El proveedor por defecto de las capas (MapQuest) ha cambiado su política de repente y nos ha dejado poco tiempo para reaccionar.

Éste es el aspecto que tienen los mapas con el cambio:


Para solucionar esto, tenemos que cambiar de proveedor de capas en la Configuración de CKAN (para los plugins geoview y spatial) y en la visualización por defecto (para el plugin reclineView).

Nosotros nos hemos cambiado a http://www.thunderforest.com/. Concretamente a esta visualización: http://www.thunderforest.com/maps/neighbourhood/

Éstos son los pasos que hay que seguir:

a) Configuración de CKAN

En el fichero de configuración de CKAN añadimos estas lineas justo debajo de la entrada ckan.plugins:

ckanext.spatial.common_map.type = custom
ckanext.spatial.common_map.custom.url = http://tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png
ckanext.spatial.common_map.attribution = Maps &copy; <ahref="http://www.thunderforest.com">Thunderforest</a>, Data &copy; <aa href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>

b) Visualización por defecto

Editamos el fichero recline.js Que se encuentra en:

/usr/lib/ckan/default/src/ckan/ckanext/reclineview/theme/public/vendor/recline/recline.js en CKAN 2.5

o

/usr/lib/ckan/default/src/ckan/ckanext/reclinepreview/theme/public/vendor/recline/recline.js en CKAN 2.2

En este fichero se crean e inicializan estas variables:

var mapUrl = "//otile{s}-s.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.png";   
var osmAttribution = 'Map data &copy; 2011 OpenStreetMap contributors, Tiles Courtesy of <a href="http://www.mapquest.com/" target="_blank">MapQuest</a> <img src="//developer.mapquest.com/content/osm/mq_logo.png">';

Lo que tenemos que hacer es cambiar su valor por este otro:

mapUrl = "//tile.thunderforest.com/neighbourhood/{z}/{x}/{y}.png";
osmAttribution = 'Maps &copy; <a href="http://www.thunderforest.com">Thunderforest</a>, Data &copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap contributors</a>';

c) Reiniciamos Apache2 y Nginx

Con estos pasos todos los mapas volverán a visualizarse correctamente.



Esperamos que estos pasos os sirvan de ayuda.

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 :)
 
 

 

miércoles, 3 de junio de 2015

Job offer / Oferta de empleo


Actualización (28-07-2015): ya hemos cubierto esta plaza. Muchas gracias a tod@s por vuestro interés.

Update (28-07-2015): we´ve already covered this offer. Many thanks to everyone for your interest.




Puedes elegir el idioma que prefieras para leer esta oferta. Primero está en inglés y luego en castellano. / You can choose your favourite language to read this job offer: first in English and then in Spanish.



We are looking for data lovers to join our team at Localidata.

After a bit more than two years since we started operations, we are now expanding our team at Localidata. We are looking for two positions to fill in, but before telling you what they would consist of we would like to tell you first what it is about to work with us:
  • We like being a real team, and we want to continue being a team for as long as possible.
  • We enjoy working together, discussing about the problems that we need to solve for our customers, and filling the walls of our office with drawings as a result of these discussions.
  • We love when our customers say that they like how we work, and at least for the time being this is happening often. It is not about creating the perfect solutions that customers may not like, but making what they need in the best manner.
  • We aim at respecting as much as possible the working hours of our employees. Not because of working long hours the results will be better. If things are done well, there is no need to work more than what would be expected in any other job.  
Are you now convinced that you want to join us? If that is the case, then continue reading. Now we tell you which are the skills that we are looking for:

Swiss Knife 1 (sorry, were you looking for the usual “frontend developer”/“backend developer” or alike?): We are looking for a person who feels happy when opening in the morning Eclipse to do some Java programming and setting up in the afternoon a Linux virtual machine in Amazon, who loves collaborating with others using Git, who likes HTML5, CSS3, Bootstrap, JSON and JavaScript, a bit of Python, who can deploy reliable and scalable Web applications, no matter whether they are running on a Tomcat server, on Google App Engine, on top of MongoDB..., who will not kill himself of herself if told to build a SQL-based database, and...

Well, you can imagine that we may well be adding more and more frameworks and technologies here. But this is not the point. It doesn’t matter if you don’t know about all these things. What we want is somebody who is passionate about what he or she does and does not mind learning about technologies (and keeping us busy learning as well). And if you do not have much professional experience yet, don’t worry, you can apply as well.

Swiss Knife 2: We are looking for a person who feels happy when opening in the morning Eclipse to do some Java programming and setting up in the afternoon a Linux virtual machine in Amazon, who loves collaborating with others using Git, who likes HTML5, CSS3, Bootstrap, JSON and JavaScript, a bit of Python… Don’t you feel like a déjà vu? Yes, there is some copy and paste activity here, but this is because this is what we are looking for...

If you like any of these positions and you like the idea of working with us in Madrid, don’t forget to send us your CV to info@localidata.com. Obviously, it will be good if you tell us everything that you are able to do, but remember to include as well a bit of why you are motivated to work with us.

The Localidata team.

PS: And if you want us to answer even more quickly and interview you as soon as possible, you may always send us something like this (http://www.nina4airbnb.com/) with ideas about what we can do with our API or with any of the services that we are currently providing for our customers, as described in our Web. But don’t feel forced to do it, we also value your free time and you will have time to demonstrate what you can do.




Estamos buscando apasionados de los datos para unirse a nuestro equipo en Localidata.

Hace poco más de dos años desde que Localidata empezó a ofrecer servicios relacionados con los datos abiertos y ahora queremos que nuestro equipo crezca. Estamos buscando a dos nuevos compañeros, pero antes de decirte en qué consiste el trabajo, te vamos a decir lo que significa trabajar con nosotros:

  • Somos un equipo, nos gusta trabajar así e intentamos hacerlo todo el tiempo que podemos.
  • Nos gusta trabajar juntos, discutir de los problemas que tenemos que solucionar para nuestros clientes y pintar en las paredes de la oficina las conclusiones de nuestras reuniones.
  • Nos encanta que nuestros clientes digan que les gusta nuestra forma de trabajar, y de momento esto nos pasa bastante a menudo. No se trata de crear la solución perfecta, sino de adaptar la solución lo máximo posible a nuestros clientes, para que tengan lo que quieren y necesitan.
  • Respetamos todo lo que podemos nuestros horarios de trabajo. No por trabajar más horas los resultados van a ser mejores. 
¿Sigues queriendo trabajar con nosotros? Si es así, sigue leyendo. Ahora te decimos qué estamos buscando:
 

Todoterreno 1 (¿esperabas "técnico de sistemas", "programador senior" o "analista orgánico"?): estamos buscando a una persona a la que le guste empezar la mañana programando en Java con Eclipse y preparando una máquina virtual en Amazon después de comer, a la que le guste colaborar en proyectos con Git, a quien le guste HTML5, las mejoras de CSS3, que use Bootstrap, JSON y JavaScript, un poco de Python, que despliegue aplicaciones Web seguras y escalables, no importa si es con Tomcat, Google App Engine, que controle un poco de MongoDB..., que no tenga tendencias suicidas por tener que trabajar con una base de datos relacional, ...

Bueno, puedes imaginar que podemos añadir más y más frameworks y tecnologías. Pero no es el caso, no nos importa si no sabes de todo esto. Lo que queremos es alguien a quien le guste su trabajo y no le importe aprender cosas nuevas (y compartir los conocimientos con tus compañeros). Y aunque no tengas mucha experiencia, no te preocupes, no te descartaremos por eso.
 

Todoterreno 2: estamos buscando a una persona a la que le guste empezar la mañana programando en Java con Eclipse y preparando una máquina virtual en Amazon después de comer, a la que le guste colaborar en proyectos con Git, a quien le guste HTML5, las mejoras de CSS3, que use Bootstrap, JSON y Javascript, un poco de Python,… ¿Sientes algo así como un déjà vu? No, es que hemos copiado y pegado, así que ya sabes lo que estamos buscando…

Si te gusta el puesto de trabajo y quieres trabajar con nosotros en Madrid, mándanos tu CV a info@localidata.com. Estaría bien que nos dijeras todo lo que eres capaz de hacer, pero recuerda incluir también por qué estas motivado para trabajar con nosotros.

El equipo de Localidata.

PD: y si quieres que te contestemos lo antes posible para concertar una entrevista, puedes enviarnos algo como esto (http://www.nina4airbnb.com/) o ideas sobre lo que podemos hacer con nuestra API o con cualquiera de los servicios que actualmente estamos proporcionando a nuestros clientes, como explicamos en nuestra Web. No es obligatorio hacerlo, valoramos tu tiempo libre y tendrás tiempo para demostrar lo que sabes hacer.