How to separate different "gravitational fields" in D3? - d3.js

I have a force enabled SVG visualisation where I want smaller circles to be attracted to bigger circles. This attraction works by calculating the elements' centre point and change it in iterations for every "tick" in the visualisation, to keep the items from going over the centre of the nodes I use a function to change the charge of the items depending on their size.
I used Mike's code here as a basis: http://mbostock.github.io/d3/talk/20110921/#14
My problem comes here - it seems like the bigger circles are affecting each others "gravitational fields" - is there a way I can separate them from eachother?
Force layout setup:
var w = 1280,
h = 800,
color = d3.scale.category10();
var force = d3.layout.force()
.gravity(0.0)
.charge(function(d){
return -10 * d.r;
})
.size([w, h]);
Element drawing:
var g = svg.selectAll("g.node")
.data(nodes)
.enter().append("svg:g")
.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
;
g.append("svg:circle")
.attr("r", 40)
.attr("transform", function(d) { return "translate(" + 0 + ","+ 0 + ")"; })
.style("fill", fill)
.call(force.drag);
g.append("svg:text")
.attr("x", 0)
.attr("dy", ".31em")
.attr("text-anchor", "middle")
.text(function(d) {
return d.label;
});
Animation loop:
force.on("tick", function(e) {
var k = e.alpha * 0.5;
nodes.forEach(function(node) {
var center = nodes[node.type];
dx = center.x - node.x;
dy = center.y - node.y;
node.x += dx * k;
node.y += dy * k;
});
svg.selectAll(".circle")
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
});
Adding smaller circles:
svg.on("mousemove", function() {
var p1 = d3.svg.mouse(this),
node = {
type: Math.random() * 3 | 0,
x: p1[0],
y: p1[1],
r: 1.5,
px: (p0 || (p0 = p1))[0],
py: p0[1]
};
p0 = p1;
svg.append("svg:circle")
.attr("class", "circle")
.data([node])
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.attr("r", 4.5)
.style("fill", fill);
nodes.push(node);
force.start();
});

Related

How can I add icons to this force simulation example in d3js and avoid code duplication?

