People Map of India:Part 2

3 minute read

I was going through The Pudding a few days and came across their “People Map of the UK” and “People Map of the US” posts. These seemed pretty cool and since I’ve been trying to pick up making visualizations using JavaScript, I thought this was the perfect thing to attempt to replicate. So I decided to do the same for India.

Having scraped the data (See previous part, it was time to get down to building the visualization. I decided to use Leaflet, an open source JavaScript library for interactive maps. I also used the D3 library and relied on the lite-server for hosting a local server conveniently. While making this visualization, I was constantly amazed by the sheer versatility of JavaScript and how powerful of a tool it can be. However, being an inveterate Python and R person, making the shift to JavaScript gave me quite a few headaches.

While my resulting visualization wasn’t as good as the one by the excellent people over at The Pudding, I like to think that I got the basic elements down and that it’s a decent start to building prettier visualizations. Here are screenshots of my visualization:

Code

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<link rel="stylesheet" href="styles.css">
<!-- Load d3.js and the geo projection plugin -->
<script src="https://d3js.org/d3.v5.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>

<!-- Load Leaflet -->
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.4/dist/leaflet.css" integrity="sha512-puBpdR0798OZvTTbP4A8Ix/l+A4dHDD0DGqYW6RQ+9jxkRFclaxxQb/SJAWZfWAkuyeQUytO7+7N4QKrDh+drA==" crossorigin=""/>
<script src="https://unpkg.com/leaflet@1.3.4/dist/leaflet.js" integrity="sha512-nMMmRyTVoLYqjP9hrbed9S+FzjZHW5gY1TWCHA5ckwXZBadntCNs8kEqAWdrb9O7rxbCaA4lKTIWjDXZxflOcA==" crossorigin=""></script>



<!-- Create an element where the map will take place -->
<div id="mapid"></div>

<style>
#mapid { height: 900px; width: 1000px; }
</style>
<script src = "mapscript.js"></script>

mapscript.js

d3.csv("PeopleMap.csv") // Load in csv
  .then(function(data){
      data.forEach(function(d) {
        d.latitude = +d.latitude;       //Convert the latitude, longitude and number of views to numeric formats
        d.longitude = +d.longitude;
        d["Number of Views"] = +d["Number of Views"];
      });
      console.log(data[0]); 
    const markers = [...Array(data.length)].map((_, i) => i); // Initialize array coordinates to be plotted
    const mags = [...Array(data.length)].map((_, i) => i); // Initialize array for radius sizes to be plotted

    for (let i = 0; i < data.length; i++) {
        markers[i] = [data[i]['latitude'], data[i]['longitude']];
        mags[i] = data[i]['Number of Views'];   
    }
    console.log(markers[0])
    const max = Math.max(...mags);
    const min = Math.min(...mags);

    console.log(max);
    console.log(min);
    for (let i = 0; i < mags.length; i++) {
        mags[i] = 10*mags[i]/max;  //Scale the views into a relevant radius size
        
    }
    console.log(mags);
    var mymap = L //Initialize map
  .map('mapid', {
        zoomDelta: 0.25,
        zoomSnap: 0})
  .setView(markers[0], 5.25);
  
mymap.createPane('labels');
mymap.getPane('labels').style.zIndex = 650;
mymap.getPane('labels').style.pointerEvents = 'none';


// Add a tile to the map 
var CartoDB_DarkMatterNoLabels = L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_nolabels/{z}/{x}/{y}{r}.png', {
	attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
	subdomains: 'abcd',
	maxZoom: 19
}).addTo(mymap);


//Make circle markers
for (let i = 0; i < markers.length; i++) {
    var circle = L.circleMarker(markers[i], {
        color: "#42d86f",
        fillColor: "##42d86f",
        fillOpacity: .5,
        radius: mags[i]
    }).addTo(mymap);    
}
//Add Person name in bold and city name underneath
var marker = []
for (let i = 0; i < markers.length; i++) {
    str1 =  "'<span style='color:white'  class='my-div-span'><b>";
    str2 = data[i]['Person'];
    str3 = "</b> <br> ";
    str4 = data[i]['City'];
    str5 = "</span>'";
    str1 = str1.concat(str2, str3, str4, str5);
    marker[i] = L.marker(markers[i], {
        
        icon: L.divIcon({
            iconSize: [100,50],
            bgPos: [0,0],
            className: 'text-labels',   // Set class for CSS styling
            html: str1
            
        }),
        zIndexOffset: 1000     // Make appear above other map features
    });

    marker[i].bindPopup(data[i]['Description']);
    /*
    marker[i].on('mouseover', function(event){
        marker[i].openPopup();
      });
    marker[i].on('mouseout', function(event){
    marker[i].closePopup();
    });
    */
    }

//Make function to add the lesser view markers when zoom is increased so as to not clutter the map when it is zoomed out.
mymap.on('zoomend' , function (e) {
    console.log(mymap.getZoom())
    var geo = mymap.getCenter();                
    //console.log(mymap.getZoom());
    if (mymap.getZoom()>6.5)
    { for (let i = 0; i < marker.length; i++) {
        if(mags[i]>.00001){
        marker[i].addTo(mymap)}
        else{
            marker[i].remove(mymap)
        }
    }    
    }
    else if (mymap.getZoom()>6.5)
    { for (let i = 0; i < marker.length; i++) {
        if(mags[i]>.0001){
        marker[i].addTo(mymap)}
        else{
            marker[i].remove(mymap)
        }
    }    
    }
    if (mymap.getZoom()>6.25)
    { for (let i = 0; i < marker.length; i++) {
        if(mags[i]>.001){
        marker[i].addTo(mymap)}
        else{
            marker[i].remove(mymap)
        }
    }    
    }
    else if (mymap.getZoom()>5.75)
    { for (let i = 0; i < marker.length; i++) {
        if(mags[i]>.001){
        marker[i].addTo(mymap)}
        else{
            marker[i].remove(mymap)
        }
    }    
    }
    else if (mymap.getZoom>5.5) {
        for (let i = 0; i < marker.length; i++) {
            if(mags[i]>0.1){
            marker[i].addTo(mymap)}
            else{
                marker[i].remove(mymap)
            }
    }
}
    else if (mymap.getZoom>5) {
        for (let i = 0; i < marker.length; i++) {
            if(mags[i]>1){
            marker[i].addTo(mymap)}
            else{
                marker[i].remove(mymap)
            }
    }
}
else if (mymap.getZoom>4.75) {
    for (let i = 0; i < marker.length; i++) {
        if(mags[i]>5){
        marker[i].addTo(mymap)}
        else{
            marker[i].remove(mymap)
        }
}
}
    else {
        for (let i = 0; i < marker.length; i++) {
            if(mags[i]>10){
            marker[i].addTo(mymap)}
            else{
                marker[i].remove(mymap)
            }
    }
}});
});

Updated: