Friday, May 17, 2024
 Popular · Latest · Hot · Upcoming
52
rated 0 times [  54] [ 2]  / answers: 1 / hits: 54583  / 7 Years ago, fri, may 5, 2017, 12:00:00

I'm tring to create a multi-line chart using D3.js v4. I'm using this example: https://bl.ocks.org/mbostock/3884955.



Sample csv Data:



storageSystem,poolId,availableVolumeCapacity,date
system01,0,18031398,20170413
system01,1,15626268,20170413
system01,2,61256286,20170413
system01,3,119514990,20170413
system02,0,15046668,20170413
system02,1,12486558,20170413
system02,2,12303396,20170413
system03,0,35171335,20170413
system03,1,17263722,20170413
system01,0,18031387,20170414
system01,1,15626257,20170414
system01,2,61256275,20170414
system01,3,119514989,20170414
system02,0,15046657,20170414
system02,1,12486547,20170414
system02,2,12303385,20170414
system03,0,35171324,20170414
system03,1,17263711,20170414


Data Object:



0: Object
color: #8c564b
key: system03
values: Array(2)
0: Object
key: 0
values: Array(23)
0: Object
availableVolumeCapacity: 35171335
date: Thu Apr 13 2017 00:00:00 GMT+0000 (Coordinated Universal Time)
poolId: 0
storageSystem: system03
1: Object
key: 1
values: Array(23)
0: Object
availableVolumeCapacity: 17263722
date: Thu Apr 13 2017 00:00:00 GMT+0000 (Coordinated Universal Time)
poolId:1
storageSystem: system03


D3.js Code:



var svg = d3.select(svg)
m = {top: 20, right: 20, bottom: 50, left: 20},
w = svg.attr(width) - m.left - m.right,
h = svg.attr(height) - m.top - m.bottom,
g = svg.append(g).attr(transform, translate( + m.left + , + m.top + ));

var parseTime = d3.timeParse(%Y%m%d);

var x = d3.scaleTime().range([0, w]),
y = d3.scaleLinear().range([h, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);

var line = d3.line()
.curve(d3.curveBasis)
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.availableVolumeCapacity); });

d3.csv(ssystem.csv, function(error, data) {
if (error) throw error;
data.forEach(function(d) {
d.date = parseTime(d.date);
d.availableVolumeCapacity = +d.availableVolumeCapacity;
});

x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.availableVolumeCapacity; })]);

var dataNest = d3.nest()
.key(function(d) {return d.storageSystem; })
.key(function(d) {return d.poolId; })
.entries(data);

console.log(dataNest)

legendSpace = w/dataNest.length;

dataNest.forEach(function(d,i) {
svg.append(path)
.attr(class, line)
.style(stroke, function() {
return d.color = z(d.key); })
.attr(id, 'tag'+d.key.replace(/s+/g, ''))
.attr(d, line(d.values));
svg.append(text)
.attr(x, (legendSpace/2)+i*legendSpace)
.attr(y, h + (m.bottom/2)+ 5)
.attr(class, legend)
.style(fill, function() {
return d.color = z(d.key); })
.on(click, function(){
// Determine if current line is visible
var active = d.active ? false : true,
newOpacity = active ? 0 : 1;
// Hide or show the elements based on the ID
d3.select(#tag+d.key.replace(/s+/g, ''))
.transition().duration(100)
.style(opacity, newOpacity);
// Update whether or not the elements are active
d.active = active;
})
.text(d.key);
});

svg.append(g)
.attr(class, axis axis--x)
.attr(transform, translate(0, + h + ))
.call(d3.axisBottom(x));

svg.append(g)
.attr(class, axis axis--y)
.call(d3.axisLeft(y))
.append(text)
.attr(transform, rotate(-90))
.attr(y, 6)
.attr(dy, 0.71em)
.attr(fill, #000)
.text(Capacity (MB));
});


I'm seeing the following error 4 times from the console:



Error: <path> attribute d: Expected number, MNaN,NaNLNaN,NaN.
(anonymous) @ d3.v4.min.js:205
ul @ d3.v4.min.js:3768
al @ d3.v4.min.js:3775
(anonymous) @ multi-line.js:51
(anonymous) @ multi-line.js:45
(anonymous) @ d3.v4.min.js:5857
call @ d3.v4.min.js:3622
e @ d3.v4.min.js:5840


Any help is much appreciated.


More From » d3.js

 Answers
41

The root of your problem is that the value d in your anonymous function passed to dataNest.forEach still contains one level of nesting but you are using it as if it doesn't have any nesting. Your code fails because it is looking for date and availableVolumeCapacity properties on an object that only has key and values properties.



There are ultimately two approaches to fix this:




  1. Use a single key function which combines both the storage system and pool ID. This reduces the nesting to only one level:



    var dataNest = d3.nest()
    .key(function(d) { return d.storageSystem + + d.poolId; })
    .entries(data);

  2. Use two nested calls to forEach:



    dataNest.forEach(function(d2,i2) {
    d2.forEach(function (d,i) {
    svg.append(path)
    // .... rest of inner function omitted
    });
    });


    You will need to go through all uses of d (in particular d.key) and i within the inner function (whose body I omitted for brevity) to see whether you need to incorporate d2 and i2. For example, perhaps you want to use d2.key + + d.key instead of d.key.



[#57879] Thursday, May 4, 2017, 7 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
collinisaaka

Total Points: 194
Total Questions: 105
Total Answers: 104

Location: Tonga
Member since Tue, Nov 30, 2021
3 Years ago
;