Skip to content

Instantly share code, notes, and snippets.

@tomshanley
Last active August 10, 2017 00:50
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tomshanley/e11e9f3e5621fc49f79b7e44fdc757ec to your computer and use it in GitHub Desktop.
Save tomshanley/e11e9f3e5621fc49f79b7e44fdc757ec to your computer and use it in GitHub Desktop.
Horizon bar chart v2 (variable bands)
license: mit
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<style>
body {
font-family: sans-serif;
margin: 0;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
rect,
line {
shape-rendering: crispEdges
}
</style>
</head>
<body>
<div>
<p>Choose number of bands:
<select>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="10">10</option>
</select>
</p>
</div>
<div id="horizon">
<h2>Horizon bar chart</h2>
</div>
<script>
const minY = 0;
const maxY = 100;
var numberOfBands = 4;
var bandWidth = (maxY - minY)/(numberOfBands);
const height = 80;
const width = 800;
const margin = { "top": 10, "bottom": 10, "left": 50, "right": 10, };
//used Draw My Data http://www.robertgrantstats.co.uk/drawmydata.html
const data = [9.5433, 4.5433, 4.5433, 6.0817, 8.7743, 10.6971, 22.2356, 34.5433, 37.2356, 37.6202, 37.2356, 35.6971, 34.5433, 38.3894, 43.3894, 47.6202, 52.2356, 55.3125, 59.1587, 59.9279, 58.3894, 56.851, 56.0817, 59.5433, 61.851, 64.9279, 67.6202, 69.9279, 69.9279, 68.004, 67.2356, 65.3125, 62.2356, 60.3125, 58.3894, 57.2356, 47.6202, 39.9279, 1.0817, 2.6202, 13.0048, 12.6202, 61.4663, 61.0817, 69.9279, 77.2356, 85.3125, 82.6202, 91.0817, 88.774, 77.6202, 66.0817, 64.5433, 54.5433, 45.3125, 46.4663, 49.9279, 40.6971, 37.6202, 36.0817, 35.3125, 39.5433, 38.774, 57.6202, 50.3125, 16.851, 17.6202, 18.774, 23.774, 58.774, 48.0048, 46.4663, 50.3125];
const barWidth = width / data.length - 1;
const xScale = d3.scaleLinear()
.domain([0, data.length])
.range([0, width]);
var colour = d3.scaleLinear()
.domain([minY,maxY])
.range(["yellow", "darkgreen"]);
var select = d3.select("select");
select.property("value", numberOfBands);
select.on("change", function(d){
var selectedBand = d3.select("select").property("value");
selectedBand = +selectedBand;
numberOfBands = selectedBand
bandWidth = (maxY - minY)/(numberOfBands);
drawHorizon(data);
drawLegend();
});
drawHorizon(data);
drawLegend();
function drawHorizon(data) {
d3.selectAll("svg").remove();
let yScale = d3.scaleLinear()
.domain([0, bandWidth])
.range([height, 0]);
let yAxis = d3.axisLeft(yScale);
let svg = d3.select("#horizon").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
let g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
let axisG = g.append("g")
.call(yAxis)
axisG.selectAll("text")
.text(function (d) { return "..." + d });
axisG.select(".domain").remove();
let bars = g.selectAll(".bars")
.data(data)
.enter()
.append("g")
.attr("transform", function (d, i) {
return "translate(" + xScale(i) + ",0)";
})
let backgroundBars = bars.append("rect")
.attr("width", barWidth)
.attr("height", height)
.style("fill", function (d) {
return d < bandWidth ? "white" : colour(band(d, bandWidth));
});
let foregroundBars = bars.append("rect")
.attr("y", function (d) {
let thisHeight = barHeight(d, bandWidth);
return yScale(thisHeight);
})
.attr("width", barWidth)
.attr("height", function (d) {
let thisHeight = barHeight(d, bandWidth);
return height - yScale(thisHeight);
})
.style("fill", function (d) {
let thisBand = band(d, bandWidth) + bandWidth;
return colour(thisBand);
});
};
function drawLegend() {
let legendWidth = 25;
let legendHeight = legendWidth * numberOfBands;
const legendMargin = {"top": 10, "bottom": 10, "left": 25, "right": 150 };
let legend = d3.select("body").append("svg")
.attr("width", legendWidth + legendMargin.left + legendMargin.right)
.attr("height", legendMargin.top + legendHeight + legendMargin.bottom)
.append("g")
.attr("transform", "translate(" + legendMargin.left + "," + legendMargin.top + ")");
let legendData = [];
let i = 0;
for (i; i < numberOfBands; i++) {
let datum = (i * bandWidth) + bandWidth;
legendData.push(datum)
};
let legendItems = legend.selectAll("g")
.data(legendData)
.enter()
.append("g")
.attr("transform", function(d, j) {
return "translate(0," + (j * legendWidth) + ")"
});
legendItems.append("rect")
.attr("width", legendWidth)
.attr("height", legendWidth)
.style("fill", function(d) { return colour(d); })
.style("stroke", "white");
legendItems.append("text")
.text(function(d){
return round(d - bandWidth) + " to " + round(d);
})
.attr("x", legendWidth + 5)
.attr("y", legendWidth/2 + 5)
};
function band(n, bandWidth) {
return Math.floor(n / bandWidth) * bandWidth;
};
function barHeight(n, bandWidth) {
return n - band(n, bandWidth);
};
function round(n){
return Math.round(n * 10)/10;
};
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment