Built with blockbuilder.org
forked from tomshanley's block: Wheat plot
license: mit |
Built with blockbuilder.org
forked from tomshanley's block: Wheat plot
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<style> | |
</style> | |
<svg width="800" height="400"></svg> | |
<script src="https://d3js.org/d3.v4.min.js"></script> | |
<script> | |
const data = d3.range(500).map(d3.randomNormal(50,10)); | |
var svg = d3.select("svg"), | |
margin = {top: 10, right: 30, bottom: 30, left: 30}, | |
width = +svg.attr("width") - margin.left - margin.right, | |
height = +svg.attr("height") - margin.top - margin.bottom, | |
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
const bandWidth = 5; | |
const domainMin = thisBand(d3.min(data, function(d) { return d; }), bandWidth); | |
const domainMax = thisBand(d3.max(data, function(d) { return d; }), bandWidth) + bandWidth; | |
const domainRange = domainMax - domainMin; | |
const noOfBands = domainRange/bandWidth; | |
var xAxisValues = []; | |
let i = 0; | |
for (i; i < (noOfBands + 1); i++) { | |
let axisValue = domainMin + (i * bandWidth); | |
xAxisValues.push(axisValue); | |
}; | |
const x = d3.scaleLinear() | |
.rangeRound([0, width]) | |
.domain([domainMin,domainMax]); | |
var f = d3.format(".1f"); | |
var xAxis = d3.axisBottom(x) | |
.tickFormat(f) | |
.tickValues(xAxisValues); | |
var xAxisG = g.append("g") | |
.attr("class", "x-axis") | |
.attr("transform", "translate(0," + height + ")") | |
.call(xAxis); | |
xAxisG.selectAll("line") | |
.attr("y1", -height) | |
.style("stroke", "lightgrey"); | |
xAxisG.select(".domain") | |
.remove(); | |
const jitter = d3.scaleLinear() | |
.range([0,(width/noOfBands)]) | |
.domain([0,bandWidth]); | |
const nestedData = d3.nest() | |
.key(function(d){ return thisBand(d, bandWidth); }) | |
.sortKeys(d3.ascending) | |
.sortValues(d3.ascending) | |
.entries(data); | |
const maxI = d3.max(nestedData, function(d){ return d.values.length }); | |
const y = d3.scaleLinear() | |
.domain([0, maxI]) | |
.range([height, 0]); | |
var band = g.selectAll(".band") | |
.data(nestedData) | |
.enter().append("g") | |
.attr("class", "band") | |
.attr("transform", function(d) { return "translate(" + x(+d.key) + "," + 0 + ")"; }); | |
var circle = band.selectAll(".circle") | |
.data(function(d){ return d.values }) | |
.enter() | |
.append("g") | |
.attr("transform", function(d, i) { | |
let offset = d - thisBand(d, bandWidth); | |
return "translate(" + jitter(offset) + "," + y(i) + ")"; | |
//return "translate(" + jitter(offset) + "," + 15 + ")"; | |
}); | |
circle.append("circle") | |
.attr("r", 2) | |
.style("fill", "none") | |
.style("stroke", "MediumVioletRed") | |
.style("opacity", 0.5); | |
function thisBand(n, bandwidth) { | |
return Math.floor(n / bandwidth) * bandwidth; | |
}; | |
</script> |