首页 文章

使用D3.js解析时间序列数据

提问于
浏览
3

您好我的StackOverflow朋友:

是时候寻求帮助了 . 我已经研究了D3.js好几周了,我才开始觉得我理解它的10%(ha,ha,ha) . 我试图生成一个非常简单的折线图 . 只要数据非常简单,我就可以做到这一点,但我的原始数据源有UTC时间戳,以及真实/十进制数字,这些数据不会让任何事情变得简单 .

原始数据源如下所示:

{
      "Links": {},
      "Items": [
        {
          "Timestamp": "2016-07-12T22:21:10Z",
          "Value": 1055.6793212890625,
          "UnitsAbbreviation": "m3/h",
          "Good": true,
          "Questionable": false,
          "Substituted": false
        },
        {
          "Timestamp": "2016-07-12T22:39:10Z",
          "Value": 989.00830078125,
          "UnitsAbbreviation": "m3/h",
          "Good": true,
          "Questionable": false,
          "Substituted": false
        }
      ],
      "UnitsAbbreviation": "m3/h"
    }

使用jQuery和javascript时间格式化功能,我能够组装以下简化数据集:

var dataset = [
    {'theTime': '2016/07/12 15:58:40', 'theValue': 1123.07275390625},
    {'theTime': '2016/07/12 16:21:10', 'theValue': 1055.6793212890625},
    {'theTime': '2016/07/12 16:45:40', 'theValue': 962.4850463867188},
    {'theTime': '2016/07/12 17:14:40', 'theValue': 831.2259521484375},
    {'theTime': '2016/07/12 17:55:10', 'theValue': 625.3046875}
    ];

这是我的代码:

