Parsing Time Series Data using D3.js

北战南征 提交于 2019-12-07 16:18:15

问题


Hello my StackOverflow friends:

It is time to ask for help. I have been studying D3.js for weeks and am just beginning to feel like I understand 10% of it (ha, ha, ha). I am trying to generate a very simple line graph. I am able to do this as long as the data is very simple, but my raw data source has UTC timestamps, and real/decimal numbers that keeps crashing anything beyond simple.

The raw data source looks like this:


    {
      "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"
    }

Using jQuery and a javascript time formatting function I am able to assemble the following simplified dataset:


    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}
    ];

Here is my code:


    //~ 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;
        };

The first error occurs at the 'dataset.forEach()' function, which is "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). If there are any D3.js mentors in the audience please help me identify what I am doing wrong and how to fix it. ¡Muchas Gracias!

// ============= APPENDED 01 ========================

I got it working!! Yeee Haaaw!

I will post the revised working code below. But for anyone following this post I wanted to explain, what I found.

Mark at the linked post (Alternatives for using forEeach() loop while converting data for D3.js) suggested altering the dataset.push() to drop all the quotes. This gave me objects instead of strings. After some troubleshooting it finally displayed as expected (totally psyched!), and thanks Mark, your suggestions did the trick.

Here is the revised code:


    //~ 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:


The problem is the date you are passing is in this format:

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

and the parsedate function you have made to parse it is(Note there is no hyphen in the date):

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

it should have been

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

Next bug is, you are passing data for getting the extent, but its not defined anywhere:

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

It should have been:

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

working code here



来源:https://stackoverflow.com/questions/38341253/parsing-time-series-data-using-d3-js

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!