jamesw1234
jamesw1234

Reputation: 338

d3 invalid value for <path>

I'm new to d3.js and am following the example at http://code.tutsplus.com/tutorials/building-a-multi-line-chart-using-d3js-part-2--cms-22973 to build a nested time series for my application.

However, I run into this error despite the data looking like the nested data in the example

Error: Invalid value for <path> attribute d="MNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaNLNaN,NaN"

My code is here, jsfiddle is http://jsfiddle.net/absail/h9hds98f/

nested_data = [{"key":"False","values":[{"date":"09/04/2015","val":0},{"date":"09/05/2015","val":222},{"date":"09/06/2015","val":168},{"date":"09/07/2015","val":203},{"date":"09/08/2015","val":219},{"date":"09/09/2015","val":237},{"date":"09/10/2015","val":241},{"date":"09/11/2015","val":397},{"date":"09/12/2015","val":158},{"date":"09/13/2015","val":154},{"date":"09/14/2015","val":193},{"date":"09/15/2015","val":202},{"date":"09/16/2015","val":218},{"date":"09/17/2015","val":466},{"date":"09/18/2015","val":439},{"date":"09/19/2015","val":278},{"date":"09/20/2015","val":271},{"date":"09/21/2015","val":475},{"date":"09/22/2015","val":494},{"date":"09/23/2015","val":498},{"date":"09/24/2015","val":503},{"date":"09/25/2015","val":437},{"date":"09/26/2015","val":286},{"date":"09/27/2015","val":280},{"date":"09/28/2015","val":496},{"date":"09/29/2015","val":514}]},{"key":"True","values":[{"date":"09/05/2015","val":3170},{"date":"09/11/2015","val":8643},{"date":"09/04/2015","val":0},{"date":"09/08/2015","val":6146},{"date":"09/12/2015","val":2414},{"date":"09/14/2015","val":5711},{"date":"09/19/2015","val":4118},{"date":"09/26/2015","val":3990},{"date":"09/06/2015","val":2565},{"date":"09/09/2015","val":6426},{"date":"09/13/2015","val":2514},{"date":"09/15/2015","val":5690},{"date":"09/16/2015","val":6222},{"date":"09/17/2015","val":10858},{"date":"09/18/2015","val":9718},{"date":"09/20/2015","val":4006},{"date":"09/21/2015","val":11135},{"date":"09/23/2015","val":11264},{"date":"09/25/2015","val":8831},{"date":"09/27/2015","val":3984},{"date":"09/28/2015","val":11554},{"date":"09/07/2015","val":5562},{"date":"09/10/2015","val":6505},{"date":"09/22/2015","val":11405},{"date":"09/24/2015","val":11411},{"date":"09/29/2015","val":12086}]}];
var parseDate = d3.time.format("%m/%d/%Y").parse;

var color = d3.scale.category10();
var vis = d3.select("#visualisation"),
WIDTH = 1000,
HEIGHT = 500,
MARGINS = {
    top: 50,
    right: 20,
    bottom: 50,
    left: 50
},

lSpace = WIDTH/nested_data.length;
xScale = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(nested_data, function(d) {
    return d.date;
}), d3.max(data, function(d) {
    return d.date;
})]),
yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(nested_data, function(d) {
    return d.val;
}), d3.max(data, function(d) {
    return d.val;
})]),
xAxis = d3.svg.axis()
.scale(xScale),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");

vis.append("svg:g")
  .attr("class", "x axis")
  .attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
  .call(xAxis);
vis.append("svg:g")
  .attr("class", "y axis")
  .attr("transform", "translate(" + (MARGINS.left) + ",0)")
  .call(yAxis);

var lineGen = d3.svg.line()
.x(function(d) {
    return xScale(d.date);
})
.y(function(d) {
    return yScale(d.val);
});
// .interpolate("basis");

// Loop through each symbol / key
nested_data.forEach(function(d, i) {

    vis.append('svg:path')
    .attr('d', lineGen(d.values))
    .attr('stroke', function(d,j) { 
            return "hsl(" + Math.random() * 360 + ",100%,50%)";
    })
    .attr('stroke-width', 2)
    .attr('id', 'line_'+d.key)
    .attr('fill', 'none');

    vis.append("text")
        .attr("x", (lSpace/2)+i*lSpace)
        .attr("y", HEIGHT)
        .style("fill", "black")
        .attr("class","legend")
        .on('click',function(){
            var active   = d.active ? false : true;
            var opacity = active ? 0 : 1;
            d3.select("#line_" + d.key).style("opacity", opacity);
            d.active = active;
        })
        .text(d.key);

});

I realize this is a common error faced by others, but it seems each time the solution was different. Some suggestions included parsing the date, but that didn't seem to solve the issue for me. Any help would be greatly appreciated, as I've been staring at this for hours. Thanks!

Upvotes: 0

Views: 70

Answers (2)

Gilsha
Gilsha

Reputation: 14591

The problem is, you have set the wrong values as the domain of xScale and and yScale. To set the correct domain values, you should either change the data structure as shown below and use the data array to set the domain.