I have two questions, one about the icons and other about code duplication.
I'm using this example:
http://bl.ocks.org/rveciana/6184054/bd294b921ebf2180eccc3aca548c895367fca2d2
(Thanks Roger Veciana)
I want to add an icon to each of those cirlces but I need to put the url inside a json instead of using the script to generate those cirlces (that is inside the code). Not sure what I'm doing wrong but is not working. Any tip on how can I add the icon to each circle ?
I've also added some text, and it is working. Basically I do this:
var circlemaint = svgmaint.selectAll("circle")
.data(nodes.maint)
.enter().append("g").append("circle")
.attr("r", function(d) { return d.radius; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; })
.style("fill", function(d) { return d.color; })
.call(d3.drag);
var txtmaint = svgmaint.selectAll("circle")
.select('text')
.data(nodes.maint)
.enter().append('text')
.text(node => node.id)
.attr('font-size', 18)
.attr('dx', -25)
.attr('dy',20)
The issue here, is that I have 9 different svg's, and I don't want to duplicate this per svg. How can avoid code duplication?
I finally call it within the tick function and I do something like this:
function tick(e) {
simulation.alpha(0.2)
circlemaint
.each(gravity(this.alpha()))
.each(collide(.5))
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
txtmaint
.each(gravity(this.alpha()))
.each(collide(.5))
.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
circleXXXX
......
txtXXXXXX
......
}
And here is the code of the example:
//Based in
///http://bl.ocks.org/mbostock/1804919
var margin = {
top: 0,
right: 0,
bottom: 0,
left: 0
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var rect = [50, 50, width - 50, height - 50];
var n = 20,
m = 4,
padding = 6,
maxSpeed = 3,
radius = d3.scale.sqrt().range([0, 8]),
color = d3.scale.category10().domain(d3.range(m));
var nodes = [];
for (i in d3.range(n)) {
nodes.push({
radius: radius(1 + Math.floor(Math.random() * 4)),
color: color(Math.floor(Math.random() * m)),
x: rect[0] + (Math.random() * (rect[2] - rect[0])),
y: rect[1] + (Math.random() * (rect[3] - rect[1])),
speedX: (Math.random() - 0.5) * 2 * maxSpeed,
speedY: (Math.random() - 0.5) * 2 * maxSpeed
});
}
var force = d3.layout.force()
.nodes(nodes)
.size([width, height])
.gravity(0)
.charge(0)
.on("tick", tick)
.start();
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 + ")");
svg.append("svg:rect")
.attr("width", rect[2] - rect[0])
.attr("height", rect[3] - rect[1])
.attr("x", rect[0])
.attr("y", rect[1])
.style("fill", "None")
.style("stroke", "#222222");
var circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", function(d) {
return d.radius;
})
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
})
.style("fill", function(d) {
return d.color;
})
.call(force.drag);
var flag = false;
function tick(e) {
force.alpha(0.1)
circle
.each(gravity(e.alpha))
.each(collide(.5))
.attr("cx", function(d) {
return d.x;
})
.attr("cy", function(d) {
return d.y;
});
}
// Move nodes toward cluster focus.
function gravity(alpha) {
return function(d) {
if ((d.x - d.radius - 2) < rect[0]) d.speedX = Math.abs(d.speedX);
if ((d.x + d.radius + 2) > rect[2]) d.speedX = -1 * Math.abs(d.speedX);
if ((d.y - d.radius - 2) < rect[1]) d.speedY = -1 * Math.abs(d.speedY);
if ((d.y + d.radius + 2) > rect[3]) d.speedY = Math.abs(d.speedY);
d.x = d.x + (d.speedX * alpha);
d.y = d.y + (-1 * d.speedY * alpha);
};
}
// Resolve collisions between nodes.
function collide(alpha) {
var quadtree = d3.geom.quadtree(nodes);
return function(d) {
var r = d.radius + radius.domain()[1] + padding,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 ||
x2 < nx1 ||
y1 > ny2 ||
y2 < ny1;
});
};
}
<script src="https://d3js.org/d3.v3.js"></script>
Thank you so much!!

How to change the size of dots in beeswarm plots in D3.js

