block by mgold 726a7dff35fa117b78a03f99edabe309

Wheat Plot

Full Screen

This is a simple wheat plot implementation, taken from a recent document from Stephen Few. It is designed so that one can see a histogram-like distribution of values, but also each value individually.

The data are randomly generated. Mouse over any one of them to see its value, an advantage of wheat plots on computer screens.

Built with blockbuilder.org

index.html

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script src="https://d3js.org/d3-random.v1.min.js"></script>
  <script src="https://d3js.org/d3-axis.v1.min.js"></script>
  <style>
    body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
    circle { fill: #777; }
    .axis line{stroke: #ccc; stroke-width: 2px }
	  .axis path{ stroke: #ccc; stroke-width: 2px }
    .axis text{ fill: #ccc; }
  </style>
</head>

<body>
  <script>
    // Feel free to change or delete any of the code you see in this editor!
    const svg = d3.select("body").append("svg")
      .attr("width", 960)
      .attr("height", 500)
    
    const overlay = svg.append("text")
      .attr("fill", "red")
      .attr("font-size", "48px")
      .attr("font-family", "avenir, sans-serif")
      .attr("transform", "translate(30, 70)")
    
    const horizontalBaseline = 450
    const r = 3.76
    
    const generator = d3.randomBates(20)
    const data = d3.range(200).map(() => generator()*280).sort()
    const x = d3.scaleLinear()
    	.domain([90, 190])
      .range([50, 910])
    
    const axis = svg.append("g")
    .attr("class", "axis")
    .attr("transform", `translate(0,${horizontalBaseline + r})`)
    .call(d3.axisBottom(x));
    
    const transitionDelay = 2000
    const transitionDuration = 3000
    
    const precision = d3.precisionRound(0.01, 200)
    const numFormat = d3.format("." + precision + "r");
    
    var lastBand = 0
    var indexInBand = 0
    const wheatVerticalOffset = r*2.3
    const bandWidth = 10
    
    svg.append("g")
      .attr("class", "data")
      .selectAll("circle")
      .data(data)
      .enter()
      .append("circle")
      .attr("r", r)
      .attr("cx", d => x(d))
      .attr("cy", horizontalBaseline)
      .on("mouseenter", function(d){
      	overlay.text(numFormat(d))
        d3.select(this).style('fill', 'red')
    	})
    	.on("mouseleave", function(d){
      	overlay.text(undefined)
        d3.select(this).style('fill', undefined)
    	})
      .transition()
      .delay(transitionDelay)
      .duration(transitionDuration)
      .attr("cy", function(d){
         const band = Math.floor(d/bandWidth)*bandWidth
         if (band !== lastBand){
           lastBand = band
           indexInBand = 0
         }else{
           indexInBand++
         }
         return horizontalBaseline - indexInBand * wheatVerticalOffset
    	})
    
    axis.selectAll(".tick")
      .select("line")
      .attr("y1", "0")
      .transition()
      .delay(transitionDelay)
      .duration(transitionDuration)
      .attr("y1", -1*horizontalBaseline+40)
    



  </script>
</body>