20 Sep 2021 Crear un mapa web interactivo con D3
Al desarrollar un mapa web interactivo nos planteamos habitualmente el uso de librerías como OpenLayers o Leaflet, tal y como vimos en posts anteriores: ¿Leaflet o OpenLayers? o Mejorando nuestros mapas de Leaflet/OpenLayers con la librería Materialize. Pero también podemos desarrollar un mapa web interactivo con D3, tal y como expondremos en el siguiente post.
¿Qué es D3.js?
D3 es una librería JavaScript diseñada para la visualización de datos de forma dinámica e interactiva utilizando estándares web. Para ello, hace uso de tecnologías bien consolidadas como HTML5, SVG y CSS. Presenta además una gran popularidad, con 168M de descargas desde Febrero de 2015, y valorado con 98k estrellas –en el momento de escribir este artículo– en su cuenta de gitHub.
Tal y como puede constatarse en la página de ejemplos de D3.js, son muchas las representaciones de datos que se pueden llevar a cabo con esta librería. Mayoritariamente gráficos y diagramas, aunque también mapas web dinámicos e interactivos.
Añadir la librería D3
Para añadir a nuestro proyecto un mapa web interactivo realizado con D3, lo primero que hay que hacer es cargar la librería. Podemos añadir directamente el CDN:
<script src="https://d3js.org/d3.v7.min.js"></script>
o bien, si desarrollamos el proyecto con Node, instalar el paquete correspondiente:
npm install d3
Cartografía y proyecciones
Los datos geográficos a partir de los cuáles crearemos el mapa web interactivo con D3, pueden estar en formato GeoJSON. Se trata de un estándar abierto, basado en el formato JSON, y que permite representar puntos, líneas y polígonos, así como sus atributos no espaciales.
Tal y como veremos, la librería D3 ofrece las herramientas necesarias para convertir el GeoJSON a SVG (Scalable Vector Graphics), el formato con el que trabaja D3 de forma nativa.
Desde la página web de Natural Earth Data, podemos descargar la cartografía vectorial (en formato Shapefile) relativa a los límites administrativos de todos los países del mundo. Será esta cartografía con la que vamos a realizar nuestro mapa web interactivo.
Desde cualquier software SIG se puede convertir el archivo Shapefile a GeoJSON. O también se puede ejecutar directamente esta comanda con GDAL:
ogr2ogr -f GeoJSON countries.json ne_10m_admin_0_countries/ne_10m_admin_0_countries.shp
El sistema de referencia de los datos descargados de Natural Earth es el WGS84. Al generar el GeoJSON a partir de esta cartografía, hemos mantenido este sistema de referencia en el nuevo archivo. Aunque una vez en D3, ya veremos cómo resultará muy fácil modificar la proyección de los mapas generados.
Asimismo, d3-geo y d3-geo-projection ofrecen multitud de proyecciones para poder utilizar.
Código para generar un mapa web con D3
En el código html de la aplicación web, deberemos crear el espacio en el que ubicar el mapa. En este ejemplo, será en la etiqueta <svg> con el id map.
<!DOCTYPE html> <html> <head> <title>Webmapping con d3</title> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script> <link rel="stylesheet" href="style.css"> </head> <body> <h1>Mapas web interactivos con D3</h1> <p>Países del mundo</p> <svg id="map" width="50vw" height="50vh"></svg> <script src="main.js"></script> </body> </html>
Añadimos algunas propiedades para centrar el contenido en el fichero de estilos:
p, h1{ text-align: center; } #map{ align-content: center; } svg { display: block; margin: auto; border: 1px solid gray; }
Y las instrucciones para generar el mapa web con D3, en el fichero javascript:
// importamos la librería import * as d3 from "d3"; // cargamos el archivo json que hemos generado previamente // en este caso, el archvio lo hemos ubicado en un servidor apache d3.json("http://localhost/countries.json").then(geodata => { // almacenamos en una variable la proyección a utilizar // en este caso, utilizamos la proyección Natural Earth (http://www.shadedrelief.com/NE_proj/) let projection = d3.geoNaturalEarth1() // creamos el elemento SVG asignándole la proyección definida anteriormente let generator = d3.geoPath().projection(projection); // añadimos el SVG en el fichero html, justo en la etiqueta que hemos creado con el nombre svg. d3.select("svg") .selectAll("path") // añadimos los datos .data(geodata.features) .join("path") .attr("d", generator) // añadimos algunos estilos básicos en el mapa .attr('stroke', '#000') .attr('fill', '#fff') });
De este modo, y en pocas líneas de código, conseguimos realizar un simple mapa con D3.
Aplicar estilo a la cartografía
La librería D3 ofrece también la posibilidad de aplicar estilo a los datos, a partir de los valores de alguno de los campos. En este caso, vamos a crear un mapa de coropletas, en base al total de población de cada uno de los países. En la cartografía de Natural Earth, los datos de población se encuentran en un campo con el nombre POP_EST.
Utilizaremos la función d3.scaleThereshold para definir los rangos de valor y el color asociado a cada uno de ellos.
var escalaColor = d3.scaleThreshold() .domain([100000, 1000000, 10000000, 30000000, 100000000, 500000000]) .range(d3.schemeBlues[7]);
En domain se definen mediante un array, los límites del rango de valores apropiado a los datos a tematizar, mientras que en range, el color asociado a cada uno de ellos.
Para generar de forma automática la rampa de color, utilizamos otra función de D3: d3.schemaBlues. En este caso, usamos una rampa de color azul, aunque hay muchas otras disponibles.
Por último, deberemos cambiar el atributo que utilizamos inicialmente para asignar el color de relleno de cada una de las entidades del mapa.
//.attr('fill', '#fff') .attr("fill", function (d) { return escalaColor(d.properties.POP_EST); })
De este modo, en pocas líneas de código podemos dar estilo a los datos, pudiendo además modificar muy rápidamente tanto la escala de color como los rangos de valor .
Dotar de interactividad al mapa
También es posible dotar de interactividad al mapa, de tal forma que, por ejemplo, podamos consultar información de las entidades representadas.
En este caso, vamos a mostrar la información relativa al país sobre el que nos situemos, así como el total de población.
En primer lugar, en el archivo html creamos el div en el que se añadirá esta información.
<div class="info">El país seleccionado es: <span id="name"></span> con una población de <span id="population"></span> habitantes</div>
Por otro lado, en el archivo javascript, creamos una función que permita obtener el nombre del país y su población, así como añadir estos datos en el documento html:
var selectCountry = function(d){ var country_name = d.target.__data__.properties.FORMAL_EN; var population = d.target.__data__.properties.POP_EST; document.getElementById("name").innerHTML = country_name; document.getElementById("population").innerHTML = population; }
Y hacemos la llamada a esta función al detectar el movimiento del puntero sobre el mapa:
.on('mousemove', selectCountry )
El resultado es el que se muestra a continuación:
Conclusiones
La librería D3 nos permite elaborar mapas web interactivos utilizando lenguaje html, css y javascript.
En este post hemos visto cómo crear un mapa interactivo bastante simple. Pero las posibilidades que nos ofrece la librería son muy amplias, permitiendo elaborar visualizaciones complejas y dotándoles de interactividad.
La librería D3 puede ser, en este sentido, una alternativa a tener en cuenta en el desarrollo de proyectos de webmapping.