Near-Earth Comets Orbital Elements is a dataset from NASA. It contains the parameters that describe orbits for 160 near-Earth comets, i.e., comets that pass close to Earth (see also this Wikipedia entry on near-Earth objects).
The highlighted points are fragments of a disintegrating comet.
Hover over a panel to see which variables are being plotted. Hover over a data point to get the values and the name of the comet.
See here for an explanation of the orbital elements.
Note: not all the variables are being plotted. A few were omitted due to large number of missing values.
See also:
forked from mbostock's block: Scatterplot Matrix Brushing
xxxxxxxxxx
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js"></script>
<title>Near-Earth Comets Orbital Elements: Scatterplot Matrix</title>
<style>
@import url("https://fonts.googleapis.com/css?family=Roboto");
body {
font-family: Roboto, sans-serif;
margin: 0;
}
svg {
padding: 15px;
padding-top: 40px;
padding-right: 10px;
}
.frame {
shape-rendering: crispEdges;
}
.axis line {
stroke: #ddd;
}
.axis path {
display: none;
}
.cell text {
font-weight: bold;
}
.frame {
fill: #ccc;
fill-opacity: 0.25;
stroke: #aaa;
}
.frame:hover {
fill-opacity: 0.5;
}
circle {
fill-opacity: .3;
transition: r 0.1s, fill-opacity 0.1s ;
}
circle:hover {
r: 6;
fill-opacity: 0.8;
}
.fragment {
fill-opacity: 0.5;
}
.varlabel {
font-size: 10pt;
fill: #333;
}
.color-legend {
font-size: 1em;
fill: #333;
}
.color-legend circle {
fill-opacity: 1;
}
</style>
</head>
<body>
<script>
const width = 960, size = 92, padding = 15;
const colorValue = d => d.type;
const x = d3.scaleLinear()
.range([padding / 2, size - padding / 2]);
const y = d3.scaleLinear()
.range([size - padding / 2, padding / 2]);
const colorScale = d3.scaleOrdinal()
.domain(["Schwassmann-Wachmann 3 fragment", "Other"])
.range(["#ff3d74","#0080bc"]);//,"#333"]);
const colorLegend = d3.legendColor()
.scale(colorScale)
.shape("circle")
.shapeRadius(6);
const nticksX = 3;
const nticksY = 3;
const xAxis = d3.axisBottom().scale(x).ticks(nticksX);
const yAxis = d3.axisLeft().scale(y).ticks(nticksY);
const isFragment = d => d.Object.startsWith("73P/Sch");
const row = d => {
d["Epoch (TDB)"] = +d["Epoch (TDB)"];
d["TP (TDB)"] = +d["TP (TDB)"];
d["e"] = +d["e"];
d["i (deg)"] = +d["i (deg)"];
d["w (deg)"] = +d["w (deg)"];
d["Node (deg)"] = +d["Node (deg)"];
d["q (AU)"] = +d["q (AU)"];
d["Q (AU)"] = +d["Q (AU)"];
d["P (yr)"] = +d["P (yr)"];
d["MOID (AU)"] = +d["MOID (AU)"];
d.type = isFragment(d) ? "Schwassmann-Wachmann 3 fragment" : "Other";
return d;
};
const tick_format_strings = {
"Epoch (TDB)": ".1s",
"TP (TDB)": ".3s",
"e": ".1f",
"i (deg)": "0",
"w (deg)": "0",
"Node (deg)": "0",
"q (AU)": ".1f",
"Q (AU)": "0",
"P (yr)": "0",
"MOID (AU)": "0"
};
const tooltip_format_strings = {
"Epoch (TDB)": ".4s",
"TP (TDB)": ".4s",
"e": ".3f",
"i (deg)": ".1f",
"w (deg)": ".1f",
"Node (deg)": ".1f",
"q (AU)": ".3f",
"Q (AU)": ".2f",
"P (yr)": ".1f",
"MOID (AU)": ".2f"
};
const tick_format = d => d3.format(tick_format_strings[d]);
const tooltip_format = d => d3.format(tooltip_format_strings[d]);
d3.csv("comets.csv", row, data => {
const domainByTrait = {};
const traits = ["Epoch (TDB)", "TP (TDB)", "e", "i (deg)", "w (deg)", "Node (deg)", "q (AU)", "Q (AU)", "P (yr)", "MOID (AU)"];
const n = traits.length;
traits.forEach(trait => {
domainByTrait[trait] = d3.extent(data, d => d[trait]);
});
xAxis.tickSize(size * n);
yAxis.tickSize(-size * n);
const svg = d3.select("body").append("svg")
.attr("width", size * n + padding)
.attr("height", size * n + padding)
.append("g")
.attr("transform", "translate(" + padding + "," + padding / 2 + ")");
svg.selectAll(".x.axis")
.data(traits)
.enter().append("g")
.attr("class", "x axis")
.attr("transform", (d, i) => "translate(" + (n - i - 1) * size + ",0)")
.each(function(d) {
x.domain(domainByTrait[d]).nice(nticksX);
d3.select(this)
.call(xAxis.tickFormat(tick_format(d)));
});
svg.selectAll(".x.axis")
.data(traits)
.selectAll("text")
.attr("transform", (d, i) => "translate(0," + (i%2) * padding*2/3 + ")");
svg.selectAll(".y.axis")
.data(traits)
.enter().append("g")
.attr("class", "y axis")
.attr("transform", (d, i) => "translate(0," + i * size + ")")
.each(function(d) {
y.domain(domainByTrait[d]).nice(nticksY);
d3.select(this)
.call(yAxis.tickFormat(tick_format(d)));
});
const colorLegendG = svg.append("g")
.attr("transform", `translate(10, -30)`);
const cell = svg.selectAll(".cell")
.data(cross(traits, traits))
.enter().append("g")
.attr("class", "cell")
.attr("transform", d => "translate(" + (n - d.i - 1) * size + "," + d.j * size + ")")
.each(plot);
colorLegendG.call(colorLegend)
.attr("class", "color-legend");
// Titles for the diagonal.
cell.filter(d => d.i === d.j).append("text")
.attr("class", "varlabel")
.attr("x", padding)
.attr("y", padding)
.attr("dy", ".71em")
.text(d => d.x);
function plot(p) {
const cell = d3.select(this);
x.domain(domainByTrait[p.x]).nice(nticksX);
y.domain(domainByTrait[p.y]).nice(nticksY);
cell.append("rect")
.attr("class", "frame")
.attr("x", padding / 2)
.attr("y", padding / 2)
.attr("width", size - padding)
.attr("height", size - padding)
.append("title")
.text(d => p.y + " vs. " + p.x);
cell.selectAll(".notfragment")
.data(data.filter(d => !isFragment(d)))
.enter().append("circle")
.attr("class", "notfragment")
.attr("cx", d => x(d[p.x]))
.attr("cy", d => y(d[p.y]))
.attr("r", 2)
.attr("fill", d => colorScale(colorValue(d)))
.append("title")
.text(d => d.Object + "\n"
+ p.x + ": " + tooltip_format(p.x)(d[p.x]) + "\n"
+ p.y + ": " + tooltip_format(p.y)(d[p.y]));
cell.selectAll(".fragment")
.data(data.filter(d => isFragment(d)))
.enter().append("circle")
.attr("class", "fragment")
.attr("cx", d => x(d[p.x]))
.attr("cy", d => y(d[p.y]))
.attr("r", 2)
.attr("fill", d => colorScale(colorValue(d)))
.append("title")
.text(d => d.Object + "\n"
+ p.x + ": " + tooltip_format(p.x)(d[p.x]) + "\n"
+ p.y + ": " + tooltip_format(p.y)(d[p.y]));
}
});
function cross(a, b) {
const c = [], n = a.length, m = b.length;
let i, j;
for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j});
return c;
}
</script>
</body>
</html>
https://d3js.org/d3.v4.min.js
https://cdnjs.cloudflare.com/ajax/libs/d3-legend/2.24.0/d3-legend.min.js