ISSN 2011-0146

Using Travis-CI with Github Pages to build a self-updating static site

publicado en general,programación,web por mga en October 25, 2015

Recently I came across a project where one collaborator was generating CSV files that would then used to produce static minisite with an ElasticSearch-powered search. I decided to use Github Pages and Travis-CI for two main reasons:

  • a simple git push would let anyone update the site any time
  • Travis-CI could take care of static file generation and search indexing whenever a new set of CSVs was deployed

If you have a similar need, read on. This post is informed by many blog posts around the web (see footnotes1 2 3 4).

NOTE: This is not a recommendation on how to produce static sites. There are better tools out there for that. Check out StaticSiteGenerators if you need a proper system for static site generation. This tutorial is more the README I wish I found in the web while looking to solve this particular problem.

About Travis-CI and Github Pages

Github Pages is a quick and easy way to host static websites (you do need to know git and a Github account, but you already do, right?).

Travis-CI is a service that lets you trigger arbitrary code whenever you push changes to a code repository. The most popular use is code-testing. We will use the free version that requires your repository to be public. Take this into account if you require your code to be private.

In this example we will use Travis-CI to execute some Python code in the repository which takes care of indexing, static file-generation and repository updates. The project in question has two branches: the mandatory gh-pages branch, which Github will use for hosting the static site, and a csv branch to which will receive the latest CSVs. The gh-pages branch will be updated every time a new push arrives in the csv branch.

Suppose a basic structure of the project like this: will update the ElasticSearch index using data.csv, and also generate static.txt as a sort of pre-caching of the site. This may sound a little roundabout but bear with me. This structure was actually useful in our case. I will eventually publish the final site.

You will also notice a /python/ file. This file contains the steps you use to create the index and static file manually. It is basically the list of UNIX commands you would type in your terminal to do the process yourself, only that you want Travis-CI to do it for you (magick!).

Setup permissions

Your Github account needs to allow Travis-CI some operations in your repositories.

NOTE: Make sure you consult others on security. I am not an expert on this subject. Refer to the footnotes for more details. I will just cover the basics.

In Github:

  • Click on your avatar in the top-right and select Settings > Personal access tokens
  • Generate a new token with these permissions: user:email, read:org, repo_deployment, repo:status, write:repo_hook, public_repo
  • IMPORTANT: Save the token somewhere you can easily retrieve it because Github shows it only once

In Travis-CI:

  • Install the Travis Ruby gem in your machine and login:

  • Go to your Travis-CI profile and turn on the repository you want to activate
  • Click the little gear icon to access the settings for that repo
  • Add any environment variables that your scripts use such as the URL to your ElasticSearch service or the path/to/some/file in the repository

The post-deploy script

Let’s look at a trimmed-down (useless) version of the Python file (the # comments in the code will clarify the main parts):

The file has two purposes:

  1. index the CSV in the ElasticSearch
  2. produce a csv/static.txt

The post-deploy script

You may have noticed a requirements.txt file above. Vanilla Python in Travis-CI does not have every module by default. We need this file to tell Travis what to install once the repository is deployed. You can add as many modules as you want, these are just examples:

Now let’s look at the file. This is where the magic happens! This is also where the token we created above enters the scene. We will encrypt it in a minute.

But first:

Travis-CI requires a .travis.yml file (you might have noticed it in the root folder, next to index.html) that describes what happens once a new deploy is detected. Let’s start with the basic structure (once again, the # comments will clarify):

Once we have that file, we can add the encrypted Github token using the following command:

The --add flag will append the encrypted string to the .travis.yml file like so:

Note the new env > global > secure structure in the above snippet where the Travis-CI command-line program inserted some encrypted-stuff-here automatically.

This creates a new environment variable named GH_TOKEN available to any scripts run by Travis-CI (similar to adding the variable in the settings panel but in a more secure way). We will also add a variable for the repository name. You may want to encrypt it also but I will leave it plain text for example purposes:

Now we need to create the build script itself, python/ The steps are:

  1. clone the repository to a new folder (I had to do it this way because the scope in Travis-initiated processes seems to be limited to a single branch and I was not able to pull/push to other branches)
  2. checkout and pull the latest code in the csv branch
  3. checkout and merge the code into the gh-pages branch
  4. run the indexing and output new static files
  5. add the new files and create a new commit
  6. push the result to gh-pages

Below is a condensed version of this script. The echos (and all other terminal-visible commands in your scripts such as print) will be visible in the Travis console so you can debug what may be going wrong:

Now we need to tell Travis-CI to add executable permissions to this file and run it in the install part of the build lifecycle. We also add before_install and script sections to .travis.yml. The end result looks like:

And voilà! Once these files are added to the repository, upon next deploy on the csv branch Travis-CI will trigger the scripts and update all the data in ElasticSearch and the Github Pages website.

Hope this is useful to you and do contact me if there’s any glaring issues/omissions in this quick example. Special thanks to @auremoser for her feedback while writing this text.

Del papel a la web: haz tus propios mapas interactivos.

publicado en arte,diseño,interacción,programación,tips,web por mga en March 20, 2015

Esta es una traducción de “From Paper Maps to the Web: A DIY Digital Maps Primer” realizada por Daniela Schütte, coordinadora del proyecto Memoria Chilena de la Biblioteca Nacional de Chile.

NOTA: hay terminología que debe mantenerse en inglés puesto que así debe escribirse en el código.

En noviembre del 2014, fui invitado a la 2a semana del libro digital organizado por la Biblioteca Nacional de Colombia. La idea era presentar los proyectos que estamos desarrollando en el NYP Labs y también, dictar un taller sobre herramientas para geolocalización de mapas. Pienso que puede ser útil compartir los contenidos de ese taller, ya que integra diversas herramientas y procesos que permiten que la cartografía digital sea, hoy en día, accesible para todos.
Se trata de un paso a paso que, utilizando herramientas de georeferenciación gratuitas, te enseñará a hacer tu propio e increíble mapa georeferenciado.


Esto es lo que haremos. Este tutorial asume que ya tienes un mapa digitalizado y que tienes claro qué información quieres incorporar. Usualmente, los pasos son:

  1. Georeferenciar el mapa escaneado para poder generar la cuadrícula (“tileset” en inglés) del mapa;

  2. Procesar los datos en GeoJSON para sobreponerlos al mapa escaneado;

  3. Crear un mapa personalizado que servirá de referencia como mapa de la actualidad;

  4. Integrar todos los elementos en una página web interactiva.

NOTA: Este tutorial asume que estás usando Mozilla Firefox, Apple Safari o Google Chrome. Tendremos que jugar con la consola de desarrollo y no tengo instrucciones multinavegador.


Esto es lo que queremos hacer. Un mapa de Bogotá de 1891 conservado en la Biblioteca Nacional de Colombia (el link requiere Flash Player) enriquecido con datos extraídos de un directorio de Bogotá de 1888.

1) Geo-localizando.

El primer paso, luego de digitalizar el mapa, es agregar la información geográfica. Para esto, es necesario establecer la equivalencia entre pixeles y ubicación exacta que ellos representan. Esto se conoce con el nombre de geolocalización. Este proceso distorsionará la imagen digitalizada:

Original scan
Imagen original digitalizada (encogida, por supuesto)

…Al hacerla calzar con la proyección de Mercator que es la que se utiliza en la mayoría de los proyectos que utilizan mapas digitales como OpenStreetMap or Google Maps:

Mapa en proyeccion Mercator
Proyección Mercator de la imagen original geolocalizada

El porcentaje de distorsión dependerá de la calidad de la muestra –el mapa digitalizado–, su estado de conservación y la proyección del mapa original. Es posible que te estés preguntando ¿y cómo ocurrirá esto? Existen softwares propietarios y open-source que permiten geolocalizar imágenes de un modo sencillo. Sin embargo, el objetivo de este tutorial es lograrlo sin que tengas que instalar ningún programa que no sea tu navegador.

Para empezar, anda a: Map Warper. Esta es una herramienta web que te permite subir tu mapa digitalizado para luego, a través de una sencilla interfaz, geolocalizarlo (o “rectificarlo” para hablar como cartógrafos). En el lado izquierdo verás el mapa digitalizado y en el lado derecho, la proyección Mercator.

Map Warper
Así se ve la interfaz dividida para la rectificación en Map Warper

Fíjate en los marcadores de la imagen. Cada pin tiene un número y el mismo marcador se ve en ambos lados de la imagen. Asimismo, cada uno de ellos te servirá para darte cuenta que en el mapa digitalizado, el Norte está hacia el lado izquierdo, mientras que el Este está hacia arriba. Si bien, cuantos más marcadores agregues, más precisa será la referenciación; debes considerar que también será más lento el procesamiento de la imagen final. No obstante, la imagen se genera sólo una vez, así que yo no me preocuparía demasiado por eso. De lo que sí debes preocuparte es de cuántos marcadores estás dispuesto a agregar. El mapa de este tutorial, por ejemplo, tiene 101.

Una consideración final en este proceso es estar seguros que, luego de la distorsión producida por la geolocalización de la imagen, tienes una imagen de alta calidad. El proceso de distorsionar la imagen original se llama resamplear 1. En las opciones avanzadas de Map Warper puedes definir si quieres que el proceso sea rápido pero de inferior calidad (seleccionando la opción “Nearest Neighbour”) o un poco más lento, pero de mejor calidad (seleccionando “Cubic Spline”):

Resampling method selection
Selecciona “Cubic Spline” en el menú “Resampling Method option”

Puedes ver el mapa final aquí. También puedes descargarlo en alta resolución en la pestaña “Export”. Sin embargo, pienso que el insumo principal que se obtiene de Map Warper es la cuadrícula o baldosas (“tileset” en inglés), como prefieran llamarlas. Y que en el fondo, es la URL que se ve aquí:

Map Warper
Puedes encontrar la URL del tileset en la pestaña “Export”

Y el template es:{z}/{x}/{y}.png

Para seguir trabajando necesitarás esta URL así que guárdala en un lugar seguro, un bloc de notas por ejemplo, para ir dejando todos estos datos, que luego ocuparemos. Map Warper tiene un motor que utiliza la imagen geolocalizada para generar un tileset en el mapa que opera a distintos niveles del zoom. Así que sólo se nuestra la parte en la que estás trabajando 2. Esta es una baldosa o una parte del tileset de ejemplo:

a web map tile
Un mapa Web está hecho de millones de estas

2) Extracción de datos.

Ya tenemos el mapa. Ahora tenemos que pensar qué información queremos mostrar en él. Nuestro ejemplo utiliza este directorio de la ciudad de Bogotá de 1888, la capital de Colombia. Este documento tiene información valiosa sobre: decenas de miles de personas, cada una de ellas con su nombre completo, ocupación y dirección; docenas de ocupaciones diferentes (descritas en la página 4) y avisos publicitarios (junto con la dirección de locales comerciales y los nombres de sus dueños). Este directorio constituye un interesante retrato de la vida colombiana en la segunda mitad del siglo XIX: abogados, fotógrafos y contadores comparten páginas con talabarteros y herreros. Yo me fui por el camino aburrido y decidí buscar políticos influyentes de la época, como por ejemplo el presidente en ejercicio (página 222, primero en la segunda columna). La lista tiene los nombres de siete personas: cuatro presidentes, un vicepresidente, un ministro, y un presidente en ejercicio 3. En ella se incluye:

  • nombre;
  • cargo (El cargo más alto en el poder ejecutivo colombiano);
  • período de ejercicio;
  • página (en la que aparece en el directorio);
  • ocupación (de acuerdo con la tipificación del directorio);
  • dirección;
  • La URL de una fotografía de Wikimedia (en caso de existir una);
  • latitud, longitud (un marcador de posición del centro de Bogotá que modificaremos en esta etapa).

Descarga la lista en CSV.

Puedes crear tu propia lista con otros datos que te parezcan más interesantes o más útiles. Sólo debes asegurarte de incluir una columna para indicar la “latitud” y la “longitud” y guardarla en una lista de valores separados por comas.


Hasta acá, tus datos están almacenados en una lista de valores separados por comas, pero las herramientas para geolocalización en la web, generalmente utilizan el estándar de datos GeoJSON. GeoJSON está basado en JSON que es una de las formas más populares de estructurar datos en la web. GeoJSON utiliza el concepto de “atributos” para describir los datos geográficos. Estos atributos pueden ser puntos (como en este caso) o formas geométricas complejas como líneas sencillas, compuestas o polígonos. Cada atributo es descrito por su geometría, en inglés geometry, (el punto, la línea o el polígono en sí mismo) y por sus propiedades, en inglés properties, que en el fondo son todos los datos extra que quieras asociar a ellos (en este caso, el nombre de la persona, su dirección, fotografía, etc.). Por ejemplo4:

Ahora tenemos que convertir la hoja de datos en un objeto GeoJSON y actualizar los valores de latitud y longitud, en inglés latitude y longitude, de los marcadores de posición. Para esto, utilizaremos el mismo mapa. Pero necesitaremos una herramienta que nos permita generar el archivo GeoJSON y manipularlo fácilmente.

Lo que nos lleva a Es “una rápida y sencilla herramienta para crear, visualizar y compartir mapas”. tiene una elegante interfaz que nos permitirá crear el archivo GeoJSON que necesitamos.

Carga la página de en una nueva pestaña del navegador. Lo primero que verás será un mapa por defecto en un zoom out completo. Entonces, tendremos que intervenir un poco. Haz click con el botón derecho en algún punto del mapa y selecciona Inspeccionar elemento (o Inspect element si tienes el navegador en inglés):

Right-Click -/> Inspect Element” title=””>  </p>
<p><em>Click botón derecho ? Inspeccionar elemento</em></p>
<p>Al hacer esto, tendrás una visualización avanzada para desarrolladores, esto significa que podrás ver y modificar el código de la página que estás viendo (en este caso, la interfaz del mapa). incluye una interfaz para programación (API) que te permitirá también, controlar el despliegue del mapa. El núcleo de este sitio es <a href=MapBoxJS, que está construido en Leaflet, una “librería JavaScript de código abierto para el desarrollo de mapas interactivos compatibles con dispositivos móviles”. Menciono ambos asuntos porque, en la mayoría de los casos, lo que funciona en uno de ellos, funcionará también en el otro. (Es importante que leas toda la documentación antes de tomar cualquier decisión). De ahora en adelante, me referiré a Leaflet en lugar de MapBoxJS.

En la pestaña “Consola” (o “Console” en inglés) verás algo de texto y, al final, un cursor en el que podrás ejecutar el código JavaScript. También te darás cuenta que hay algunos comentarios del creador de Escribe esto en el área que mencioné y presiona ENTER (fíjate en el GIF animado de más abajo):

Con esto, lograrás que el mapa se centre y haga un “zoom” en Bogotá, Colombia, el área comprendida por el mapa de 1891. Ahora escribe esto:

y presiona ENTER. Al hacerlo, agregarás el tileset que ya habíamos creado. Fíjate que la línea de código que acabamos de escribir incluye la URL que copiamos en el paso 1. El resultado, debiera verse más o menos así:

Antes y despues de ejecutar los comandos
Una rápida “intervención” a

Ahora, puedes cerrar la ventana de consola (No la ventana del navegador).

NOTA: Será necesario que apliques este código cada vez que cargues ya que no guarda las modificaciones vía consola. Lo que puedes hacer es registrarte y así guardar los datos que agregaste a tu mapa.

Agregando datos a

Ahora usaremos la versión modificada del mapa como base para geolocalizar correctamente la lista CSV de presidentes. Arrastra la lista CSV que descargaste sobre el mapa:

drag and drop magic
La magia de arrastrar y soltar en

Te darás cuenta cómo los datos inmediatamente son convertidos a GeoJSON (panel derecho) y el mapa muestra los marcadores de cada presidente (panel izquierdo). Aparecerá un pequeño mensaje verde (arriba a la izquierda) que indica que siete atributos fueron importados.

Pero… ¡El mapa de 1891 desapareció! No te asustes. Esto sólo significa que el mapa ha hecho un zoom “demasiado cerca de la tierra” y la URL del tileset no tiene imágenes a esa escala. Haz un zoom out y verás que el mapa de 1891 aparece otra vez.

Moviendo lo marcadores.

Como podrás darte cuenta, los marcadores de la lista CSV quedaron geolocalizados, uno encima de otro, en la misma ubicación, la Plaza de Bolívar en Bogotá. Así que tendremos que moverlos a su ubicación correcta. Si haces click sobre el marcador gris, verás los datos adicionales del primero en la lista (el General Rafael Reyes). Su dirección, en ese entonces, era 50, Calle 16 (el número 50 de la Calle 16). Encontrar la dirección en el mapa será relativamente sencillo ya que cada cuadra tiene la numeración de inicio y término escrita en cada esquina. Si te fijas, la numeración de las “Carreras” (vías verticales) aumenta hacia el Norte con los números pares e impares de Este a Oeste, mientras que la numeración de las “Calles” (vías horizontales) aumenta hacia el Oeste con los números pares e impares de Norte a Sur:

Address numbers

Como puede ser que no sepamos exactamente dónde estaba una dirección, pondremos los marcadores en su ubicación estimada. Para hacerlo, es necesario que actives el modo de edición, haciendo click en el ícono editar:

Edit icon

Los marcadores tendrán ahora un borde rosado y los podrás mover donde quieras. Una vez ubicados en su posición correcta, recuerda guardar, haciendo click sobre el botón “Save”:

Moving points around

Hay algunas direcciones más complejas que otras, pero como podrás imaginarte, esta es una tarea bastante agradable, porque literalmente, te pierdes en las calles de Bogotá de 1891. Un aspecto interesante de este mapa es que los edificios de gobierno aparecen coloreados con los tonos de la bandera colombiana. Cuando encuentres la casa de Rafael Núñez Moledo, el entonces presidente en ejercicio, notarás que su dirección coincide con uno de esos edificios del color de la bandera colombiana; esa es la Casa de Nariño.

Guardando el GeoJSON.

Ahora, tenemos que generar la versión final del archivo GeoJSON para crear el mapa interactivo. Simplemente selecciona Save > GeoJSON en el menú de Un archivo llamado map.geojson se descargará en tu computador. Si prefieres, puedes descargar el que hice yo.

3) Haciendo un mapa del 2014 personalizado (opcional).

En verdad, lo que queremos es poder comparar cómo ha cambiado Bogotá desde 1891 a nuestros días. Entonces, lo que necesitamos es un “mapa base”, que básicamente, es lo que aparece en tu pantalla cuando cargas un mapa (esperemos, exacto) “color vainilla” de calles del mundo actual. Puedes usar la cuadrídula estándar de OpenStreetMap o también, puedes usar un servicio como MapBox para generar un mapa completamente a tu gusto (MapBox usa datos OSM). MapBox ofrece bastantes alternativas: te deja cambiar los colores, elegir qué se muestra (calles, edificios, parques, etc.) e incluso te permite usar imágenes satelitales.

No voy a describir cómo hacer tu propio mapa en MapBox. Mejor, puedes leerlo en su excelente tutorial. Una vez que estén listos, tienen que guardar el identificador del mapa que crearon, que es algo así como usuario.k53dp4io. Puedes usar la página de proyectos de MapBox para ver todos sus mapas y copiar fácilmente el ID al bloc de notas:

MapBox Map ID

NOTA: Si no quieren explorar el proceso de personalizar su propio mapa, pueden usar el ID de alguno de los ejemplos de MapBox.

4) El montaje final.

Ya tenemos todas las piezas para ensamblar nuestro mapa interactivo. Para eso tenemos:

  • los datos del mapa en formato GeoJSON;
  • el tileset del mapa de 1891;
  • el tileset del mapa actual o el ID de MapBox del mapa de 2014.

El prototipo del mapa interactivo lo armaremos en JSFiddle, una herramienta que permite crear y testear rápidamente código HTML/JavaScript/CSS. Revisa este breve tutorial para que te familiarices con la interfaz.

JSFiddle tiene cuatro paneles principales:

  • Código HTML (arriba a la izquierda);
  • Código CSS (arriba a la derecha);
  • Código JavaScript (abajo a la izquierda);
  • Resultado final (abajo a la derecha).

JSFiddle se encarga de ensamblar los componentes de los tres códigos en el resultado, cada vez que presionas “Run” (arriba, barra azul).


En este ejemplo, la parte de HTML y CSS son muy sencillas. Sólo necesitamos un área rectangular en la página, en la que ubicaremos el mapa y todos sus controles.

Primero, el elemento HTML en el que ubicaremos el mapa. Escribe o copia y pega esto en el panel HTML:

Con este código, creas un elemento div cuyo identificador es map y, como te podrás imaginar, contendrá al mapa. Ahora, necesitamos darle “estilo” a este elemento (debe tener alto, ancho, altura y, si queremos, bordes y otros atributos). El estilo se controla con el código CSS. Escribe o copia y pega lo siguiente en el panel CSS:

