【JavaScript】D3.js ~ 積み上げ縦棒グラフを作成する ~

サンプル

例1

* ただし、負の値は未対応
<!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;
}

</style>
<body>
<script src="">https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js">
<script>
var dataset = [
  {graphId: "001", y1Val: 2, y2Val: 15, y3Val: 9, y4Val: 15},
  {graphId: "002", y1Val: 3, y2Val: 17, y3Val: 4, y4Val: 12},
  {graphId: "003", y1Val: 7, y2Val: 4, y3Val: 9, y4Val: 14},
];

var isSorted = true;

var margin = {top: 20, right: 20, bottom: 30, left: 40},
    width = 960 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var xScale = d3.scale.ordinal()
    .rangeRoundBands([0, width], .1);

var yScale = d3.scale.linear()
    .rangeRound([height, 0]);

var colors = d3.scale.ordinal()
    .range(["#98abc5", "#8a89a6", "#7b6888", "#6b486b"]);

var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(yScale)
    .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 + ")");


colors.domain(d3.keys(dataset[0]).filter(function(key) { return key !== "graphId"; }));

dataset.forEach(function(d) {
  var y0 = 0;
  d.xValues = colors.domain().map(function(name) { return {name: name, y0: y0, y1: y0 += +d[name]}; });
  d.total = d.xValues[d.xValues.length - 1].y1;
});

if (isSorted) {
  dataset.sort(function(a, b) { return b.total - a.total; });
}

xScale.domain(dataset.map(function(d) { return d.graphId; }));
yScale.domain([0, d3.max(dataset, 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", ".71em")
    .style("text-anchor", "end")
    .text("Population");

var state = svg.selectAll(".state")
    .data(dataset)
    .enter()
    .append("g")
    .attr("class", "g")
    .attr("transform", function(d) { return "translate(" + xScale(d.graphId) + ",0)"; });

state.selectAll("rect")
    .data(function(d) { return d.xValues; })
    .enter()
    .append("rect")
    .attr("width", xScale.rangeBand())
    .attr("y", function(d) { return yScale(d.y1); })
    .attr("height", function(d) { return yScale(d.y0) - yScale(d.y1); })
    .style("fill", function(d) { return colors(d.name); });

var legend = svg.selectAll(".legend")
    .data(colors.domain().slice().reverse())
    .enter().append("g")
    .attr("class", "legend")
    .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

legend.append("rect")
      .attr("x", width - 18)
      .attr("width", 18)
      .attr("height", 18)
      .style("fill", colors);

legend.append("text")
    .attr("x", width - 24)
    .attr("y", 9)
    .attr("dy", ".35em")
    .style("text-anchor", "end")
    .text(function(d) { return d; });

</script>

例2 : 負の値を対応版

<!DOCTYPE html>
<html>
<head>
<script src="">http://mbostock.github.com/d3/d3.v2.js">
<title>Sample Stacked Bar Chart</title>  
<style>
.axis text {
font: 10px sans-serif;
}
.axis path, .axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
</style>
</head>
<body>
<script type="text/javascript" >
function buildStackedBarChart(chartDataset) {
  var index = chartDataset[0].length;
  while (index--) {
    var positive = 0;
    var negative = 0;
    chartDataset.forEach(function(datum) {
      datum = datum[index];
      datum.size = Math.abs(datum.y);
      if (datum.y  <0)  {
        datum.y0 = negative;
        negative -= datum.size;
      } else {
        datum.y0 = positive = positive + datum.size;
      }
    })
  }
  chartDataset.extent= d3.extent(d3.merge(d3.merge(chartDataset.map(function(datum) {
    return datum.map(function(d) { return [d.y0, d.y0 - d.size]})}))));
  
  return chartDataset;
}

var dataset = [
  [{y:3},{y:6},{y:-3}],
  [{y:4},{y:-2},{y:-9}],
  [{y:10},{y:-3},{y:4}]
];

var height = 500;
var width = 500;
var margin = 10;
var colors = d3.scale.category10();
var xScale = d3.scale.ordinal()
  .domain(['abc','abc2','abc3'])
  .rangeRoundBands([margin, width - margin], .1)
var yScale = d3.scale.linear()
  .range([height - margin, 0 + margin]);
var xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickSize(6, 0);
var yAxis = d3.svg.axis().scale(yScale).orient("left");

buildStackedBarChart(dataset);
yScale.domain(dataset.extent);

svg = d3.select("body")
  .append("svg")
  .attr("height", height)
  .attr("width", width)

svg.selectAll(".series")
  .data(dataset)
  .enter()
  .append("g")
  .classed("series", true)
  .style("fill", function(d, i) { return colors(i); })
  .selectAll("rect")
  .data(Object)
  .enter()
  .append("rect")
  .attr("x", function(d, i) { return xScale(xScale.domain()[i]); })
  .attr("y", function(d) { return yScale(d.y0)})
  .attr("height", function(d) { return yScale(0) - yScale(d.size)})
  .attr("width", xScale.rangeBand())

svg.append("g")
  .attr("class", "axis x")
  .attr("transform", "translate (0, " + yScale(0) + ")")
  .call(xAxis)

svg.append("g")
  .attr("class", "axis y")
  .attr("transform", "translate (" + (xScale(margin) - 10) + ", 0)")
  .call(yAxis)

</script>
</body>
</html>

補足

 * 上記の例2にツールチップをつけたサンプルは、以下の関連記事を参照のこと。
http://blogs.yahoo.co.jp/dk521123/35480801.html


関連記事

D3.js ~ 入門編 ~

http://blogs.yahoo.co.jp/dk521123/35423681.html

D3.js ~ 円グラフを作成する ~

http://blogs.yahoo.co.jp/dk521123/35435961.html

D3.js ~ 折れ線グラフを作成する ~

http://blogs.yahoo.co.jp/dk521123/35430148.html

D3.js ~ 縦棒グラフを作成する ~

http://blogs.yahoo.co.jp/dk521123/35435053.html

D3.js ~ 積み上げ縦棒グラフを作成する ~

http://blogs.yahoo.co.jp/dk521123/35450750.html

D3.js / TopoJSON / DataMaps [1] ~ 世界地図を作成する ~

http://blogs.yahoo.co.jp/dk521123/35443473.html

D3.js / TopoJSON / DataMaps [2] ~ DataMaps Plugin編 ~

http://blogs.yahoo.co.jp/dk521123/35446731.html

D3.js / TopoJSON / DataMaps [3] ~ DataMaps Custom Plugin編 ~

http://blogs.yahoo.co.jp/dk521123/35450674.html

D3.js ~ ツールチップを表示する ~

http://blogs.yahoo.co.jp/dk521123/35480801.html