【问题标题】:d3.js v4 bar chart with negative values on y axisd3.js v4 条形图,y 轴为负值
【发布时间】:2018-03-21 08:01:30
【问题描述】:

我在 d3.js 中使用了很多在 x 轴上具有负值的图表,但我看到很少有在 y 轴上具有负值的示例,而且我都无法正常工作。

我正在尝试创建一个图表,其中我的日期在 x 轴上,相应的值在 y 轴上。

我已经尝试通过操作以下链接中的代码来做到这一点:

D3 v4 bar chart X axis with negative values

我的代码如下:

var margin2 = { top: 20, right: 20, bottom: 40, left: 30 };
var height2 = 650 - margin2.top - margin2.bottom;
var width2 = 900 - margin2.left - margin2.right;

// Add svg to
var svg = d3.select('#macdChart').
    append('svg').
    attr('width', width2 + margin2.left + margin2.right).
    attr('height', height2 + margin2.top + margin2.bottom).
    append('g').
    attr('transform', 'translate(' + margin2.left + ',' + margin2.top + ')');

//title
svg.append("text")
    .attr("x", (width2 / 2))
    .attr("y", 0 - (margin2.top / 3))
    .attr("text-anchor", "middle")
    .style("font-size", "16px")
    .style("text-decoration", "underline")
    .text("Title");

// X scale
var x2 = d3.scaleBand().
    range([width2, 0])
    .padding(0.1);

//y scale
var y2 = d3.scaleLinear()
    .range([height2, 0]);



var xAxis = d3.axisBottom(x2);

var yAxis = d3.axisLeft(y2).
    tickSize(6, 0);

// text label for the x axis
svg.append("text")
    .attr("transform", "translate(" + (width2 / 2) + " ," + (height2 + margin2.top + 20) + ")")
    .style("text-anchor", "middle")
    .text("X Label");


function render(data) {
    data.forEach(function (d) {
        d.Macd = +d.Macd;
        d.MacdSignal = +d.MacdSignal;
        d.MacdHistogram = +d.MacdHistogram;
    });

    x2.domain(data.map(function (d) { return d["date"]; }));
    y2.domain(d3.extent(data, function (d) { return d["MacdHistogram"]; })).nice();

    svg.selectAll('.bar').
        data(data).
        enter().append('rect').
        attr('class', function (d) {
            return "bar bar--" + (d["MacdHistogram"] < 0 ? "negative" : "positive");
        }).
        attr('x', function (d) { return x2(d["date"]); }).
        attr('y', function (d) { return y2(Math.min(0, d["MacdHistogram"])); }).
        attr('height', function (d) { return Math.abs(y2(d["MacdHistogram"]) - y2(0)); }).
        attr('width', x2.bandwidth());

    svg.append('g').
        attr('class', 'y axis').
        attr('transform', 'translate(' + width2 + ',0)').
        call(yAxis);

    var tickNegative = svg.append('g').
        attr('class', 'x axis').
        attr('transform', 'translate(0,' + y2(0) + ')').
        call(xAxis).
        selectAll('.tick').
        filter(function (d, i) { return data[i].value < 0; });

    }

产生以下内容:

现在,如果我将 y 的范围从:

    var y2 = d3.scaleLinear()
        .range([height2, 0]);

收件人:

    var y2 = d3.scaleLinear()
        .range([0, height2]);

我得到了下面的图表,条形值正确显示,但负值在顶部,正值在底部(正如您在我的 y 轴标签上看到的那样):

有人可以建议如何让图表看起来完全一样,现在只是翻转了,所以负数在底部?

