Cartogramas de desaparecidos: detrás de las cámaras

Imágen del cartograma de desaparecidos

Imágen del cartograma de desaparecidos

Recientemente, un compañero de CentroGeo y yo, publicamos un post en el blog de la redacción de Nexos en donde presentamos una serie de cartogramas para ilustrar la evolución espacio-temporal del fenómeno de desaparecidos. Lo que quiero hacer ahora, en esta publicación, es una especie de detrás de las cámaras de las visualizaciones que presentamos, hacer un pequeño tutorial sobre cómo hacer un cartograma simple usando D3.js y la librería de cartogramas desarrollada por Shawn Allen. Ahora, como la visualización que presentamos en esa ocasión tiene varios componentes (animación, gráficas de barras, etc), en lugar de detallar cómo la hicimos, mejor voy a presentar un cartograma simple: la transición entre el mapa original y el mapa deformado por una variable.

Preparando los datos

Lo primero que necesitamos es un mapa que deformar, para mantener las cosas simples, vamos a usar un mapa de México y deformarlo utilizando la población en cada estado (en esta liga puedes encontrar el archivo ).

Para poder crear un cartograma necesitamos que las geometrías de los polígonos estén codificadas topológicamente, es decir, que las fronteras de los polígonos estén codificadas a través de referencias a segmentos comunes. Este tipo de estructuras de datos tiene varias ventajas:

  •  podemos conocer qué polígonos son adyacentes a uno en específico sin usar operaciones geométricas (esto es importante porque las operaciones geométricas son computacionalmente costosas).
  • Ahorramos espacio porque las fronteras de los polígonos se codifican una sola vez.
  • Podemos deformar las fronteras conservando las relaciones entre los polígonos, por ejemplo, simplificar una geometría sin dejar huecos entre los polígonos.

Como vamos a usar D3.js, el formato natural para objetos geográficos en el GeoJSON, pero, para poder usar las ventajas de la topología, necesitamos usar topoJSON. La forma más sencilla de crear un topoJSON es usar mapshaper: simplemente subimos nuestro zip con el shape de los estados y lo exportamos como topoJSON.

Como el algoritmo que vamos a usar para hacer los cartogramas corre en el browser y no queremos que tarde demasiado tiempo en ejecutarse, es conveniente trabajar con una geometría simplificada de los estados de la república. Afortunadamente, mapshaper también nos ayuda a simplificar nuestros polígonos: seleccionamos la opción simplify del menú y seleccionamos algún algoritmo de simplificación (yo uso Visvalingam / weighted area, aunque para este caso cualquier algoritmo es bueno), después ajustamos el slider hasta un valor de alrededor del 4%, este es un buen compromiso entre simplicidad y detalle para hacer cartogramas. Después de esto exporta los datos como topoJSON y ya tenemos los datos preparados para empezar a hacer cartogramas.

Haciendo el mapa base

Lo primero que vamos a hacer es preparar un html para la página, en realidad lo único que necesitamos es un <div> para albergar el mapa:

También necesitamos importar las librerías que vamos a usar, D3.js, topojson.js y cartograms.js:

Ahora vamos a leer los datos (el topoJSON que creamos anteriormente), usando el parser de json:

Lo que estamos haciendo aquí es leer los datos del topoJSON usando d3.json y luego poner la topología y las geometrías en variables de javascript. Fíjate que para crear las geometrías estamos haciendo:

es decir, le estamos hablando a la capa mex_estados adentro del la topología (en general la capa se llama de la misma forma que el archivo, si tienes duda puedes explorar el objeto en la consola de javascript de tu browser).

También vamos a necesitar una proyección para desplegar los datos:

En este caso estamos usando mercator, pero puedes experimentar con diferentes proyecciones. El valor de translate se usa para centrar el mapa en la pantalla y la escala representa el nivel de zoom.

Entonces, hasta aquí lo que tenemos es la proyección definida y los datos de las geometrías que queremos usar para dibujar el mapa. El mapa va a estar contenido en un svg dentro del div #map-container, seleccionémoslos y pongámoslos en variables:

En las primeras líneas agregamos un svg al div del mapa y le pusimos un id para poder darle estilo más adelante. Después, agregamos un grupo (g) al svg y seleccionamos todos los paths al interior (esta es la manera clásica de trabajar en d3, esos paths no existen todavía, pero al seleccionarlos estamos declarando que los queremos crear cuando liguemos los datos a estos elementos del DOM), estos paths son (van a ser, pues) los contornos de los polígonos del mapa.

Ahora sí, ya que tenemos la proyección, los datos y los elementos del svg, podemos instanciar el cartograma y el d3.geo.path:

El d3.geo.path va a construir los contornos de los estados (los paths que declaramos arriba) a partir del topojson y la instancia de cartogram va a generar el path actualizado cuando deformemos las geometrías. En features estamos guardando las formas originales (geometries) y las relaciones de vecindad (topology).

Todo lo que necesitamos ahora es dibujar cada uno de los paths que van a ir en el g edos, para hacer esto, usamos la selección enter de edos:

Hasta aquí, lo que hemos creado es un mapa de los estados de la República Mexicana, naturalmente el siguiente paso sería colorear el mapa de acuerdo a alguna variable, sin embargo, para mantener las cosas simples y concentrarnos sólo en hacer un cartograma, les vamos a dar a todos los estados un estilo único, para hacer esto vamos a añadir un estilo para los polígonos:

Para ir resumiendo, hasta aquí tenemos un html con un sólo div y un script más o menos así:

Fíjate cómo las variables proj, carto, topology y geometry son globales, esto es para poder usarlas en la función que va a actualizar el mapa para producir el cartograma.

Actualizando el mapa.

Lo que nos hace falta ahora es actualizar el mapa original para deformarlo por una variable. Para hacer el código más legible vamos a hacer dos funciones, una que crea el mapa original y otra que actualiza los paths para deformar el mapa. La función para crear el mapa ya la tenemos, es el código del callback del d3.json arriba, solo hay que encapsularla en una función:

Dentro del callback del d3.json llamamos a la función que acabamos de crear:

Ahora sólo nos falta la función que actualiza los paths del mapa. Lo primero que necesitamos hacer es decirle a carto cuál es la variable que vamos a utilizar:

Lo primero que hacemos es fijar la escala en la que vamos a mapear la variable, para eso usamos una escala lineal y mapeamos el dominio, de 0 a 17,000,000 (esta es la población máxima de un estado de la República),  al rango de 0 a 1000. Luego usamos esa escala para calcular el valor con el que vamos a deformar los polígonos, es decir, el valor que regresa carto.value.

Ahora ya sólo falta actualizar cada uno de los paths:

Primero definimos los carto_features, que son los polígonos deformados y luego, usando una transición, actualizamos cada uno de los paths. Finalmente, encapsulamos este comportamiento en la función doUpdate():

 

Ahora, todo lo que nos falta hacer es ligar la función doUpdate() a una acción del usuario. En este caso vamos a agregar un div con texto y ligar la acción onClick del div a la función doUpdate:

Para terminar el ejemplo solo falta agregar un par de estilos al inicio del html para que todas las cosas se acomoden bien:

Con esto terminamos de hacer un cartograma sencillo, todo el código y el ejemplo funcionando lo puedes ver aquí

There are no comments

Join the conversation

Your email address will not be published. Required fields are marked *