Marcos Dione: barely-working-centerline-JOSM-plugin

I just uploaded my first semi-automated change. This change was generated with my hack for generating centerlines for riverbank polygons. This time I expanded it to include a JOSM plugin which will take all the closed polygons from the selection and run the algorithm on them, creating new lines. It still needs some polishing, like making sure they're riverbanks and copying useful tags to the new line, and probably running a simplifying algo at some point. Also, even simple looking polygons might generate complex lines (in plural, and some of these lines could be spurious), so some manual editing might be required afterwards, specially connecting the new line to existing centerlines. Still, I think it's useful.

Like I mentioned last time, its setup is quite complex: The JOSM plugin calls a Python script that needs the Python module installed. That module, for lack of proper bindings for SFCGAL, depends on PostgreSQL+PostGIS (but we all have one, right? :-[ ), and connection strings are currently hardcoded. All that to say: it's quite hacky, not even alpha quality from the installation point of view.

Lastly, as imagico mentioned in the first post about this hack, the algorithms are not fast, and I already made my computer start thrashing the disk swapping like Hell because pg hit a big polygon and started using lots of RAM to calculate its centerline. At least this time I can see how complex the polygons are before handing them to the code. As an initial benchmark, the original data for that changeset (I later simplified it with JOSM's tool) took 0.063927s in pg+gis and 0.004737s in the Python code. More test will come later.

Okey, one last thing: Java is hard for a Pythonista. At some point it took me 2h40 to write 60 lines of code, ~2m40 per line!

openstreetmap gis python

Marcos Dione: interesting-pycon-talks

Like I said in my last post[1], I'm looking at last PyCon's videos. Here are my selected videos, in the order I saw them:

Ned Batchelder - Machete-mode debugging: Hacking your way out of a tight spot. In fact, I saw this twice.

Larry Hastings - Removing Python's GIL: The Gilectomy

The Report Of Twisted’s Death or: Why Twisted and Tornado Are Relevant In The Asyncio Age

How I built a power debugger out of the standard library and things I found on the internet

Davey Shafik - HTTP/2 and Asynchronous APIs

Sumana Harihareswara - HTTP Can Do That?! Points for informative and funny.

Matthias Kramm - Python Typology Types are comming, so get used to them.

Scott Sanderson, Joe Jevnik - Playing with Python Bytecode Nice, very nice trick. I'm talking about the way the presentation is given.

Brian Warner - Magic Wormhole - Simple Secure File Transfer

And of course, the lighning talks. I always like these, because you can get exposed to any kind of things, some not even remotely connected to Python, but which can get your brain rolling down nice little bunny holes, or at least get a smile from you. So here:

LT#1. Please watch it at least between 20-25m.




And of course, check the other ones, don't stop at my own interests.

[1] Yes, I started writing this a month ago.


Marcos Dione: ayrton-0.8-Home-Sweet-New-Home

Long time for this release. A couple of hard bugs (which fix was just moving a line down a little), a big-ish new feature, and moving in a new city. Here's the ChangeLog:

  • You can import ayrton modules and packages!
  • Depends on Python3.5 now.
  • argv is not quite a list: for some operations (len(), iter(), pop()), argv[0] is left alone.
  • option() raises KeyError or ValueError if the option or its 'argument' is wrong.
  • makedirs() and stat() are available as functions.
  • -p|--pdb launches pdb when there is an unhandled exception.
  • Fix for line in foo(...): ... by automatically adding the _bg=True option.
  • Better Command() detection.
  • A lot of internal fixes.

Get it on github or pypi!

python ayrton

Damián Avila: RISE 4.0.0b1 is available, please test it!

Quick post! I have beta packages available for you to test RISE, if you can test it that would be awesome!!

In case you don't know about it, with RISE you get your Jupyter notebook rendered as a Reveal.js-based slideshow, where you can execute code on the fly or show to the audience whatever you can show/do inside the notebook itself (but in a "slidy" way).

How you can get it?

Read more… (1 min remaining to read)

Marcos Dione: adding-columns-from-osm-to-postgis-with-osmium

My latest Europe import was quite eventful. First, I run out of space several times during the import itself, at indexing time. The good thing is that, if you manage to reclaim some space, and reading a little of source code[1], you can replay the missing queries by hand and stop cursing. To be fair, osm2pgsql currently uses a lot of space in slim+flat-nodes mode: three tables, planet_osm_node, planet_osm_way and planet_osm_relation; and one file, the flat nodes one. Those are not deleted until the whole process has finished, but they're actually not needed after the processing phase. I started working on fixing that.

But that was not the most difficult part. The most difficult part was that I forgot, somehow, to add a column to the file. Elevation, my own style, renders different icons for different types of castles (and forts too), just like the Historic Place map of the Hiking and Bridle map[2]. So today I sat down and tried to figure out how to reparse the OSM extract I used for the import to add this info.

The first step is to add the column to the tables. But first, which tables should be impacted? Well, the line I should have added to the import style is this:

node,way   castle_type  text         polygon

That says that this applies to nodes and ways. If the element is a way, polygon will try to convert it to a polygon and put it in the planet_osm_polygon table; if it's a node, it ends in the planet_osm_point table. So we just add the column to those tables:

ALTER TABLE planet_osm_point   ADD COLUMN castle_type text;
ALTER TABLE planet_osm_polygon ADD COLUMN castle_type text;

Now how to process the extract? Enter pyosmium. It's a Python binding for the osmium library with a stream-like type of processing à la expat for processing XML. The interface is quite simple: one subclasses osmium.SimpleHandler, defines the element type handlers (node(), way() and/or relation()) and that's it! Here's the full code of the simple Python script I did:

#! /usr/bin/python3

import osmium
import psycopg2

conn= psycopg2.connect ('dbname=gis')
cur= conn.cursor ()

class CastleTypes (osmium.SimpleHandler):

    def process (self, thing, table):
        if 'castle_type' in thing.tags:
                name= thing.tags['name']
            # osmium/boost do not raise a KeyError here!
            # SystemError: <Boost.Python.function object at 0x1329cd0> returned a result with an error set
            except (KeyError, SystemError):
                name= ''
            print (table,, name)

            cur.execute ('''UPDATE '''+table+
                         ''' SET castle_type = %s
                            WHERE osm_id = %s''',

    def node (self, n):
        self.process (n, 'planet_osm_point')

    def way (self, w):
        self.process (w, 'planet_osm_polygon')

    relation= way  # handle them the same way (*honk*)

ct= CastleTypes ()
ct.apply_file ('europe-latest.osm.pbf')

The only strange part of the API is that it doesn't seem to raise a KeyError when the tag does not exist, but a SystemError. I'll try to figure this out later. Also interesting is the big amount of unnamed elements with this tag that exist in the DB.

[1] I would love for GitHub to recognize something like and be directed to that method, because #Lxxx gets old pretty quick.

[2] I just noticed how much more complete those maps are. more ideas to use :)

openstreetmap gis python

Marcos Dione: our-man-in-marseille

Remember this?

For a few months now I've been trying to have a random slideshow of images. I used to do this either with kscreensaver, which for completely different reasons I can't use now, or xscreensavers' glslideshow, which, even when I compiled it by hand, I can't find the way to give it the root dir of the images. So, based on OMIT, I developed my own.

The differences with OMIT are minimal. It has to scan the whole tree for finding the appropriate files (its definition of "appropriate" could be improved, it's true); it goes into full screen mode with black background; and it (more) properly handles EXIF rotation[1]. All that in 176 LOCs, including proper licensing (GPLv3), and developed in one day and refined the next one.

One interesting thing I found out is that pyexiv2 is deprecated, with is last release in 2011 (!!!). What this new app uses is its recommended replacement, gexiv2.

So, there you are. Like OMIT, it's in PyQt4, but this time in Python3 (that's why I used gexiv2 instead). Its TODO includes porting it to PyQt5 and a few other things. You can grab it here. I plan to do a proper release soon, but for the moment just drop it in your PATH and be happy with it.


omit omim pykde python

Facundo Batista: Europython 2016, la conferencia

El evento estuvo dividido principalmente en tres partes, tutoriales para principiantes, conferencia propiamente dicha, y los sprints.

A los tutoriales (Beginners day, y Django girls), que duraban un día, no fui.  La conferencia fue de lunes a viernes. Y los sprints fueron sábado y domingo.  Del primer día de conferencia ya les conté, y el domingo estuve viajando. El resto, se los cuento acá :)

Charlas interesantes

Recopilación de lo que más me gustó de la conferencia... ojo, en algunos casos incluyo links a los videos o presentaciones mismas, en otros no porque me dió paja buscarla, pero tienen que estar :)

