I am trying to create a multi-line graph and updating the data on button click. On each line, I want to highlight the intersection point with a cirlce. Now on button click, I was able to update the line path, but the old highlighted intersection points are not removed from the svgContainer(for eaxmple clicking update2 then update1 do not removes the last set of circles which are not connected to any line).
<input type="button" onclick="update1()" value="Update" />
<input type="button" onclick="update2()" value="UpdateDimension_T" />
<div id="outputViz">
</div>
<script type="text/javascript">
var data = [
[{'index':1,'score':0},{'index':2,'score':5},{'index':3,'score':10},{'index':4,'score':0},{'index':5,'score':6}],
[{'index':1,'score':1},{'index':2,'score':6},{'index':3,'score':11},{'index':4,'score':1},{'index':5,'score':7}],
[{'index':1,'score':2},{'index':2,'score':7},{'index':3,'score':12},{'index':4,'score':2},{'index':5,'score':8}],
[{'index':1,'score':3},{'index':2,'score':8},{'index':3,'score':13},{'index':4,'score':3},{'index':5,'score':9}],
[{'index':1,'score':4},{'index':2,'score':9},{'index':3,'score':14},{'index':4,'score':4},{'index':5,'score':10}]
];
var data_O = [
[{'index':1,'score':1},{'index':2,'score':6},{'index':3,'score':11},{'index':4,'score':1},{'index':5,'score':7},{'index':6,'score':12}],
[{'index':1,'score':2},{'index':2,'score':7},{'index':3,'score':12},{'index':4,'score':2},{'index':5,'score':8},{'index':6,'score':13}],
[{'index':1,'score':3},{'index':2,'score':8},{'index':3,'score':13},{'index':4,'score':3},{'index':5,'score':9},{'index':6,'score':14}],
[{'index':1,'score':4},{'index':2,'score':9},{'index':3,'score':14},{'index':4,'score':4},{'index':5,'score':10},{'index':6,'score':15}],
[{'index':1,'score':5},{'index':2,'score':10},{'index':3,'score':15},{'index':4,'score':5},{'index':5,'score':11},{'index':6,'score':16}]
];
var data_T = [
[{'index':1,'score':5},{'index':2,'score':10},{'index':3,'score':15},{'index':4,'score':5},{'index':5,'score':12},{'index':6,'score':20},{'index':7,'score':15}],
[{'index':1,'score':6},{'index':2,'score':11},{'index':3,'score':16},{'index':4,'score':6},{'index':5,'score':13},{'index':6,'score':21},{'index':7,'score':16}],
[{'index':1,'score':7},{'index':2,'score':12},{'index':3,'score':17},{'index':4,'score':7},{'index':5,'score':14},{'index':6,'score':22},{'index':7,'score':17}],
[{'index':1,'score':8},{'index':2,'score':13},{'index':3,'score':18},{'index':4,'score':8},{'index':5,'score':15},{'index':6,'score':23},{'index':7,'score':18}],
[{'index':1,'score':9},{'index':2,'score':14},{'index':3,'score':19},{'index':4,'score':9},{'index':5,'score':16},{'index':6,'score':24},{'index':7,'score':19}]
];
var colors = [
'steelblue',
'green',
'red',
'purple',
'black'
];
var dataset = ["","Or","Se","Tr","De","Cc"];
var dataset_O = ["","O_1","O_2","O_3","O_4","O_5","O_6"];
var dataset_T = ["","T_1","T_2","T_3","T_4","T_5","T_6","T_7"];
var margin = {top: 20, right: 30, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
padding = 30;
var x = d3.scale.linear()
.domain([0, dataset.length])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 16])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.tickFormat(function(d) { return dataset[d]; })
.tickSize(-height)
.tickPadding(10)
.tickSubdivide(false)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(false)
.orient("left");
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("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
svg.append("g")
.attr("class", "y axis")
.append("text")
.attr("class", "axis-label")
.attr("transform", "rotate(-90)")
.attr("y", (-margin.left) + 10)
.attr("x", -height/2)
.text('Axis Label');
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.index); })
.y(function(d) { return y(d.score); });
svg.selectAll('.line')
.data(data)
.enter()
.append("path")
.attr("class", "line")
.attr('stroke', function(d,i){
return colors[i%colors.length];
})
.attr("d", line);
var points = svg.selectAll('.dots')
.data(data)
.enter()
.append("g")
.attr("class", "dots")
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")"; }
);
function update1(){
var x = d3.scale.linear()
.domain([0, dataset_O.length])
.range([0, width]);
var y = d3.scale.linear()
.domain([-1, 16])
.range([height, 0]).nice();
xAxis = d3.svg.axis()
.scale(x)
.tickFormat(function(d) { return dataset_O[d]; })
.tickSize(-height)
.tickPadding(10)
.tickSubdivide(false)
.orient("bottom");
yAxis = d3.svg.axis()
.scale(y)
.tickPadding(10)
.tickSize(-width)
.tickSubdivide(false)
.orient("left");
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.index); })
.y(function(d) { return y(d.score); });
svg.selectAll('.line')
.data(data_O)
.transition(750)
.attr("d", line)
.attr("class", "line");
// change the x axis
svg.select(".x.axis").call(xAxis);
// change the y axis
svg.select(".y.axis").call(yAxis);
var points = svg.selectAll('.dots').data(data_O);
//UPDATE - HANDLE the current count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
//ENTER - add the newly added count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
d3.selectAll('g.dots').data(data_O).exit().remove();
}
function update2(){
var x = d3.scale.linear()
.domain([0, dataset_T.length])
.range([0, width]);
//var yExtents = d3.extent(d3.merge(data_T), function (d) { return d.score; });
var y = d3.scale.linear()
.domain([-1, 29])
.range([height, 0]).nice();
xAxis = d3.svg.axis()
.scale(x)
.tickFormat(function(d) { return dataset_T[d]; });
var line = d3.svg.line()
.interpolate("linear")
.x(function(d) { return x(d.index); })
.y(function(d) { return y(d.score); });
svg.selectAll('.line')
.data(data_T)
.transition(750)
.attr("d", line)
.attr("class", "line");
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
var points = svg.selectAll('.dots').data(data_T);
//ENTER - add the newly added count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.enter()
.append('circle')
.attr('class','dot')
.attr("r", 2.5)
.attr('fill', function(d,i){
return colors[d.index%colors.length];
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
//UPDATE - HANDLE the current count
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.attr("transform", function(d) {
return "translate(" + x(d.point.index) + "," + y(d.point.score) + ")";
});
}
</script>
Here is the link to fiddle:
https://jsfiddle.net/aakashjain/1dc57aL7/1/
You'll need an "exit" selection:
points.selectAll('.dot')
.data(function(d, index){
var a = [];
d.forEach(function(point,i){
a.push({'index': index, 'point': point});
});
return a;
})
.exit()
.remove();
Here is the update fiddle:. https://jsfiddle.net/1dc57aL7/2/
(Just a tip: you have a lot of duplicated code here. Your "update1" and "update2" functions could be way smaller)
I am using d3 chart with zoom
i don't want negative values in y axis when zoom out. how can i avoid it.
Even i should avoid y axis values don't exceed to the actual value in zooming
For example:
My best y axis value is 5000
When i zoom out i don't want to see 5100, 5500 and 6000 like this
How can i avoid this.
thanks
Subash
Here is my code
var margin = { top: 0, right: 45, bottom: 20, left: 0 },
width = $('#realtimechart').width() - 40,
height = 300;
var x = d3.time.scale.utc()
.domain(d3.extent(data, function (d) {
return d.date;
}))
.range([0, width]);
var y = d3.scale.linear()
.domain([0, d3.max(data, function (d) {
return d.close;
})])
.range([height, 0]);
var line = d3.svg.line()
.x(function (d) {
return x(d.date);
})
.y(function (d) {
return y(d.close);
});
var xAxis = d3.svg.axis().scale(x).ticks(10).orient("bottom");
var yAxis = d3.svg.axis().scale(y).ticks(8).orient("right");
console.log(y)
var zoom = d3.behavior.zoom().x(x).y(y).translate([0,0]).scale(1).scaleExtent([0, 1000]).on("zoom", refresh);
var svg = d3.select("#realtimechart").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 + ")")
.call(zoom)
.append("g");
var make_x_axis = function () {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function () {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
};
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis);
svg.append("g")
.attr("class", "x grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.append("g")
.attr("class", "y grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(0));
var clip = svg.append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var chartBody = svg.append("g")
.attr("clip-path", "url(#clip)");
chartBody.append("svg:path")
.datum(data)
.attr("class", "line")
.attr("d", line);
function refresh() {
//$('#realtimechart').yAxis.scale().domain();
console.log(d3.svg.axis().scale().domain());
//console.log(i);
if(i < 1000) {
i++;
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
}
}
i want to include scrollbar and navigator, range selector functionality in my line graph . something similar to http://www.highcharts.com/products/highstock Can this be done on d3 if so give me a link on a tutorial or code.
the code is
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 30, left: 40},
width = 2000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");
var x = d3.time.scale().range([0, width]);
var x2= d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });
var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.json("data/data2.php", function(error, data) { data.forEach(function(d,i) {
//document.write(d.date);
d.date = parseDate(d.date);
//document.write(d.date);
d.close = +d.close;
//document.write(d.close);
arr[i]=d.close;
len=i+1;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([min-10, max+10]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path") // Add the valueline path.
.datum(data)
.attr("class","valueline")
.attr("d", valueline);
focus.selectAll("dot")
.data(data)
.enter().append("a")
.attr("xlink:href",function(d,i){if(d.close>=usl||d.close<=lsl||signal8[i]==8||signal8dw[i]==8||signal6up[i]==6||signal6dw[i]==6)return "http://en.wikipedia.org";})
.append("circle")
.attr("r", 2)
.style("fill", function(d,i) { // <== Add these
if(d.close==0) {return "none"}
if((ul[i]==9999)||(dl[i]==9999)) {return "red"}
else if(signal8[i]==8 ){ return "orange" }
else if(signal8dw[i]==8 ){return "gold"}
else if(signal6up[i]==6 ){return "indianred"}
else if(signal6dw[i]==6 ){return "#FF5C33"}
else { return "steelblue" } // <== Add these
;})
.attr("cx", function(d) { return x(d.date); })
.attr("cy", function(d) { return y(d.close); })
.on("mouseover", function(d,i) {
div.transition()
.duration(200)
.style("opacity", .9);
div.html(function(){
if(d.close==0)
{return}
if(ul[i]==9999)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " UPPER "}
else if(dl[i]==9999)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " LOWER "}
else if(signal8[i]==8)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else if(signal8dw[i]==8)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else if(signal6up[i]==6)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else if(signal6dw[i]==6)
{return formatTime(d.date) + "<br/><b>" + d.close+ "</b><br/>" + " ( hello1 )"}
else {return formatTime(d.date) + "<br/><b>" + d.close+ "</b>"}
;})
context.append("path") // Add the valueline path.
.attr("d", valueline2(data));
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select(".valueline").attr("d",valueline);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.close = +d.close;
return d;
}
the above code is a snippet of the overall code. here when im executing im getting a parse error d="". where am i wrong. and i have drawn a few limit lines in the graph which i have not included in the above code. the bottom brush is working but the main graph is not getting updated as per the brush.
i want to update the dots too. what should i include the brushed function.
For the point marks, you again need a selectAll, and then reset the cx property to match the modified x scale:
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
//change the x-scale on the focus graph to match the brush extent
//(or reset it to the full domain if the brush is empty)
focus.selectAll(".valueline").attr("d",valueline);
// redraw the lines (using the updated scale)
focus.selectAll("dot").select("circle")
.attr("cx", function(d) { return x(d.date); });
//update the x position of the dots based on the updated x-scale
focus.select(".x.axis").call(xAxis);
//redraw the x-axis based on the updated x-scale
}
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 30, left: 40},
width = 2000 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%d").parse;
var formatTime = d3.time.format("%e %B");
var x = d3.time.scale().range([0, width]);
var x2= d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
var y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(25);
var xAxis2 = d3.svg.axis().scale(x2).orient("bottom");
var yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var valueline = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x(d.date); }).y(function(d) { return y(d.close); });
var valueline2 = d3.svg.line().defined(function(d) { return d.close != 0; }).x(function(d) { return x2(d.date); }).y(function(d) { return y2(d.close); });
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var svg = d3.select("body").append("svg").attr("width", width + margin.left + margin.right).attr("height", height + margin.top + margin.bottom);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
var focus = svg.append("g")
.attr("class", "focus")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("class", "context")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.json("data/data2.php", function(error, data) { data.forEach(function(d,i) {
//document.write(d.date);
d.date = parseDate(d.date);
//document.write(d.date);
d.close = +d.close;
//document.write(d.close);
arr[i]=d.close;
len=i+1;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([min-10, max+10]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path") // Add the valueline path.
.datum(data)
.attr("class","valueline")
.attr("d", valueline);
context.append("path") // Add the valueline path.
.attr("d", valueline2(data));
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7);
});
function brushed() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.selectAll(".valueline").attr("d",valueline); // selectAll is the answer
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.close = +d.close;
return d;
}
I`m using d3.js, Sortable Barchart with the following code:
function countrydownloads(input) {
d3.select(".barchartCountryDownloads").select("svg").remove();
var data = [{"country":"Austria","downloads":"10000"},{"country":"Germany","downloads":"20000"},{"country":"Spain","downloads":"30000"}];
var margin = {top: 20, right: 20, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1, 1);
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")
.tickFormat(formatPercent);
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 + ")");
data.forEach(function(d) {
d.downloads = +d.downloads;
});
x.domain(data.map(function(d) { return d.country; }));
y.domain([0, d3.max(data, function(d) { return d.downloads; })]);
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("Frequency");
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.country); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.downloads); })
.attr("height", function(d) { return height - y(d.downloads); });
d3.select("input").on("change", change);
var sortTimeout = setTimeout(function() {
d3.select("input").property("checked", true).each(change);
}, 2000);
function change() {
clearTimeout(sortTimeout);
// Copy-on-write since tweens are evaluated after a delay.
var x0 = x.domain(data.sort(this.checked
? function(a, b) { return b.downloads - a.downloads; }
: function(a, b) { return d3.ascending(a.country, b.country); })
.map(function(d) { return d.country; }))
.copy();
var transition = svg.transition().duration(750),
delay = function(d, i) { return i * 50; };
transition.selectAll(".bar")
.delay(delay)
.attr("x", function(d) { return x0(d.country); });
transition.select(".x.axis")
.call(xAxis)
.selectAll("g")
.delay(delay);
};
}
I don`t get anything displayed. I tried Barchart with the same kind of data, there it worked. Where is the mistake with Sortable Barchart?
.append("g:")
should be
.append("g")
If you haven't used them before, you might want to check out the chrome dev tools. Small typos like this are a lot easier to debugger when you can step through your code to see exactly what line is is causing the error to occur.
What would be causing this chart to have a value appear below the x-axis (0:00)?
My data looks like this (no values less than zero):
[{"x":1341806400,"y":4},
{"x":1342411200,"y":0},
{"x":1343016000,"y":0},
{"x":1343620800,"y":7},
{"x":1344225600,"y":6},
{"x":1344830400,"y":73},
{"x":1345435200,"y":328},
{"x":1346040000,"y":0},
{"x":1346644800,"y":0},
{"x":1347249600,"y":0},
{"x":1347854400,"y":0},
{"x":1348459200,"y":11},
{"x":1349064000,"y":17},
{"x":1349668800,"y":0},
{"x":1350273600,"y":0}]
Rendered Chart
The above chart is rendered via:
var margin = {top: 20, right: 30, bottom: 30, left: 40};
var width = max_width - margin.left - margin.right;
var height = 300; // + margin.top + margin.bottom;
var height_offset = 100;
var x = d3.time.scale()
.range([0, width]);
var y = d3.scale.linear()
.range([height, 0]);
var z = d3.scale.category20c();
var ticks_interval;
switch(this.period_type){
case "day":
ticks_interval = d3.time.days;
break;
case "week":
ticks_interval = d3.time.weeks;
break;
case "month":
ticks_interval = d3.time.months;
break;
case "year":
ticks_interval = d3.time.years;
break;
}
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(ticks_interval);
var yAxis = d3.svg.axis()
.scale(y)
.tickFormat(function(d){
return numeral(d).format("00:00").replace(/^0:/,""); })
.orient("left");
var stack = d3.layout.stack()
.offset("zero")
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.value; });
var nest = d3.nest()
.key(function(d) { return d.key; });
var area = d3.svg.area()
.interpolate("cardinal")
.x(function(d) { return x(d.date); })
.y0(function(d) {return y(d.y0);})
.y1(function(d) { return y(d.y0 + d.y); });
var svg = d3.select(chart_dom_el)
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + height_offset)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var layers = stack(nest.entries(data));
x.domain(d3.extent(data, function(d){ return d.date; }));
y.domain([0,d3.max(data,function(d){
return d.y0+ d.y;
})]);
// re-map for formatted date
data = _.map(data,function(d){
return {date: d.date.format("MM/D"),value:d.value};
});
svg.selectAll(".layer")
.data(layers)
.enter().append("path")
.attr("class", "layer")
.attr("d", function(d) { return area(d.values); })
.style("fill", function(d, i) { return z(i); });
var x_axis_options = {x: 4, y: 9, rotate: 0};
if(data.length > 20){
x_axis_options = {x: -27, y: 8, rotate: -45};
}else if(data.length > 13){
x_axis_options = {y: -5, x: 27, rotate: 90};
}
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", x_axis_options.y)
.attr("x", x_axis_options.x)
.attr("transform", "rotate("+(x_axis_options.rotate)+")");
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
This appears to have to do with the interpolation mode you used on the area generator - try changing from cardinal to linear, or some other area interpolation mode