【问题讨论】:

    标签: javascript d3.js svg charts


    【解决方案1】:

    y 位置使用Math.max,而不是Math.min

    .attr('y', function (d) { 
        return y2(Math.max(0, d["MacdHistogram"]))
    });
    

    原因是,无论您的范围的方向如何,SVG 矩形 总是(除非您弄乱了 transform)的宽度从左到右增长,而高度从从上到下。

    这是一个使用虚假数据进行更改的演示:

    var margin2 = {
      top: 20,
      right: 20,
      bottom: 20,
      left: 20
    };
    var height2 = 400 - margin2.top - margin2.bottom;
    var width2 = 500 - margin2.left - margin2.right;
    
    // Add svg to
    var svg = d3.select('body').
    append('svg').
    attr('width', width2 + margin2.left + margin2.right).
    attr('height', height2 + margin2.top + margin2.bottom).
    append('g').
    attr('transform', 'translate(' + margin2.left + ',' + margin2.top + ')');
    
    //title
    svg.append("text")
      .attr("x", (width2 / 2))
      .attr("y", 0 - (margin2.top / 3))
      .attr("text-anchor", "middle")
      .style("font-size", "16px")
      .style("text-decoration", "underline")
      .text("Title");
    
    // X scale
    var x2 = d3.scaleBand().
    range([width2, 0])
      .padding(0.1);
    
    //y scale
    var y2 = d3.scaleLinear()
      .range([height2, 0]);
    
    
    
    var xAxis = d3.axisBottom(x2);
    
    var yAxis = d3.axisLeft(y2).
    tickSize(6, 0);
    
    // text label for the x axis
    svg.append("text")
      .attr("transform", "translate(" + (width2 / 2) + " ," + (height2 + margin2.top + 20) + ")")
      .style("text-anchor", "middle")
      .text("X Label");
    
    
    function render(data) {
      x2.domain(data.map(function(d) {
        return d["date"];
      }));
      y2.domain(d3.extent(data, function(d) {
        return d["MacdHistogram"];
      })).nice();
    
      svg.selectAll('.bar').
      data(data).
      enter().append('rect').
      attr('class', function(d) {
        return "bar bar--" + (d["MacdHistogram"] < 0 ? "negative" : "positive");
      }).
      attr('x', function(d) {
        return x2(d["date"]);
      }).
      attr('y', function(d) {
        return y2(Math.max(0, d["MacdHistogram"]));
      }).
      attr('height', function(d) {
        return Math.abs(y2(d["MacdHistogram"]) - y2(0));
      }).
      attr('width', x2.bandwidth());
    
      svg.append('g').
      attr('class', 'y axis').
      attr('transform', 'translate(' + width2 + ',0)').
      call(yAxis);
    
      var tickNegative = svg.append('g').
      attr('class', 'x axis').
      attr('transform', 'translate(0,' + y2(0) + ')').
      call(xAxis).
      selectAll('.tick').
      filter(function(d, i) {
        return data[i].value < 0;
      });
    }
    
    var data = [{
      date: 1,
      MacdHistogram: 1
    }, {
      date: 2,
      MacdHistogram: -2
    }, {
      date: 3,
      MacdHistogram: 8
    }, {
      date: 4,
      MacdHistogram: 3
    }, {
      date: 5,
      MacdHistogram: 12
    }, {
      date: 6,
      MacdHistogram: -5
    }, {
      date: 7,
      MacdHistogram: 1
    }, {
      date: 8,
      MacdHistogram: 9
    }, {
      date: 9,
      MacdHistogram: -1
    }, {
      date: 10,
      MacdHistogram: 10
    }, {
      date: 11,
      MacdHistogram: 7
    }, {
      date: 12,
      MacdHistogram: -8
    }, {
      date: 13,
      MacdHistogram: 7
    }, {
      date: 14,
      MacdHistogram: -4
    }, {
      date: 15,
      MacdHistogram: 1
    }];
    
    render(data)
    &lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 太好了!我很欣赏关于为什么这样做的明确解释。 d3.js 无疑是一个学习曲线,我正在等待 d3.js in action 2nd edition 出来 [manning.com/books/d3js-in-action-second-edition] 。您还有其他参考建议吗?我发现很多例子,但解释较少。
    • 根据你的水平(对于初学者),Scott Murray 的书真的很不错:chimera.labs.oreilly.com/books/1230000000345/index.html
    • 感谢它的帮助。如果有人想知道 d3.js "Math.abs(y2(d["MacdHistogram"]) - y2(0));"和 "y2(Math.abs(d["MacdHistogram"] - 0 ));"在 d3.js 中不返回相同的值
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-25
    • 2022-06-19
    • 1970-01-01
    • 1970-01-01
    • 2014-07-07
    • 1970-01-01
    相关资源
    最近更新 更多