I've been looking at this example of a beeswarm plot in d3.js and I'm trying to figure out how to change the size of the dots and without getting the circles to overlap. It seems if the radius of the dots change, it doesn't take this into account when running the calculations of where to place the dots.
This is a cool visualization.
I've made a plunk of it here: https://plnkr.co/edit/VwyXfbc94oXp6kXQ7JFx?p=preview and modified it to work a bit more like you're looking for (I think). The real key is changing the call to handle collision to vary based on the radius of the circles (in the original post it's hard coded to 4, which works well when r === 3 but fails as r grows). The changes:
Make the circle radius into a variable (line 7 of script.js, var r = 3;)
Change the d3.forceCollide call to use that radius and a multiplier - line 110 (.force("collide", d3.forceCollide(r * 1.333)))
Change the .enter() call to use that radius as well (line 130: .attr("r", r))
This works reasonably well for reasonable values of r - but you'll need to adjust the height, and it might even be nice to just change the whole thing so that r is based on height (e.g. var r = height * .01). You'll notice that as is now, the circles go off the bottom and top of the graph area.
This post might be of interest as well: Conflict between d3.forceCollide() and d3.forceX/Y() with high strength() value
Here's the whole of script.js for posterity:
var w = 1000, h = 280;
var padding = [0, 40, 34, 40];
var r = 5;
var xScale = d3.scaleLinear()
.range([ padding[3], w - padding[1] ]);
var xAxis = d3.axisBottom(xScale)
.ticks(10, ".0s")
.tickSizeOuter(0);
var colors = d3.scaleOrdinal()
.domain(["asia", "africa", "northAmerica", "europe", "southAmerica", "oceania"])
.range(['#e41a1c','#377eb8','#4daf4a','#984ea3','#ff7f00','#ffff33']);
d3.select("#africaColor").style("color", colors("africa"));
d3.select("#namericaColor").style("color", colors("northAmerica"));
d3.select("#samericaColor").style("color", colors("southAmerica"));
d3.select("#asiaColor").style("color", colors("asia"));
d3.select("#europeColor").style("color", colors("europe"));
d3.select("#oceaniaColor").style("color", colors("oceania"));
var formatNumber = d3.format(",");
var tt = d3.select("#svganchor").append("div")
.attr("class", "tooltip")
.style("opacity", 0);
var svg = d3.select("#svganchor")
.append("svg")
.attr("width", w)
.attr("height", h);
var xline = svg.append("line")
.attr("stroke", "gray")
.attr("stroke-dasharray", "1,2");
var chartState = {};
chartState.variable = "totalEmission";
chartState.scale = "scaleLinear";
chartState.legend = "Total emissions, in kilotonnes";
d3.csv("co2bee.csv", function(error, data) {
if (error) throw error;
var dataSet = data;
xScale.domain(d3.extent(data, function(d) { return +d.totalEmission; }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (h - padding[2]) + ")")
.call(xAxis);
var legend = svg.append("text")
.attr("text-anchor", "middle")
.attr("x", w / 2)
.attr("y", h - 4)
.attr("font-family", "PT Sans")
.attr("font-size", 12)
.attr("fill", "darkslategray")
.attr("fill-opacity", 1)
.attr("class", "legend");
redraw(chartState.variable);
d3.selectAll(".button1").on("click", function(){
var thisClicked = this.value;
chartState.variable = thisClicked;
if (thisClicked == "totalEmission"){
chartState.legend = "Total emissions, in kilotonnes";
}
if (thisClicked == "emissionPerCap"){
chartState.legend = "Per Capita emissions, in metric tons";
}
redraw(chartState.variable);
});
d3.selectAll(".button2").on("click", function(){
var thisClicked = this.value;
chartState.scale = thisClicked;
redraw(chartState.variable);
});
d3.selectAll("input").on("change", filter);
function redraw(variable){
if (chartState.scale == "scaleLinear"){ xScale = d3.scaleLinear().range([ padding[3], w - padding[1] ]);}
if (chartState.scale == "scaleLog"){ xScale = d3.scaleLog().range([ padding[3], w - padding[1] ]);}
xScale.domain(d3.extent(dataSet, function(d) { return +d[variable]; }));
var xAxis = d3.axisBottom(xScale)
.ticks(10, ".0s")
.tickSizeOuter(0);
d3.transition(svg).select(".x.axis").transition().duration(1000)
.call(xAxis);
var simulation = d3.forceSimulation(dataSet)
.force("x", d3.forceX(function(d) { return xScale(+d[variable]); }).strength(2))
.force("y", d3.forceY((h / 2)-padding[2]/2))
.force("collide", d3.forceCollide(r * 1.333))
.stop();
for (var i = 0; i < dataSet.length; ++i) simulation.tick();
var countriesCircles = svg.selectAll(".countries")
.data(dataSet, function(d) { return d.countryCode});
countriesCircles.exit()
.transition()
.duration(1000)
.attr("cx", 0)
.attr("cy", (h / 2)-padding[2]/2)
.remove();
countriesCircles.enter()
.append("circle")
.attr("class", "countries")
.attr("cx", 0)
.attr("cy", (h / 2)-padding[2]/2)
.attr("r", r)
.attr("fill", function(d){ return colors(d.continent)})
.merge(countriesCircles)
.transition()
.duration(2000)
.attr("cx", function(d) { console.log(d); return d.x; })
.attr("cy", function(d) { return d.y; });
legend.text(chartState.legend);
d3.selectAll(".countries").on("mousemove", function(d) {
tt.html("Country: <strong>" + d.countryName + "</strong><br>"
+ chartState.legend.slice(0, chartState.legend.indexOf(",")) + ": <strong>" + formatNumber(d[variable]) + "</strong>" + chartState.legend.slice(chartState.legend.lastIndexOf(" ")))
.style('top', d3.event.pageY - 12 + 'px')
.style('left', d3.event.pageX + 25 + 'px')
.style("opacity", 0.9);
xline.attr("x1", d3.select(this).attr("cx"))
.attr("y1", d3.select(this).attr("cy"))
.attr("y2", (h - padding[2]))
.attr("x2", d3.select(this).attr("cx"))
.attr("opacity", 1);
}).on("mouseout", function(d) {
tt.style("opacity", 0);
xline.attr("opacity", 0);
});
d3.selectAll(".x.axis, .legend").on("mousemove", function(){
tt.html("This axis uses SI prefixes:<br>m: 10<sup>-3</sup><br>k: 10<sup>3</sup><br>M: 10<sup>6</sup>")
.style('top', d3.event.pageY - 12 + 'px')
.style('left', d3.event.pageX + 25 + 'px')
.style("opacity", 0.9);
}).on("mouseout", function(d) {
tt.style("opacity", 0);
});
//end of redraw
}
function filter(){
function getCheckedBoxes(chkboxName) {
var checkboxes = document.getElementsByName(chkboxName);
var checkboxesChecked = [];
for (var i=0; i<checkboxes.length; i++) {
if (checkboxes[i].checked) {
checkboxesChecked.push(checkboxes[i].defaultValue);
}
}
return checkboxesChecked.length > 0 ? checkboxesChecked : null;
}
var checkedBoxes = getCheckedBoxes("continent");
var newData = [];
if (checkedBoxes == null){
dataSet = newData;
redraw();
return;
};
for (var i = 0; i < checkedBoxes.length; i++){
var newArray = data.filter(function(d){
return d.continent == checkedBoxes[i];
});
Array.prototype.push.apply(newData, newArray);
}
dataSet = newData;
redraw(chartState.variable);
//end of filter
}
//end of d3.csv
});

how to add title to d3js bubble chart with force layout

This is the code of the bubble chart i created. I have used force layout to create the chart.
var margin = {
top: 10,
right: 10,
bottom: 10,
left: 10
},
width = 1000 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
d3.select('#' + divId).append('div').attr('id', 'chart').attr('class', 'chart');
var n = data.vistaJson.length;
m = 1,
padding = 5,
radius = d3.scale.sqrt().range([10, 50]),
color = d3.scale.category10().domain(d3.range(m)),
x = d3.scale.ordinal().domain(d3.range(m)).rangePoints([0, width], 1);
var xscale = d3.scale.linear()
.domain([0, 500])
.range([20, 500]);
var nodes = [];
for(var i=0; i< n; i++){
var coordinates = data.vistaJson[i].SLAB.split('_');
v = data.vistaJson[i].COUNT
nodes.push({
radius: radius(v),
color: color(i),
count: v,
cx: xscale(x(i)),
cy: xscale(height / 2),
xAxis: coordinates[0],
yAxis: coordinates[1]
});
}
var svg = d3.select("#chart").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 force = d3.layout.force()
.nodes(nodes)
.size([width, height])
.gravity(0.5)
.charge(0.5)
.on("tick", tick)
.start();
var circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", function (d) {
return d.radius;
})
.style("fill", function (d) {
return d.color;
})
.call(force.drag);
var labels = svg.selectAll("text")
.data(nodes)
.enter()
.append("text")
.attr({"x":function(d){return d.x;},
"y":function(d){return d.y;}})
.text(function(d){return d.count;})
.call(force.drag);
circle.each(gravity(.2 * e.alpha))
.each(collide(.5))
.attr("cx", function (d) {
return d.x;
})
.attr("cy", function (d) {
return d.y;
});
labels.attr("x", function(d) { return d.x; })
.attr("y", function(d) { return d.y; });
}
// Move nodes toward cluster focus.
function gravity(alpha) {
return function (d) {
d.y += (d.cy - d.y) * alpha;
d.x += (d.cx - d.x) * alpha;
};
}
// Resolve collisions between nodes.
function collide(alpha) {
var quadtree = d3.geom.quadtree(nodes);
return function (d) {
var r = d.radius + radius.domain()[1] + padding,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function (quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = d.radius + quad.point.radius + (d.color !== quad.point.color) * padding;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}
I want to add title to the node which is displayed when mouse is hovered on the node .
Earlier I used pack layout and I gave title like this :
var node = vis.selectAll("g.node")
.data(bubble.nodes(classes(json), function(d) { return d.name; })
.filter(function(d) { return !d.children; }))
.enter()
.append("svg:g")
.attr("class", "node")
.attr("transform", function(d) { return "translate(" + xscale(d.x) + "," + xscale(d.y) + ")"; });
node.append("svg:title")
.text(function(d) { return d.xAxis + ": " + d.yAxis; });
How can we show title when using forceLayout . Please help .
I think it should look something like this in the force layout:
var node = svg.selectAll(".node")
.data(graph.nodes)
.enter().append("circle")
.attr("class", function(d) { return d.nodes ? "nonleaf" : "leaf"; })
.attr("r", 5)
.call(force.drag);
node.append("title")
.text(function(d) { return d.count; });
I hope this helps somehow. For me it works like that..

Drill down pie chart disappears

I make a drill down pie chart and it works well.
You can see it here.
But there is an issue:
1) click a node then it shows its children (level 1) or level 0 nodes.
2) Move mouse to another position and move back to the new node which contains its original position, the node disappears.
I think there is problem in this code (gradientPie.js)
var paths = gPie.selectAll("path").data(pieChart(currData), function(d) {return d.data.cat;});
var texts = gPie.selectAll("text").data(pieChart(currData), function(d) {return d.data.cat;});
var lines = gPie.selectAll("line").data(pieChart(currData), function(d) {return d.data.cat;});
var arcs = paths.enter().append("g").attr('class', 'slice');
arcs.append("path").attr("fill", function(d, i) { return "url(#gradient" + d.data.cat + ")"; })
.transition().duration(1000).attrTween("d", tweenIn).each("end", function(){
this._listenToEvents = true;
gradPie.transitioning = false;
})
.attr("id", function(d, i){return 'p' + i;})
.each(function(d) { this._current = d; });
arcs.append("text").attr("transform", function(d) {
var c = d3.svg.arc().outerRadius(radius * 1.4).innerRadius(radius).centroid(d);
return "translate(" + (0 + c[0]) + "," + (0 + c[1]) + ")";
})
.attr("dy", ".35em")
.attr("class", "text-main")
.style("text-anchor", "middle")
.style("fill", "#3f5763")
.style("font", "bold 14px Helvetica")
.text(function(d) {
$("#" + d.data.domID + " p").html(d.data.percent + "%");
return d.data.percent + "%";
});
arcs.append("line").attr("transform", function (d, i) {
var rAngle = ((d.startAngle + d.endAngle) / 2 - (Math.PI / 2)) * 180 / Math.PI;
return "rotate(" + rAngle + ")translate(" + radius * 1.1 + ")";
})
.attr("class", "line-ticks")
.attr('stroke-width', '1')
.attr("x2", -0.5 * radius)
.style("stroke", "#3f5763")
.style("fill", "none");
// Mouse interaction handling
paths.on("click", function(d, i){
if(this.childNodes[0]._listenToEvents && !gradPie.transitioning){
// Reset inmediatelly
d3.select(this).attr("transform", "translate(0,0)")
// Change level on click if no transition has started
paths.each(function(){
this.childNodes[0]._listenToEvents = false;
});
updateGraph(d.data.subfractions? d.data.cat : undefined);
}
})
.on("mouseover", function(d, i){
// Mouseover effect if no transition has started
if(this.childNodes[0]._listenToEvents && !gradPie.transitioning) {
// Calculate angle bisector
var ang = (d.endAngle + d.startAngle)/2;
// Transformate to SVG space
ang = (ang - (Math.PI / 2) ) * -1;
// Calculate a 10% radius displacement
var x = Math.cos(ang) * radius * 0.1;
var y = Math.sin(ang) * radius * -0.1;
d3.select(this).transition()
.duration(250).attr("transform", function() {
return "translate(" + x + ", " + y + ")";
})
}
})
.on("mouseout", function(d){
// Mouseout effect if no transition has started
if(this.childNodes[0]._listenToEvents && !gradPie.transitioning){
d3.select(this).transition()
.duration(150).attr("transform", function() {
return "translate(0,0)";
});
}
});
// Collapse sectors for the exit selection
paths.exit().transition()
.duration(1000)
.attrTween("d", tweenOut).remove();
texts.exit().transition()
.duration(100).remove();
lines.exit().transition()
.duration(100).remove();
Any help?

