Skip to content

Instantly share code, notes, and snippets.

@jayrambhia
Last active August 29, 2015 13:59
Show Gist options
  • Save jayrambhia/10473767 to your computer and use it in GitHub Desktop.
Save jayrambhia/10473767 to your computer and use it in GitHub Desktop.
Multibar transition using d3
axis = function(){
var ldomain = 0, rdomain = 0, lrange = 0, rrange = 0;
var orientation = "left", ticks = 0;
var xpadding = 10, ypadding = 10;
var plotted = false;
var scale, Axis, AxisGroup;
function chart(selection){}
chart.ticks = function(_) {
if (!arguments.length) return ticks;
ticks = _;
chart.update();
return chart;
}
chart.ldomain = function(_) {
if (!arguments.length) return ldomain;
ldomain = _;
chart.update();
return chart;
}
chart.rdomain = function(_) {
if (!arguments.length) return rdomain;
rdomain = _;
chart.update();
return chart;
}
chart.lrange = function(_) {
if (!arguments.length) return lrange;
lrange = _;
chart.update();
return chart;
}
chart.rrange = function(_) {
if (!arguments.length) return rrange;
rrange = _;
chart.update();
return chart;
}
chart.orientation = function(_) {
if (!arguments.length) return orientation;
orientation = _;
chart.update();
return chart;
}
chart.xpadding = function(_) {
if (!arguments.length) return xpadding;
xpadding = _;
chart.update();
return chart;
}
chart.ypadding = function(_) {
if (!arguments.length) return ypadding;
ypadding = _;
chart.update();
return chart;
}
chart.change_rrange = function(_){
if(!arguments.length) return rrange;
rrange = _;
chart.update();
return chart;
}
chart.plot = function(svg) {
plotted = true;
scale = d3.scale.linear()
.domain([ldomain, rdomain])
.range([lrange, rrange]);
Axis = d3.svg.axis()
.scale(scale)
.orient(orientation)
.ticks(ticks);
AxisGroup = svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(" + xpadding + "," + ypadding + ")")
.call(Axis);
return svg;
}
chart.update = function(){
if (!plotted) {return chart;}
scale = d3.scale.linear()
.domain([ldomain, rdomain])
.range([lrange, rrange]);
Axis = d3.svg.axis()
.scale(scale)
.orient(orientation)
.ticks(ticks);
AxisGroup.transition().duration(1000)
.attr("transform", "translate(" + xpadding + "," + ypadding + ")")
.call(Axis);
}
return chart;
}
barChart = function() {
var width = 600
, height = 300
, colorPalette = d3.scale.category20c()
, barWidth = 40
, separation = 5
, xpadding = 30
, ypadding = 10
, textXOffset = 15
, textYOffset = 15
, textYPosition = 300
, yTicks = 5
, xTicks = 0
, maxData = 0
, xrange = 0
, yrange = 0
, cols = 0
, rows = 0
, maxData = 0
, xrange = 0
, yrange = 0
, barHeightMultiplier = 1
, showAxis = true
, showYText = false
, showXText = false
, textSpace = 50
, plotted = false;
var xAxis = axis() , yAxis = axis();
function chart(selection) {
//selection.each
}
chart.plot = function() {
plotted = true;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
if (showAxis)
{
xAxis.ldomain(0)
.rdomain(rows)
.lrange(0)
.rrange(xrange)
.xpadding(10)
.ypadding(height - textSpace)
.orientation("bottom")
.ticks(xTicks)
.plot(svg);
yAxis.ldomain(0)
.rdomain(maxData)
.lrange(0)
.rrange(height - textSpace - ypadding)
.ticks(yTicks)
.ypadding(ypadding)
.xpadding(10)
.orientation("left")
.plot(svg);
}
var dataEnter = svg.selectAll("rect").data(data).enter();
dataEnter.append("rect").attr("x", function(d, i)
{
return (xpadding + (i)*(barWidth+separation));
}).attr("y", function(d)
{
return height - textSpace - d[1] * barHeightMultiplier - 1;
}).attr("width", function(d)
{
return barWidth;
}).attr("height", function(d)
{
return d[1] * barHeightMultiplier;
}).style("fill", function(d, i) {return colorPalette(i);});
if (showXText)
{
dataEnter.append("text").text(function(d)
{
return d[0];
})/*
.attr("x", function(d, i)
{
return (xpadding + 20 + (i)*(barWidth+separation));;
}).attr("y", textYPosition)*/
.attr("font-family", "sans-serif")
.attr("font-size", "12px")
.attr("fill", function(d, i){return colorPalette(i);})
.attr("transform", function(d, i)
{
var xvar = (xpadding + 20 + (i)*(barWidth+separation));
var yvar = textYPosition ;
return "rotate(-90," + xvar + "," + yvar + ")";
});
}
return chart;
}
chart.load = function(indata) {
data = indata;
rows = data.length;
cols = data[0].length;
for(var s=0; s<rows; s++)
{
if (maxData < Number(data[s][1]))
{
maxData = Number(data[s][1]);
}
}
xrange = rows * (barWidth + separation) + xpadding;
yrange = maxData;
barHeightMultiplier = (height - ypadding - textSpace) / maxData;
textYPosition = height - 1;
return chart;
}
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.separation = function(_) {
if (!arguments.length) return separation;
separation = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.xpadding = function(_) {
if (!arguments.length) return xpadding;
xpadding = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.ypadding = function(_) {
if (!arguments.length) return ypadding;
ypadding = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.xTicks = function(_) {
if (!arguments.length) return xTicks;
xTicks = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.yTicks = function(_) {
if (!arguments.length) return yTicks;
yTicks = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.barWidth = function(_) {
if (!arguments.length) return barWidth;
barWidth = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.showAxis = function(_) {
if (!arguments.length) return showAxis;
showAxis = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.showXText = function(_) {
if (!arguments.length) return showXText;
showXText = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.changeBarWidth = function(_){
if (!arguments.length) return barWidth;
barWidth = _;
if (!plotted) return chart;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.changeSeparation = function(_){
if (!arguments.length) return separation;
separation = _;
//if (!plotted) return chart;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.changeHeight = function(_){
if (!arguments.length) return height;
height = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.updatePlotValues = function(){
xrange = rows * (barWidth + separation) + xpadding;
yrange = maxData;
barHeightMultiplier = (height - ypadding - textSpace) / maxData;
textYPosition = height - 1;
}
chart.update = function(_){
if (!plotted) { return chart; }
if(showAxis)
{
xAxis.ldomain(0)
.rdomain(rows)
.lrange(0)
.rrange(xrange)
.xpadding(10)
.ypadding(height - textSpace)
.orientation("bottom")
.ticks(xTicks)
.update();
yAxis.ldomain(0)
.rdomain(maxData)
.lrange(0)
.rrange(height - textSpace - ypadding)
.ticks(yTicks)
.ypadding(ypadding)
.xpadding(10)
.orientation("left")
.update();
}
var barNodes = document.querySelectorAll("svg");
d3.select("svg").attr("height", height).attr("width", width);
for(var n=0; n<barNodes.length; n++) {
d3.select(barNodes.item(n)).selectAll("rect").transition().duration(1000)
.attr("x", function(d, i)
{
return (xpadding + (i)*(barWidth+separation));
}).attr("y", function(d)
{
return height - textSpace - d[1] * barHeightMultiplier - 1;
}).attr("width", function(d)
{
return barWidth;
}).attr("height", function(d)
{
return d[1] * barHeightMultiplier;
}).style("fill", function(d, i) {return colorPalette(i);});
if (showXText)
{
d3.select(barNodes.item(n)).selectAll("text")
/*
.attr("x", function(d, i)
{
return (xpadding + barWidth/2 + (i)*(barWidth+separation));
}).attr("y", textYPosition)
*/
.attr("transform", function(d, i)
{
var xvar = (xpadding + barWidth/2 + (i)*(barWidth+separation));
var yvar = textYPosition ;
return "translate("+ (xvar) +","+(yvar)+")rotate(-90)";
});
}
}
}
//return this;
return chart;
}
multibarChart = function() {
var width = 600
, height = 300
, colorPalette = d3.scale.category20()
, barWidth = 40
, separation = 5
, xpadding = 10
, ypadding = 10
, textXOffset = 15
, textYOffset = 15
, textYPosition = 300
, yTicks = 5
, xTicks = 0
, maxData = 0
, xrange = 0
, yrange = 0
, cols = 0
, rows = 0
, maxData = 0
, xrange = 0
, yrange = 0
, barHeightMultiplier = 1
, showAxis = true
, showYText = false
, showXText = false
, textSpace = 50
, plotted = false
, stacked = true;
var xAxis = axis() , yAxis = axis();
function chart(selection) {
//selection.each
}
chart.plot = function() {
plotted = true;
var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
if (showAxis)
{
xAxis.ldomain(0)
.rdomain(rows)
.lrange(0)
.rrange(xrange)
.xpadding(10)
.ypadding(height)
.orientation("bottom")
.ticks(xTicks)
.plot(svg);
yAxis.ldomain(0)
.rdomain(maxData)
.lrange(0)
.rrange(height - ypadding)
.ticks(yTicks)
.ypadding(ypadding)
.xpadding(10)
.orientation("left")
.plot(svg);
}
var dataEnter = svg.selectAll("rect").data(data).enter();
if(stacked)
{
// stacked bars
for(var n=0; n<cols-1; n++)
{
dataEnter.append("rect").attr("x", function(d, i)
{
if (i == 0) { return 0; }
return (xpadding + 5 + (i-1)*(barWidth+separation));
}).attr("y", function(d, i)
{
if (i == 0) { return 0; }
var ytop = 0;
for(var m = cols - 1; m > n; m--)
{
ytop += Number(d[m]);
}
return height - 1 - ytop * barHeightMultiplier;
}).attr("width", function(d, i)
{
if (i == 0) { return 0; }
return barWidth;
}).attr("height", function(d, i)
{
if (i == 0) { return 0; }
return d[n+1] * barHeightMultiplier;
}).style("fill", function(d, i) {return colorPalette(n);})
.attr("row",function(d,i){if (i == 0) { return 0; }return i;})
.attr("col", function(d,i){if (i == 0) { return 0; }return n+1;});
}
}
else
{
// grouped bars
var sBarWidth = barWidth/cols;
for(var n=0; n < cols - 1; n++)
{
dataEnter.append("rect").attr("x", function(d, i)
{
if (i == 0) { return 0; }
return (xpadding + 5 + (n*sBarWidth) + (i-1)*(cols-1)*(sBarWidth) + (i-1)*(separation));
//return ((i-1) + 0.5) * horizontalBarDistance + (n * barWidth) + xpadding;
}).attr("y", function(d, i)
{
if (i == 0) { return 0; }
return height - 1 - d[n+1] * barHeightMultiplier;
}).attr("width", function(d, i)
{
if (i == 0) { return 0; }
return sBarWidth;
}).attr("height", function(d, i)
{
if (i == 0) { return 0; }
return d[n+1] * barHeightMultiplier;
}).style("fill", function(d, i) {return colorPalette(n);})
.attr("row",function(d,i){if (i == 0) { return 0; }return i;})
.attr("col", function(d,i){if (i == 0) { return 0; }return n+1;});
}
}
return chart;
}
chart.load = function(indata) {
data = indata;
rows = data.length;
cols = data[0].length;
var cData = 0;
for(var i=1; i<rows; i++)
{
for(var j=1; j<cols; j++)
{
cData += Number(data[i][j]);
}
if(cData > maxData)
{
maxData = cData;
}
cData = 0;
}
xrange = (rows - 1) * (barWidth) + (rows - 2)*separation + xpadding;
yrange = maxData;
barHeightMultiplier = (height - ypadding) / maxData;
textYPosition = height - 1;
return chart;
}
chart.width = function(_) {
if (!arguments.length) return width;
width = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.stacked = function(_) {
if (!arguments.length) return stacked;
stacked = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.height = function(_) {
if (!arguments.length) return height;
height = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.separation = function(_) {
if (!arguments.length) return separation;
separation = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.xpadding = function(_) {
if (!arguments.length) return xpadding;
xpadding = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.ypadding = function(_) {
if (!arguments.length) return ypadding;
ypadding = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.xTicks = function(_) {
if (!arguments.length) return xTicks;
xTicks = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.yTicks = function(_) {
if (!arguments.length) return yTicks;
yTicks = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.barWidth = function(_) {
if (!arguments.length) return barWidth;
barWidth = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.showAxis = function(_) {
if (!arguments.length) return showAxis;
showAxis = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.showXText = function(_) {
if (!arguments.length) return showXText;
showXText = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.changeBarWidth = function(_){
if (!arguments.length) return barWidth;
barWidth = _;
if (!plotted) return chart;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.changeSeparation = function(_){
if (!arguments.length) return separation;
separation = _;
//if (!plotted) return chart;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.changeHeight = function(_){
if (!arguments.length) return height;
height = _;
chart.updatePlotValues();
chart.update();
return chart;
}
chart.updatePlotValues = function(){
if (stacked)
{
var cData = 0;
maxData = 0;
for(var i=1; i<rows; i++)
{
for(var j=1; j<cols; j++)
{
cData += Number(data[i][j]);
}
if(cData > maxData)
{
maxData = cData;
}
cData = 0;
}
}
else
{
maxData = 0;
for(var i=1; i<rows; i++)
{
for(var j=1; j<cols; j++)
{
if(Number(data[i][j]) > maxData)
{
maxData = Number(data[i][j]);
}
}
}
}
xrange = (rows - 1) * (barWidth) + (rows - 2)*separation + xpadding;;
yrange = maxData;
barHeightMultiplier = (height - ypadding) / maxData;
textYPosition = height - 1;
}
chart.update = function(_){
if (!plotted) { return chart; }
if(showAxis)
{
xAxis.ldomain(0)
.rdomain(rows)
.lrange(0)
.rrange(xrange)
.xpadding(10)
.ypadding(height)
.orientation("bottom")
.ticks(xTicks)
.update();
yAxis.ldomain(0)
.rdomain(maxData)
.lrange(0)
.rrange(height - ypadding)
.ticks(yTicks)
.ypadding(ypadding)
.xpadding(10)
.orientation("left")
.update();
}
var barNodes = document.querySelectorAll("svg");
d3.select("svg").attr("height", height).attr("width", width);
if(stacked)
{
//replot stacked bars
for(var m=0; m<barNodes.length; m++) {
var rect = d3.select(barNodes.item(m)).selectAll("rect");
var rowval = 0;
var colval = 0;
rect.transition().duration(1000)
.attr("x", function(d, i)
{
rowval = d3.select(this).attr("row");
colval = d3.select(this).attr("col");
if (rowval == 0) {return 0;}
return (xpadding + 5 + (rowval-1)*(barWidth+separation));
}).attr("y", function(d, i)
{
if (rowval == 0) { return 0; }
var ytop = 0;
for(var s = cols - 1; s >= colval; s--)
{
ytop += Number(d[s]);
}
return height - 1 - (ytop * barHeightMultiplier);
}).attr("width", function(d, i)
{
if (rowval == 0) { return 0; }
return barWidth;
}).attr("height", function(d, i)
{
if (rowval == 0) { return 0; }
return d[colval] * barHeightMultiplier;
});
}
}
else
{
// replot grouped bars
var sBarWidth = barWidth/(cols-1);
for(var m=0; m<barNodes.length; m++) {
var rect = d3.select(barNodes.item(m)).selectAll("rect");
var rowval = 0;
var colval = 0;
rect.transition()
.delay(function(d,i){return i * 20;})
.attr("y", function(d, i)
{
rowval = d3.select(this).attr("row");
colval = d3.select(this).attr("col");
if (rowval == 0) { return 0; }
return height - 1 - (d[colval] * barHeightMultiplier);
}).attr("height", function(d, i)
{
if (rowval == 0) { return 0; }
return d[colval] * barHeightMultiplier;
}).transition().duration(500)
.attr("x", function(d, i)
{
if (rowval == 0) {return 0;}
return (xpadding + 5 + ((colval - 1)*sBarWidth) + (rowval-1)*(cols-1)*(sBarWidth) + (rowval-1)*(separation));
}).transition()
.attr("width", function(d, i)
{
if (rowval == 0) { return 0; }
return sBarWidth;
});
}
}
}
return chart;
}
function draw() {
var data = generateData(60, 6);
console.log(data);
var chart = multibarChart().width(800).height(300).barWidth(10).separation(2).showAxis(false).load(data).plot();
chart.stacked(false).separation(3);
return chart;
}
function generateData(n, o) {
var data = []
for (var i=0; i<n; i++)
{
var coldata = [];
for(var j=0; j<o; j++)
{
coldata.push(Math.random());
}
data.push(coldata);
}
return data;
}
<html>
<head>
<style type="text/css">
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.xaxis path,
.xaxis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.slice text {
font-size: 16pt;
font-family: Arial;
}
</style>
<script type="text/javascript" src="http://mbostock.github.com/d3/d3.v2.js"></script>
<script type="text/javascript" src="barChart.js"></script>
</head>
<body>
<form>
<label><input type="radio" name="mode" value="grouped"> Grouped</label>
<label><input type="radio" name="mode" value="stacked" checked> Stacked</label>
</form>
<script type="text/javascript">
var data = generateData(46, 6); // for 50 rows and 5 cols of data. I'm skipping first col and first row
var chart = multibarChart().width(900).height(300).barWidth(15).separation(5).showAxis(false).load(data).plot();
d3.selectAll("input").on("change", change);
function change() {
if (this.value == "grouped")
{
chart.stacked(false);
}
else
{
chart.stacked(true);
}
}
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment