Built with blockbuilder.org
xxxxxxxxxx
<meta charset="utf-8">
<style>
.axis text {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
form {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
position: absolute;
left: 10px;
top: 10px;
}
label {
display: block;
}
</style>
<body>
<form>
<label><input type="radio" name="mode" value="grouped"> Grouped</label>
<label><input type="radio" name="mode" value="stacked" checked> Stacked</label>
</form>
<svg width="960" height="500"></svg>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>
var svg = d3.select('svg'),
margin = {top: 20, right: 30, bottom: 30, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var y = d3.scaleLinear()
.rangeRound([height, 0]);
var x0 = d3.scaleBand()
.rangeRound([0, width])
.paddingInner(0.1);
var x1 = d3.scaleBand()
var color = d3.scaleOrdinal(d3.schemeCategory10);
d3.csv("stocks.csv", function(dataset) {
data = dataset
var pricesByDate = d3.nest()
.key(function(d){ return d.date })
.entries(data)
var keys = pricesByDate[0].values.map(function(d){ return d.symbol; });
var clean_data = [];
pricesByDate.forEach(function(d){
var dict = {};
dict.key = d.key;
var sumPrice = 0;
var maxPrice = 0;
d.values.forEach(function(v){
var price = +v.price;
dict[v.symbol] = price;
sumPrice += price;
if (price > maxPrice){
maxPrice = price;
}
});
dict.maxPrice = maxPrice;
dict.sumPrice = sumPrice;
clean_data.push(dict);
});
// console.log(clean_data);
//clean_data = [{ key: "Mar 2000", MSFT: 43.22, AMZN: 67,... }, ...]
var maxSumPrice = d3.max(clean_data, function(d){ return d.sumPrice; });
var maxPrice = d3.max(clean_data, function(d){ return d.maxPrice; });
x0.domain(pricesByDate.map(function(d){ return d.key; }));
x1.domain(keys).rangeRound([0, x0.bandwidth()]);
y.domain([0, maxSumPrice]).nice();;
var stack = d3.stack().keys(keys)
var rectGroup = g.append('g')
.selectAll('g')
.data(stack(clean_data))
.enter().append('g')
.attr('fill', function(d){ return color(d.key) });
var rect = rectGroup.selectAll('rect')
.data(function(d){ return d; })
.enter().append('rect')
.attr('x', function(d){ return x0(d.data.key); })
.attr('y', function(d){ return y(d[1]); })
.attr('height', function(d){ return y(d[0]) - y(d[1]); })
.attr('width', x0.bandwidth());
d3.selectAll('input')
.on('change', changed);
function changed(){
if (this.value === 'grouped') groupedBars();
else stackedBars();
}
function groupedBars(){
y.domain([0, maxPrice]);
x0.paddingInner(0);
rect
.transition().duration(500)
.attr('x', function(d){ return x0(d.data.key) + x1(this.parentNode.__data__.key) })
.transition().duration(500)
.attr('y', function(d){ return y(d[1] - d[0]); })
.attr('height', function(d){ return y(0) - y(d[1] - d[0]) })
.attr('width', function(d){ return x1.bandwidth(); });
};
function stackedBars(){
y.domain([0, maxSumPrice]);
x0.paddingInner(0.1);
rect
.transition().duration(500)
.attr('x', function(d){ return x0(d.data.key); })
.transition().duration(500)
.attr('y', function(d){ return y(d[1]); })
.attr('height', function(d){ return y(d[0]) - y(d[1]); })
.attr('width', x0.bandwidth());
}
// Legende
var legendRectSize = 18;
var legendSpacing = 4;
var legend = svg.selectAll('.legend')
.data(keys)
.enter()
.append('g')
.attr('class', 'legend')
.attr('transform', function(d, i){
var horizontal_offset = 2 * legendRectSize ;
var vertical_offset = (i+1) * (legendRectSize + legendSpacing) - (legendRectSize + legendSpacing);
return 'translate(' + horizontal_offset + ', ' + (vertical_offset + 100) + ')';
});
legend.append('rect')
.attr('width', legendRectSize)
.attr('height', legendRectSize)
.style('fill', color)
.style('stroke', color);
legend.append('text')
.attr('x', legendRectSize + legendSpacing)
.attr('y', legendRectSize - legendSpacing)
.text(function(d) { return d; });
});
</script>
https://d3js.org/d3.v4.min.js