D3.js stacked Barchart Error

I Need your help... why is this Chart not running.. Error in Console (d3.v2.js Zeile 2396):
TypeError: string.substring is not a function
var n = d3_time_numberRe.exec(string.substring(i, i + 2));
Could anybody help me please?
<script type="text/javascript">
var w = 960,
h = 500,
p = [20, 50, 30, 20],
x = d3.scale.ordinal().rangeRoundBands([0, w - p[1] - p[3]]),
y = d3.scale.linear().range([0, h - p[0] - p[2]]),
z = d3.scale.ordinal().range(["lightpink", "darkgray", "lightblue"]),
parse = d3.time.format("%m/%Y").parse,
format = d3.time.format("%b");
var data = [
[
new Date('1991-01-18T00:00:00'),
52.380001068115234,
28.56999969482422,
10.0
],
[
new Date('1994-11-17T00:00:00'),
57.88999938964844,
21.049999237060547,
10.0
]
];
var svg = d3.select("body").append("svg:svg")
.attr("width", w)
.attr("height", h)
.append("svg:g")
.attr("transform", "translate(" + p[3] + "," + (h - p[2]) + ")");
// Transpose the data into layers by cause.
var causes = d3.layout.stack()([data[1], data[2], data[3]].map(function(cause) {
return data.map(function(d) {
return {x: parse(d[0]), y: +d[cause]};
});
}));
// Compute the x-domain (by date) and y-domain (by top).
x.domain(causes[0].map(function(d) { return d.x; }));
y.domain([0, d3.max(causes[causes.length - 1], function(d) { return d.y0 + d.y; })]);
// Add a group for each cause.
var cause = svg.selectAll("g.cause")
.data(causes)
.enter().append("svg:g")
.attr("class", "cause")
.style("fill", function(d, i) { return z(i); })
.style("stroke", function(d, i) { return d3.rgb(z(i)).darker(); });
// Add a rect for each date.
var rect = cause.selectAll("rect")
.data(Object)
.enter().append("svg:rect")
.attr("x", function(d) { return x(d.x); })
.attr("y", function(d) { return -y(d.y0) - y(d.y); })
.attr("height", function(d) { return y(d.y); })
.attr("width", x.rangeBand());
// Add a label per date.
var label = svg.selectAll("text")
.data(x.domain())
.enter().append("svg:text")
.attr("x", function(d) { return x(d) + x.rangeBand() / 2; })
.attr("y", 6)
.attr("text-anchor", "middle")
.attr("dy", ".71em")
.text(format);
// Add y-axis rules.
var rule = svg.selectAll("g.rule")
.data(y.ticks(5))
.enter().append("svg:g")
.attr("class", "rule")
.attr("transform", function(d) { return "translate(0," + -y(d) + ")"; });
rule.append("svg:line")
.attr("x2", w - p[1] - p[3])
.style("stroke", function(d) { return d ? "#fff" : "#000"; })
.style("stroke-opacity", function(d) { return d ? .7 : null; });
rule.append("svg:text")
.attr("x", w - p[1] - p[3] + 6)
.attr("dy", ".35em")
.text(d3.format(",d"));
</script>
The problem is here:
var causes = d3.layout.stack()([data[1], data[2], data[3]].map(function(cause) {
return data.map(function(d) {
return {x: parse(d[0]), y: +d[cause]};
});
}));
d[0] is already a date object - new Date('1991-01-18T00:00:00') - and parse is expecting a string.
Instead, pass d[0] directly:
return {x: d[0], y: +d[cause]};
Sidenote: check out the debugging tools for chrome. Most of the error messages you get working with d3 will not give very useful messages (like "TypeError: string.substring is not a function") and being able to look through the stack is extremely helpful.

Resources