Al hacer esto, el elemento, cuyo identificador es map, tendrá una altura y un ancho de 400 pixeles (el prefijo # significa “ID” en CSS). Por supuesto que pueden hacer el rectángulo más grande (si tu monitor es lo suficientemente grande) o aplicarle algunos otros atributos entre las llaves { } (por ejemplo: background-color: #f00; para un fondo rojo, si quieres ver el elemento sin el mapa) pero en realidad, preferiría que lo mantuvieras lo más sencillo posible.

Si presionas “Run” en este momento, no verás mucho (a menos que hayas añadido algún color de fondo o borde al elemento). En cualquier caso, ese es todo el HTML y CSS que necesitas por el momento.

Agregar el MapBoxJS.

Para visualizar el mapa y hacerlo interactivo necesitaremos de algunas piezas adicionales y un poco de JavaScript. Mencioné hace un rato Leaflet y MapBoxJS. Leaflet está incluido en MapBoxJS, así que más tarde nos ocuparemos de él.

MapBoxJS se compone de dos archivos separados: uno JS y otro CSS. Ya tenemos una idea de qué es lo que hace el CSS. El archivo JavaScript contiene toda la magia del mapeo interactivo. Estas son las URLs de los archivos en cuestión (Esta no es la más reciente versión de MapBoxJS pero no hay que preocuparse, funcionará):

Archivo CSS:

Archivo JavaScript:

En la columna de la izquierda de JSFiddle busca la sección “External Resources”. Ahora, copia estas URLs y pégalas en la caja JavaScript/CSS URI y luego presiona el botón +. Verás que algo como esto aparece después de hacerlo:

jQuery in JSFiddle
Este es tu “fiddle” una vez has agregado los dos archivos de MapBoxJS

Esto hará que JSFiddle cargue los archivos la próxima vez que hagas clic en el botón “Run”.

¡Hola mapa!

¡Ahora sí viene la parte que hemos estado esperando! Escribamos unas líneas de JavaScript para poder ver el mapa de 1891. Copia y pega esto en el panel de JavaScript:

…y presiona “Run”. Esto es lo que deberías ver:

Hello map
¡Tu primer mapa web!

Gracias a Leaflet, es así de fácil trabajar con mapas web.

NOTA: No voy a entrar en detalles respecto de los diferentes aspectos de las APIs de Leaflet o MapBoxJS. Cada uno tiene sus propios tutoriales y ejemplos.

Lo que sí voy a hacer es dar algunos snippets y explicar, en términos sencillos, para qué sirven. La idea es que copies, pegues, hagas clic en “Run” y que la magia ocurra5. Luego podrás investigar, probar y resolver cómo hacer otras cosas por tu cuenta.

Trabajando con múltiples tilesets.

Habrás notado que el mapa es completamente blanco, a excepción del mapa de 1891. Esto es bueno y ocurre porque el tileset sólo tiene el mapa rectificado y nada más. Necesitamos un tileset adicional, del 2014, para poder comparar (podemos usar el ID de un mapa de MapBox, en caso de que no hayas creado el tuyo en el paso 3 de más arriba). Reemplazaremos el código JS con uno nuevo que incluirá:

  • Información de la fuente y/o atribución del mapa;
  • el tileset del 2014;
  • una herramineta de control que nos permitirá cambiar entre un tileset y otro.

Este código debe reemplazar el anterior código JS:

Si miras con detención este código, te darás cuenta que es bastante similar al que habíamos usado antes. La diferencia principal está en los datos de atribución y en los tilesets de MapBox (que incorporamos con su respectivo ID del mapa). La herramienta de control, son sólo dos líneas: la primera, que crea la variable “mapa base” y que soporta los tilesets (puedes agregar cuantos sets quieras); y la segunda, que crea “el control” y lo incrusta en el mapa. Veamos el control en acción:

Tile set magic
Fíjate cómo cambia la atribución (al pie del mapa) al cambiar de un tileset a otro

¡Ya casi terminamos!

Ahora lo único que falta es que podamos desplegar nuestros datos. Leaflet hace este proceso bastante sencillo porque es soporte nativo de GeoJSON. Bastan unas pocas líneas de código… pero primero debes borrar la linea que hace zoom map.setView([4.598056, -74.075833],14). Ahora pega este código en la parte de abajo del panel JS:

Debes copiar el código GeoJSON del archivo de texto que descargaste de y pegarlo en donde dice 'pegar_geojson_aca_mantener_comillas'. Asegúrate de conservar las comillas sencillas: ''. Hecho el cambio, esa línea debiera verse como esta (por brevedad reemplacé el contenido de las “features” con un …):

Ahora, reemplacemos la función del zoom con map.fitBounds(geolayer.getBounds()). Esto hace al mapa “más inteligente”: en lugar de especificar de forma manual la longitud, latitud y el nivel del zoom, dejamos que Leaflet calcule el área que ocupa el set de marcadores con getBounds() y entregue ese valor al mapa mediante la función fitBounds(). Voilá, el zoom del mapa muestra ahora todos los marcadores. Si quieres agregar algunos más… ¡el área cambiará automáticamente!

También puedes agregar puntos u otra información adicional sobrepuesta en el control de capas. Sólo tienes que crear una variable similar a la que creamos anteriormente y actualizar el código de creación, por ejemplo:

Cuando presiones “Run” deberás ver algo así:

Hello pins
El mapa con datos

NOTA: Asegúrate de mover el código de creación del control L.control.layers por debajo de donde está el GeoJSON. La variable geolayer necesita existir para poder ser añadida a as otras capas. Puedes guiarte por mi resultado en JSFiddle si necesitas más detalles.

Otra línea importante es la de la función L.geoJson() que es la encargada de regular el comportamiento de todos los atributos descritos por map.geojson. Leaflet/MapBoxJS tiene por defecto íconos azules para los marcadores, pero pueden ser modificados si quisieran. L.geoJson() también permite agregar interacción a los marcadores. Si ahora hacemos click con el botón derecho, no pasa nada.

Marcadores que cobran vida.

Me gustaría que, al hacer clic sobre un marcador, apareciera una ventana o “popup” con la información que asociamos a cada uno de ellos (en las properties de cada punto). Para lograrlo, tenemos que hacer dos cosas:

  1. Crear una función que construya y despliegue el popup para cada punto (marcador).

  2. Modificar el llamado L.geoJson() para que utilice esta función.

Leaflet tiene la función bindPopup(), que hace precisamente eso: dibuja una caja con un texto para un determinado layer (el término en inglés para los elementos que se dibujan en el mapa). Este texto puede incluir HTML. Copia y pega este código, debajo de todo lo que llevas hasta el momento:

Esta función showPopup() recibe un feature, la pieza de GeoJSON que contiene toda la información (geometría y propiedades), y un layer (en nuestro caso, el marcador azul). Estos dos parámetros son procesados automáticamente por la función L.geoJson(). showPopup() extrae las propiedades de cada atributo (nombre, dirección, etc.) y las articula en una cadena HTML que luego es usada para crear el popup.

Pero para que funcione, tenemos que conectar la función showPopup a algo. Para hacerlo, debemos modificar la actual línea de L.geoJson de la siguiente forma:

…solamente estamos agregando , {onEachFeature: showPopup} después de geodata. Lo que hicimos fue decirle a Leaflet que aplique la función showPopup a cada atributo en GeoJSON.

NOTA: Si nuestro GeoJSON tiene multiples tipos de atributos (por ejemplo: puntos, líneas o polígonos) es importante tener en mente que la misma función será aplicada a cada uno de ellos. Por ejemplo, los polígonos tienen un área, pero los puntos no; entonces será necesario que revisemos si el atributo sobre el que clickeamos tiene área antes de intentar usar la función fitBounds en el mapa.

Al cargar el mapa y hacer clic sobre un marcador, debiera verse así:

A popup!

Se ve bastante bien y todo, pero… ¿no sería mejor ver la foto y quizás linkear a la página que corresponde del directorio?

¡Hagamos eso!

Remplacemos la función showPopup con esta:

Lo que acabamos de hacer fue agregar una cosa más para el popup: Si key es igual a “Page” linkeamos al directorio y si key es igual a “Photo” construimos un contenedor para la imagen que la despliega a 150 pixels de alto (sólo en caso de que sea demasiado grande).

Así es como se veía el Sr. Núñez:

Rafael Núñez bio

…digno de un presidente!

Y, ahora sí, casi terminamos.


Lo último sería compilar estos tres snippets de código en una página HTML para que puedas publicar tu nuevo mapa en alguna parte. No te preocupes, para esto hay otra plantilla que tiene marcados los sitios en los que debes pegar el CSS, HTML y JS. Guarda todo el código como un archivo .html y publícalo donde quieras:

Puedes ver el mapa terminado aquí. Sólo hice algunas modificaciones mínimas al CSS para que se viera mejor en la ventana del navegador.

Ojalá este tutorial sea útil. Cuéntame si tienes algún comentario o sugerencia.

  1. Similar a lo que ocurre con la música cuando se convierte de calidad CD a MP3.
  2. Esta explicación puede ser útil para una introducción más profunda sobre cómo funcionan los tilesets en los mapas web.
  3. No hice una investigación acuciosa de los nombres, así que puede ser (aunque es improbable) que existan homónimos.
  4. De
  5. ¡Todo debiera funcionar así!

From Paper Maps to the Web: A DIY Digital Maps Primer

publicado en arte,diseño,interacción,programación,tips,web por mga en January 8, 2015

Este post fue publicado inicialmente en los blogs de NYPL. Versión en español pronto.

I was invited to the National Library of Colombia’s 2nd Digital Book Week as a speaker and to give a workshop on digital mapping tools. I thought it would be useful to share that workshop since it encompasses a lot of different processes and tools that make digital cartography today very accessible. It is a primer on working with various free web mapping tools so you can make your own awesome maps.


You will make this. This tutorial assumes you have a digitized map and some data you want to overlay on it. The general steps covered are:

  1. geo-referencing the scanned map so that web tiles can be generated
  2. generating GeoJSON data to be overlaid
  3. creating a custom base map (to serve as reference/present day)
  4. integrating all assets in an interactive web page

Note: This tutorial assumes you are using Mozilla Firefox, Apple Safari or Google Chrome. You will be playing with the developer console and I don’t have multi-browser instructions.

Let’s get started!

This is what we want to make. It is an 1891 map of Bogotá available in the National Library of Colombia (link requires Flash Player) annotated with some data found in an 1888 Bogotá City Directory.

1) Geo-referencing

The first step after scanning a map is to add geographical data to it; to establish an equivalence between its pixels and the geographic location they represent. This is called geo-referencing. This process will distort the scanned image:

Original scan
Original scan (shrunk, of course)

…to match the Mercator projection which is used in most web mapping projects such as OpenStreetMap or Google Maps:

Geo-referenced scan in Mercator projection
Geo-referenced scan in Mercator projection

The amount of distortion will depend on the quality of the survey, preservation state and original projection of the map. You may be asking: how did this magically happen? There’s commercial and open-source software that allows you to geo-reference images but the point of this tutorial is doing all of this without installing any software other than your web browser. Enter: The Map Warper! Map Warper is a web tool that lets you upload your scanned maps and provides a simple interface for you to geo-reference them (or “rectify” in geo parlance). Referencing boils down to you telling what part of the scanned map (left) corresponds to what part of the Mercator projection (right):

Map Warper
The split-view rectification interface in Map Warper

Notice the pins in the image. Each pin has a number and the same pin is present in both views. From them you can tell that North in the scan is pointing leftwards while East is pointing upwards. The more pins you add, the more precise the referencing will be but the slower the final image generation. However, image generation happens only once so I wouldn’t worry too much about that. It’s more an issue of how many pins you are willing to add. The map in this tutorial has 101 pins.

A final consideration in this process is to make sure you get a high-quality geo-referenced image after distortion. The process of distorting the original image is called resampling 1. In the Map Warper’s Advanced options you can set the method from the low-quality but fast Nearest Neighbour to high-quality but slow Cubic Spline:

Resampling method selection
Select “Cubic Spline” in the Resampling Method option

You can view the final map here. You can also download high-resolution assets in the Export tab. However, I think the main perk you get from the Map Warper are the tiles. It’s that URL template you see here:

Map Warper
You can find the tile URL in the “Export” tab

The template is:{z}/{x}/{y}.png

You will need this URL! Keep it somewhere safe. Map Warper has a tile-generating engine that uses the geo-referenced image to produce square map tiles at different zoom levels and coordinates so that only the necessary parts of the interactive map get displayed as you use it2. This is an example tile:

a web map tile
Web maps are made up of millions of these

2) Data extraction

We have the map. Now we want to figure out what data to show on it. Our example uses this 1888 City Directory of Bogotá, Colombia’s capital city. This directory is information-rich, containing tens of thousands of person names (each with address and occupation), dozens of different occupations (described in page 4) and advertisements (along with many store addresses and owner names).

The directory provides an interesting view of life in late XIX century Colombia: lawyers, photographers and accountants share pages with saddlers and blacksmiths. I went the boring route and looked for some prominent politicians of the time, such as then-sitting president (page 222, first in the second column). The current list contains seven people: four presidents, a vice-president, a minister and an acting president3. The list includes:

  • name
  • office (highest office held in the Colombian executive branch)
  • term
  • page (where it appears in the directory)
  • occupation (as displayed in the directory)
  • address
  • Wikimedia Commons photo URL
  • latitude, longitude (a placeholder set to downtown Bogotá that we will change in this step)

Download the CSV list

You can create your own list from other data you find more interesting or useful. Make sure to include latitude and longitude columns and save it as a comma-separated list.


So far our data is contained in a comma-separated list, but web mapping tools generally use the GeoJSON standard. GeoJSON is based on JSON which is one of the most popular ways of structuring data in the web. GeoJSON uses the concept of “features” to describe geographic data. Those features can be points (as is our current case) or more complex geometries such as lines, multilines and polygons. Each feature is described by its geometry (the point, line, polygon itself) accompanied by its properties which is whatever extra data you want to associate with it (in our case, a person’s name, address, photo, etc.). For example4:

