简体   繁体   中英

Customize grid lines in d3 bar chart

I am developing a two-way bar chart using d3. I want to add grid lines to the bar chart, how to customize those grid lines. I've used d3fc to draw the grid lines. It looks something like

var x = d3.scaleLinear()
    .rangeRound([0, width])

var y = d3.scaleBand()
    .rangeRound([0, height]).padding(0.5);

var xAxis = d3.axisBottom(x)
    .ticks(8)
    .tickSize(0)
    .tickFormat(function(d){
        return d3.format('.00s')(Math.abs(d));   // Use Math.abs() to get the absolute value
    });

var yAxis = d3.axisLeft(y)
    .ticks(5)
    .tickSize(0);
//draw grid lines
const gridline = fc.annotationSvgGridline()
    .xScale(x)
    .yScale(y);
var svg = d3.select("#ageSexNotif").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
    .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

x.domain([-d3.max(data, function(d){
    return d.female
})*1.2,d3.max(data, function(d){
    return d.female
})*1.2])
y.domain(data.map(function (d) {
    return d.age;
}));

svg.append("g")
    .attr("class", "x axis")
    .call(xAxis)
    .call(gridline);

svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);
    // .call(gridline);

var barsRight = svg.selectAll(".bar")
    .data(data)
    .enter().append("g")

barsRight.append("rect")
    .attr("class", "bar")
    .attr("x", function (d) {
        return x(Math.min(0, d.female));
    })
    .attr("y", function (d) {
        return y(d.age);
    })
    .attr("width", function (d) {
        return Math.abs(x(d.female) - x(0));
    })
    .transition()
    .duration(1500)
    .delay(200)
    .style("margin-top", "10px")
    .attr("height", y.bandwidth())
    .attr("fill", "#F293C9")
    .attr("text", "label");

barsRight.append("text")
    .attr("class", "label")
    //y position of the label is halfway down the bar
    .attr("y", function (d) {
        return y(d.age) + y.bandwidth()- 6;
    })
    //x position is 3 pixels to the right of the bar
    .attr("x", function (d) {
        return x(d.female) + 10;
    })
    .text(function (d) {
        return (d.female/1000)+'k';
    })
    .style("font-family", "Source Sans Pro")
    .style("font-size", "14px")
    .style("font-weight", "bold")
    .attr("fill", "#F293C9");  


var barsLeft = svg.selectAll(".bar2")
    .data(data)
    .enter().append("g")

barsLeft.append("rect")
    .attr("class", "bar2")
    .attr("x", function (d) {
        return x(Math.min(0, -d.male));
    })
    .attr("y", function (d) {
        return y(d.age);
    })
    .attr("width", function (d) {
        return Math.abs(x(-d.male) - x(0));
    })
    .transition()
    .duration(1500)
    .delay(200)
    .style("margin-top", "10px")
    .attr("height", y.bandwidth())
    .attr("fill", "#4880FF");

barsLeft.append("text")
    .attr("class", "label")
    .style("font-family", "Source Sans Pro")
    .style("font-size", "14px")
    .style("font-weight", "bold")
    .attr("fill","#4880FF")
    //y position of the label is halfway down the bar
    .attr("y", function (d) {
        return y(d.age) + y.bandwidth()- 6;
    })
    //x position is 3 pixels to the right of the bar
    .attr("x", function (d) {
        return x(-d.male) - 40;
    })
    .text(function (d) {
        return (d.male/1000)+'k';
    });

The result of my chart is

图片

My chart should look like this

图片

How to join the edges in x-axis and highlight the base axis as shown in the image? Any help for customizing the grid lines is appreciated. Link to my example link

Thanks in advance!

您可以使用attr('class', 'class-name')将类名添加到网格线,并通过 CSS 添加效果。

I've made some changes to your pen that you can see here .

The main changes:

join the edges in x-axis

If you remove the *1.2 multiplier from the domains and add .nice() then the x-axis will be squared off with the gridlines.

var x = d3.scaleLinear()
   .rangeRound([0, width])
   .domain([-d3.max(data, d => d.female), d3.max(data, d => d.female)])
   .nice();

highlight the base axis

We can do this using an annotation line from d3fc.

const line = fc.annotationSvgLine()
  .xScale(x)
  .yScale(y)
  .orient('vertical')
  .label('')
  .decorate(selection => {
    selection.select('line')
      .attr('stroke', 'black'); 
  });
svg.datum([0]).call(line);

Here we are creating an annotation line using our scales. We set the line to be vertical and we remove the default label by replacing it with an empty string. After that we use the decorate function to colour the line black.

customizing the gridlines

We can control the opacity of the gridlines using a decorate function.

const opacityDecorate = selection => {
  selection.attr('opacity', 0.2);
};

const gridline = fc.annotationSvgGridline()
          .xScale(x)
          .yScale(y)
          .xDecorate(opacityDecorate)
          .yDecorate(opacityDecorate);

Here we are using a decorate function to set the opacity for the both the horizontal and vertical gridlines. Alternatively you could also use different decorate functions to style the horizontal and vertical lines differently.

I hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM