Cannot read property 'values' of null - d3.js

I am following this example, but I am using d3 v4. My d.date have no values. Can't figure out why. The csv file has correct time format. Can you help me?
<script type="text/javascript">
var margin = {top: 20, right: 80, bottom: 30, left: 50},
w = 800 - margin.left - margin.right,
h = 600 - margin.top - margin.bottom;
var x = d3.scaleTime()
.domain([new Date("January 1, 2012"), new Date("May 31, 2017")])
.range([0, w]);
var y = d3.scaleLinear()
.range([h, 0]);
var xAxis = d3.axisBottom()
.scale(x)
.tickFormat(d3.timeFormat("%m/%Y"));
var yAxis = d3.axisLeft()
.scale(y)
var parseDate = d3.timeParse("%d%m%Y");
console.log(parseDate);
var color = d3.scaleOrdinal(d3.schemeCategory10);
var line = d3.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.stat); });
var svg = d3.select("body").append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("svg:g")
.attr("class", "x_axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
svg.append("svg:g")
.attr("class", "y_axis")
.call(yAxis)
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("Numbers");
var menu = d3.select("#menu select")
.on("change", change);
d3.csv("Data4.csv", function(csv) {
console.log(csv);
medias = csv
redraw();
});
d3.select(window)
.on("keydown", function() { altKey = d3.event.altKey; })
.on("keyup", function() { altKey = false; });
var altKey;
function change() {
clearTimeout(timeout);
d3.transition()
.duration(altKey ? 7500 : 1500)
.each(redraw);
}
function redraw() {
var nested = d3.nest()
.key(function(d) { return d.indicatorCode;})
.object(medias)
var series = menu.property("value");
var data = nested[series];
console.log(data);
var keyring = d3.keys(data[0]).filter(function(key) {
return (key !== "Sel_name" && key !== "monthCode" && key !== "indicatorCode" && key !== "date");
// console.log(keyring);
});
var transpose = keyring.map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: new Date(parseDate(d.date)), stat: d[name]};
})
};
});
console.log(transpose);
x.domain([
d3.min(transpose, function(c) { return d3.min(c.values, function(d) { return d.date; }); }),
d3.max(transpose, function(c) { return d3.max(c.values, function(d) { return d.date; }); })
]);
y.domain([
d3.min(transpose, function(c) { return d3.min(c.values, function(d) { return d.stat; }); }),
d3.max(transpose, function(c) { return d3.max(c.values, function(d) { return d.stat; }); })
]);
var media = svg.selectAll(".media")
.data(transpose)
.enter().append("g")
.attr("class", "media")
.attr("id", function(d) { return d.name; });
media.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
media.append("text")
.attr("class", "names")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.stat) + ")"; })
.attr("x", 4)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
var mediaUpdate = d3.transition(media);
mediaUpdate.select("path")
.attr("d", function(d) { return line(d.values); });
mediaUpdate.select("text")
.attr("transform", function(d) { return "translate(" + x(d.values[d.values.length - 1].date) + "," + y(d.values[d.values.length - 1].stat) + ")"; });
d3.transition(svg).select("y_axis")
.call(yAxis);
d3.transition(svg).select("x_axis")
.attr("transform", "translate(0," + h + ")")
.call(xAxis);
}
var timeout = setTimeout(function() {
menu.property("value", "NSPM").node().focus();
change();
}, 7000);
function smedia() {
var chkbox = document.getElementById("statmedia");
if (chkbox.checked) {
document.getElementById("media5").style.cssText = "opacity:1;",
document.getElementById("media6").style.cssText = "opacity:1;",
document.getElementById("media7").style.cssText = "opacity:1;",
document.getElementById("media8").style.cssText = "opacity:1;"
} else {
document.getElementById("media5").style.cssText = "",
document.getElementById("media6").style.cssText = "",
document.getElementById("media7").style.cssText = "",
document.getElementById("media8").style.cssText = "";
}};
function nstmedia() {
var chkbox = document.getElementById("nonstmedia")
if (chkbox.checked) {
document.getElementById("media1").style.cssText = "opacity:1;",
document.getElementById("media2").style.cssText = "opacity:1;",
document.getElementById("media3").style.cssText = "opacity:1;",
document.getElementById("media4").style.cssText = "opacity:1;",
document.getElementById("media5").style.cssText = "opacity:1;",
document.getElementById("media6").style.cssText = "opacity:1;",
document.getElementById("media7").style.cssText = "opacity:1;",
document.getElementById("media8").style.cssText = "opacity:1;",
document.getElementById("media9").style.cssText = "opacity:1;"
} else {
document.getElementById("media1").style.cssText = "",
document.getElementById("media2").style.cssText = "",
document.getElementById("media3").style.cssText = "",
document.getElementById("media4").style.cssText = "",
document.getElementById("media5").style.cssText = "",
document.getElementById("media6").style.cssText = "",
document.getElementById("media7").style.cssText = "",
document.getElementById("media8").style.cssText = "",
document.getElementById("media9").style.cssText = "";
}};
</script>
My cvs file looks like following:
Sel_name,indicatorCode,date,monthCode,media1,media2,media3,media4,media5,media6,media7,media8,media9,media10,media11,media12,media13
Num_posts_pmon,NPPM,31/01/2012,m1201,217,146,0,1114,0,0,0,0,0,0,0,0,54
Num_posts_pmon,NPPM,29/02/2012,m1202,159,161,0,1402,0,0,0,0,0,0,0,0,31
Num_posts_pmon,NPPM,31/03/2012,m1203,8,7,0,1212,0,0,0,24,0,0,0,28,17
Num_posts_pmon,NPPM,30/04/2012,m1204,10,14,0,1004,0,0,0,111,0,0,26,28,6
Num_posts_pmon,NPPM,31/05/2012,m1205,15,73,0,1070,0,0,0,76,0,0,127,557,6
Num_posts_pmon,NPPM,30/06/2012,m1206,102,396,0,834,0,0,0,97,0,0,23,893,1
Num_posts_pmon,NPPM,31/07/2012,m1207,148,276,0,993,0,0,0,63,0,0,67,602,0
Num_posts_pmon,NPPM,31/08/2012,m1208,167,189,0,909,34,0,0,54,0,0,31,606,3
Num_posts_pmon,NPPM,30/09/2012,m1209,176,196,0,991,254,0,0,80,0,0,81,608,8
Num_posts_pmon,NPPM,31/10/2012,m1210,121,184,0,1064,190,0,0,41,0,0,93,600,100
Num_posts_pmon,NPPM,30/11/2012,m1211,107,137,0,1301,78,0,0,68,0,0,110,416,116
Num_posts_pmon,NPPM,31/12/2012,m1212,73,108,0,1190,40,0,0,41,0,0,163,306,158
Num_posts_pmon,NPPM,31/01/2013,m1301,98,122,0,1266,121,0,0,53,0,0,137,329,201
Num_posts_pmon,NPPM,28/02/2013,m1302,92,108,0,1248,175,0,0,32,0,0,86,221,205
Num_posts_pmon,NPPM,31/03/2013,m1303,95,101,0,1330,88,0,0,59,0,0,112,160,243
Num_posts_pmon,NPPM,30/04/2013,m1304,122,127,0,1764,280,0,0,61,0,0,151,264,189
Num_posts_pmon,NPPM,31/05/2013,m1305,89,90,0,1645,630,0,785,123,715,0,144,275,203
Num_posts_pmon,NPPM,30/06/2013,m1306,83,103,0,1541,830,0,1105,130,1425,0,99,260,268
Num_posts_pmon,NPPM,31/07/2013,m1307,89,111,0,1468,895,0,1515,133,1443,0,40,145,318
Num_posts_pmon,NPPM,31/08/2013,m1308,82,86,0,1508,1105,0,1720,125,1488,0,65,227,250
Num_posts_pmon,NPPM,30/09/2013,m1309,264,117,0,1690,1900,14,1507,195,2515,0,105,226,251

