Below are two examples of similar D3 code, one works and the other doesn't. In this example, I want to change the color of the lines of an axis -
This doesn't work, stroke color lines of the axis do not get changed to green -
var x_axis = svg.append("g")
.attr("class", "axis")
.attr("transform", `translate(20, ${height - 50})`)
.call(d3.axisBottom(ordinalScale))
.selectAll("text")
.attr("transform", "translate(-5,5)rotate(-45)")
.style("text-anchor", "end")
.style("font-size", "8px")
.style("fill", "#102040");
x_axis.selectAll("line, path").style("stroke", "green");
BUT this works, the lines get changed to green:
var x_axis = svg.append("g")
.attr("class", "axis")
.attr("transform", `translate(20, ${height - 50})`)
.call(d3.axisBottom(ordinalScale));
x_axis.selectAll("text")
.attr("transform", "translate(-5,5)rotate(-45)")
.style("text-anchor", "end")
.style("font-size", "8px")
.style("fill", "#102040");
x_axis.selectAll("line, path").style("stroke", "green");
The difference being that in the first (failed) example, I chain the 'selectAll("text")' operations to the 'call(d3.axisBottom)' with the 'selectAll("line, path")' operations in a following expression, and in the second (successful) example, I have following seperate expressions for each of the text and line/path operations.
This is not critical since I can get the effect I want, but it seems to me that they should be equivalent but obviously there is some subtlety of the syntax that I do not understand. Does this have something to do with the '.call' operation?
The first code block doesn't work because x_axis
doesn't contain what you think it does.
var x_axis = svg.append("g") // returns a selection of a g element
.attr("class", "axis") // returns the same selection of a g
...
.call(d3.axisBottom(ordinalScale)) // returns the same selection of a g
.selectAll("text") // returns a new selection of text elements
...
.style("fill", "#102040"); // returns the same selection of text elements
x_axis
is defined by the last value returned by the chain. So,
x_axis
in the above is a selection of text elements, text elements can't (and in this case don't) contain any child path or line elements, so x_axis.selectAll('line, path')
will return an empty selection. Consequently, setting any property for an empty selection won't change anything.
The second code block works because x_axis
remains a selection of a g - selection.call()
returns the same selection
that .call()
was chained to, like .attr()
or .style()
, among other methods. Whereas selectAll()
and select()
, among other methods, return new selections.