We need to convert our spreadsheet into a GeoJSON object and then update the placeholder latitude and longitude values to the proper values. We will use the map itself to help us figure out those. We need a tool that lets us generate GeoJSON that we can easily manipulate.

Enter! This is “a quick, simple tool for creating, viewing, and sharing maps”. has this nifty interface we can use to create the GeoJSON we need.

Go ahead and open in a new browser window. you will see the default map at full zoom out. Now we need to do a little hacking. Right-click somewhere on the map and select Inspect Element:

Right-Click -> Inspect Element
Right-Click ? Inspect Element

This opens an advanced developer view that let’s you view and modify the code of the page you are viewing (in this case, the map interface). includes a programming interface (API) that lets you control the map being displayed. The core of this site is MapBoxJS, which is itself built on top of Leaflet, an “Open-Source JavaScript Library for Mobile-Friendly Interactive Maps”. I mention both because, for the most part, whatever works on one of them works on the other (do read the documentation before making any decisions!) and I will be referring to it as Leaflet instead of MapBoxJS.

In the Console tab you’ll see some text and, at the bottom, a cursor where you can execute JavaScript code. You’ll see some comments from the creator of and a row where you can type new JavaScript commands. Type this in that area and press ENTER (refer to the animated GIF below):

This will center and zoom the map in Bogotá, Colombia, the area covered by the 1891 map. Now type this:

…and press ENTER. This will add the tile layer itself. Notice that line of code includes the URL you copied in step 1. The end result will look something like this:

Before and after executing the commands
A quick “hacking” of

You can now close the development window (not the browser window!).

Note: You will need to re-apply this code every time you load since it doesn’t save modifications made via console. You can save the data you add to the map by logging in.

Adding data to

Now we will use this modified version of the map as a base to properly geo-locate the CSV list of presidents.

Drag the CSV file you downloaded on the map:

drag and drop magic
Drag and drop magic in

You will notice how the data is immediately converted to GeoJSON (right pane) and the map zooms in to show the points that represent each president (left pane). You can see a small green message (top left) showing seven features were imported.

But the 1891 map disappears! No worries. This just means that the map is zoomed in “too close to the ground” and the tile URL template does not have images up to that level. Zoom out a bit and you will see the 1891 map appear again.

Moving the points around

The points in the CSV are all geo-located on top of each other on the same point in Bogotá’s Plaza de Bolívar. We need to move them to their proper location. If you click the gray pin you will see the additional data for the topmost one (General Rafael Reyes). His address at the time was 50, Calle 16 (50 16th Street). We need to find that address in the map.

Finding the address will be relatively easy since each block has its starting and ending address numbers written on the corners. You will notice that “Carrera” (vertical-ish streets) numbers increase northward with odd numbers east and even numbers west while “Calle” (horizontal-ish streets) numbers increase westward with odd numbers south and even numbers north:

Address numbers

We will place the point in the approximate location between corners in a given block. To do so, activate editing mode by clicking the Edit icon icon. Pins will have a pink outline and you can move them around. Place the pins in the desired location and click “Save” to commit the changes:

Moving points around

There are some tricky addresses but this task can be quite enjoyable since you literally get lost in 1891 Bogotá. An interesting aspect of this map is that government buildings are colored with the Colombian flag. When you place Rafael Núñez Moledo, the sitting president at the time, you will notice that his address matches one of those flag-colored buildings (the Casa de Nariño).

Saving the GeoJSON

Now we must generate the final GeoJSON that we will use to create our interactive map. Simply select Save > GeoJSON in the editor menu. A file called map.geojson will be generated and downloaded to your computer. You can also just download the one I did, cheater!

3) Creating a 2014 custom map (optional)

We want to be able to compare this 1891 map with present day Bogotá so we can see how things have changed over time. We need a “base map” which is basically what has when you load it: a (hopefully accurate) “plain vanilla” street map of the present day world. You could use the standard OpenStreetMap tiles or use a service such as MapBox to produce a completely custom map (MapBox uses OSM data). MapBox is quite powerful: it lets you change colors, customize what gets shown (streets, buildings, parks, etc.) and even use satellite imagery!

I’m not going to describe how to create your own map in MapBox. I will leave that to their excellent tutorial. When you’re done, you will need to write down the Map ID which looks something like username.k53dp4io. You can use the MapBox projects page to see all your maps and easily copy the ID to clipboard:

MapBox Map ID

NOTE: If you don’t want to go through the process of customizing your map, you can use an example MapBox ID later.

4) Final assembly

We now have all the assets required to assemble our interactive map:

  • map data in GeoJSON format
  • a tile template for the 1891 map
  • a tile template or MapBox ID for the 2014 map

We will prototype the interactive map in JSFiddle, a tool that lets you quickly create and test HTML/JavaScript/CSS code. Check out this quick tutorial to familiarize yourself with the interface.

JSFiddle has four main panes:

  • HTML code (top left)
  • CSS code (top right)
  • JavaScript code (bottom left)
  • The end result (bottom right)

JSFiddle takes care of assembling the three code components into the result every time you click “Run” (in top, blue bar).


In this example the HTML and CSS parts are very simple. We only need a rectangular area in the page that will display the map and all its controls.

We need an HTML element where the map will go. Type or copy/paste this in the HTML pane:

With this code we create a div element whose identifier is map and, as you can imagine, it will contain the map. We now need to “style” the element (give it a width and a height and, if you want to, borders and other attributes). Styling is controlled with CSS. Type or copy/paste this in the CSS pane:

