Cómo hacer un mapa web de afectados por el covid-19 con Leaflet

El covid-19 supone una amenaza para la salud pública de todo el mundo. Para el seguimiento e información de la pandemia se emplean mapas que muestran el avance de la enfermedad por regiones y países. Una forma habitual de representar esos datos es mediante círculos graduados cuyo radio es proporcional al número de casos. Mediante la librería Leaflet podemos crear un mapa de estas características de forma sencilla.

En este artículo veremos lo sencillo que es crear un mapa web de afectados por el covid-19 con Leaflet. Te lo explicamos desde el principio.

mapa web de afectados por el covid-19 con Leaflet

Primeros pasos: los datos

Como vimos en el artículo mapa del coronavirus en tiempo real y descarga de datos en QGIS disponemos de datos actualizados facilitados por la Universidad Johns Hopkins (JHU), Maryland, EE. UU.

Esos datos una vez que los tenemos en QGIS los podemos exportar a formato GeoJSON utilizando las propias herramientas de la aplicación. En el artículo como crear un mapa web en leaflet a partir de GeoJSON explicamos como convertir un archivo shp en GeoJSON. El archivo obtenido lo editamos con un editor de texto para añadirle el nombre de una variable y lo guardamos como archivo JavaScript.  En este caso lo hemos llamado covid.js y lo incorporamos al proyecto de la siguiente forma:

 <script src="covid.js"></script>

Leaflet es muy fácil de aprender y sencillo de utilizar. Para incorporarlo a nuestra aplicación solo tenemos que escribir las referencias a sus archivos css y js.

<link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
   integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
   crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
   integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
   crossorigin=""></script>

Para crear el mapa necesitamos un lugar en la página web que lo aloje. Para eso creamos un espacio de la siguiente forma:

 <div id ="map"> </div>

Damos un estilo o lo que es lo mismo unas dimensiones a este id que hemos creado.

body {
        padding: 0;
	margin: 0;
		}
html, body, #map {
    	height: 100%;
		}

Estructura del código

Vamos a reunir lo que tenemos hasta el momento:

<!DOCTYPE html><html>
<head> 
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>Covid-19</title>
     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
   integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
   crossorigin=""/>
		  	
	<style> 
  	body {
	    	padding: 0;
	    	margin: 0;
		}
		html, body, #map {
    		height: 100%;
		}

	</style> 
</head>  
<body>
	 <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
   integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
   crossorigin=""></script>
	 <script src="covid.js"></script>
		

	 <div id ="map"> </div> 
	<script>

	</script>
	</body> 
</html>

Como se puede ver no es más que una estructura HTML típica en que hemos añadido la librería Leaflet, creado un <div> y añadido el archivo con los datos: covid.js

Dibujando marcadores  circulares

Una vez que tenemos la estructura geneal del código estamos en disposición de construir nuestro mapa. Lo primero es realizar una instancia a la clase L.map de Leaflet. Esta clase es el corazón de la librería y la que nos permite definir las características del mapa como el centro, nivel de zoom inicial, etc…

var map = L.map('map', {
		center: [40, -5],
		zoom: 3,
	});

Creado el mapa vamos a incorporar una capa base que contenga un mapa de OpenStretMap, lo que conseguimos mediante una instancia a L.tileLayer.

L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
			attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors.Datos: Universidad Johns Hopkins (JHU)',
			}).addTo(map);

PointToLayer

Leaflet utiliza de forma nativa el formato geojson mediante la clase L.geoJSON

Esta clase dispone de varias opciones siendo una de las más utilizadas PointToLayer. Con esta opción podemos crear unos marcadores con forma de círculo al que se le pueden asignar diferentes estilos. En primer lugar definimos unas propiedades para estos marcadores como su color, color de relleno, opacidad…

var MarkerOptions = {
    fillColor: "#FF4000",
    color: "#000",
    weight: 1,
    opacity: 1,
    fillOpacity: 0.8
	};

A partir de estas características ya se pueden crear los marcadores mediante una instancia a la clase L.geoJSON, en donde se pasa como parámetro el nombre de la variable que contiene los datos de covid.js.

var covidMundo = L.geoJSON(covid, {
		pointToLayer: function (feature, latlng) {
			return L.circleMarker(latlng, MarkerOptions);
					}						
		});
map.addLayer(covidMundo);

Representando los valores

La forma habitual de presentar los datos es mediante un círculo en que el radio se corresponde con los datos. En el ejemplo que estamos desarrollando vamos a establecer cuatro categorías. El radio de cada círculo se corresponderá con un intervalo en el número de afectados. Para realizar esta acción creamos una función que contenga los rangos de valores.

function getRadius(r) { 
		return r >= 100000 ? 25 : 
		r >= 10000  ? 15 : 
		r >= 5000  ? 7 : 
		r >= 1000 ? 3:  
				3; 
	};