Por lejos, la mejor Keynote fue la de Jameson Rollins, "LIGO: The Dawn of Gravitational Wave Astronomy", aunque también estuvo buena la de Naomi Ceder, "Come for the Language, Stay for the Community". Tercera podríamos poner "Scientist meets web dev: how Python became the language of data", por Gaël Varoquaux. El resto me aburrió un poco, o no me interesó tanto.

LIGO is a...

Otras charlas que me gustaron fueron "High Performance Networking in Python" de Yury Selivanov, "Build your first OpenStack application with OpenStack PythonSDK" por Victoria Martinez de la Cruz, "Implementación de un Identificador de Sonido en Python" por Cameron Macleod, "FAT Python: a new static optimizer for Python 3.6" de Victor Stinner, "CFFI: calling C from Python" de Armin Rigo, "The Gilectomy" de Larry Hastings, "A Gentle Introduction to Neural Networks (with Python)" de Tariq Rashid, y "Music transcription with Python" de Anna Wszeborowska.

De esta última charla me quedé con el proyecto a futuro (ya lo anoté, está en la posición 1783461° entre otros proyectos) de mostrar en tiempo real, usando Bokeh, la info que levanta y las transformaciones que va haciendo.

Imagen típica de Bilbao

También quiero resaltar dos lightning talks: a Armin Rigo mostrando un "Reverse debugging for Python", y una de alguien que no me acuerdo mostrando "A better Python REPL".

