Plotting data points on Interactive Map Visualisation using D3js

Nikita Sharma

Nikita Sharma

Data Science Intern

In the last post, we learned how to plot a basic map using D3js. In this post, we will learn how to plot data points on the map. Here we are using Australia's population data to plot points on the map.

Basic Map Visualization

Here we will plot the city's population details on the map. We already know how to plot the basic map, then we just need to add circles for each data points on the map.

Loading data

d3.csv("population_data.csv", (data) => {
});

This is how we will load the population data. We will add the properties of the circle inside this function.

Defining circle properties

// Create a color scale
let color = d3.scale.category20();
// Add a scale for bubble size
let valueExtent = d3.extent(data, (d) => { return +d.n; })
let size = d3.scaleSqrt()
.domain(valueExtent) // What's in the data
.range([ 1, 20]) // Size of circle in pixel

This will set different random colors for all the points based on the states they are in. We will also define the size of the circle based on the city population.

Adding Tooltip to the points

let tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("text-align", "center")
.style("padding", "15px")
.style("font", "12px sans-serif")
.style("background", "#03bafc")
.style("border", "0px")
.style("border-radius", "8px")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");

From the above code, we will able to generate the tooltip that contains more info about the circle. The tooltip will show when we place the cursor above the circle point.

Drawing circles with all the properties

svg.selectAll("myCircles")
.data(data.sort((a,b) => { return +b.n - +a.n }).filter((d,i) => { return i<1000 }))
.enter()
.append("circle")
.attr("cx", (d) => { return projection([+d.homelon, +d.homelat])[0] })
.attr("cy", (d) => { return projection([+d.homelon, +d.homelat])[1] })
.attr("r", (d) => { return size(+d.n +1) + 2 })
.style("fill", (d) => { return color(d.state)})
.attr("stroke-width", 1)
.attr("fill-opacity", 0.6)
.on("mouseover", () => {
return tooltip.style("visibility", "visible");
})
.on("mousemove", (d) => {
tooltip.text(d.city + ' (' + d.n + ' Population)');
return tooltip.style("top",
(d3.event.pageY-10)+"px").style("left",(d3.event.pageX+10)+"px");
})

Using above code, we will connect all the properties of the circle and plot the data points over the map. We also have an event function i.e; mouseover that will show more info about the city as a tooltip.

All the code

<!DOCTYPE html>
<html lang="en">
<head>
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<meta charset="utf-8">
<title> Interactive map visualization</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-geo-projection.v2.min.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/topojson/1.6.19/topojson.min.js"></script>
<style type="text/css">
body {
margin: 0;
background-color: whitesmoke;
font-family: 'Times New Roman', sans-serif;
font-weight: 300;
}
#svgcontainer {
width: 1000px;
margin-left: auto;
margin-right: auto;
margin-top: 50px;
padding: 5px 50px 10px 50px;
background-color: whitesmoke;
}
h1 {
font-weight: 800;
color: #5a7388;
font-size: 48px;
margin-bottom: 10px;
}
svg {
background-color: whitesmoke;
}
</style>
</head>
<body>
<div id="svgcontainer">
<h1>Interactive map visualization</h1>
<div id="svganchor"></div>
<br>
</div>
<script type="text/javascript">
//Width and height
let w = 1000;
let h = 800;
//Define map projection
let projection = d3.geo.mercator()
.center([132, -28])
.translate([w / 2, h / 2])
.scale(1000);
//Define path generator
let path = d3.geo.path()
.projection(projection);
let states_color = d3.scale.ordinal()
.range(['#faf7d4', '#faf7d4', '#faf7d4', '#faf7d4', '#faf7d4', '#faf7d4', '#faf7d4', '#faf7d4', '#faf7d4']);
//Create SVG
let svg = d3.select("#svganchor")
.append("svg")
.attr("width", w)
.attr("height", h);
//Load in GeoJSON data
d3.json("aust.json", (json) => {
//Bind data and create one path per GeoJSON feature
svg.selectAll("path")
.data(json.features)
.enter()
.append("path")
.attr("d", path)
.attr("stroke", "dimgray")
.style("opacity", 1)
.attr("fill", (d, i) => { return states_color(i) })
.each((d, i, j) => {
// Fix to move map behind the plotted points
let firstChild = j[i].parentNode.firstChild;
if (firstChild) {
j[i].parentNode.insertBefore(j[i], firstChild);
}
});
//States
svg.selectAll("text")
.data(json.features)
.enter()
.append("text")
.attr("fill", "darkslategray")
.attr("transform", (d) => { return "translate(" + path.centroid(d) + ")"; })
.attr("text-anchor", "middle")
.attr("dy", ".35em")
.text((d) => {
return d.properties.STATE_NAME;
});
//Append the name
svg.append("text")
.attr("x", 0)
.attr("y", 340)
.attr("font-size", 90)
.attr("font-weight", "bold")
.attr("font-family", "Times New Roman")
.attr("text-anchor", "middle")
.attr("opacity", 0.5)
});
// Add circles:
d3.csv("population_data.csv", (data) => {
// Create a color scale
let color = d3.scale.category20();
// Add a scale for bubble size
let valueExtent = d3.extent(data, (d) => { return +d.n; })
let size = d3.scaleSqrt()
.domain(valueExtent) // What's in the data
.range([1, 20]) // Size of circle in pixel
let tooltip = d3.select("body")
.append("div")
.style("position", "absolute")
.style("text-align", "center")
.style("padding", "15px")
.style("font", "12px sans-serif")
.style("background", "#03bafc")
.style("border", "0px")
.style("border-radius", "8px")
.style("z-index", "10")
.style("visibility", "hidden")
.text("a simple tooltip");
svg
.selectAll("myCircles")
.data(data.sort((a, b) => { return +b.n - +a.n }).filter((d, i) => { return i < 1000 }))
.enter()
.append("circle")
.attr("cx", (d) => { return projection([+d.homelon, +d.homelat])[0] })
.attr("cy", (d) => { return projection([+d.homelon, +d.homelat])[1] })
.attr("r", (d) => { return size(+d.n + 1) + 2 })
.style("fill", (d) => { return color(d.state) })
.attr("stroke-width", 1)
.attr("fill-opacity", 0.6)
.on("mouseover", () => {
return tooltip.style("visibility", "visible");
})
.on("mousemove", (d) => {
tooltip.text(d.city + ' (' + d.n + ' Population)');
return tooltip.style("top",
(d3.event.pageY - 10) + "px").style("left", (d3.event.pageX + 10) + "px");
})
});
</script>
</body>
</html>

Interactive Map Visualization

This is how we plot an interactive Australia map with the population details of all the cities.