【问题标题】:Plotting a line graph along with Bar graph in d3js. Issue with Date在 d3js 中绘制线图和条形图。日期问题
【发布时间】:2015-11-06 22:29:27
【问题描述】:

我正在使用网上找到的各种示例学习 d3js。

我一直在尝试绘制带有双 Y 轴和 X 轴的图表。左侧的 Y 轴将针对 X 轴绘制 条形 图表,右侧的 Y 轴将针对 X 轴绘制 折线 图表。条形图完全按照要求绘制,但折线图没有。 X 轴是日期 (2015-10-15 04:10)。以this 为例。

我写的代码

var margin = {top: 50, right: 50, bottom: 100, left: 50},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%m/%d/%Y %H:%M:%S").parse;

var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);

var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);

var xAxis = d3.svg.axis()
    .scale(x)
    .orient("bottom")

var yAxis = d3.svg.axis()
    .scale(yTxnVol)
    .orient("left")

var yAxis2 = d3.svg.axis()
    .scale(yResTime)
    .orient("right")
    .ticks(10);
var svg = d3.selectAll("body").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 + ")");

d3.csv("../res/data.csv", function(error, data) {

   data.forEach(function(d) {
       d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
       d.TXN_VOL = +d.TXN_VOL;
  });

  x.domain(data.map(function(d) { return d.TYM; }));
  yTxnVol.domain([0, d3.max(data, function(d) { return d.TXN_VOL+50; })]);
  yResTime.domain([0, d3.max(data, function(d) { return d.AVRG_RESP_TIME+50; })]);

  var minDate = d3.min(data, function(d){return d.TYM});
  var maxDate = d3.max(data, function(d){ return d.TYM});
  var xScale = d3.time.scale().range([0,width]);//.domain([minDate, maxDate]);
  xScale.domain(d3.extent(data, function(d) { return new Date(d.TYM); }));

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis)
    .selectAll("text")
      .style("text-anchor", "end")
      .attr("dx", "-.8em")
      .attr("dy", "-.55em")
      .attr("transform", "rotate(-90)" );

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

   svg.append("g")
      .attr("class","y axis")
      .attr("transform","translate("+width+ ", 0)")
      .call(yAxis2)

   svg.selectAll("bar")
      .data(data)
    .enter().append("rect")
      .attr("class", "yhover")
      .attr("x", function(d) { return x(d.TYM); })
      .attr("width", x.rangeBand())
      .attr("y", function(d) { return yTxnVol(d.TXN_VOL); })
      .attr("height", function(d) { return height - yTxnVol(d.TXN_VOL); })

   var line = d3.svg.line()
      .x(function(d) { return xScale(new Date(d.TYM));})
      .y(function(d) { return d.AVRG_RESP_TIME; });

   svg.append("path")
      .datum(data)
      .attr("class", "line")
      .attr("d", line);   
});

输出 试图把它变成一个有意义的折线图。格式化日期时出现 NaN 错误。 有人可以帮我制作一个合适的折线图吗?

csv 数据样本

TYM、AVRG_RESP_TIME、TXN_VOL

2015-10-15 04:00:00, 12, 170

2015-10-15 04:10:00, 18, 220

2015-10-15 04:20:00, 28, 251

2015-10-15 05:00:00, 19, 100

【问题讨论】:

  • 你的问题真的归结为,我如何将我的AVRG_RESP_TIME 转换为一个有意义的完整数字? 04:10:238.00 代表什么?分:秒:毫秒?时:分:秒?只是做+'04:10:238.00' 不会将时间跨度转换为数字。
  • 对数据样本感到抱歉。 TYM 数据为 2015-10-15 04:00:00(04 小时 00 分 00 秒)。我一直在尝试将日期转换为数字。虽然没有得到正确的结果。

标签: javascript d3.js svg


【解决方案1】:

首先,修复您的 csv 文件。格式不正确,逗号后不应有空格。

其次,您正在尝试为 xAxis 混合一个序数刻度和一个时间刻度。这是行不通的。对于您的用例,请坚持使用时间。

这是使用解释性 cmets 对代码进行的修改:

<!DOCTYPE html>
<html>

