Reputation: 520
I am implementing a Stacked Bar graph in d3.js. It is for populations of various categories (category of people) in city over the years . Although I have achieved a bit of outcome with the help of some references but I haven't got the exact result I wanted.
I guess I am facing some problems in data mapping and filter functions, and assigning them in color domain.
Any help would be much appreciated.
Here is my code :-
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.bar {
fill: steelblue;
}
.x.axis path {
display: none;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js">
</script>
<script>
var margin = {
top: 20, right: 20, bottom: 30, left: 40}
,
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
yAxMin_PA = 0,
yAxMax_PA = 1500;
var x = d3.scale.ordinal()
.rangeRoundBands([0, width], .1);
var y = d3.scale.linear()
.domain([yAxMin_PA, yAxMax_PA])
.range([height, 0]);
var color = d3.scale.category20();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom");
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickFormat(d3.format(".2s"));
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data = {
"bars": [
{
"year": 2004,
"population": [
{
"category": 1,
"strength": 31
}
,
{
"category": 2,
"strength": 21
}
,
{
"category": 3,
"strength": 41
}
]
}
,
{
"year": 2005,
"population": [
{
"category": 1,
"strength": 23
}
,
{
"category": 2,
"strength": 43
}
,
{
"category": 3,
"strength": 33
}
]
}
,
{
"year": 2006,
"population": [
{
"category": 1,
"strength": 29
}
,
{
"category": 2,
"strength": 41
}
,
{
"category": 3,
"strength": 55
}
,
{
"category": 4,
"strength": 69
}
,
{
"category": 5,
"strength": 89
}
,
{
"category": 6,
"strength": 75
}
]
}
,
{
"year": 2007,
"population": [
{
"category": 1,
"strength": 49
}
,
{
"category": 2,
"strength": 43
}
,
{
"category": 3,
"strength": 25
}
]
}
,
{
"year": 2008,
"population": [
{
"category": 1,
"strength": 20
}
,
{
"category": 2,
"strength": 43
}
,
{
"category": 3,
"strength": 55
}
]
}
]
}
;
x.domain(data.bars.map(function(d) {
return d.year;
}
));
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("Population");
for (k = 0; k < data.bars.length; k++) {
var state = svg.append("g")
.attr("class", "g")
.attr("transform", function (d) {
return "translate(" + x(data.bars[k].year) + ",0)";
});
state.selectAll("rect")
.data(data.bars[k].population)
.enter().append("rect")
//.attr("width", x.rangeBand())
.attr("class", "rect_grp" + k)
.attr("id", function (d, i) {
return "rect" + i;
})
.attr("width", function () {
return x.rangeBand();
})
.attr("y", function (d, i) { /*console.log("hiii");*/
if (i != 0) {
var prevHgt = d3.select(".rect_grp" + k + "#rect" + (i - 1)).attr("height"); // Select height of previous rectangle
var ylimit = d3.select(".rect_grp" + k + "#rect" + (i - 1)).attr("y"); // Select y of previous rectangle
console.log("prevHgt=>" + prevHgt);
return ((parseFloat(ylimit)) - (parseFloat(prevHgt)));
} else {
return y(d.strength);
}
})
.attr("height", function (d, i) {
return (Math.round(y(yAxMin_PA)) - Math.round(y(d.strength)));
})
.style("fill", function (d, i) {
console.log(i);
return color(i);
});
}
</script>
Upvotes: 2
Views: 5255
Reputation: 1616
I find it is useful to give people the example instead of making them run it themselves. See here: http://tributary.io/inlet/5835233.
Around line 157 where it says
d.population.forEach (function(d){
color.domain(d3.keys(d).filter(function(name) {
return name;
}
name
is always either "category"
or "strength"
. This is because of how your data is arranged. I think what you want is to have your data be
{year: 2008,
population: {
category1: 20,
category2: 43,
category3: 55}
}
If you put your data like this, you'll have to mess around with how exactly you are setting the domain of your color
instance, since forEach
only works on arrays, and we have now set the data to be in an object. Something like color.domain(d3.keys(d.population))
. Fork my example on tributary and try a couple things. Look at the d3.keys()
documentation to see how it works.
Upvotes: 1