Your specifier is wrong, you're forgetting the forward slashes.
Since your dates are like this:
31/01/2012
Your specifier should be:
var parseDate = d3.timeParse("%d/%m/%Y");
Besides that, you don't need the new Date in the map function:
var date = "31/01/2012";
var parseDate = d3.timeParse("%d/%m/%Y");
console.log(parseDate(date))
console.log(new Date(parseDate(date)))
<script src="https://d3js.org/d3.v4.min.js"></script>

Related

How can I refactor a d3 pie to accept more or less data points?

I have a project that almost works the way I want. When a smaller dataset is added, slices are removed. It fails when a larger dataset is added. The space for the arc is added but no label or color is added for it.
This is my enter() code:
newArcs.enter()
.append("path")
.attr("stroke", "white")
.attr("stroke-width", 0.8)
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
What am I doing wrong?
I've fixed the code such that it works now:
// Tween Function
var arcTween = function(a) {
var i = d3.interpolate(this.current || {}, a);
this.current = i(0);
return function(t) {
return arc(i(t));
};
};
// Setup all the constants
var duration = 500;
var width = 500
var height = 300
var radius = Math.floor(Math.min(width / 2, height / 2) * 0.9);
var colors = ["#d62728", "#ff9900", "#004963", "#3497D3"];
// Test Data
var d2 = [{
label: 'apples',
value: 20
}, {
label: 'oranges',
value: 50
}, {
label: 'pears',
value: 100
}];
var d1 = [{
label: 'apples',
value: 100
}, {
label: 'oranges',
value: 20
}, {
label: 'pears',
value: 20
}, {
label: 'grapes',
value: 20
}];
// Set the initial data
var data = d1
var updateChart = function(dataset) {
arcs = arcs.data(donut(dataset), function(d) { return d.data.label });
arcs.exit().remove();
arcs.enter()
.append("path")
.attr("stroke", "white")
.attr("stroke-width", 0.8)
.attr("fill", function(d, i) {
return color(i);
})
.attr("d", arc);
arcs.transition()
.duration(duration)
.attrTween("d", arcTween);
sliceLabel = sliceLabel.data(donut(dataset), function(d) { return d.data.label });
sliceLabel.exit().remove();
sliceLabel.enter()
.append("text")
.attr("class", "arcLabel")
.attr("transform", function(d) {
return "translate(" + (arc.centroid(d)) + ")";
})
.attr("text-anchor", "middle")
.style("fill-opacity", function(d) {
if (d.value === 0) {
return 1e-6;
} else {
return 1;
}
})
.text(function(d) {
return d.data.label;
});
sliceLabel.transition()
.duration(duration)
.attr("transform", function(d) {
return "translate(" + (arc.centroid(d)) + ")";
})
.style("fill-opacity", function(d) {
if (d.value === 0) {
return 1e-6;
} else {
return 1;
}
});
};
var color = d3.scale.category20();
var donut = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.value;
});
var arc = d3.svg.arc()
.innerRadius(radius * .4)
.outerRadius(radius);
var svg = d3.select("body")
.append("svg")
.attr("width", width)
.attr("height", height);
var arc_grp = svg.append("g")
.attr("class", "arcGrp")
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
var label_group = svg.append("g")
.attr("class", "lblGroup")
.attr("transform", "translate(" + (width / 2) + "," + (height / 2) + ")");
var arcs = arc_grp.selectAll("path");
var sliceLabel = label_group.selectAll("text");
updateChart(data);
// returns random integer between min and max number
function getRand() {
var min = 1,
max = 2;
var res = Math.floor(Math.random() * (max - min + 1) + min);
//console.log(res);
return res;
}
// Update the data
setInterval(function(model) {
var r = getRand();
return updateChart(r == 1 ? d1 : d2);
}, 2000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

Incomplete line chart with missing points and missing lines

var maindata=[
{"date":"21-APR-16 04:19 AM","Delhi":30,"Mumbai":28},
{"date":"21-APR-16 05:19 AM","Delhi":32,"Mumbai":30},
{"date":"21-APR-16 06:19 AM","Delhi":34,"Mumbai":34},
{"date":"21-APR-16 10:19 AM","Kolkata":34},
{"date":"21-APR-16 11:19 AM","Delhi":48,"Chennai":40,"Kolkata":36}
];
var that = this;
var deepClonedCopy = jQuery.extend(true, {}, maindata);
var data;
data = $.map(deepClonedCopy, function(el) { return el });
// var passedheight = this.getHeight();
//var containerWidth = jQuery.sap.byId(this.oParent.sId).width() || 800; // gets super parent width
var margin = {top: 15, right: 30, bottom: 20, left: 30},
width = 960- margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
if(data.length >= 1){
//alert(JSON.stringify(data));
var parseDate = d3.time.format("%d-%b-%y %H:%M %p").parse;
var maxDate = d3.time.hour.offset(parseDate(d3.max(data, function(d) { return d.date; })),+1);
var minDate = d3.time.hour.offset(parseDate(d3.min(data, function(d) { return d.date; })),-1);
var div = d3.select("#toolTip");
var x = d3.time.scale()
.domain([minDate, maxDate])
.range([0, width]);
var y = d3.scale.linear()
.range([Math.ceil(height), 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom").ticks(4);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left").ticks(4).tickSize(-width, 0, 0);
var line = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.tonneValue); });
var svg = d3.select("body").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 + ")");
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date" && key !== "maxLength"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var wsfs = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, tonneValue: +d[name]};
})
};
});
//x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
//d3.min(wsfs, function(c) { return d3.min(c.values, function(v) { return v.tonneValue; }); }),
0,
Math.ceil(d3.max(wsfs, function(c) { return d3.max(c.values, function(v) { return v.tonneValue; }); }))
]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var wsf = svg.selectAll(".wsf")
.data(wsfs)
.enter().append("g")
.attr("class", "wsf");
wsf.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
wsf.selectAll("dot")
.data(function(d) { return d.values;})
.enter().append("circle")
.attr("class", "dot")
.attr("r", 3)
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.tonneValue); })
.attr("stroke", function (d) {
return color(this.parentNode.__data__.name) })
.attr("fill", function (d) {
return color(this.parentNode.__data__.name) })
//.attr("fill-opacity", .5)
//.attr("stroke-width", 2)
.on("mouseover", function (d) {
formatDate = d3.time.format("%d-%m-%Y %H:%M %p");
div.transition().duration(100).style("opacity", .9);
div.html(/*this.parentNode.__data__.name + "<br/>" +*/ d.tonneValue /*+ "<br/>" + "<br/>"*/ +" Tonne handled at "+ formatDate(d.date))
.style("left", (d3.event.pageX) + "px").style("top", (d3.event.pageY - 28) + "px").attr('r', 8);
d3.select(this).attr('r', 8)
}).on("mouseout", function (d) {
div.transition().duration(600).style("opacity", 0)
d3.select(this).attr('r', 3);
});
var legendNames = d3.keys(data[0]).filter(function(key) { return key !== "date" });
data.forEach(function(d) {
d.ages = legendNames.map(function(name) { return {name: name, value: +d[name]}; });
});
var legend = svg.selectAll(".legend")
.data(legendNames.slice())
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 4)
.style("fill", function(d) {return color(d); });
legend.append("text")
.attr("x", width - 24)
.attr("y", 6)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) { return d; });
}
The above code gives 2 lines, until first 3 json elements till the data format is similar.
but from 4th element there is no Delhi / Mumbai and there is just Kolkata, but I don't find a line for Kolkata 34, Kolkata 36 neither Delhi's 48 point, where Delhi's line should extend from 34 to 48 and Chennai a simple dot is expected as there is only one point of Chennai i.e. 40.
Can any one tell where am I doing wrong. Here is a fiddle.
The main problem in the code (missing lines and points and incomplete legend) is that your data needs some structuring.
You dataset some times has cities which may or may not be present.
So The first task will be to make a proper data set
From this:
var maindata = [{
"date": "21-APR-16 04:19 AM",
"Delhi": 30,
"Mumbai": 28
}, {
"date": "21-APR-16 05:19 AM",
"Delhi": 32,
"Mumbai": 30
}, {
"date": "21-APR-16 06:19 AM",
"Delhi": 34,
"Mumbai": 34
}, {
"date": "21-APR-16 10:19 AM",
"Kolkata": 34
}, {
"date": "21-APR-16 11:19 AM",
"Delhi": 48,
"Chennai": 40,
"Kolkata": 36
}];
To this:
[
{
"name":"Delhi",
"values":[
{
"date":"2016-04-20T22:49:00.000Z",
"value":30
},
{
"date":"2016-04-20T23:49:00.000Z",
"value":32
},
{
"date":"2016-04-21T00:49:00.000Z",
"value":34
},
{
"date":"2016-04-21T05:49:00.000Z",
"value":48
}
]
},
{
"name":"Mumbai",
"values":[
{
"date":"2016-04-20T22:49:00.000Z",
"value":28
},
{
"date":"2016-04-20T23:49:00.000Z",
"value":30
},
{
"date":"2016-04-21T00:49:00.000Z",
"value":34
}
]
},
{
"name":"Kolkata",
"values":[
{
"date":"2016-04-21T04:49:00.000Z",
"value":34
},
{
"date":"2016-04-21T05:49:00.000Z",
"value":36
}
]
},
{
"name":"Chennai",
"values":[
{
"date":"2016-04-21T05:49:00.000Z",
"value":40
}
]
}
]
So now all cities have their respective data.
Number of cities x so number of lines will be x.
To make the dataset do this:
var cities = []
var parseDate = d3.time.format("%d-%b-%y %H:%M %p").parse;
maindata.forEach(function(d) {
cities.push(d3.keys(d).filter(function(key) {
return key !== "date" && key !== "maxLength";
}));
});
cities = d3.set(d3.merge(cities)).values();//get all cites and make it unique
console.log(cities)
var myData = [];
var allValues = [];
var allDates =[];
//generate cities and its values as shown in my dataset above.
cities.forEach(function(city){
var cityData = {};
cityData.name = city;
cityData.values = [];
maindata.forEach(function(md){
if (md[city]){
allValues.push(md[city])
allDates.push(parseDate(md.date))
cityData.values.push({date: parseDate(md.date), value: md[city]})
}
})
myData.push(cityData)
});
Next make lines like this:
var wsf = svg.selectAll(".wsf")
.data(myData)
.enter().append("g")
.attr("class", "wsf");
wsf.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) {
return color(d.name);
});
And Legends like this:
var legend = svg.selectAll(".legend")
.data(cities)
.enter().append("g")
.attr("class", "legend")
.attr("transform", function(d, i) {
return "translate(0," + i * 20 + ")";
});
legend.append("rect")
.attr("x", width - 18)
.attr("width", 18)
.attr("height", 4)
.style("fill", function(d) {
return color(d);
});
legend.append("text")
.attr("x", width - 24)
.attr("y", 6)
.attr("dy", ".35em")
.style("text-anchor", "end")
.text(function(d) {
return d;
});
}
working code here
Here is the updated fiddle
some keys(i.e. Kolkata)aren't included in binding data
Original code:
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date" && key !== "maxLength"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var wsfs = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, tonneValue: +d[name]};
})
};
});
To(you need change ['Delhi', 'Mumbai', 'Kolkata', 'Chennai'] to code more formally):
var wsfs = ['Delhi', 'Mumbai', 'Kolkata', 'Chennai'].map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, tonneValue: +d[name]};
}).filter(function(d) {
return !isNaN(d.tonneValue)
})
};
});
Filter data
Original code:
var wsfs = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, tonneValue: +d[name]};
})
};
});
To:
var wsfs = ['Delhi', 'Mumbai', 'Kolkata', 'Chennai'].map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, tonneValue: +d[name]};
}).filter(function(d) {
return !isNaN(d.tonneValue)
})};
});

