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> |