block by nitaku 5c39929f53ab6af7b16f

Hexbin polar area chart

Full Screen

-

index.js

(function() {
  var color, height, hexbin, left, points_a, points_b, points_c, radius, randomX_a, randomX_b, randomX_c, randomY_a, randomY_b, randomY_c, right, skew, slice, svg, width;

  svg = d3.select('svg');

  width = svg[0][0].getBoundingClientRect().width / 2;

  height = svg[0][0].getBoundingClientRect().height;

  /* left and right side of the vis
  */


  left = svg.append('g').attr('clip-path', 'url(#left)');

  right = svg.append('g').attr('clip-path', 'url(#right)').append('g').attr('transform', 'translate(480,0)');

  svg.append('line').attr('class', 'separator').attr('x1', 479.5).attr('y1', 0).attr('x2', 479.5).attr('y2', 500);

  /* random data
  */


  skew = 80 * Math.random();

  randomX_a = d3.random.normal(width / 2 - skew, 80);

  randomY_a = d3.random.normal(height / 2 - skew, 80);

  points_a = d3.range(1500 + 1000 * Math.random()).map(function() {
    return [randomX_a(), randomY_a()];
  });

  randomX_b = d3.random.normal(width / 2 + skew, 80 + 80 * Math.random());

  randomY_b = d3.random.normal(height / 2 + skew, 80);

  points_b = d3.range(2000).map(function() {
    return [randomX_b(), randomY_b()];
  });

  randomX_c = d3.random.normal(width / 2 + skew, 120);

  randomY_c = d3.random.normal(height / 2 - skew, 120);

  points_c = d3.range(1500).map(function() {
    return [randomX_c(), randomY_c()];
  });

  /* dot plot
  */


  left.selectAll('.point.a').data(points_a).enter().append('circle').attr('class', 'point a').attr('cx', function(d) {
    return d[0];
  }).attr('cy', function(d) {
    return d[1];
  }).attr('r', 1);

  left.selectAll('.point.b').data(points_b).enter().append('circle').attr('class', 'point b').attr('cx', function(d) {
    return d[0];
  }).attr('cy', function(d) {
    return d[1];
  }).attr('r', 1);

  left.selectAll('.point.c').data(points_c).enter().append('circle').attr('class', 'point c').attr('cx', function(d) {
    return d[0];
  }).attr('cy', function(d) {
    return d[1];
  }).attr('r', 1);

  /* hexbin and scales
  */


  hexbin = d3.hexbin().size([width, height]).radius(20);

  radius = d3.scale.sqrt().domain([0, 70]).range([0, 20]);

  color = d3.scale.linear().domain([0, 20]).range(['white', 'steelblue']).interpolate(d3.interpolateLab);

  slice = d3.svg.arc().innerRadius(0);

  /* polar area charts - WARNING: Area encoding
  */


  right.selectAll('.pie.a').data(hexbin(points_a)).enter().append('path').attr('class', 'pie a').attr('d', function(d) {
    return slice({
      outerRadius: radius(d.length) * Math.sqrt(3) / 2,
      startAngle: 4 * Math.PI / 3,
      endAngle: 2 * Math.PI
    });
  }).attr('transform', function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });

  right.selectAll('.pie.b').data(hexbin(points_b)).enter().append('path').attr('class', 'pie b').attr('d', function(d) {
    return slice({
      outerRadius: radius(d.length) * Math.sqrt(3) / 2,
      startAngle: 0,
      endAngle: 2 * Math.PI / 3
    });
  }).attr('transform', function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });

  right.selectAll('.pie.c').data(hexbin(points_c)).enter().append('path').attr('class', 'pie c').attr('d', function(d) {
    return slice({
      outerRadius: radius(d.length) * Math.sqrt(3) / 2,
      startAngle: 2 * Math.PI / 3,
      endAngle: 4 * Math.PI / 3
    });
  }).attr('transform', function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });

}).call(this);

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="description" content="Hexbin polar area chart" />
    <title>Hexbin polar area chart</title>
    <link rel="stylesheet" href="index.css">
    <script src="//d3js.org/d3.v3.min.js"></script>
    <script src="//d3js.org/d3.hexbin.v0.min.js?5c6e4f0"></script>
</head>
<body>
  <svg height="500" width="960">
    <defs>
      <clipPath id="left">
        <rect x="0" y="0" width="480" height="500" />
      </clipPath>
      <clipPath id="right">
        <rect x="480" y="0" width="480" height="500" />
      </clipPath>
    </defs>
  </svg>
  
  <script src="index.js"></script>
</body>
</html>

index.coffee

svg = d3.select('svg')
width = svg[0][0].getBoundingClientRect().width / 2
height = svg[0][0].getBoundingClientRect().height

### left and right side of the vis ###
left = svg.append('g')
    .attr('clip-path', 'url(#left)')
right = svg.append('g')
    .attr('clip-path', 'url(#right)')
  .append('g')
    .attr('transform', 'translate(480,0)')

svg.append('line')
    .attr('class', 'separator')
    .attr('x1', 479.5)
    .attr('y1', 0)
    .attr('x2', 479.5)
    .attr('y2', 500)

### random data ###
skew = 80 * Math.random()

randomX_a = d3.random.normal(width / 2 - skew, 80)
randomY_a = d3.random.normal(height / 2 - skew, 80)
points_a = d3.range(1500+1000*Math.random()).map(() -> [randomX_a(), randomY_a()])

randomX_b = d3.random.normal(width / 2 + skew, 80+80*Math.random())
randomY_b = d3.random.normal(height / 2 + skew, 80)
points_b = d3.range(2000).map(() -> [randomX_b(), randomY_b()])

randomX_c = d3.random.normal(width / 2 + skew, 120)
randomY_c = d3.random.normal(height / 2 - skew, 120)
points_c = d3.range(1500).map(() -> [randomX_c(), randomY_c()])

### dot plot ###
left.selectAll('.point.a')
    .data(points_a)
  .enter().append('circle')
    .attr('class', 'point a')
    .attr('cx', (d) -> d[0])
    .attr('cy', (d) -> d[1])
    .attr('r', 1)
    
left.selectAll('.point.b')
    .data(points_b)
  .enter().append('circle')
    .attr('class', 'point b')
    .attr('cx', (d) -> d[0])
    .attr('cy', (d) -> d[1])
    .attr('r', 1)
    
left.selectAll('.point.c')
    .data(points_c)
  .enter().append('circle')
    .attr('class', 'point c')
    .attr('cx', (d) -> d[0])
    .attr('cy', (d) -> d[1])
    .attr('r', 1)

### hexbin and scales ###
hexbin = d3.hexbin()
    .size([width, height])
    .radius(20)
    
radius = d3.scale.sqrt() # WARNING: Area encoding
    .domain([0, 70])
    .range([0, 20])
    
color = d3.scale.linear()
    .domain([0, 20])
    .range(['white', 'steelblue'])
    .interpolate(d3.interpolateLab)

slice = d3.svg.arc()
  .innerRadius(0)
  
### polar area charts - WARNING: Area encoding ###
right.selectAll('.pie.a')
    .data(hexbin(points_a))
  .enter().append('path')
    .attr('class', 'pie a')
    .attr('d', (d) ->
        slice( {
          outerRadius: radius(d.length)*Math.sqrt(3)/2,
          startAngle: 4*Math.PI/3,
          endAngle: 2*Math.PI
        })
    )
    .attr('transform', (d) -> "translate(#{d.x},#{d.y})")

right.selectAll('.pie.b')
    .data(hexbin(points_b))
  .enter().append('path')
    .attr('class', 'pie b')
    .attr('d', (d) ->
        slice( {
          outerRadius: radius(d.length)*Math.sqrt(3)/2,
          startAngle: 0,
          endAngle: 2*Math.PI/3
        })
    )
    .attr('transform', (d) -> "translate(#{d.x},#{d.y})")

right.selectAll('.pie.c')
    .data(hexbin(points_c))
  .enter().append('path')
    .attr('class', 'pie c')
    .attr('d', (d) ->
        slice( {
          outerRadius: radius(d.length)*Math.sqrt(3)/2,
          startAngle: 2*Math.PI/3,
          endAngle: 4*Math.PI/3
        })
    )
    .attr('transform', (d) -> "translate(#{d.x},#{d.y})")

index.css

body {
    margin: 0;
    padding: 0;
}
svg {
    background: white;
    display: inline-block;
    margin: 0;
    padding: 0;
}
.separator {
  stroke: #DEDEDE;
}
.a {
  fill: teal;
}
.b {
  fill: orange;
}
.c {
  fill: purple;
}

.pie {
  fill-opacity: 0.7;
}