Mis presentaciones

Ya les hablé de la charla que había dado el lunes, pero aprovecho y les dejo el video de la misma.

El martes dí Entendiendo Unicode, en castellano. Fue la 12° vez que la doy, y me podrán decir "dejá de robar con la misma charla"... qué quieren que les diga, el público se renueva. Yo también a veces pienso si no será demasiado, ¡pero a la gente le gusta y le sirve! Una decena de personas me saludaron y me comentaron lo buena y lo útil que fue la charla. Así que nada, la seguiré ofreciendo en próximas conferencias, :). El video, acá.

Espacio común de trabajo

Además de esas dos presentaciones "largas", dí dos lightning talks. La primera sobre fades; no es la primera vez que la doy, pero la había renovado y traducido al inglés, y estuvo muy bien. La segunda fue sobre Python Argentina. La hice el mismo viernes, a los apurones, pero a la gente le gustó mucho (me sorprendió la cantidad de veces que se rieron en esos cinco minutos (cinco minutos que tuve que pelear, como ven en el video, porque me querían dar dos, luego la confusión de que yo iba a hablar de una PyCon).


El sábado, estuve sprinteando, trabajando con fades, más que nada ofreciendo ayuda a gente que quería usarlo o que querían enterarse más sobre el proyecto. Incluso se acercó alguien con un detalle, lo charlamos, lo solucionamos y hasta hice un pull request.


Ese sábado era mi última noche en Bilbao. Medio coordinamos con Juan Luis y fuimos a cenar pinchos con otras personas, luego por una cerveza. Y cuando estaba cerrando la noche, tipo once y media, me comentaron de una zona en la ciudad donde hay toda una movida heavy y punk.

No me la podía perder.

Así que nos fuimos cinco personas hasta allí, saltamos por tres o cuatro bares, tomando algo en cada uno, escuchando muy buena música, terminando en un antro de mala muerte, jugando metegol, pasando música que elegíamos nosotros, y disfrutando mucho.

En un bar punkie

A eso de las dos y media dí por concluido el paseo, porque a las cuatro me pasaba a buscar el taxi, así que con Oriol (uno de los chicos) nos tomamos un taxi, llegué a la habitación, terminé de armar todo, me pegué una ducha, dejé las llaves en la mesa de la cocina y arranqué las 23 horas de viaje que me iban a reecontrar con mi familia :)

Todas las fotos de la conferencia y Bilbao, acá.

Marcos Dione: osm-centerlines-two-days-after

In this last two days I've been expanding osm-centerlines. Now it not only supports ways more complex than a simple rectangle, but also ones that lead to 'branches' (unfortunately, most probably because the mapper either imported bad data or mapped it himself). Still, I tested it in very complex polygons and the result is not pretty. There is still lots of room for improvements.

Unluckily, it's not as stand alone as it could be. The problem is that, so far, the algos force you to provide now only the polygon you want to process, but also its skeleton and medial. The code extends the medial using info extracted from the skeleton in such a way that the resulting medial ends on a segment of the polygon, hopefully the one(s) that cross from one riverbank to another at down and upstream. Calculating the skeleton could be performed by CGAL, but the current Python binding doesn't include that function yet. As for the medial, SFCGAL (a C++ wrapper for CGAL) exports a function that calculates an approximative medial, but there seem to be no Python bindings for them yet.