//~ Populate the 'dataset':
    var dataset = [];
    $.get(url, function(data){
        var itemCount = data.Items.length;
        var commaCount = itemCount - 1;
        for(i=0; i < itemCount; i++){
            if(i == commaCount){
                dataset.push("{'theTime': '" + formattedDateTime(data.Items[i].Timestamp) + "', 'theValue': " + data.Items[i].Value + "}");
            }
            else {
            dataset.push("{'theTime': '" + formattedDateTime(data.Items[i].Timestamp) + "', 'theValue': " + data.Items[i].Value + "},");
        }
        }

        var margin = {top: 20, right: 20, bottom: 30, left: 50};
        var width = 960 - margin.left - margin.right;
        var height = 500 - margin.top - margin.bottom;
        var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
        var x = d3.time.scale()
            .range([0, width]);

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

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

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

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

        var svg = d3.select("#myChart").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 + ")");

            dataset.forEach(function(d) {
                d.theTime = parseDate(d.theTime);
                d.theValue = +d.theValue;
             });

             x.domain(d3.extent(data, function(d) { return d.theTime; }));
             y.domain(d3.extent(data, function(d) { return d.theValue;}));

             svg.append("g")
                .attr("class", "x axis")
                .attr("transform", "translate(0," + height + ")")
                .call(xAxis);

             svg.append("g")
                .attr("class", "y axis")
                .call(yAxis)
                .append("text")
                .attr("transform", "rotate(-90)")
                .attr("y", 6)
                .attr("dy", ".71em")
                .style("text-anchor", "end")
                .text("return time(ms)");

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

        //~~~ Format The Date:
        function formattedDateTime(dateAndTime) {
            var d = new Date(dateAndTime);
            var numDate = d.getDate();
            var numMonth = d.getMonth() + 1;
            var numYear = d.getFullYear();
            var numHours = d.getHours();
            var numMinutes = d.getMinutes();
            var numSeconds = d.getSeconds();
            numDate = (numDate < 10) ? "0" + numDate : numDate;
            numMonth = (numMonth < 10) ? "0" + numMonth : numMonth;
            numHours = (numHours < 10) ? "0" + numHours : numHours;
            numMinutes = (numMinutes < 10) ? "0" + numMinutes : numMinutes;
            numSeconds = (numSeconds < 10) ? "0" + numSeconds : numSeconds;

            return numYear + "/" + numMonth + "/" + numDate + " " + 
        numHours + ":" + numMinutes + ":" + numSeconds;
        };

第一个错误发生在'dataset.forEach()'函数,即“ Uncaught TypeError: Cannot read property 'length' of undefined ". My effort there to parse that data stems from another error that occurs at the 'svg.append(" path ")' point in the code, which is " Error: <path> attribute d: Expected number, "MNaN,NaNLNaN,NaNL… ” .

Uggghhhh! (:-C) . 如果 Spectator 中有任何D3.js导师,请帮助我确定我做错了什么以及如何解决 . ¡Muchas Gracias!

// =============附上01 ========================

我搞定了!! Yeee Haaaw!

我将在下面发布修订后的工作代码 . 但对于关注这篇文章的人,我想解释一下,我发现了什么 .

在链接的帖子(Alternatives for using forEeach() loop while converting data for D3.js)上标记建议更改dataset.push()以删除所有引号 . 这给了我对象而不是字符串 . 经过一些故障排除后,它最终按预期显示(完全令人兴奋!),谢谢马克,你的建议就行了 .

这是修改后的代码:

//~ Populate the 'dataset':
    var dataset = [];
    $.get(url, function(data){
        var itemCount = data.Items.length;
        var commaCount = itemCount - 1;
        for(i=0; i<itemCount; i++){
            dataset.push({theTime: formattedDateTime(data.Items[i].Timestamp), theValue: data.Items[i].Value});
        }

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

        var x = d3.time.scale()
          .range([0, width]);

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

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

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

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


        var svg = d3.select("#myChart").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 + ")");

        dataset.forEach(function(d) {
            d.theTime = parseDate(d.theTime);
            d.theValue = parseFloat(d.theValue);
        });

         x.domain(d3.extent(dataset, function(d) { return d.theTime; }));
         y.domain(d3.extent(dataset, function(d) { return d.theValue;}));

         svg.append("g")
                 .attr("class", "x axis")
                 .attr("transform", "translate(0," + height + ")")
                 .call(xAxis);

         svg.append("g")
                 .attr("class", "y axis")
                 .call(yAxis)
                 .append("text")
                 .attr("transform", "rotate(-90)")
                 .attr("y", 6)
                 .attr("dy", ".71em")
                 .style("text-anchor", "end")
                 .text("M³/hr");

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

      //~~~ Format The Date:
      function formattedDateTime(dateAndTime) {
            var d = new Date(dateAndTime);
            var numDate = d.getDate();
            var numMonth = d.getMonth() + 1;
            var numYear = d.getFullYear();
            var numHours = d.getHours();
            var numMinutes = d.getMinutes();
            var numSeconds = d.getSeconds();
            numDate = (numDate < 10) ? "0" + numDate : numDate;
            numMonth = (numMonth < 10) ? "0" + numMonth : numMonth;
            numHours = (numHours < 10) ? "0" + numHours : numHours;
            numMinutes = (numMinutes < 10) ? "0" + numMinutes : numMinutes;
            numSeconds = (numSeconds < 10) ? "0" + numSeconds : numSeconds;

            return numYear + "/" + numMonth + "/" + numDate + " " + numHours + ":" + numMinutes + ":" + numSeconds;
      };

1 回答

  • 4

    问题是您传递的日期是这种格式:

    '2016/07/12 15:58:40'

    你解析它的解析函数是(注意日期中没有连字符):

    var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
    

    应该是的

    var parseDate = d3.time.format("%Y/%m/%d %H:%M:%S").parse;
    

    接下来的错误是,您传递数据以获取范围,但未在任何位置定义:

    x.domain(d3.extent(data, function(d) { return d.theTime; }));
     y.domain(d3.extent(data, function(d) { return d.theValue;}));
    

    应该是:

    x.domain(d3.extent(dataset, function(d) {
      return d.theTime;
    }));
    y.domain(d3.extent(dataset, function(d) {
      return d.theValue;
    }));
    

    工作代码here

相关问题