Draw a grid or rectangles with a scale

I am building my first line graph in d3:

http://jsfiddle.net/j94RZ/

I want to know how to use either the scale or the axis so that I can draw a grid (presumably rectangles) where I can set a different background color for each section of the grid ... so I can alternate the colors for each grid cell. I want the grid to be drawn and limited by the axes of my chart, and then adapted if the tick ticks change, the ticks change (i.e., the axes change as follows: http://bl.ocks.org/mbostock/1667367 ). Therefore, if my graph has an x โ€‹โ€‹axis with 4 ticks and a y axis of 7 ticks, then my graph will have a background grid that is 7 blocks high and 4 blocks wide.

I played with the idea of โ€‹โ€‹using a range that starts from zero and ends at the full width of the graph, but I don't know what value I can use for this step. Is there a way to sort the request by axis and return the number of ticks?

var gridRange = d3.range(0, width, step?); 
+7
source share
2 answers

So, after a few helpful comments above, I came close to a solution. Using Ordinary Range Ranges, I get closer to where I want to.

I created range ranges using the number of ticks on my axis as the basis for the range of the input domain:

  var xScale = d3.scale.ordinal() .domain(d3.range(10)) .rangeRoundBands([0, width],0); var yScale = d3.scale.ordinal() .domain(d3.range(4)) .rangeRoundBands([0, height],0); 

Then I tried to cross out the rectangles like this:

 svg.selectAll("rect") .data(p) .enter() .append("rect") .attr("x", function(d, i) { return xScale(i); }) .attr("y", function(d,i) { 0 }) .attr("width", xScale.rangeBand()) .attr("height", yScale.rangeBand()) .attr("fill", "green"). attr('stroke','red'); 

This gives me the desired effect, but only for one line:

http://jsfiddle.net/Ny2FJ/2/

I want to somehow draw green blocks for the entire table (and also without the need to hard-code the number of ticks in the domain of ordinal scales). Then I tried to apply the range ranges to the y axis like this (knowing that this really doesn't work) http://jsfiddle.net/Ny2FJ/3/

 svg.selectAll("rect") .data(p) .enter() .append("rect") .attr("x", function(d, i) { return xScale(i); }) .attr("y", function(d,i) { return yScale(i); }) .attr("width", xScale.rangeBand()) .attr("height", yScale.rangeBand()) .attr("fill", "green"). attr('stroke','red'); 

The only way I can do this is to enter a for loop to run the code block in this script http://jsfiddle.net/Ny2FJ/2/ for each tick of the y axis.

+1
source share

A better approach than your current solution would be to use scale.ticks() explicitly to get the tick values. The advantage of this is that it will still work if for some reason you change the number of ticks.

To get an alternative grid pattern instead of a single fill, you can use something like this code.

 .attr("fill", function(d, i) { return (i % 2) == 1 ? "green" : "blue"; }) 

Finally, to get the full grid pattern, you can use an explicit loop, as you suggested, or nested options . The idea here is to first go through the y ticks, create g for each element, and then pass x tags for each of these groups. In code, it looks something like this.

 svg.selectAll("g.grid") .data(y.ticks()).enter().append("g").attr("class", "grid") .selectAll("rect") .data(x.ticks()).enter().append("rect"); 

To set a position, you can access the indexes in the upper and lower level data arrays like this.

 .attr("x", function(d, i) { return xScale(i); }) .attr("y", function(d, i, j) { return yScale(j); }) 

To set the position of x , you need the index of the internal array (passed to the set of elements g ), which can be accessed through the second argument of your callback. For an external array, just add one more argument ( j here).

And thatโ€™s really all. Fill out jsfiddle here . To dynamically update this grid, you just have to enter new check values โ€‹โ€‹(obtained from scale.ticks() ), match the existing data and handle the input / update / output selection in the usual way.

If you want to do without auxiliary scales (i.e. without .rangeBand() ), you can calculate the width / height of the rectangles using the scale of the scale and dividing it by the number of ticks minus 1. In general, this makes the code a little ugly (mainly because that you need less rectangle than ticks, and therefore you need to subtract / delete it), but a little more general. The jsfiddle that uses this approach is here .

+8
source share

All Articles