【问题标题】:Customize grid lines in d3 bar chart在 d3 条形图中自定义网格线
【发布时间】:2020-02-20 09:11:44
【问题描述】:

我正在使用 d3 开发一个双向条形图。我想在条形图中添加网格线,如何自定义这些网格线。我使用 d3fc 来绘制网格线。它看起来像

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';
    });

我的图表结果是

我的图表应该是这样的

如何连接 x 轴的边缘并突出显示如图所示的基轴?感谢您对自定义网格线的任何帮助。 链接到我的示例link

提前致谢!

【问题讨论】:

  • 你有一个可行的例子吗?
  • 我在我的问题@ksav 中添加了一个指向我的示例的链接
  • 我在示例中看不到任何网格线。
  • @ksav 实际上 d3fc 在 codepen 中不起作用,但我已经评论了网格线的代码。你可以参考一下。

标签: javascript d3.js d3fc


【解决方案1】:

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

【讨论】:

  • 我试过了,但是没用。我们可以不使用 CSS 吗? @丹尼尔
  • @Max 也许你想试试 d3.js 中的opacity 属性。
【解决方案2】:

我对您的笔进行了一些更改,您可以看到 here

主要变化:

在 x 轴上连接边

如果您从域中删除 *1.2 乘数并添加 .nice(),则 x 轴将与网格线对齐。

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

突出显示基轴

我们可以使用 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);

在这里,我们正在使用我们的比例创建注释线。我们将线设置为垂直,并通过将其替换为空字符串来删除默认标签。之后我们使用decorate 函数将线条染成黑色。

自定义网格线

我们可以使用decorate 函数来控制网格线的不透明度。

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

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

这里我们使用装饰函数来设置水平和垂直网格线的不透明度。或者,您也可以使用不同的装饰函数来设置不同的水平线和垂直线样式。

我希望这会有所帮助!

【讨论】:

  • 好东西。谢谢! @奥利弗
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-30
  • 1970-01-01
  • 2017-08-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多