function estilo_covid (feature) {
		return{
			radius: getRadius(feature.properties.Confirmed), 
			};
	};

Como vemos en el código anterior hemos creado en primer lugar la función getRadius que define cuatro intervalos en el número de infectado y les asigna un valor para el radio. En este caso el valor del radio está comprendido entre 3 y 25. A continuación se define la función estilo_covid que toma el valor de la propiedad «Confirmed» del GeoJSON.

Además de la representación gráfica vamos a crear un popup que muestre los datos al hacer clic sobre el marcador de cada país.

function popup_covid (feature, layer) {
	layer.bindPopup("<div style=text-align:center><h3>"+feature.properties.Country_Region+
        "<h3></div><hr><table><tr><td>Confirmed: "+feature.properties.Confirmed+
        "</td></tr><tr><td>Deaths: "+feature.properties.Deaths+
        "</td></tr><tr><td>Recovered: "+feature.properties.Recovered+        
        "</td></tr></table>",
        {minWidth: 150, maxWidth: 200});				
		};

Ahora solo tenemos que añadir estas opciones al mapa, para lo que modificamos la instancia a L.geoJSON que habíamos utilizado antes.

var covidMundo = L.geoJSON(covid, {
				pointToLayer: function (feature, latlng) {
						return L.circleMarker(latlng, MarkerOptions);
					},	
				style:estilo_covid,
				onEachFeature: popup_covid				
		});

De esta manera tan sencilla hemos creado un mapa que representa el número de infectado por covid-19 en cada país.

Añadiendo una leyenda

El mapa que hemos creado hasta aquí no estaría completo sin una leyenda que indique la simbología de los marcadores utilizados en relación a los datos.

En Leaflet las leyendas se incorporar como un control. Por lo tanto debemos utilizar la clase L.control para definir la leyenda y su posición en el mapa.

 var legend = L.control({position: 'bottomright'});

Ahora se definen los símbolos de la leyenda.

legend.onAdd = function (map) {

 var div = L.DomUtil.create('div', 'info legend');
 var grades = [1000, 5000, 10000, 100000];
 var labels = ['<strong>Número de afectados</strong>'];
 var categories = ['< 5000','5000-10000','10000-100000','>100000'];

 for (var i = 0; i < grades.length; i++) {
        var grade = grades[i];//*0.5;
   labels.push(
        '<i class="circlepadding" style="width: '+Math.max(8,(7-2.2*getRadius(grade)))+'px;"></i> <i style="background: #FF4000; width: '+getRadius(grade)*2+'px; height: '+getRadius(grade)*2+'px; border-radius: 50%; margin-top: '+Math.max(0,(9-getRadius(grade)))+'px;"></i><i class="circlepadding" style="width: '+Math.max(2,(25-2*getRadius(grade)))+'px;"></i> ' + categories[i]);
   }
 div.innerHTML = labels.join('<br>');
 return div;
 };
 legend.addTo(map);

Para que la leyenda se muestre correctamente hay que definir unos estilos. Para eso modificamos el <style> de nuestro HTML de la siguiente forma.

	<style> 
  	body {
	    	padding: 0;
	    	margin: 0;
		}
		html, body, #map {
    		height: 100%;
		}

   .info
   {
        padding: 6px 8px;
        font: 13px/16px Verdana, Geneva, sans-serif;
        background: white;
        background: rgba(255,255,255,0.8);
        box-shadow: 0 0 15px rgba(0,0,0,0.2);
        border-radius: 10px;
    }

   .legend {
        line-height: 35px;
        padding:7px;
        color: #555;
       }

   .legend i {
        width: 15px;
        height: 15px;
        float: left;
        margin-right: 8px;
        opacity: 0.7;
      }

    .circle
	 {
	float: left;
	border: 1px solid #222;
	border-radius: 50%;
	 }

	 .legend .colorcircle {
	border-radius: 50%;
	width: 15px;
	height: 15px;
	margin-top: 0px;
	 }
	.legend .circlepadding {
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.85);
	}
</style>

Título

Para finalizar incorporamos un título al mapa.

var title = L.control();
	 
	title.onAdd = function (map) {
		var div = L.DomUtil.create('div', 'info');
		    div.innerHTML +=
		    '<h2>COVID-19</h2>Número de afectador por país.(23-04-2020)';
		 return div;
	};
	 
	title.addTo(map);

El resultado es el mapa siguiente:

Código completo

A continuación escribimos todo el código para facilitar su lectura.

<!DOCTYPE html><html>
<head> 
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
    <title>Covid-19</title>
     <link rel="stylesheet" href="https://unpkg.com/leaflet@1.6.0/dist/leaflet.css"
   integrity="sha512-xwE/Az9zrjBIphAcBb3F6JVqxf46+CDLwfLMHloNu6KEQCAWi6HcDUbeOfBIptF7tcCzusKFjFw2yuvEpDL9wQ=="
   crossorigin=""/>
		  	
	<style> 
  	body {
	    	padding: 0;
	    	margin: 0;
		}
		html, body, #map {
    		height: 100%;
		}