So, a partial solution would be to use PostGIS-2.2's ST_StraightSkeleton() and ST_ApproximateMedialAxis(), so I added a function called skeleton_medial_from_postgis(). The parameters are a psycopg2 connection to a PostgreSQL+PostGIS database and the way you want to calculate, as a shapely.geometry, and it returns the skeleton and the medial ready to be fed into extend_medials(). The result of that should be ready for mapping.

So there's that. I'll be trying to improve it in the next days, and start looking into converting it into a JOSM plugin.

openstreetmap gis python

Marcos Dione: deriving-centerlines-from-riverbanks-without

For a long time now I've been thinking on a problem: OSM data sometimes contains riverbanks that have no centerline. This means that someone mapped (part of) the coasts of a river (or stream!), but didn't care about adding a line that would mark its centerline.

But this should be computationally solvable, right? Well, it's not that easy. See, for given any riverbank polygon in OSM's database, you have 4 types of segments: those representing the right and left riverbanks (two types) and the flow-in and flow-out segments, which link the banks upstream and downstream. With a little bit of luck there will be only one flow-in and one flow-out segment, but there are no guarantees here.

One method could try and identify these segments, then draw a line starting in the middle of the flow-in segment, calculating the middle by traversing both banks at the same time, and finally connect to the middle for the flow-out segment. Identifying the segments by itself is hard, but it is also possible that the result is not optimal, leading to a jagged line. I didn't try anything on those lines, but I could try some examples by hand...

Enter topology, the section of maths that deals with this kind of problems. The skeleton of a polygon is a group of lines that are equidistant to the borders of the polygon. One of the properties this set of lines provides is direction, which can be exploited to find the banks and try to apply the previous algorithm. But a skeleton has a lot of 'branches' that might confuse the algo. Going a little further, there's the medial axis, which in most cases can be considered a simplified skeleton, without most of the skeleton branches.

Enter free software :) CGAL is a library that can compute a lot of topological properties. PostGIS is clever enough to leverage those algorithms and present, among others, the functions ST_StraightSkeleton() and ST_ApproximateMedialAxis(). With these two and the original polygon I plan to derive the centerline. But first an image that will help explaining it:

The green 'rectangle' is the original riverbank polygon. The thin black line is the skeleton for it; the medium red line is the medial. Notice how the medial and the center of the skeleton coincide. Then we have the 4 branches forming a V shape with its vertex at each end of the medial and its other two ends coincide with the ends of the flow in and flow out segments!

So the algorithm is simple: start with the medial; from its ends, find the branches in the skeleton that form that V; using the other two ends of those Vs, calculate the point right between them, and extend the medial to those points. This only calculates a centerline. The next step would be to give it a direction. For that I will need to see if there are any nearby lines that could be part of the river (that's what the centerline is for, to possibly extend existing rivers/centerlines), and use its direction to give it to the new centerline.

For the moment the algorithm only solves this simple case. A slightly more complex case is not that trivial, as skeletons and medials are returned as a MultiLineString with a line for each segment, so I will have to rebuild them into LineStrings before processing.

I put all the code online, of course :) Besides a preloaded PostgreSQL+PostGIS database with OSM data, you'll need python3-sqlalchemy, geoalchemy, python3-fiona and python3-shapely. The first two allows me to fetch the data from the db. Ah! by the way, you will need a couple of views:

CREATE VIEW planet_osm_riverbank_skel   AS SELECT osm_id, way, ST_StraightSkeleton (way)      AS skel   FROM planet_osm_polygon WHERE waterway = 'riverbank';
CREATE VIEW planet_osm_riverbank_medial AS SELECT osm_id, way, ST_ApproximateMedialAxis (way) AS medial FROM planet_osm_polygon WHERE waterway = 'riverbank';

Shapely allows me to manipulate the polygonal data, and fiona is used to save the results to a shapefile. This is the first time I ever use all of them (except SQLAlchemy), and it's nice that it's so easy to do all this in Python.

openstreetmap gis python

Facundo Batista: Europython 2016, Bilbao


Estuve cinco horas en el aeropuerto de Río de Janeiro. La comida más elaborada que encontré en las dos terminales fueron sánguches de Subway y panchos. No, gracias.

El aeropuerto de Lisboa, por otro lado, era inmenso y tenía mil locales de comida. Eso sí, ni un cartel de "Bienvenido a Portugal" o similar, que busqué para mandarle foto a los peques...