This applies a width and a height of 400 pixels to the element whose identifier is map (the # prefix means “id” in CSS). Of course you can make the rectangle bigger (if your monitor is big enough) and apply other attributes between those { } brackets (e.g.: background-color: #f00; for a red background if you want to see the element with no map) but I just wanted to keep it very simple.

If you click “Run” now you won’t see much (unless you added a background color or a border to the element). That’s all the HTML and CSS you will need for now.

Adding MapBoxJS

To present the map and make it interactive we will need some external assets and JavaScript. I mentioned Leaflet and MapBoxJS before. We are going to need them in order to present and control the map. Leaflet is included in MapBoxJS so we just need to worry about the latter. MapBoxJS is composed of two separate files: a JS file and a CSS file. You already have an idea of what the CSS file does. The JavaScript file contains all the interactive mapping magic. These are the URLs to the files in question (note that it is not the latest MapBoxJS version but no worries, it will work):

CSS file:

JavaScript file:

In the left column in JSFiddle find the “External Resources” section. You need to copy those URLs and paste each in the JavaScript/CSS URI box and click the + button. You will see something like this after you do it:

jQuery in JSFiddle
Your “fiddle” once you add the two MapBoxJS files

This will make JSFiddle load those files the next time you click “Run” and from then on.

Hello map!

Now comes the part we’ve been waiting for! Let’s write some JavaScript so we can see the 1891 map. Write this in the JavaScript pane:

…and click “Run”. This is what you should see:

Hello map
You first web map!

Thanks to Leaflet, it’s that easy to work with web maps.

Note: I’m not going into details here about the different aspects of the Leaflet or MapBoxJS APIs. They each have their own tutorials and examples. I will instead give some code snippets and superficially explain what they do. You will copy, paste and click “Run” and magic will happen5. You will later figure out how to do more awesome things on your own.

Managing multiple tile sets

You may notice that the map is all white except for the 1891 map and that is good. The tile set URL only has the rectified map on it and nothing else. We need to have an additional 2014 tile set to compare (I will use an example MapBox Map ID, in case you did not create your own in step 3 above). We will replace the JS code with new one that will contain:

  • some attribution information for the map (useful for when you want to, you know, attribute data in the map)
  • the 2014 tile set
  • a control that will let us swap one tile set for another

This code should replace your previous JS:

If you look throught this code you will notice it is quite similar to what we had before. The main differences are the addition of attributions and MapBox tile sets (via the map ID). The control itself is two lines: one to create a baseMaps variable that will hold the tile sets (you can add as many tile sets as you want) and another to create the control and add it to the map. Behold the control in action:

Tile set magic
Notice how the attribution changes when you toggle the tile sets

We’re almost there! We now need to display our data. Leaflet makes this process quite easy since it natively supports GeoJSON. The process is just a few lines, but first remove the map zoom function map.setView([4.598056, -74.075833],14). Now paste this code at the bottom of the JS pane:

You need to copy the GeoJSON output from the text file you downloaded from and paste it where you see 'paste_geojson_here_keep_quotes'. Make sure you keep those quotes! That line should end up looking something like:

We replaced the zoom function with map.fitBounds(geolayer.getBounds()). This makes the map “smarter”: instead of us typing longitude, latitude and zoom level by hand we let Leaflet calculate the bounding area for the set of points provided with getBounds() and pass that as a value to the map’s fitBounds() function. Voilá, the map now zooms to show all the points in the set. If you add more points the bounds will change automatically!

You can also add the points and any other data overlay to the layer toggler. You just need to create a variable similar to the one you created for the tile sets and update the control creation code:

You will see something like this when you click “Run”:

Hello pins
Your map with custom data on it

Note: Make sure to move the control creation code L.control.layers to a point below where the GeoJSON is being parsed. The geolayer variable needs to exist for it to be added to the overlays. Refer to my JSFiddle result for details.

Another important line is the one with the L.geoJson() function. This function parses all the features described by the map.geojson. Leaflet/MapBoxJS have default blue pin icons for point features which you can customize if you want. L.geoJson() will also let us add some interaction to the pins. Right now clicking them does nothing.

Making the pins come alive

We want to click on the pins and show a popup box with the data we have associated to it (in the feature’s properties). We need to do two things:

  1. a function that will build and present the popup for a given feature (point)
  2. modify the L.geoJson() call to use this function

Leaflet’s bindPopup() layer function does just that: draws a box with text next to a given layer. This text can be marked up with HTML. Copy/paste this code below all you have so far:

This showPopup() function receives a feature, the piece of GeoJSON that contains all the information (geometry and properties), and a layer, the same GeoJSON as displayed by Leaflet (in our case, the blue pin). These two parameters are passed automatically by the L.geoJson() function. showPopup() then loops through each property in the feature (name, address, etc.) and builds an HTML string. This string is used as the markup for the popup.

We have not connected showPopup to anything. Modify your current L.geoJson line as follows:

…you are just adding , {onEachFeature: showPopup} after geodata. This tells Leaflet to apply the showPopup function for each feature in the GeoJSON.

Note: If your GeoJSON contains multiple types of features (e.g.: points, lines and polygons) you need to keep in mind the same function will be applied to all of them. For example, polygons have bounds but points do not. You will need to check to see if the feature being clicked has bounds before trying to fitBounds the map.

Running the map and clicking on a pin will result in something like this:

A popup!

This is nice and all but wouldn’t it be better to actually see the photo and maybe link that page number to the directory itself? Let’s do just that! Replace the showPopup function with this one:

We just added a check in the loop: if key equals “Page” we build a link to the directory and if key equals “Photo” we build an image tag and constrain the height to 150 pixels (just in case the image is too big).

This is how Mr. Núñez looks like now:

Rafael Núñez bio

…worthy of a president!

And we’re done!

Wrapping it all up

You will want to compile these three code snippets in an HTML page to publish your new map somewhere. Worry not, below is a code snippet that has the requisite spots for you to paste CSS, HTML and JS. Save all the code as a .html file and publish it somewhere:

You can see the finished map here. I made minor modifications to the CSS to fill the browser window.

Hope you found this tutorial useful. Drop me a line if you have any comments or questions!

  1. Similar to what happens with music when converted from CD quality to MP3.
  2. Read this explanation for a better introduction on how web map tiles work.
  3. I did not thoroughly research the names in question so it may be (however unlikely) that they are homonyms.
  4. From
  5. Everything should work this way!

Generative ebook covers

publicado en general,programación,tipografí­a,visualización por mga en October 10, 2014

Este post fue publicado inicialmente en los blogs de NYPL. Versión en español pronto.


Finding better covers for public domain ebooks

Here at NYPL Labs we’re working on an ebook-borrowing and reading app. On the technical side, Leonard Richardson is doing all the back end magic, consolidating multiple data sources for each book into a single concise format: title, author, book cover and description. John Nowak is writing the code of the app itself (that you will be able to download to your phone). I am doing the design (and writing blog posts). Many of the ebooks we will be offering come from public domain sites such as Project Gutenberg. If you spend a few minutes browsing that site you will notice that many of its ebooks either have a really crappy cover image or none at all:

PG cover PG cover PG cover

Book covers weren’t a big deal until the 20th century, but now they’re how people first interact with a book, so not having one really puts a book at a disadvantage. They are problematic, and not only in ebooks. It’s difficult to find high-quality, reusable covers of out-of-print or public domain books. There are some projects such as Recovering the Classics that approach this problem in interesting ways. However, we at NYPL are still left with very limited (and expensive) solutions to this problem.

Given that the app’s visual quality is highly dependant on ebook cover quality (a wall of bad book covers makes the whole app look bad) we had to have a solution for displaying ebooks with no cover or a bad cover. The easy answer in this situation is doing what retail websites do for products with no associated image: display a generic image.

iTunes no cover S&S no cover Abrams no cover

This is not a very elegant solution. When dealing with books, it seems lazy to have a “nothing to see here” image. We will have at least a title and an author to work with. The next obvious choice is to make a generic cover that incorporates the book’s title and author. This is also a common choice in software such as iBooks:

iBooks cover

Skeuomorphism aside, it is a decent book cover. However, it feels a bit cheesy and I wanted something more in line with the rest of the design of the app (a design which I am leaving for a future post). We need a design that can display very long titles (up to 80 characters) but that would also look good with short ones (two or three characters); it should allow for one credited author, multiple authors or none at all. I decided on a more plain and generic cover image:

NYPL cover 1

Needless to say this didn’t impress anyone; which is OK because the point was not to impress; we needed a cover that displayed author and title information and was legible to most people and this checked every box… but… at the same time… wouldn’t it be cool if


While discussing options for doing a better generative cover I remembered 10 PRINT, a generative-art project and book led by Casey Reas that explores one line of Commodore 64 (C64) code:

10 PRINT CHR$(205.5+RND(1)); : GOTO 10

This code draws one of two possible characters (diagonal up or diagonal down) on the screen at random, over and over again. The C64 screen can show up to 40 characters in a row. The end result is a maze-like graphic like the one seen in this video:

At the 2012 Eyeo festival, Casey Reas talked about this project, which involves nine other authors who are collected in this book. I highly recommend watching Reas’s presentation (link jumps to 30:11 when 10 PRINT is mentioned). The two characters–diagonal up and diagonal down–come from the C64 PETSCII character list which is laid out here on the Commodore keyboard:


Each key on the PETSCII keyboard has a geometric shape associated with it. These shapes can be used to generate primitive graphics in the C64 operating system. For example, here is a rounded rectangle (I added some space to make it easier to see each character):

5 3 3 3 9

2 0 0 0 2

2 0 0 0 2

a 3 3 3 b

In terms of the letters on the same keyboard, that rectangle looks like this:

B   B
B   B

10 PRINT was the starting point for my next ebook cover generator. In 10 PRINT a non-alphanumeric character is chosen by a random “coin toss” and displayed as a graphic. In my cover generator, a book’s title is transformed into a graphic. Each letter A-Z and digit 0-9 is replaced with its PETSCII graphic equivalent (e.g. the W gets replaced with an empty circle). I used Processing to quickly create sketches that allowed for some parameter control such as line thickness and grid size. For characters not on the PETSCII “keyboard” (such as accented Latin letters or Chinese characters) I chose a replacement graphic based on the output of passing the character into Processing’s int() function.

Colors and fonts

In order to have a variety of colors across the books, I decided to use the combined length of the book title and the author’s name as a seed number, and use that seed to generate a color. This color and its complimentary are used for drawing the shapes. Processing has a few functions that let you easily create colors. I used the HSL color space which facilitates generating complimentary colors (each color, or hue in HSL parlance, is located in a point on a circle, its complementary is the diametrically opposite point). The gist code:

This results in something like:


To ensure legibility and avoid clashes with the generated colors, I always use black on white for text. I chose Avenir Next as the font. The app as a whole uses that font for its interface, it’s already installed on the OS and it contains glyphs for multiple languages.

There are more (and better) ways to create colors using code. I didn’t really go down the rabbit hole here but if you feel so inclined, take a look at Herman Tulleken’s work with procedural color palettes, Rob Simmon’s extensive work on color, or this cool post on emulating iTunes 11’s album cover color extractor.


I created a function that draws graphic alternate characters for the letters A-Z and the digits 0-9. I decided to simplify a few graphics to more basic shapes: the PETSCII club (X) became three dots, and the spade (A) became a triangle.

I wrote a function that draws a shape given a character k, a position x,y and a size s. Here you can see the code for drawing the graphics for the letter Q (a filled circle) and the letter W (an open circle).

My cover generator calls drawShape repeatedly for each character in a book’s title. The size of the shape is controlled by the length of the title: the longer the title, the smaller the shape.

Each letter in the title is replaced by a graphic and repeated as many times as it can fit in the space allotted. The resulting grid is a sort of visualization of the title; an alternate alphabet. In the example below, the M in “Macbeth” is replaced by a diagonal downwards stroke (the same character used to great effect in 10 PRINT). The A is replaced by a triangle (rather than the club found on the PETSCII keyboard). The C becomes a horizontal line offset from the top, the B a vertical line offset from the left, and so on. Since the title is short, the grid is large, and the full title is not visible, but you get the idea:


There is a Git repository for this cover generator you can play with.

Some more examples (notice how “Moby Dick”, nine characters including the space, does fit in the 3×3 grid below and how the M in “Max” is repeated):





And so on:

Douglass Aesop

The original design featured the cover on a white (or very light) background. This proved problematic, as the text could be dissociated from the artwork, so we went for a more “enclosed” version (I especially like how the Ruzhen Li cover turned out!):

Doctorow Li Justice

We initially thought about generating all these images and putting them on a server along with the ebooks themselves, but 1) it is an inefficient use of network resources since we needed several different sizes and resolutions and 2) when converted to PNG the covers lose a lot of their quality. I ended up producing an Objective-C version of this code (Git repo) that will run on the device and generate a cover on-the-fly when no cover is available. The Obj-C version subclasses UIView and can be used as a fancy-ish “no cover found” replacement.

Cover, illustrated

Of course, these covers do not reflect the content of the book. You can’t get an idea of what the book is about by looking at the cover. However, Leonard brought up the fact that many Project Gutenberg books, such as this one, include illustrations embedded as JPG or PNG files. We decided to use those images, when they are available, as a starting point for a generated cover. Our idea is to generate one cover for each illustration in a book and let people decide which cover is best using a simple web interface.

I tried a very basic first pass using Python (which I later abandoned for Processing):


This lacks personality and becomes problematic as titles get longer. I then ran into Chris Marker and Jason Simon’s work, and was inspired:

Marker & Simon

I liked the desaturated color and emphasis on faces. Faces can be automatically detected in images using computer-vision algorithms, and some of those are included in OpenCV, an open-source library that can be used in Processing. Here’s my first attempt in the style of Marker and Simon, with and without face detection added:

no cv cv

I also tried variations on the design, adding or removing elements, and inverting the colors:

no cv line cv line no cv inverted

Since Leonard and I couldn’t agree on which variation was best, we decided to create a survey and let the people decide (I am not a fan of this approach, which can easily become a 41 shades of blue situation but I also didn’t have a compelling case for either version). The clear winner was, to my surprise, using inverted colors and no face detection:

flatland ten girls procopius

The final Processing sketch (Git repo) has many more parameters than the 10 PRINT generator:

Image Cover P5


As with many subjects, you can go really deep down the rabbit hole when it comes to creating the perfect automated book cover. What if we detect illustrations vs. photographs and produce a different style for each? What about detecting where the main image is so we can crop it better? What if we do some OCR on the images to automatically exclude text-heavy images which will probably not work as covers?

This can become a never-ending project and we have an app to ship. This is good enough for now. Of course, you are welcome to play with and improve on it:

BodyType v0.1

publicado en arte,diseño,interacción,kinect,programación,tipografí­a por mga en March 4, 2012

Create fonts by waving in thin air!

I have finally found some time to build a semi-standalone binary (Mac OS X 10.6 or better) of BodyType, my Kinect-based font creation software. This version supports only UPPERCASE A-Z and 0-9. If you want to create more glyphs, let me know. The download includes a README.txt file that, as its name indicates, you must read. BodyType v0.1 is dependent in other libraries and programs in order to create your fonts properly and that file explains how to install them. They all should be installed with MacPorts.

The code is also available for download in Google Code.


This project was done as part of the requirements to complete the Spring 2011 Interactive Art and Computational Design course with Professor Golan Levin in Carnegie Mellon University.

BodyType was built with openFrameworks and makes use of ImageMagick, FontForge and Potrace.

siguiente página »