My requirement is to generate grouped category bar chart. I am able to generate that graph but the problem is if x axis labels names are bigger than bar range band then label names are overlapping.because of this unable to get good look and feel as expected.I found some where that we can wrap text labels but I don't know how to achieve that.
here js and html code related to generated grouped category chart
var margin = {
top: 20,
right: 20,
bottom: 130,
left: 40
},
width = 2360 - margin.left - margin.right,
height = 560 - margin.top - margin.bottom;
var color = {
Mechanical: '#4A7B9D',
Electrical: '#54577C',
Hydraulic: '#ED6A5A'
};
var barPadding = 40;
var data = [
{
"key" : "portFolio1",
"values" :[
{
"key" : "project1",
"values" :[
{
"key" : "config1",
"values" :[
{
"key" :"date1",
"value": 12
},
{
"key" : "date2",
"value": 10
},
{
"key" : "date3",
"value": 2
}
],
},
{
"key" : "configurationwithvalue",
"values" :[
{
"key" :"date1asa",
"value": 10
},
{
"key" : "date2",
"value": 10
},
{
"key" : "date3",
"value": 2
}
],
},
{
"key" : "config2",
"values" :[
{
"key" : "date1",
"value": 1
},
{
"key" : "date3",
"value": 14
}
],
}
],
},
{
"key" : "projct2",
"values" :[
{
"key" : "congi1",
"values" :[
{
"key" : "date2",
"value" :1
},
{
"key" : "date3",
"value": 10
}
],
}
],
}
] ,
},
{
"key" : "portfolio2",
"values" :[
{
"key" : "portfolio2_project1",
"values" :[
{
"key" : "congie1",
"values" : [
{
"key" : "date12",
"value": 23
},
{
"key" : "date1",
"value" : 1
}
],
}
],
}
],
},
{
"key" : "portFolio3",
"values" :[
{
"key" : "project_portfolio3",
"values" :[
{
"key" : "congi1",
"values" :[
{
"key" :"date1",
"value": 12
}
],
},
{
"key" : "congi2",
"values" :[
{
"key" : "date1",
"value": 1
},
{
"key" : "date3",
"value": 14
}
],
}
],
},
{
"key" : "projct2_prortfolio_23",
"values" :[
{
"key" : "congi1",
"values" :[
{
"key" : "date2",
"value" :1
},
{
"key" : "date3",
"value": 10
}
],
}
],
}
] ,
}
]
var rangeBands = [];
var cummulative = 0; // to get transform position of categories 'portfolio1,portfolio2,portfolio3 on x axis scale
data.forEach(function(val, i) {
var valLength = 0; // to get position of x axis for categories 'portfolio1,portfolo2,portfolio3 on x axis scale
val.cummulative = cummulative;
var cum = 0; // to get trnsfrom position of categories 'projct1,project2,project3' on x axis scale
val.values.forEach(function(values) {
var valLe = 0; // to get position of x axis for categories 'projct1,project2,project3' on x axis scale
values.cummulative2 = cum;
values.parentKey = val.key;
var cum3 = 0; // to get trnsfrom position of categories 'config1,config2...etc on x axis scale
values.values.forEach(function(values) { // config level
values.cummulative3 = cum3;
values.parentKey = values.key;
values.values.forEach(function(values) {
cum3 = cum3 +1;
valLe = valLe + 1;
cum = cum+1;
valLength = valLength +1 ;
cummulative = cummulative+1;
values.parentKey = values.key;
rangeBands.push(i);
})
})
values.valueLength2 = valLe;
})
val.valueLength = valLength;
});
// set x axis domain adn range
var x_category = d3.scale.linear()
.range([0, width]);
var x_defect = d3.scale.ordinal().domain(rangeBands).rangeRoundBands([0, width], .1);
var x_category_domain = x_defect.rangeBand() * rangeBands.length*3;
x_category.domain([0, x_category_domain]);
// y axis domain and range
var y = d3.scale.linear()
.range([height, 0]);
y.domain([0, d3.max(data, function(cat) {
return d3.max(cat.values, function(def) {
return d3.max(def.values, function(def) {
return d3.max(def.values, function(def) {
return def.value;
});
});
});
})]);
// x axis scale
var category_axis = d3.svg.axis()
.scale(x_category)
.orient("bottom");
// y axis scale
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)
.style('background-color', 'EFEFEF')
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
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");
//add all category groups of 'profolio1,portfolio2,portfolio3 ..etc for svg
var category_g = svg.selectAll(".category")
.data(data)
.enter().append("g")
.attr("class", function(d) {
return 'category category-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_category((d.cummulative * x_defect.rangeBand())) + ",0)";
});
//add all category groups of projct1,project2 etc for every category group of category_g
var category_g1 = category_g.selectAll(".category1")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'category category1-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_category((d.cummulative2 * x_defect.rangeBand())) + ",0)";
})
//add all category groups of 'congif1,config2' etc for every category group of category_g1
var category_g2 = category_g1.selectAll(".category2")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'category category2-' + d.key;
})
.attr("transform", function(d) {
return "translate(" + x_category((d.cummulative3 * x_defect.rangeBand())) + ",0)";
})
// lables for category_g
var category_label = category_g.selectAll(".category-label")
.data(function(d) {
return [d];
})
.enter().append("text")
.attr("class", function(d) {
return 'category-label category-label-' + d.key;
})
.attr("transform", function(d) {
var x_label = x_category((d.valueLength * x_defect.rangeBand() + barPadding) / 2);
var y_label = height + 120;
return "translate(" + x_label + "," + y_label + ")";
})
.text(function(d) {
return d.key;
})
.attr('text-anchor', 'middle');
// lines to separate each category_g labels
category_g.append("line")
.attr("x1", function(d) {
return x_category((d.valueLength * x_defect.rangeBand()+ barPadding));
})
.attr("y1", 0)
.attr("x2", function(d) {
return x_category((d.valueLength * x_defect.rangeBand()+ barPadding));
})
.attr("y2", 120)
.attr("transform", function(d) {
var x_label = 0;
var y_label = height;
return "translate(" + x_label + "," + y_label + ")";
})
.style("stroke-width", 1)
.style("stroke", "red")
.style("fill", "none");
// lables for category_g1
var category_label1 = category_g1.selectAll(".category-label1")
.data(function(d) {
return [d];
})
.enter().append("text")
.attr("class", function(d) {
return 'category-label category-label-' + d.key;
})
.attr("transform", function(d) {
var x_label = x_category((d.values.length * x_defect.rangeBand()+ barPadding) / 2);
var y_label = height + 80;
return "translate(" + x_label + "," + y_label + ")";
})
.text(function(d) {
return d.key;
})
.attr('text-anchor', 'middle');
// lines to separate each category_g1 labels
category_g1.append("line")
.attr("x1", function(d) {
return x_category((d.valueLength2* x_defect.rangeBand()+ barPadding));
})
.attr("y1", 0)
.attr("x2", function(d) {
return x_category((d.valueLength2 * x_defect.rangeBand()+ barPadding));
})
.attr("y2", 80)
.attr("transform", function(d) {
var x_label = 0;
var y_label = height;
return "translate(" + x_label + "," + y_label + ")";
})
.style("stroke-width", 1)
.style("stroke", "blue")
.style("fill", "none");
// lables for category_g2
var category_label2 = category_g2.selectAll(".category-label2")
.data(function(d) {
return [d];
})
.enter().append("text")
.attr("class", function(d) {
return 'category-label category-label2-' + d.key;
})
.attr("transform", function(d) {
var x_label = x_category((d.values.length * x_defect.rangeBand()) / 2);
var y_label = height + 50;
return "translate(" + x_label + "," + y_label + ")";
})
.text(function(d) {
return d.key;
})
.attr('text-anchor', 'middle');
// lines to separate each category_g2 labels
category_g2.append("line")
.attr("x1", function(d) {
return x_category((d.values.length* x_defect.rangeBand()+ barPadding));
})
.attr("y1", 0)
.attr("x2", function(d) {
return x_category((d.values.length * x_defect.rangeBand()+ barPadding));
})
.attr("y2", 60)
.attr("transform", function(d) {
var x_label = 0;
var y_label = height;
return "translate(" + x_label + "," + y_label + ")";
})
.style("stroke-width", 1)
.style("stroke", "black")
.style("fill", "none");
// lables for defect_g
var defect_g = category_g2.selectAll(".defect")
.data(function(d) {
return d.values;
})
.enter().append("g")
.attr("class", function(d) {
return 'defect defect-' + d.key;
})
.attr("transform", function(d, i) {
return "translate(" + x_category((i * x_defect.rangeBand())) + ",0)";
});
var defect_label = defect_g.selectAll(".defect-label")
.data(function(d) {
return [d];
})
.enter().append("text")
.attr("class", function(d) {
return 'defect-label defect-label-' + d.key;
})
.attr("transform", function(d) {
var x_label = x_category((x_defect.rangeBand() + barPadding) / 2);
var y_label = height + 10;
return "translate(" + x_label + "," + y_label + "),rotate(-90)";
})
.text(function(d) {
return d.key;
})
.attr('text-anchor', 'middle');
var rects = defect_g.selectAll('.rect')
.data(function(d) {
return [d];
})
.enter().append("rect")
.attr("class", "rect")
.attr("width", x_category(x_defect.rangeBand() - barPadding))
.attr("x", function(d) {
return x_category(barPadding);
})
.attr("y", function(d) {
return y(d.value);
})
.attr("height", function(d) {
return height - y(d.value);
});
// to display values on top of bar chart
defect_g.selectAll("text.bar")
.data(function(d) {
return [d];
})
.enter().append("text")
.attr("class", "rect1")
.attr("text-anchor", "middle")
.attr("x", function(d) { return x_category(x_defect.rangeBand()-barPadding)/2; })
.attr("y", function(d) { return y(d.value); })
.text(function(d) { return d.value+"%"; });
<!DOCTYPE html>
<html>
<head>
<script data-require="[email protected]" data-semver="3.5.3" src="https://d3js.org/d3.v3.min.js"></script>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<script src="script2.js"></script>
</body>
</html>
I think rotating labels will do good with area without overlapping.
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.attr("y", 0)
.attr("x", 9)
.attr("dy", ".35em")
.attr("transform", "rotate(90)")
.style("text-anchor", "start");
or in order to wrap text:
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll(".tick text")
.call(wrap, x.rangeBand());
function wrap(text, width) {
text.each(function() {
var text = d3.select(this),
words = text.text().split(/\s+/).reverse(),
word,
line = [],
lineNumber = 0,
lineHeight = 1.1, // ems
y = text.attr("y"),
dy = parseFloat(text.attr("dy")),
tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em");
while (word = words.pop()) {
line.push(word);
tspan.text(line.join(" "));
if (tspan.node().getComputedTextLength() > width) {
line.pop();
tspan.text(line.join(" "));
line = [word];
tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word);
}
}
});
}
Here are examples of :
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With