Basic 2d histogram





This post describes how to build a very basic 2d histogram with d3.js. The 2d histogram is a representation of a 2d density. It is made thanks to the d3-rectbin plugin. Visit data-to-viz.com for more theoretical info on 2d density charts.


2d density section

Steps:

  • The Html part of the code just creates a div that will be modified by d3 later on. It also load the d3-hexbin plugin

  • The input dataset has 2 numeric variables: x and y. A 2d histogram basically represents the amount of data point on each part of the grid.

  • The d3-rectbin plugin allows to group two-dimensional points into hexagonal bins using the d3.rectbin().

  • Finally, paths can be drawn using rect
<!DOCTYPE html>
<meta charset="utf-8">

<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>

<!-- specific plugin -->
<script src="https://cdn.rawgit.com/fabid/d3-rectbin/master/rectbin.js"></script>

<!-- Create a div where the graph will take place -->
<div id="my_dataviz"></div>

<script>

// set the dimensions and margins of the graph
var margin = {top: 20, right: 30, bottom: 30, left: 30},
    width = 460 - margin.left - margin.right,
    height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3.select("#my_dataviz")
  .append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform",
          "translate(" + margin.left + "," + margin.top + ")");

// read data
d3.csv("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/data_for_density2d.csv", function(data) {

  // Get max and min of data
  var xLim = [4,18]
  var yLim = [6,20]

  // Add X axis
  var x = d3.scaleLinear()
    .nice()
    .domain(xLim)
    .range([ 0, width ]);
  svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

  // Add Y axis
  var y = d3.scaleLinear()
    .nice()
    .domain(yLim)
    .range([ height, 0 ]);
  svg.append("g")
    .call(d3.axisLeft(y));

  // Reformat the data: d3.rectbin() needs a specific format
  var inputForRectBinning = []
  data.forEach(function(d) {
    inputForRectBinning.push( [+d.x, +d.y] )  // Note that we had the transform value of X and Y !
  })

  // Compute the rectbin
  var size = 0.5
  var rectbinData = d3.rectbin()
    .dx(size)
    .dy(size)
    (inputForRectBinning)

  // Prepare a color palette
  var color = d3.scaleLinear()
      .domain([0, 350]) // Number of points in the bin?
      .range(["transparent",  "#69a3b2"])

  // What is the height of a square in px?
  heightInPx = y( yLim[1]-size )

  // What is the width of a square in px?
  var widthInPx = x(xLim[0]+size)

  // Now we can add the squares
  svg.append("clipPath")
      .attr("id", "clip")
    .append("rect")
      .attr("width", width)
      .attr("height", height)
  svg.append("g")
      .attr("clip-path", "url(#clip)")
    .selectAll("myRect")
    .data(rectbinData)
    .enter().append("rect")
      .attr("x", function(d) { return x(d.x) })
      .attr("y", function(d) { return y(d.y) - heightInPx })
      .attr("width", widthInPx )
      .attr("height", heightInPx )
      .attr("fill", function(d) { return color(d.length); })
      .attr("stroke", "black")
      .attr("stroke-width", "0.4")

})
</script>

Related blocks →