Trying to develop a stacked chart plugin.
This was the basic version
http://jsfiddle.net/NYEaX/131/
this is my current plugin
http://jsfiddle.net/NYEaX/149/
_ there are issues though with a) having more than one chart b) updating the chart(s)
I've tried breaking up the code required to build the chart and update it/handle the block/morphs. I think I need to add transitions - enter/exit/remove on the code responsible for adding the stacked chart blocks.
buildChart: function(data, w, h, yLabel){
var that = this;
var margin = {top: 30, right: 55, bottom: (h * 0.56), left: 95},
width = w - margin.left - margin.right,
height = h - margin.top - margin.bottom;
this.x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
this.y = d3.scale.linear()
.rangeRound([height, 0]);
var colorArray = ["#538ed5", "#953735", "#e46d0a", "#75923c", "#b2a1c7", "#dc143c", "#87cefa", "#90ee90", "#add8e6", "#d3d3d3", "#cf1256", "#12cf5e"];
this.color = d3.scale.ordinal()
.range(colorArray);
var xAxis = d3.svg.axis()
.scale(this.x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(this.y)
.orient("left")
//.tickFormat(d3.format(".2s"));
var chartWidth = parseInt(width + margin.left + margin.right,10);
var chartHeight = parseInt(height + margin.top + margin.bottom,10);
var svg = d3.select(methods.el["selector"])
.append("svg")
.attr("class", "stackedchart")
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr('viewBox', "0 0 "+chartWidth+" "+chartHeight)
.attr('perserveAspectRatio', "xMinYMid")
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
this.color.domain(d3.keys(data[0]).filter(function(key) { return key !== "Label"; }));
data.forEach(function(d) {
var y0 = 0;
d.blocks = that.color.domain().map(function(name) {
return {name: name, values: d[name], y0: y0, y1: y0 += +d[name]};
});
d.total = d.blocks[d.blocks.length - 1].y1;
});
this.x.domain(data.map(function(d) { return d.Label; }));
this.y.domain([0, d3.max(data, function(d) { return d.total; })]);
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", "-3.5em")
.style("text-anchor", "end")
.text(yLabel);
var xlabels = svg.selectAll(".x.axis text")
.attr("transform", "rotate(-60) translate(-10,-10)")
that.manageStack(svg, data);
that.buildLegend();
//that.resizeChart();
}
Related
I have an error while representing my data through a bar chart graph with D3JS . Even if I see that logically, everything is right:
the X axis show gets the whole values of X and Y, ad the errors are:
Error: attribute y: Expected length, "NaN".
Error: attribute height: Expected length, "NaN".
here's My code and my data:
function HGlob(){
var margin = {top: 40, right: 20, bottom: 30, left: 40},
width = 850 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .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")
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([-10, 0])
.html(function(d) {
return d.somme;
})
var svg = d3.select("#countries").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.call(tip);
d3.tsv("data.tsv", type, function(error, data) {
x.domain(data.map(function(d) { return d.Zone_Geographique; }));
y.domain([0, d3.max(data, function(d) { return d.somme; })]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return x(d.Zone_Geographique); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return y(d.somme); })
.attr("height", function(d) { return height - y(d.somme); })
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
});
function type(d) {
d.somme = +d.somme;
return d;
}
}
/*callign the HGlob fucntion*/
var HGlobal=HGlob();
/** data tsv file **/
Zone_Geographique annee1 annee2 annee3 somme
Europe_hors Schengen 473947 525119 582245 1581311
Maghreb 377022 415607 472250 1264879
Asie_océanie 436002 464936 513985 1414923
Moyen_orient 310525 352504 336209 999238
afrique_francophone 163944 151661 155352 470957
afrique_non_francophone 112027 113830 125657 351514
amérique_latine_Caraïbes 67571 66980 66298 200849
amérique_du_nord 52975 57392 51452 161819
Europe_Schengen 5399 8162 7812 21373
I'm learning d3js using various examples found online.
I've been trying to plot a chart with dual Y axis and an X-axis. The Y axis on the left side would plot a bar chart against the X-axis and the Y-axis on the right side would plot a line chart against X-axis. The Bar graph plots as exactly as required but the line graph does not. The X-axis is date (2015-10-15 04:10). Following this example.
The code I wrote
var margin = {top: 50, right: 50, bottom: 100, left: 50},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%m/%d/%Y %H:%M:%S").parse;
var x = d3.scale.ordinal().rangeRoundBands([0, width], .05);
var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yTxnVol)
.orient("left")
var yAxis2 = d3.svg.axis()
.scale(yResTime)
.orient("right")
.ticks(10);
var svg = d3.selectAll("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("../res/data.csv", function(error, data) {
data.forEach(function(d) {
d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
d.TXN_VOL = +d.TXN_VOL;
});
x.domain(data.map(function(d) { return d.TYM; }));
yTxnVol.domain([0, d3.max(data, function(d) { return d.TXN_VOL+50; })]);
yResTime.domain([0, d3.max(data, function(d) { return d.AVRG_RESP_TIME+50; })]);
var minDate = d3.min(data, function(d){return d.TYM});
var maxDate = d3.max(data, function(d){ return d.TYM});
var xScale = d3.time.scale().range([0,width]);//.domain([minDate, maxDate]);
xScale.domain(d3.extent(data, function(d) { return new Date(d.TYM); }));
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)" );
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("g")
.attr("class","y axis")
.attr("transform","translate("+width+ ", 0)")
.call(yAxis2)
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "yhover")
.attr("x", function(d) { return x(d.TYM); })
.attr("width", x.rangeBand())
.attr("y", function(d) { return yTxnVol(d.TXN_VOL); })
.attr("height", function(d) { return height - yTxnVol(d.TXN_VOL); })
var line = d3.svg.line()
.x(function(d) { return xScale(new Date(d.TYM));})
.y(function(d) { return d.AVRG_RESP_TIME; });
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
});
The Output Trying to make this to a meaningful line graph. Got NaN error while formatting the dates.
Could someone help me to make this a proper line graph ?
The csv data sample
TYM, AVRG_RESP_TIME, TXN_VOL
2015-10-15 04:00:00, 12, 170
2015-10-15 04:10:00, 18, 220
2015-10-15 04:20:00, 28, 251
2015-10-15 05:00:00, 19, 100
First, fix your csv file. It is improperly formatted and should not have spaces after the comma.
Second, You are trying to mix an ordinal scale and a time scale for you xAxis. This isn't going to work. For your use case, just stick with time.
Here's a reworking of your code with explanatory comments:
<!DOCTYPE html>
<html>
<head>
<script data-require="d3#3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>
<body>
<script>
var margin = {
top: 50,
right: 50,
bottom: 100,
left: 50
},
width = 900 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse;
// x scale should be time and only time
var x = d3.time.scale().range([0, width]);
var yTxnVol = d3.scale.linear().range([height, 0]);
var yResTime = d3.scale.linear().range([height, 0]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
var yAxis = d3.svg.axis()
.scale(yTxnVol)
.orient("left")
var yAxis2 = d3.svg.axis()
.scale(yResTime)
.orient("right")
.ticks(10);
var svg = d3.selectAll("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) {
var data = [{"TYM":"2015-10-15 04:00:00","AVRG_RESP_TIME":"12","TXN_VOL":"170"},{"TYM":"2015-10-15 04:10:00","AVRG_RESP_TIME":"18","TXN_VOL":"220"},{"TYM":"2015-10-15 04:20:00","AVRG_RESP_TIME":"28","TXN_VOL":"251"},{"TYM":"2015-10-15 05:00:00","AVRG_RESP_TIME":"19","TXN_VOL":"100"}];
// just make TYM a date and keep it as a date
data.forEach(function(d) {
d.TYM = parseDate(d.TYM);
d.AVRG_RESP_TIME = +d.AVRG_RESP_TIME;
d.TXN_VOL = +d.TXN_VOL;
});
// get our min and max date in milliseconds
// set a padding around our domain of 15%
var minDate = d3.min(data, function(d){
return d.TYM;
}).getTime();
var maxDate = d3.max(data, function(d){
return d.TYM;
}).getTime();
var padDate = (maxDate - minDate) * .15;
x.domain([new Date(minDate - padDate), new Date(maxDate + padDate)]);
yTxnVol.domain([0, d3.max(data, function(d) {
return d.TXN_VOL + 50;
})]);
yResTime.domain([0, d3.max(data, function(d) {
return d.AVRG_RESP_TIME + 50;
})]);
// set an intelligent bar width
var barWidth = (width / x.ticks().length) - 20;
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", "-.55em")
.attr("transform", "rotate(-90)");
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ", 0)")
.call(yAxis2)
svg.selectAll("bar")
.data(data)
.enter().append("rect")
.attr("class", "yhover")
.attr("x", function(d) {
// center bar on time
return x(d.TYM) - (barWidth / 2);
})
.attr("width", barWidth)
.attr("y", function(d) {
return yTxnVol(d.TXN_VOL);
})
.attr("height", function(d) {
return height - yTxnVol(d.TXN_VOL);
})
.style("fill","orange");
var line = d3.svg.line()
.x(function(d) {
return x(d.TYM);
})
.y(function(d) {
return d.AVRG_RESP_TIME;
});
svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.style("fill","none")
.style("stroke","steelblue")
.style("stoke-width","3px");
// });
</script>
</body>
</html>
The issue with the line graph filling with black was due to improper css. The new css property.
.line {
fill: none;
stroke: darkgreen;
stroke-width: 2.5px;
}
For the dates I formatted it to (%Y-%m-%d %H:%M) format and it worked.
I'm trying to modify Zoomable area from http://bl.ocks.org/mbostock/4015254 with adding data points from csv file in it, but couldn't get things right. Only lines can be zoomed and moved but not points.
My guess is I need to put circle's .attr("transform", function(d){ return "translate("+x(d[key0])+","+y(d[key1])+")";}); within function draw, but then it cannot recognize key0 and key1 (I have multiple columns in the csv file).
The following is the code I modified. Any idea how to fix this?
<script>
var margin = {top: 20, right: 60, bottom: 30, left: 20},
width = 960 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;`
var parseDate = d3.time.format("%Y-%m-%d %H:%M:%S").parse,
formatDate = d3.time.format("%Y");
var x = d3.time.scale()
.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("right")
.tickSize(-width)
.tickPadding(6);
var xGrid = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height,0)
.ticks(5)
.tickPadding(1)
.tickFormat("");
var line = d3.svg.line();
var zoom = d3.behavior.zoom()
.scaleExtent([1,128])
.on("zoom", draw);
var zoom2 = d3.behavior.zoom()
.scaleExtent([1,128])
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 + ")")
.call(zoom);
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + width + ",0)");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height/2 + ")");
svg.append("g")
.attr("class", "x line")
.attr("transform", "translate(0," + height/2 + ")")
.append("svg:line")
.attr("x1",x(0))
.attr("y1",-y(0))
.attr("x2",x(width))
.attr("y2",-y(0));
svg.append("g")
.attr("class", "grid")
.attr("transform", "translate(0,"+ height + ")");
svg.append("path")
.attr("class", "line");
svg.append("rect")
.attr("class", "pane")
.attr("width", width)
.attr("height", height);
circle = svg.selectAll("circle");
d3.csv("encounter.csv", function(error, data) {
key0 = Object.keys(data[0])[1];
key1 = Object.keys(data[0])[3];
data.forEach(function(d,i) {
d[key0] = parseDate(d[key0]);
d[key1] = +d[key1];
});
x.domain([new Date(2014, 0, 1), new Date(2015, 0, 1)]);
y.domain(d3.extent(data, function(d){return d[key1];})).nice();
zoom.x(x);
svg.select("path.line").data([data]);
line.x(function(d) { return x(d[key0]); })
.y(function(d) { return y(d[key1]); });
circle.data(data)
.enter().append("circle")
.attr("class", "dot")
.attr("r", 5)
.attr("transform", function(d){ return "translate("+x(d[key0])+","+y(d[key1])+")";});
draw();
});
function draw() {
svg.select("g.x.axis").call(xAxis);
svg.select("g.y.axis").call(yAxis);
svg.select("g.grid").call(xGrid);
svg.select("path.line").attr("d", line);
}
i am trying to visualize some data using Focus + Context via brushing using D3. I am having some problems with the data. I have just changed the data fetch lines of code since i am fetching 2 values using d3.json. Here is my code -
<script type="text/javascript">
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("%a %e %H %M").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.receiveddate); })
.y0(height)
.y1(function(d) { return y(d.gtse); });
var area2 = d3.svg.area()
.interpolate("monotone")
.x(function(d) { return x2(d.receiveddate); })
.y0(height2)
.y1(function(d) { return y2(d.gtse); });
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("transform", "translate(" + margin.left + "," + margin.top + ")");
var context = svg.append("g")
.attr("transform", "translate(" + margin2.left + "," + margin2.top + ")");
d3.json("rest.php/lastweek"+"/"+"dibya", function(error, data) {
var allData = data.records;
allData.forEach(function(d) {
var formattedDate = new Date(+d.receiveddate).toString();
d.receiveddate = parseDate(d3.time.format("%a %e %H %M")(new Date(formattedDate)));
d.gtse = +d.gtse;
});
x.domain(d3.extent(allData.map(function(d) { return d.receiveddate; })));
y.domain([0, d3.max(allData.map(function(d) { return d.gtse; }))]);
x2.domain(x.domain());
y2.domain(y.domain());
focus.append("path")
.datum(data)
.attr("clip-path", "url(#clip)")
.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("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("path").attr("d", area);
focus.select(".x.axis").call(xAxis);
}
Here the received date is fetched as date in Millis and converted accordingly. The received date is in the frequency of 10 mins. The browser loads the x and y axes according to the values passed but no graph is plotted. Neither do i get any error in console. What am i missing?
Iam new to D3.i just want to draw a line chart.For that i just put the static values ,its working fine,But when i fetch data from server db graph is not getting properly.Problem iam getting is x and y axis with values are getting.But not getting the line graph.here is the code
// Line chart creation....................................................
var deviceTime = 0;
var margin = { top: 20, right: 80, bottom: 30, left: 50 };
var da = '<%=#display.to_json(:only => [:DeviceTime, :Speed])%>'
var margin = { top: 20, right: 80, bottom: 30, left: 50 };
var dataset=JSON.parse(da.replace(/"/g,'"'));
//test code TODO :need to move somewhere else
var data = [];
for (var vAlue in dataset[0]) {
var tempData = d3.values(dataset[0][vAlue]);
data.push(tempData[1]);
}
// test end
var yExtents = d3.extent(d3.merge(dataset), function (d) { return d.Speed; });
var xExtents = d3.extent(d3.merge(dataset), function (d) { return d.DeviceTime; });
//alert("xevents[0]-------"+xExtents[0] "xevents[1]-------"+xExtents[1]);
var w = 900;
var h = 400;
var padding = 30;
deviceTime = xExtents[1];
//Create scale functions
var xScale = d3.scale.linear()
.domain([xExtents[0], xExtents[1]])
.range([padding, w - padding * 2]);
var yScale = d3.scale.linear()
.domain([0, yExtents[1]])
//.domain([0, 160])
.range([h - padding, padding]);
//Define X axis
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(10);
//Define Y axis
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
///////////////// need to remove
var line = d3.svg.line()
.x(function (d, i) { return xScale(i); })
.y(function (d, i) { return yScale(d); });
//Create SVG element
var svg = d3.select("#bar-demo")
.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 + ")");
//Create X axis
var hh = svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + padding + ",0)")
.call(yAxis);
var path = svg.append("g")
//.attr("clip-path", "url(#clip)")
.append("path")
.data([data])
.attr("class", "line")
.attr("transform", "translate(" + 102 + ",0)")
.attr("d", line);
svg.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 0-margin.left+10)
.attr("x",0-h/2)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Speed km/h");
svg.append("text")
.attr("y", h)
.attr("x", h)
.attr("dy", "1em")
.style("text-anchor", "middle")
.text("Time Stamp");