I am teaching myself D3 without too much knowledge on syntax / grammar of javascript. Could anyone explain the use of \"d\" as a parameter in the following function literal?
This is called an anonymous function, which is a function that isn't given a named label. Anonymous functions in Javascript are objects like everything else and this is why you can pass them as parameters into other javascript functions.
In the case of d3, it allows you to pass in a function as the second parameter. As you discovered, this function will be called with the current data element as well as the index of the current data element. If the second parameter is not a function, it can use a value instead.
In your example:
d3.selectAll("circle")
.attr("cy",function (d) { return percent_scale(d.late_percent);})
.attr("cx",function (d) { return time_scale(d.time);})
.attr("r",1);
Both cy
and cx
are being assigned values based on the return value of an anonymous function call, while r
is being assigned a static value. We could rewrite this as:
function setY(d) { return percent_scale(d.late_percent);}
function setX(d) { return time_scale(d.time); }
d3.selectAll("circle")
.attr("cy", setY)
.attr("cx", setX)
.attr("r",1);
Here I've replaced the anonymous function calls with more standard function definitions and specified the name of the function to be called in the d3
call. This works exactly the same as before. Also note that there is nothing magical about d
in this case.
function setY(foo) { return percent_scale(foo.late_percent);}
function setX(foo) { return time_scale(foo.time); }
d3.selectAll("circle")
.attr("cy", setY)
.attr("cx", setX)
.attr("r",1);
This code will also do the same thing. Note that I've renamed the parameter from d
to foo
, but this just changes how you access the parameter within the function. It has no effect outside of the function call. Generally in d3
documentation and tutorials, you'll see d
used for the current data element and i
used for the index of the current data element. The index is passed in as the second element to the function calls like so:
function setY(d, i) { return percent_scale(d.late_percent);}
function setX(d, i) { return time_scale(d.time); }
d3.selectAll("circle")
.attr("cy", setY)
.attr("cx", setX)
.attr("r",1);
Now specifically in the d3
case:
// Select all of the 'circle' elements (that is <circle>) elements
// in the HTML document and put the associated data into an array
d3.selectAll("circle")
// For each circle element, set the Y position to be the result
// of calling percent_scale on the data element late_percent
.attr("cy",function (d) { return percent_scale(d.late_percent);})
// For each circle element, set the X position to be the result
// of calling time_scale on the data element time
.attr("cx",function (d) { return time_scale(d.time);})
// For each circle element, set the radius to be 1
.attr("r",1);
This is a very common construct in d3
. The first step is always to make a selection to define which set of elements you want to modify (this is the .selectAll in this case). After that, you can chain together additional calls (in this case the .attr calls) that actually perform the desired modifications to the elements.
This creates a very powerful method of working with data driven documents (like graphs, charts, etc) without having to track the data elements manually or have to create lots of loops. In fact, you can usually tell you are using d3
incorrectly if you have any loops in your code that deals with modifying elements.
If you don't have much experience with javascript, the tutorials at https://www.dashingd3js.com/ might be helpful for getting started with d3
.