I'm trying to learn d3.js focus + context via brushing using Twitter Data Analysis. I'm trying to generate the time series plot from the data given, but it's not coming up as it should. I have created fiddle. Could someone please take a look at it, and give me a suggestion on how I can fix this?
var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = { top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;
var parseDate = d3.time.format("%Y-%m-%d %I:%M:%S").parse;
var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var brush = d3.svg.brush()
.x(x2)
.on("brush", brushed);
var area = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.count); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.date); })
.y0(height2)
.y1(function(d) { return y2(d.count); });
var svg = d3.select(".trend-graph").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.csv("/TwitterProject/slides/results.csv", type, function(error, data){
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.count; }))])
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area);
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
focus.append("g")
.attr("class","y axis")
.call(yAxis);
context.append("path")
.datum(data)
.attr("class","area")
.attr("d", area2);
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(".area").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
function type(d) {
d.date = parseDate(d.date);
d.count = +d.count;
return d;
}
JSFiddle
Also, the y-axis is showing up wrong. I think the problem is somewhere counting the "counts" per minute, but I couldn't figure out how to fix this.
The plot is supposed to look like this.
EDIT:
Changes I made:
var bins = {};
x.domain(d3.extent(data.map(function(d) { return d.date; })));
//y.domain([0, d3.max(data.map(function(d) { return d.count; }))]).
y.domain([0, bins]).range([height, 0]);
x2.domain(x.domain());
y2.domain(y.domain()).range([height2, 0]);
function type(d) {
d.date = parseDate(d.date);
d.count = +d.count;
var key = d.date.toDateString();
bins[key] = bins[key] || 0;
bins[key] += d.count;
console.log(bins);
return d;
}
Your data has a resolution of one second, so you're going to get a very noisy graph (in fact exactly what you're getting). You probably want to do some binning, where you aggregate the data to make it less noisy.
In principle, the code looks like this (to aggregate by the minute):
function type(d) {
d.date = parseDate(d.date);
d.count = +d.count;
d.date.setSeconds(0);
var key = df(d.date);
bins[key] = bins[key] || 0;
bins[key] += d.count;
return d;
}
and then inside d3.csv:
var binData = d3.entries(bins);
binData.forEach(function(d) { d.key = parseDate(d.key); });
binData.sort(function(a,b) { return b.key - a.key; });
There's a bit of additional cruft because Date objects don't play nice as associative array keys. Now you have elements with key (date) and value in binData, which you can use to create the graph.
Complete demo here.
Related
I'm trying to get 2 completely different d3 charts (2 line charts but totally different data - one with several lines and negative data, other with one line positive data) on the same page.
Right now, I only get the first one to be generated and shown correctly on the HTML page, the second chart doesn't show at all (not even svg container is generated).
Here is my code:
(function() {
// Get the data
d3.json("../assets/js/json/temperature.json", function(data) {
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 25},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.temps); })
.y(function(d) { return y(d.temperature); });
// prepare data
data.forEach(function(d) {
d.temps = parseDate(d.temps);
d.temperature = +d.temperature;
});
// Adds the svg canvas
var svg = d3.select("#graphTemp")
.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 + ")");
// Scale the range of the data on domain
x.domain(d3.extent(data, function(d) { return d.temps; }));
y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
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("Temperatures");
});
})();
(function(){
// loads the data and loads it into chart - main function
d3.json("../assets/js/json/maitrise.json", function(data) {
var m = {top: 20, right: 5, bottom: 30, left: 40},
w = 70 - m.left - m.right,
h = 30 - m.top - m.bottom;
var x = d3.scale.linear().domain([0, data.length]).range([0 + m.left, w - m.right]);
var y = d3.scale.linear()
.rangeRound([h, 0]);
var line = d3.svg.line()
.interpolate("cardinal")
.x(function(d,i) { return x(i); })
.y(function (d) { return y(d.value); });
var color = d3.scale.ordinal()
.range(["#28c6af","#ffd837","#e6443c","#9c8305","#d3c47c"]);
var svg2 = d3.select("#maitrisee").append("svg")
.attr("width", w + m.left + m.right)
.attr("height", h + m.top + m.bottom)
.append("g")
.attr("transform", "translate(" + m.left + "," + m.top + ")");
// prep axis variables
var xAxis2 = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis2 = d3.svg.axis()
.scale(y)
.orient("left");
//console.log("Inital Data", data);
var labelVar = 'id'; //A
var varNames = d3.keys(data[0])
.filter(function (key) { return key !== labelVar;}); //B
color.domain(varNames); //C
var seriesData = varNames.map(function (name) { //D
return {
name: name,
values: data.map(function (d) {
return {name: name, label: d[labelVar], value: +d[name]};
})
};
});
console.log("seriesData", seriesData);
y.domain([
d3.min(seriesData, function (c) {
return d3.min(c.values, function (d) { return d.value; });
}),
d3.max(seriesData, function (c) {
return d3.max(c.values, function (d) { return d.value; });
})
]);
var series = svg2.selectAll(".series")
.data(seriesData)
.enter().append("g")
.attr("class", function (d) { return d.name; });
series.append("path")
.attr("class", "line")
.attr("d", function (d) { return line(d.values); })
.style("stroke", function (d) { return color(d.name); })
.style("stroke-width", "2px")
.style("fill", "none");
});
})();
OK, I found where the error was coming from. There was a piece of javascript in the middle of the HTML page that stopped d3 to generate the second graph further down in the page.
Thanks for all the help!
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 have some data ranging from 2003 - 2007 plotted as a line graph using the following code:
var x = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]);
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
and later when I've pulled my data in:
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
context.append("path")
.datum(data)
.attr("d", area);
I've implemented a brush to filter the data. It works like this one:
http://bl.ocks.org/mbostock/4349545
But instead of a scatterplot, I have a line graph. I want to select arbitrary portions of the graph area and recolour it based on the brush selection. Just like the second graph on this yahoo chart:
http://uk.finance.yahoo.com/echarts?s=SAN.MC#symbol=san.mc;range=20040915,20131007;compare=;indicator=volume;charttype=area;crosshair=on;ohlcvalues=0;logscale=off;source=undefined;
I have a brush function that's fired on brushmove:
function brushmove() {
var s = brush.extent();
console.log(s);
}
which logs out the selected range correctly. I'm just not sure how to select a portion of my graph area based on the range coming back from the brushmove function.
Full code is here:
//specify some margins
var margin = {top: 500, right: 10, bottom: 20, left: 40},
width = 960,
height = 100;
var bigMargin = {top: 20, right: 10, bottom: 20, left: 40},
bigWidth = 960,
bigHeight = 400;
//parse the date
var parseDate = d3.time.format("%b %Y").parse;
//create scales
var x = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]);
//create scales
var bigX = d3.time.scale().range([0, bigWidth]),
bigY = d3.scale.linear().range([bigHeight, 0]);
//create axis
var xAxis = d3.svg.axis().scale(x).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");
var bigXAxis = d3.svg.axis().scale(bigX).orient("bottom"),
bigYAxis = d3.svg.axis().scale(bigY).orient("left");
//create a brush area accessor function
var brush = d3.svg.brush()
.x(x)
.on("brush", brushmove);
//create an area accessor function
var area = d3.svg.area()
.x(function(d) { return x(d.date); })
.y0(height)
.y1(function(d) { return y(d.price); });
var bigArea = d3.svg.area()
.x(function(d) { return bigX(d.date); })
.y0(bigHeight)
.y1(function(d) { return bigY(d.price); });
//append the svg container
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", bigWidth)
.attr("height", bigHeight);
//append a container
var context = svg.append("g")
.attr('class','container')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var bigContext = svg.append("g")
.attr('class','bigContainer')
.attr("transform", "translate(" + bigMargin.left + "," + bigMargin.top + ")");
//loop over the data
d3.csv("data.csv", function(error, data) {
//coerce the data a little because values from .CSv are always strings
data.forEach(function(d) {
d.date = parseDate(d.date);
d.price = +d.price;
});
//set the scale domains based on the data
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
bigContext.append("path")
.datum(data)
.attr("clip-path", "url(#clip)")
.attr("fill","red")
.attr("d", bigArea);
//set the scale domains based on the data
bigX.domain(d3.extent(data.map(function(d) { return d.date; })));
bigY.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
var t = new Date(2003, 0, 1);
//append the graph as an area
context.append("path")
.datum(data)
.attr("d", area).
attr("fill",function(d) {
//if the data is at a certain range then give it a particular fill
return (new Date(d.date) > t ? "orange" : "yellow"); });
//append the x axis
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
//append the x axis
context.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0,0)")
.call(yAxis);
//append the x axis
bigContext.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + bigHeight + ")")
.call(bigXAxis);
//append the x axis
bigContext.append("g")
.attr("class", "y axis")
.attr("transform", "translate(0,0)")
.call(bigYAxis);
//append the brush
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height + 7)
});
function brushstart() {
svg.classed("selecting", true);
}
function brushmove() {
bigX.domain(brush.extent());
bigContext.select("path").attr("d", bigArea);
bigContext.select(".x.axis").call(bigXAxis);
}
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.
I am a newbie with D3 library and I am stuck with zooming on a graph.
I display correctly my data over several graphs. But when I zoom, everything goes wrong. I don't know if I miss something with Domains or Ranges or anything... so I ask.
You can find a demo of my code here: http://pastehtml.com/view/cos13vodt.html
And here is the jsFiddle example: http://jsfiddle.net/84mSQ/
And my JS code is there:
var margin = {top: 30, right: 150, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
//To parse dates as they are into the CSV
var parseDate = d3.time.format("%Y/%m/%d-%H:%M").parse;
var format = d3.time.format("%d/%m/%y-%H:%M");
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")/*.ticks(30)*/;
var zoom = d3.behavior.zoom()
.x(x)
.scaleExtent([1, 2])
.on("zoom", function(scale, translate){
console.log("fonction zoom");
console.log(scale); console.log(translate);
zoomed(scale, translate);
});
// A line generator.
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("svg:g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
.call(zoom);
svg.append("rect")
.attr("class", "pane")
.attr("width", width)
.attr("height", height);
// Get the data
d3.csv("./enregistrement-subset2.csv", function(data) {
color.domain(d3.keys(data[0])
.filter(function(key) {
return key !== "date" && key !== "ECS - Button A" ;
}));
data.forEach(function(d) {
//Parse the date
d.date = parseDate(d.date);
});
var dataSet = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
//parses the number by using the '+' operator
if(name == "CO2 chambre"){
return { date: d.date, value: (+d[name])/10};
}
else{
return { date: d.date, value: +d[name]};
}
})
};
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([
d3.min(dataSet, function(c) { var mini = d3.min(c.values, function(v) { return v.value; }); return mini; }),
d3.max(dataSet, function(c) { var maxi = d3.max(c.values, function(v) { return v.value; }); return maxi; })
]);
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("Value of");
var valueSet = svg.selectAll(".valueSet")
.data(dataSet)
.enter().append("g")
.attr("class", "valueSet");
valueSet.append("path")
.attr("class", "line")
.attr("d", function(d) { return line(d.values); })
.style("stroke", function(d) { return color(d.name); })
.call(line);
valueSet.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.value) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
//zoomed();
});
function zoomed() {
console.log("here", d3.event);
svg.select("g.x.axis").call(xAxis);
svg.select("g.y.axis").call(yAxis);
//svg.selectAll("path.line").call(line);
svg.selectAll("path.line").attr("d", line);
//d3.select("#footer span").text("PĂ©riode de temps: " + x.domain().map(format).join("-"));
}
Can anybody tell me what I did wrong with this code ?
Should I re-design it ?
Are there performances issue to preview if I use a huge amount of data and what should I do then ?
var zoom = d3.behavior.zoom()
.x(x)
**.scaleExtent([1, 2])** <---
.on("zoom", function(scale, translate){
console.log("fonction zoom");
console.log(scale); console.log(translate);
zoomed(scale, translate);
});
take out the .scaleExtent([1, 2]) and check if it is working
should be
var zoom = d3.behavior.zoom()
.x(x)
.on("zoom", function(scale, translate){
console.log("fonction zoom");
console.log(scale); console.log(translate);
zoomed(scale, translate);
});
it is because your x axis is time.