.info
  {
        padding: 6px 8px;
        font: 13px/16px Verdana, Geneva, sans-serif;
        background: white;
        background: rgba(255,255,255,0.8);
        box-shadow: 0 0 15px rgba(0,0,0,0.2);
        border-radius: 10px;
    }

   .legend {
        line-height: 35px;
        padding:7px;
        color: #555;
       }

   .legend i {
        width: 15px;
        height: 15px;
        float: left;
        margin-right: 8px;
        opacity: 0.7;
      }

    .circle
	 {
	float: left;
	border: 1px solid #222;
	border-radius: 50%;
	 }

	 .legend .colorcircle {
	border-radius: 50%;
	width: 15px;
	height: 15px;
	margin-top: 0px;
	 }
	.legend .circlepadding {
	border-radius: 50%;
	background: rgba(255, 255, 255, 0.85);
	}

	</style> 
</head>  
<body>
	 <script src="https://unpkg.com/leaflet@1.6.0/dist/leaflet.js"
   integrity="sha512-gZwIG9x3wUXg2hdXF6+rVkLF/0Vi9U8D2Ntg4Ga5I5BZpVkVxlJWbSQtXPSiUTtC0TjtGOmxa1AJPuV0CPthew=="
   crossorigin=""></script>
	 <script src="covid.js"></script>
		

	 <div id ="map"> </div> 
	<script>
	var map = L.map('map', {
		center: [40, -5],
		zoom: 3,
	});

	L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
			attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors.Datos: Universidad Johns Hopkins (JHU)',
			}).addTo(map);

	var MarkerOptions = {
    fillColor: "#FF4000",
    color: "#000",
    weight: 1,
    opacity: 1,
    fillOpacity: 0.8
	};

	function getRadius(r) { 
		return r >= 100000 ? 25 : 
		r >= 10000  ? 15 : 
		r >= 5000  ? 7 : 
		r >= 1000 ? 3:  
				3; 
	};

	function estilo_covid (feature) {
		return{
			radius: getRadius(feature.properties.Confirmed), 
			};
	};
	function popup_covid (feature, layer) {
		layer.bindPopup("<div style=text-align:center><h3>"+feature.properties.Country_Region+
        "<h3></div><hr><table><tr><td>Confirmed: "+feature.properties.Confirmed+
        "</td></tr><tr><td>Deaths: "+feature.properties.Deaths+
        "</td></tr><tr><td>Recovered: "+feature.properties.Recovered+        
        "</td></tr></table>",
        {minWidth: 150, maxWidth: 200});				
		};

 	var covidMundo = L.geoJSON(covid, {
				pointToLayer: function (feature, latlng) {
						return L.circleMarker(latlng, MarkerOptions);
					},	
				style:estilo_covid,
				onEachFeature: popup_covid				
		});
	map.addLayer(covidMundo);


//Leyenda-----------------------------------------------------------

 var legend = L.control({position: 'bottomright'});

 legend.onAdd = function (map) {

 var div = L.DomUtil.create('div', 'info legend');
 var grades = [1000, 5000, 10000, 100000];
 var labels = ['<strong>Número de afectados</strong>'];
 var categories = ['< 5000','5000-10000','10000-100000','>100000'];

 for (var i = 0; i < grades.length; i++) {
        var grade = grades[i];//*0.5;
   labels.push(
        '<i class="circlepadding" style="width: '+Math.max(8,(7-2.2*getRadius(grade)))+'px;"></i> <i style="background: #FF4000; width: '+getRadius(grade)*2+'px; height: '+getRadius(grade)*2+'px; border-radius: 50%; margin-top: '+Math.max(0,(9-getRadius(grade)))+'px;"></i><i class="circlepadding" style="width: '+Math.max(2,(25-2*getRadius(grade)))+'px;"></i> ' + categories[i]);
   }
 div.innerHTML = labels.join('<br>');
 return div;
 };
 legend.addTo(map);

 // Insertando un título en el mapa---------------------------------

	var title = L.control();
	 
	title.onAdd = function (map) {
		var div = L.DomUtil.create('div', 'info');
		    div.innerHTML +=
		    '<h2>COVID-19</h2>Número de afectador por país.(23-04-2020)';
		 return div;
	};
	 
	title.addTo(map);
	</script>
	</body> 
</html>
Si quieres aprender a hacer más cosas como éstas, apúntate ya a nuestro curso online de web mapping interactivo con Leaflet.

1 comentario en «Cómo hacer un mapa web de afectados por el covid-19 con Leaflet»

  1. Hola!
    Tutorial muy interesante. Tengo una duda, si quiero representar los datos del covid desde una API, cómo modificó el código? Gracias

Los comentarios están cerrados.