El único aeropuerto con wifi libre era Aeroparque, en Argentina. El de Río y Lisboa tenían redes que podías usar si tenías contratos con empresas de ahí. En el de Bilbao también pude conseguir internet, luego de registrarme en una página que le fallaba el certificado SSL :/; pero bueno, me sirvió para avisarle a Moni que había llegado bien.


Luego de llegar a donde me hospedé, me pegué un baño y salí a pegar una vuelta (eran las siete y media de la tarde, así que tenía todavía más de dos horas de luz). Algo que me llamó la atención es que la gente, en los barcitos, agarran su cerveza o vino y salen a tomarlo a la calle (el clima estaba hermoso), así que veías un montón de gente super empilchada, con sus copas de tinto o blanco, sentados en los muchos banquitos que hay por todos lados...

Yo me metí un un bar que pintaba lindo, me tomé un par de cervezas con un par de pinchos, y luego arranqué la vuelta. No me fui a dormir demasiado tarde (antes de las doce y media), y habiendo dormido un poco en los dos vuelos cortos, y casi cinco horas en el vuelo largo, no esperaba dormir tanto: me levanté a la una y pico de la tarde!! Parece que el truco de no poner despertador, un oscuro casi absoluto, y no estar pendiente de niños, le aportaron mucho a lo cansadísimo que había llegado al fin de semana...

Parte del Guggenheim a la izquierda, el Puppy a la derecha

Así que me levanté, desayuné y salí a pasear. Me tomé el metro y me fuí para el casco viejo, hice un par de recorridos, saqué un par de fotos, y un par de horas después encaré para uno de los edificios de la conferencia donde se hacía el Django Girls, a saludar conocidos.

Al rato me fui para el edificio principal de la conferencia, donde desde media tarde ya uno se podía registrar, así hacía el trámite el domingo, y de paso encontraba bien el edificio, sabía por donde entrar, etc.

Ahí me encontré con gente que no conocía personalmente pero sí de redes sociales virtuales, estuvimos charlando un rato y después con Juan Luis Cano, Yamila Moreno y otra gente fuimos caminando hasta un funicular, con el que subimos una montaña para mirar la ciudad de arriba.

Desde lo alto

Después nos fuimos a cenar con otra gente a un restaurant bastante piola, comimos rico. Y ya se hicieron las doce, así que volví a donde me hospedé, revisé un rato la charla del lunes, y a dormir!

Primer día de conferencia

Es el día que más charlas tenía marcada. Hubo una plenaria apenas interesante sobre la base de "podés ganar plata haciendo lo que quieras, no tengas miedo de probar", y luego me fuí a una charla de Efficient Django, de la cual me anoté algunos puntos a investigar. Después fui a una charla que mostraba como realmente funciona mezclar AsyncIO y Cython, logrando código asincrónico rapidísimo, y después me tocó a mí.

Yo dí It's not magic: descriptors exposed, la que preparamos con Joac y dimos en la PyCon de Mendoza, pero en inglés. Es una charla difícil, pero creo que la gente se va con info nueva. Hubieron varias preguntas, y luego se me acercaron en los pasillos para seguir charlando del tema, y también me saludaron un par de veces para decirme que la charla les había gustado, así que estoy contento con como salió.

A la tarde estuvo más tranquilo. Una charla que me gustó bastante fue la The Report of Twisted's Death, dada por Amber Brown, una Twisted core developer (y también release manager) que contó en qué estaban, los planes con respecto a asyncio, qué pasaba con Tornado, etc.

An open space in the conference

También me enganché con unos acertijos que te daban en una empresa, algo estilo el pythonchallenge, donde resolver un problema te da la info para encontrar el próximo, y así. La realidad es que era medio buggy, en el segundo acertijo al flaco le marqué dos bugs, y en el último caso le dije que no se podía resolver, y lo hostigué hasta que me pasó la solución y le mostré como no había forma de llegar, :). Así que me gané el premio (una boludez, un hub usb), más que nada por mostrarles a ellos dónde tenían el problema :p.

Como frutilla del postre de la tarde, nos regalaron a todos los asistentes una micro:bit!!! Si no la conocen, una micro:bit es una pequeñísimo hardware que corre Python, que la BBC le regaló a todos los estudiantes de 7 años en el Reino Unido para que jueguen y aprendan. Ahora tengo que ver qué cosas se puede hacer para ponernos con Felipe :D (aunque creo que es un poco más para el año que viene...).

Luego vinieron las lightning talks, y ya se terminó el día!