3

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…".

3
  • Hi @WebFixItMan, could you share the data object "dataSet" after you perform the for loop at the top. I believe the main reason for both errors comes from the output of the formattedDateTime function. Commented Jul 13, 2016 at 3:27
  • What version of D3? Commented Jul 13, 2016 at 3:39
  • Hi Alex and Gerardo! I believe Cyril's reply answers Alex's question. For Gerardo I am using the CDN link: <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> Commented Jul 13, 2016 at 22:12

1 Answer 1

4

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

Sign up to request clarification or add additional context in comments.

1 Comment

Hi Cyril: Your advice has almost cleared a path to success. It has given me a direction to solve this. I am still getting the Uncaught TypeError: Cannot read property 'length' of undefined. My display also worked when I hard coded the variable 'dataset' like your example on JSFiddle. However, in my version I am confined to using the dynamic 'dataset' variable. I performed an alert(typeof(dataset)) before the 'dataset.forEach' function and it reported it as an 'object'. I am going to start researching how to overcome this, but if you have insight I greatly appreciate the feedback.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.