<head>
  <script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <script>
    var margin = {
        top: 50,
        right: 50,
        bottom: 100,
        left: 50
      },
      width = 900 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;
      
    var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;

    // x scale should be time and only time
    var x = d3.time.scale().range([0, width]);
    var yTxnVol = d3.scale.linear().range([height, 0]);
    var yResTime = d3.scale.linear().range([height, 0]);

    var xAxis = d3.svg.axis()
      .scale(x)
      .orient("bottom")

    var yAxis = d3.svg.axis()
      .scale(yTxnVol)
      .orient("left")

    var yAxis2 = d3.svg.axis()
      .scale(yResTime)
      .orient("right")
      .ticks(10);
      
    var svg = d3.selectAll("body").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 + ")");

    //d3.csv("data.csv", function(error, data) {
      
      var data = [{"TYM":"2015-10-15 04:00:00","AVRG_RESP_TIME":"12","TXN_VOL":"170"},{"TYM":"2015-10-15 04:10:00","AVRG_RESP_TIME":"18","TXN_VOL":"220"},{"TYM":"2015-10-15 04:20:00","AVRG_RESP_TIME":"28","TXN_VOL":"251"},{"TYM":"2015-10-15 05:00:00","AVRG_RESP_TIME":"19","TXN_VOL":"100"}];

      // just make TYM a date and keep it as a date
      data.forEach(function(d) {
        d.TYM = parseDate(d.TYM);
        d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
        d.TXN_VOL = +d.TXN_VOL;
      });
      
      // get our min and max date in milliseconds
      // set a padding around our domain of 15%
      var minDate = d3.min(data, function(d){
        return d.TYM;
      }).getTime();
      var maxDate = d3.max(data, function(d){
        return d.TYM;
      }).getTime();
      var padDate = (maxDate - minDate) * .15;
      x.domain([new Date(minDate - padDate), new Date(maxDate + padDate)]);
      
      yTxnVol.domain([0, d3.max(data, function(d) {
        return d.TXN_VOL + 50;
      })]);
      
      yResTime.domain([0, d3.max(data, function(d) {
        return d.AVRG_RESP_TIME + 50;
      })]);
      
      // set an intelligent bar width
      var barWidth = (width / x.ticks().length) - 20;
      
      svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis)
        .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", "-.55em")
        .attr("transform", "rotate(-90)");

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

      svg.append("g")
        .attr("class", "y axis")
        .attr("transform", "translate(" + width + ", 0)")
        .call(yAxis2)

      svg.selectAll("bar")
        .data(data)
        .enter().append("rect")
        .attr("class", "yhover")
        .attr("x", function(d) {
          // center bar on time
          return x(d.TYM) - (barWidth / 2);
        })
        .attr("width", barWidth) 
        .attr("y", function(d) {
          return yTxnVol(d.TXN_VOL);
        })
        .attr("height", function(d) {
          return height - yTxnVol(d.TXN_VOL);
        })
        .style("fill","orange");

      var line = d3.svg.line()
        .x(function(d) {
          return x(d.TYM);
        })
        .y(function(d) {
          return d.AVRG_RESP_TIME;
        });

      svg.append("path")
        .datum(data)
        .attr("class", "line")
        .attr("d", line)
        .style("fill","none")
        .style("stroke","steelblue")
        .style("stoke-width","3px");
   // });
  </script>
</body>

</html>

【讨论】:

  • 感谢您的回答。我想知道是否可以为单个时间戳(TYM)和它们之间的间隔设置单独的条。我可以使用序数尺度而不是时间尺度来实现它。
  • 折线图用黑色填充的问题是css不当造成的。对于我将其格式化为 (%Y-%m-%d %H:%M) 格式的日期,它可以正常工作。
【解决方案2】:

线图用黑色填充的问题是由于css不当造成的。新的 CSS 属性。

.line {
  fill: none;
  stroke: darkgreen;
  stroke-width: 2.5px;
}

对于我将其格式化为 (%Y-%m-%d %H:%M) 格式的日期,它有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-19
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 2016-10-30
    • 1970-01-01
    相关资源
    最近更新 更多