block by mbostock 3007180

Exoplanets

Full Screen

This is a recreation (for the purpose of tinkering with a simplified version) of Lane Harrison’s Exoplanets interactive, which was inspired by Randall Munroe’s XKCD comic. The data is from the Planetary Habitability Laboratory.

D3’s pack layout places circles so that they touch by default. The XKCD version however uses padding, which is more aesthetically pleasing. Fortunately, D3 2.10’s pack layout now supports padding. You could achieve a similar result through collision detection, but the pack layout is faster to compute. My implementation uses a quantize scale for color, which is my best guess to what’s used in the original, but I can’t know for sure. I make no guarantees to the accuracy of this chart. I also removed extra dimensions to reduce the size of the data file, but as a consequence I can’t show additional details on mouseover.

Updated Example →

index.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>Exoplanets</title>
<style>

.group {
  fill: none;
  stroke: #000;
  stroke-width: 1.5px;
}

</style>
<body>
<script src="//d3js.org/d3.v4.min.js"></script>
<script>

var color = d3.scaleQuantize()
    .range(["#156b87", "#876315", "#543510", "#872815"]);

var size = 960;

var pack = d3.pack()
    .size([size, size])
    .padding(5);

var svg = d3.select("body").append("svg")
    .attr("width", size)
    .attr("height", size);

d3.csv("exoplanets.csv", type, function(error, data) {
  var planets = data.filter(function(d) { return d.distance === 0; }),
      exoplanets = data.filter(function(d) { return d.distance !== 0; });

  color.domain(d3.extent(data, function(d) { return d.radius; }));

  var root = d3.hierarchy({children: [{children: planets}].concat(exoplanets)})
      .sum(function(d) { return d.radius * d.radius; })
      .sort(function(a, b) {
        return !a.children - !b.children
            || isNaN(a.data.distance) - isNaN(b.data.distance)
            || a.data.distance - b.data.distance;
      });

  pack(root);

  svg.selectAll("circle")
    .data(root.descendants().slice(1))
    .enter().append("circle")
      .attr("r", function(d) { return d.r; })
      .attr("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; })
      .classed("group", function(d) { return d.children; })
    .filter(function(d) { return d.data; })
      .style("fill", function(d) { return color(d.data.radius); })
    .append("title")
      .text(function(d) {
        return d.data.name
            + "\nplanet radius: " + d.data.radius + " EU"
            + "\nstar distance: " + (isNaN(d.data.distance) ? "N/A" : d.data.distance + " pc");
      });
});

function type(d) {
  d.radius = +d.radius;
  d.distance = d.distance ? +d.distance : NaN;
  return d;
}

</script>

Makefile

GENERATED_FILES = \
	exoplanets.csv

all: $(GENERATED_FILES)

clean:
	rm -rf -- $(GENERATED_FILES)

build/exoplanets.zip:
	mkdir -p build
	curl -o $@ 'http://www.hpcf.upr.edu/~abel/phl/phl_hec_all_confirmed.csv.zip'

exoplanets.csv: build/exoplanets.zip planets.csv
	unzip -u -d build $<
	cp -f planets.csv $@
	cut -d, -f1,12,46 build/phl_hec_all_confirmed.csv | tail -n+2 >> $@

planets.csv

name,radius,distance
Jupiter,10.97,0
Saturn,9.14,0
Uranus,3.98,0
Neptune,3.86,0
Earth,1,0
Venus,0.950,0
Mars,0.532,0
Mercury,0.383,0
Pluto,0.181,0