Making a d3.js scatter-plot interactive-part one
This tutorial explains how to add interactivity to a scatter-plot that was built in an earlier tutorial. As a reminder, this is what the data structure looks like:
This tutorial will explain how to update Province. The final code can be viewed here.
There are two important aspects in building user interactivity:
- Capturing the user’s choice.
- Updating the page based on user’s choice.
As a reminder, the focus of this tutorial is d3.js so coverage of other topics will be minimal.
Capturing The User’s Choice
- Add a
select
HTML tag with options for each of the province names and one for “All Provinces”.
Updating The Page Based On User’s Choice
- Filter inputted data (argument to
updateChart
) and return new dataset based on user’s Geographic Choice.
function updateChart(someData) {
let dataAdultLit = d3
.nest()
.key(function (d) {
return d[“Year”];
})
.entries(someData[0]);let filteredData = dataAdultLit[5]; //Note update here; important!filteredData =
$(“#geographicChoice”).val() === “allProv”
? filteredData[“values”]
: filteredData[“values”].filter(
(each) => each[“Province”] === $(“#geographicChoice”).val()
);
- Upon initial page load,
$(“#geographicChoice”).val() === “allProv”
will betrue
because that is the default value of the dropdown and user has not changed it. - Once the user selects a new choice,
updateChart
will have to be re-triggered. Add the following code in after initial data load function:
//Add in event listener for geographic choice.
$(“#geographicChoice”).on(“change”, function () {
updateChart(allData);
});
- If you
console.log(filteredData)
inupdateChart
, you will see that the data is updating as user makes different choices. This is whered3
(finally) comes in. We have to “call” all the items in the chart we want updated (circles in scatter-plot, in this case) and “instruct” them to change based on the new data.
Exit, Update, Enter
This is a tough d3
concept and I have to think it through each time I use it.
- Important reminder:
d3
works because we attach one row of data per SVG element (like a circle or a rectangle). The attributes of the SVG element, such asradius
,length
,width
are determined by various datum within that row of data. When the data changes (because, for example, user chose a different province), then the datum changes, and so the attributes of the SVG element changes. Enter, Exit, Update is the way for the SVG elements to reflect the initial data and then to reflect the updated data. As per previous tutorial, the first step is to attach — or join — data to SVG elements. - Now, we want to update the SVG elements so we have to take in the new data (based on user choice), remove any no-longer-necessary SVG elements, and update existing SVG elements. In this case, when a user selects a province, we have to remove data for all other provinces and update chart to match selected province. This is a rough outline of the process:
- Join updated data to SVG element:
// JOIN new data with old elements.
var circles = svg.selectAll(“circle”).data(filteredData, function (d) {
return d[“District”];
});
- Exit: after joining to the updated data, remove any SVG elements (i.e. circles) that became unnecessary.
// EXIT old elements not present in new data.
circles.exit().remove();
- Enter: use the updated dataset to create the circles.
// ENTER new elements present in new data.
circles
.enter()
.append(“circle”)
.attr(“class”, “enter”)
.attr(“fill”, function (d) {
return color(d[“Province”]);
})
.attr(“cy”, function (d) {
return y(d[“Poverty Rate (%)”]);
})
.attr(“cx”, function (d) {
return x(
d[
“Adult literacy, 25 or more years old (% of population aged 25 or more)”
]
);
})
.attr(“r”, 5);
- Update: at this point, because we are not doing anything with the circles that already exist in the scatter-plot, we can skip the
update
selection. We are only removing old unwanted circles (thinkDistricts
)and then (possibly, depending on that specific user choice) adding in new circles (again, thinkDistricts
). We would needupdate
selection if, for example, there was a circle on the page that representedDistrict X
which had values of(5,10)
for thex,y
attributes but after the data is updated,District X
data changes so thatx,y
attributes have the values(0,15)
. In this case,exit
wouldn’t do anything because I want to keep the data point, i.e thatDistrict
.enter
wouldn’t help becauseDistrict X
was already on the page. So I need to useupdate
to move the circle over.
If anyone runs through this tutorial, please let me know what you think especially if any concept is still confusing. I would love to hear from you.
Next tutorial: how to use update
selection to move existing circles around. Why would we want to do that? If we have a bunch of circles representing a bunch of districts for the year 2004 but now want to show the same districts in the year 2014, we have to use the update
selection.