d3.js parallel coordinate with one different scale

I'm trying to generate a parallel coordinate using d3.js
My problem is that the first scale should display different strings.
with the original code it looks like this:
and with my test it looks like this (no lines):
the error code is:
Error: Invalid value for attribute d="M33,NaNL99,161.37817638266068L165,6.543121881682145L231,16.962488563586458L297,180"
here is my code:
function parallelChart (id, size) {
if(size == 'small') {
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 460 - margin.left - margin.right,
height = 230 - margin.top - margin.bottom;
} else {
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
}
var x = d3.scale.ordinal().rangePoints([0, width], 1),
y = {},
dragging = {};
var line = d3.svg.line(),
axis = d3.svg.axis().orient("left"),
background,
foreground;
var svg = d3.select(id).append("svg")
.attr("class", 'center-block')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// Original
d3.csv("dataNew.csv", function(error, healthdata) {
x.domain(dimensions = d3.keys(healthdata[0]).filter(function(d) {
return d != "Datum" && (y[d] = d3.scale.linear()
.domain(d3.extent(healthdata, function(p) { return +p[d]; }))
.range([height, 0]));
}));
// this did not work
// d3.csv("dataNew.csv", function(error, healthdata) {
// x.domain(dimensions = d3.keys(healthdata[0]).filter(function(d) {
// if(d == "Datum") {
// return d == "Datum" && ( (y[d] = d3.time.scale()
// .domain(d3.extent(healthdata, function(p) { return +p[d]; }))
// .range([height, 0])));
// }
// return d != "Datum" && ( (y[d] = d3.scale.linear()
// .domain(d3.extent(healthdata, function(p) { return +p[d]; }))
// .range([height, 0])));
// }));
// Add grey background lines for context.
background = svg.append("g")
.attr("class", "background")
.selectAll("path")
.data(healthdata)
.enter().append("path")
.attr("d", path);
// Add blue foreground lines for focus.
foreground = svg.append("g")
.attr("class", "foreground")
.selectAll("path")
.data(healthdata)
.enter().append("path")
.attr("d", path);
// Add a group element for each dimension.
var g = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + x(d) + ")"; })
.call(d3.behavior.drag()
.origin(function(d) { return {x: x(d)}; })
.on("dragstart", function(d) {
dragging[d] = x(d);
background.attr("visibility", "hidden");
})
.on("drag", function(d) {
dragging[d] = Math.min(width, Math.max(0, d3.event.x));
foreground.attr("d", path);
dimensions.sort(function(a, b) { return position(a) - position(b); });
x.domain(dimensions);
g.attr("transform", function(d) { return "translate(" + position(d) + ")"; })
})
.on("dragend", function(d) {
delete dragging[d];
transition(d3.select(this)).attr("transform", "translate(" + x(d) + ")");
transition(foreground).attr("d", path);
background
.attr("d", path)
.transition()
.delay(500)
.duration(0)
.attr("visibility", null);
}));
// Add an axis and title.
g.append("g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(axis.scale(y[d])); })
.append("text")
.style("text-anchor", "middle")
.attr("y", -9)
.text(function(d) { return d; });
// Add and store a brush for each axis.
g.append("g")
.attr("class", "brush")
.each(function(d) {
d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brushstart", brushstart).on("brush", brush));
})
.selectAll("rect")
.attr("x", -8)
.attr("width", 16);
});
function position(d) {
var v = dragging[d];
return v == null ? x(d) : v;
}
function transition(g) {
return g.transition().duration(500);
}
// Returns the path for a given data point.
function path(d) {
return line(dimensions.map(function(p) { return [position(p), y[p](d[p])]; }));
}
function brushstart() {
d3.event.sourceEvent.stopPropagation();
}
// Handles a brush event, toggling the display of foreground lines.
function brush() {
var actives = dimensions.filter(function(p) { return !y[p].brush.empty(); }),
extents = actives.map(function(p) { return y[p].brush.extent(); });
foreground.style("display", function(d) {
return actives.every(function(p, i) {
return extents[i][0] <= d[p] && d[p] <= extents[i][1];
}) ? null : "none";
});
}
}
Here goes one example where the author manage string and numbers in the same parallel coord:
http://bl.ocks.org/syntagmatic/4020926
Create an array of dimensions that will be further used...
var dimensions = [
{
name: "name",
scale: d3.scale.ordinal().rangePoints([0, height]),
type: "string"
},
{
name: "economy (mpg)",
scale: d3.scale.linear().range([0, height]),
type: "number"
},
...
]
...before load the data, define the domains by mapping your previous dimensions definition...
var x = d3.scale.ordinal()
.domain(dimensions.map(function(d) { return d.name; }))
.rangePoints([0, width]);
...define a variable dimension (pay attention, dimensions != dimension) with the locations of each axis...
var dimension = svg.selectAll(".dimension")
.data(dimensions)
.enter().append("g")
.attr("class", "dimension")
.attr("transform", function(d) { return "translate(" + x(d.name) + ")"; });
...once the data is loaded, execute a for each to define the domain of each dimension...
d3.csv("cars.small.csv", function(data) {
dimensions.forEach(function(dimension) {
dimension.scale.domain(dimension.type === "number"
? d3.extent(data, function(d) { return +d[dimension.name]; })
: data.map(function(d) { return d[dimension.name]; }).sort());
});
...
}
... axis lines and foreground are still loaded in the same way...
svg.append("g")
.attr("class", "background")
.selectAll("path")
.data(data)
.enter().append("path")
.attr("d", draw);
svg.append("g")
.attr("class", "foreground")
.selectAll("path")
.data(data)
.enter().append("path")
.attr("d", draw);
... this code will load the text of each axis, observe that it is now using properties from the dimensions that we defined in the beggining.
dimension.append("g")
.attr("class", "axis")
.each(function(d) { d3.select(this).call(yAxis.scale(d.scale)); })
.append("text")
.attr("class", "title")
.attr("text-anchor", "middle")
.attr("y", -9)
.text(function(d) { return d.name; });
that`s all =).

Invalid value for<path> attribute in d3.js

I am a complete newbie in d3.js and I was working around with some code but it's failing to create the path. Can someone help me to figure out what I am doing wrong?
Link for jsfiddle: http://jsfiddle.net/p8S7p/154/
var data = [
{
data: [
[
1420815600000,
2
],
[
1420826400000,
2
],
[
1420837200000,
2
],
[
1420848000000,
2
],
],
parameter: "t1"
},
{
data: [
[
1420815600000,
2
],
[
1420826400000,
2
],
[
1420837200000,
2
],
[
1420848000000,
2
],
],
parameter: "t2"
}
];
var margin = {
top: 20,
right: 80,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var x = d3.scale.linear()
.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()
.interpolate("basis")
.x(function (d) { return x(d[0]); })
.y(function (d) {
return y(d[1]);
});
var svg = d3.select("body").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 + ")");
var cities = [];
for (var i = 0; i < data.length; i++) {
var t = {};
t["name"] = data[i].parameter;
t["values"] = [];
for (var j = 0; j < data[i].data.length; j++) {
var m = {};
m["date"] = data[i].data[j][0];
m["temperature"] = data[i].data[j][1];
t["values"].push(m);
}
cities.push(t);
}
x.domain(d3.extent(data[0].data, function (d) {
return d[0];
}));
y.domain([
d3.min(cities, function (c) {
return d3.min(c.values, function (v) {
return v.temperature;
});
}),
d3.max(cities, function (c) {
return d3.max(c.values, function (v) {
return v.temperature;
});
})]);
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("Temperature (ºF)");
var city = svg.selectAll(".city")
.data(cities)
.enter().append("g")
.attr("class", "city");
city.append("path")
.attr("class", "line")
.attr("d", function (d) {
return line(d.values);
});
Its meant to be dates on x -axis. How should I parse milliseconds dates to D3 time format?
In your code
var line = d3.svg.line()
.interpolate("basis")
.x(function (d) { return x(d[0]); }) //this is incorrect why d[0]
.y(function (d) {
return y(d[1]); //this is incorrect why d[1]
});
should have been
var line = d3.svg.line()
.interpolate("basis")
.x(function (d) { return x(d.date); })
.y(function (d) {
return y(d.temperature);
});
Coz that's how you have parsed your data here
var cities = [];
for (var i = 0; i < data.length; i++) {
var t = {};
t["name"] = data[i].parameter;
t["values"] = [];
for (var j = 0; j < data[i].data.length; j++) {
var m = {};
m["date"] = data[i].data[j][0];//storing this in date
m["temperature"] = data[i].data[j][1];//storing it in temperature
t["values"].push(m);
}
cities.push(t);
}
Working code here
Hope this helps!

d3js - TypeError: string is undefined

I don't understand this error:
TypeError: string is undefined
function d3_time_parse(date, template, string, j) {
var c, p, i = 0, n = template.length, m = string.length;
...
Here my code:
var margin = {top: 20, right: 80, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y%m%d").parse;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left");
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.index); });
var svg = d3.select("body").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 + ")");
d3.csv("data.csv", function(error, data) {
color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; }));
data.forEach(function(d) {
d.date = parseDate(d.date);
});
var indexes = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {date: d.date, index: +d[name]};
})
};
});
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(indexes, function(c) { return d3.min(c.values, function(v) { return v.index; }); }),
d3.max(indexes, function(c) { return d3.max(c.values, function(v) { return v.index; }); })
]);
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("Variation (%)");
var index = svg.selectAll(".index")
.data(indexes)
.enter().append("g")
.attr("class", "index");
index.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); });
index.append("text")
.datum(function(d) { return {name: d.name, value: d.values[d.values.length - 1]}; })
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.index) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
});
and my csv file look like this:
Date,DAX,CAC40,FTSE,NASDAQ,Other
20060407,-0.000712859,-0.009013212,0.010819606,0.009846526,0.003082604
20060413,-0.007765968,-0.024263398,0.011238971,0.004128621,0.005952774
20060421,0.02261859,0.00330204,0.028734861,0.001688981,0.003459211
20060428,0.007170521,-0.007531405,0.010534438,-0.002416181,0.004012361
...
Could someone please help me?
thx
skeut
Date,DAX,CAC40,FTSE,NASDAQ,Other
JavaScript variable names are case sensitive, so when parsing CSV file with headers as above you need to refer to fields with:
d.Date // note the uppercase D
d.DAX // note all uppercase
Here's an example from d3 wiki https://github.com/mbostock/d3/wiki/CSV#wiki-parse
Year,Make,Model,Length
1997,Ford,E350,2.34
2000,Mercury,Cougar,2.38
When parsed with d3's CSV parser, the resulting data will be represented by the following array:
[
{"Year": "1997", "Make": "Ford", "Model": "E350", "Length": "2.34"},
{"Year": "2000", "Make": "Mercury", "Model": "Cougar", "Length": "2.38"}
]
Note the uppercase object keys. To access the year of the first entry, a "Year" with an uppercase Y in data[0].Year would be necessary.
Thus in your forEach function you'll need:
data.forEach(function (d) {
d.Date = parseDate(d.Date);
});
... and later on:
return {date: d.Date, index: +d[name]};

Resources