1

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?

CJH
  • 163
  • 1
  • 12

1 Answers1

1

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.

Andrew Reid
  • 37,021
  • 7
  • 64
  • 83