OpenSource OpenData

Jorge Aguilera

Who I am?

Jorge Aguilera

https://jorge.aguilera.soy

@jagedn

Groovy developer

Speaker MadridGuG, Codemotion

Tutorial Asciidoctor (Amazon)

Agenda

Qué es (y qué no es) esta charla

  • Charla práctica, nada académica

  • Catálogo de datos abiertos de Madrid y otros

  • Aplicaciones OpenSource, NO comerciales

  • Tal vez sean "inspiradoras"

Buzzwords

  • html, csv, json, xls, kml

  • Groovy como lenguaje principal

  • Grails y Micronaut como frameworks

  • Gradle como herramienta construcción

  • Telegram, Gitlab Pipeline, Google AppEngine y Heroku como infraestructura

OpenSource - OpenData - OpenSource

Mi planteamiento:

  • usar OpenSource en la medida de lo posible

  • consumir OpenData

  • publicar OpenSource

Catálogos de datos abiertos

Cámaras trafico bot (Madrid,Barcelona,Granada)

Bot de Telegram que recibe peticiones de calles y devuelve la última imagen (png o gif animado )

Micronaut corriendo en capa gratuita Heroku

Cámaras trafico bot, proyecto

Parseo XML con Groovy

Namespace gml = new Namespace("http://www.opengis.net/gml", 'gml')
Namespace cite = new Namespace("http://www.opengeospatial.net/cite", 'cite')

String xml = barcelonaUrl.toURL().text
def kml = new XmlParser().parseText(xml)

kml[gml.featureMember].eachWithIndex{ f, idx->

   String nombre = f[cite.cameres][cite.carretera].text()
   camaras.add new Camara(ciudad: 'barcelona',
                    id: idx,
                    nombre: nombre,
                    url: f[cite.cameres][cite.link].text()
}

Spin-off Gif generator

Bot Fuentes públicas cercana

Bot de Telegram para ubicar la fuente pública más cercana a tu posición (Madrid, Barcelona, Caceres y Granada por ahora)

FuentesPublicasBot, proyecto

Micronaut corriendo en capa gratuita de Heroku

Parseo CSV con Groovy

String url = 'https://datos.madrid.es/egob/catalogo/300051-7-fuentes.csv'

url.toURL().text.split('\n').each{ String entry ->

    String[]fields = entry.split(';',-1)

    fuentes.add new mn.fuentes.bot.Fuente(
            calle: "${fields[3]}, ${fields[4]}",
            location: new Location(latitude: fields[-1] as float, longitude: fields[-2] as float)
    )
}

Localización

List<Fuente> sorted = fuentes.sort(false, { Fuente fuente->
    metersTo( userLocation, fuente.location )
}).take(2)

float metersTo(float lat1, float lng1, float lat2, float lng2) {
    double radioTierra = 6371;
    double dLat = Math.toRadians(lat2 - lat1);
    double dLng = Math.toRadians(lng2 - lng1);
    double sindLat = Math.sin(dLat / 2);
    double sindLng = Math.sin(dLng / 2);
    double va1 = Math.pow(sindLat, 2) + Math.pow(sindLng, 2) * Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
    double va2 = 2 * Math.atan2(Math.sqrt(va1), Math.sqrt(1 - va1));
    double meters = radioTierra * va2;
    meters as float;
}

Otros

Spin-off TelegramApi para Micronaut

(in progress)

@Client('https://api.telegram.org')
interface TelegramClient {

    @Post('/bot${telegram.token}/sendMessage')
    Single<Message> sendMessage(@Body Message message)

    @Post(value='/bot${telegram.token}/sendPhoto', produces = MediaType.MULTIPART_FORM_DATA)
    Single<Message> sendPhoto(@Body MultipartBody photo)

    @Post(value='/bot${telegram.token}/sendAnimation', produces = MediaType.MULTIPART_FORM_DATA)
    Single<Message> sendAnimation(@Body MultipartBody animation)

    @Get(value='/bot${telegram.token}/sendLocation')
    Single<Message> sendLocation(@QueryValue("chat_id") String chat_id,
                                 @QueryValue("latitude") float latitude,
                                 @QueryValue("longitude") float longitude)

}

Social Network: OpenDataMadrid

Mensaje diario a un canal de Telegram y a Twitter con los próximos eventos en Madrid

(por ahora carreras urbanas y actividades de bibliotecas)

OpenDataMadrid, proyecto

Usando el scheduler pipeline de Gitlab ejecutamos diariamente un build de Gradle que envía a Telegram y/o Twitter los eventos

Parseo Excel con Groovy

xlsx.bytes = 'https://datos.madrid.es/egob/catalogo/300302-10875226-carreras-urbanas.xlsx'.toURL().bytes
Workbook workbook = WorkbookFactory.create(xlsx)
workbook.sheetIterator().each{ sheet ->
    sheet.rowIterator().each{ row ->
        Cell when = row.getCell(0)
        if( when.cellTypeEnum == CellType.NUMERIC ){
            Cell prueba = row.getCell(2)
            Cell distancia = row.getCell(3)
            Cell lugar = row.getCell(4)
            ...
            eventos.add([
                    when:when.dateCellValue.format( 'dd/MM/yyyy' ),
                    duration: duration.days,
                    title: prueba,
                    distance: distancia,
                    where: lugar
            ])
            ....

Spin-off Gradle Plugin SocialNetwork

Plugin Gradle para enviar mensajes vía Telegram, Twitter y Slack

"Little" Data, Préstamos Bibliotecas

Compartir en el canal los libros más leídos en las Bibliotecas de Madrid del mes anterior

Reto: parsear CSV con 200K líneas y buscar los TOP en pocos minutos

Solución (entre muchas): usar una bbdd Derby embebida

Spin-off 1: QueryCSV Plugin

Plugin Gradle para tratar CSV "pesados" y extraer información mediante SQL

"Little" Data, Dataset público con BigQuery

Recolectando en un BigQuery los prestamos desde 2014 para ofrecerlos como dataset publico

(Tal vez en tu empresa quereis compartir datos y no sabéis cómo…​)

Conclusiones

  • Infinidad de datos ahí fuera

  • OpenData NO es sólo tratar ingentes cantidades de datos

  • Múltiples formas de interactuar

  • Oportunidad de aprender

  • Coste "cero" (económico)

Q&A & Feedback

ContactFeedback

@jagedn

https://forms.gle/A3CkzVadYRdhBYXi8 https://forms.gle/A3CkzVadYRdhBYXi8

https://gitlab.com/puravida-software

https://www.linkedin.com/in/jagedn/

gracias multilingue