var data = [{"date":"09/04/2015","val":0,"status":false},
{"date":"09/05/2015","val":222,"status":false},
{"date":"09/06/2015","val":168,"status":false},
{"date":"09/07/2015","val":203,"status":false},
{"date":"09/08/2015","val":219,"status":false}, 
{"date":"09/09/2015","val":237,"status":false},
{"date":"09/10/2015","val":241,"status":false},   
{"date":"09/11/2015","val":397,"status":false},  
{"date":"09/12/2015","val":158,"status":false},
{"date":"09/13/2015","val":154,"status":false},
{"date":"09/14/2015","val":193,"status":false},
{"date":"09/15/2015","val":202,"status":false},
{"date":"09/16/2015","val":218,"status":false},
{"date":"09/17/2015","val":466,"status":false},
{"date":"09/18/2015","val":439,"status":false},
{"date":"09/19/2015","val":278,"status":false},
{"date":"09/20/2015","val":271,"status":false},
{"date":"09/21/2015","val":475,"status":false},
{"date":"09/22/2015","val":494,"status":false},
{"date":"09/23/2015","val":498,"status":false},
{"date":"09/24/2015","val":503,"status":false},
{"date":"09/25/2015","val":437,"status":false},
{"date":"09/26/2015","val":286,"status":false},
{"date":"09/27/2015","val":280,"status":false},
{"date":"09/28/2015","val":496,"status":false},
{"date":"09/29/2015","val":514,"status":false},   
{"date":"09/05/2015","val":3170,"status":true},  
{"date":"09/11/2015","val":8643,"status":true},
{"date":"09/04/2015","val":0,"status":true},
{"date":"09/08/2015","val":6146,"status":true},
{"date":"09/12/2015","val":2414,"status":true},
{"date":"09/14/2015","val":5711,"status":true},
{"date":"09/19/2015","val":4118,"status":true},
{"date":"09/26/2015","val":3990,"status":true},
{"date":"09/06/2015","val":2565,"status":true},
{"date":"09/09/2015","val":6426,"status":true},
{"date":"09/13/2015","val":2514,"status":true},
{"date":"09/15/2015","val":5690,"status":true},
{"date":"09/16/2015","val":6222,"status":true},
{"date":"09/17/2015","val":10858,"status":true},
{"date":"09/18/2015","val":9718,"status":true},
{"date":"09/20/2015","val":4006,"status":true},
{"date":"09/21/2015","val":11135,"status":true},
{"date":"09/23/2015","val":11264,"status":true},
{"date":"09/25/2015","val":8831,"status":true},
{"date":"09/27/2015","val":3984,"status":true},
{"date":"09/28/2015","val":11554,"status":true},
{"date":"09/07/2015","val":5562,"status":true},
{"date":"09/10/2015","val":6505,"status":true},
{"date":"09/22/2015","val":11405,"status":true},
{"date":"09/24/2015","val":11411,"status":true},
{"date":"09/29/2015","val":12086,"status":true}];

var nested_data = d3.nest()
   .key(function(d) {
      return d.status;
   })
   .entries(data);

var xScale = d3.scale.linear()
   .range([MARGINS.left, WIDTH - MARGINS.right])
   .domain([d3.min(data, function(d) {
        return new Date(d.date);
   }), d3.max(data, function(d) {       
        return new Date(d.date);
   })]),
yScale = d3.scale.linear()
   .range([HEIGHT - MARGINS.top, MARGINS.bottom])
   .domain([d3.min(data,function(d) {
       return d.val;
   }), d3.max(data, function(d) {
       return d.val;
   })]);

or

Keep the nested_data array as it is and generate the total list of date and values to set find the domain values.

var allValues = nested_data.map(function(d){ return d.values }).reduce(function(a,b){ return d3.merge([a,b]); });

var xScale = d3.scale.linear()
   .range([MARGINS.left, WIDTH - MARGINS.right])
   .domain([d3.min(allValues, function(d) {
        return new Date(d.date);
   }), d3.max(allValues, function(d) {       
        return new Date(d.date);
   })]),
yScale = d3.scale.linear()
   .range([HEIGHT - MARGINS.top, MARGINS.bottom])
   .domain([d3.min(allValues,function(d) {
       return d.val;
   }), d3.max(allValues, function(d) {
       return d.val;
   })]);

Note: Also use new Date(d.date); instead of d.date

Upvotes: 1

Cyril Cherian
Cyril Cherian

Reputation: 32327

Mistake 1:

The way you calculate max and min is wrong:

yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(nested_data, function(d) {
    return d.val;
}), d3.max(data, function(d) {
    return d.val;
})]),

Here nested_data is an array of object which has values array. So the max min will not work correctly.

Fix:

You need to collect all the values in the array and make a single array like this:

//get the array of all values.
var arrays = nested_data.map(function (k) {
    return k.values
});
var collect = [].concat.apply([], arrays);

Mistake 2:

Not handling the date correctly in the code.

xScale = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(nested_data, function(d) {
    return d.date;
}), d3.max(data, function(d) {
    return d.date;//this is a string d3 does not know its a date
})]),

Fix:

You will need to convert it into date like this

var parseDate = d3.time.format("%m/%d/%Y").parse;
//get the array of all values.
var arrays = nested_data.map(function (k) {
    return k.values
});
var collect = [].concat.apply([], arrays);
//converting date
collect.forEach(function(d){d.date1 = parseDate(d.date)});

Then x axis max min function will be like

xScale = d3.time.scale().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(collect, function (d) {

    return d.date1;
}), d3.max(collect, function (d) {
    return d.date1;
})]),
yScale = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(collect, function (d) {
    return d.val;
}), d3.max(collect, function (d) {
    return d.val;
})]),

Full working corrected code here

Hope this helps!

Upvotes: 1

Related Questions