Skip to content

Instantly share code, notes, and snippets.

@1wheel
Last active September 13, 2019 12:43
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save 1wheel/68073eeba4d19c454a8c25fcd6e9e68a to your computer and use it in GitHub Desktop.
Save 1wheel/68073eeba4d19c454a8c25fcd6e9e68a to your computer and use it in GitHub Desktop.
d3-module-faces
node_modules

To visualize the d3 modules being used, I made a log scaled scatter plot of forced directed Chernoff faces. By transforming many different attributes of our dataset into friendly glyphs, Chernoff faces allow us to understand multidimensional datasets. The encoding scheme is probably self explanatory, but I've included it below just in case:

'face':  ƒ('dependentsCount')
'hair':  ƒ('description', 'length')
'mouth': ƒ('downloads')
'nosew': ƒ('githubContributers')
'noseh': ƒ('githubIssues')
'eyew':  ƒ('githubStars')
'eyeh':  d => Math.random()
'brow':  ƒ('repoSize')

I used the following modules:

Data is from nprms.io - see download-data.js to your generate your own listing of modules with different data points.

var ƒ = d3.f
var width = 960
var height = 500
var faceRadius = 20
d3.loadData(['dense-modules.json', 'annotations.json'], function(err, res){
d3.select('body').html('').selectAppend('div.tooltip')
modules = res[0]
annotations = res[1]
c = d3.conventions({
totalWidth: width,
totalHeight: height,
margin: {left: 40, top: 5, bottom: 20, right: 11}
})
c.svg.append('text')
.text('NPM downloads v. Github stars')
.translate([10, 10])
.st({fontWeight: 600, fontFamily: 'monospace'})
chernoff = d3.chernoff()
d3.entries({
'face': ƒ('dependentsCount'),
'hair': ƒ('description', 'length'),
'mouth': ƒ('downloads'),
'nosew': ƒ('githubContributers'),
'noseh': ƒ('githubIssues'),
'eyew': ƒ('githubStars'),
'eyeh': d => Math.random(),
'brow': ƒ('repoSize'),
}).forEach(function(d){
var scale = d3.scaleLog().domain(d3.extent(modules, ƒ(d.value, addOne)))
chernoff[d.key](ƒ(d.value, addOne, scale))
})
c.x = d3.scaleLog()
.domain(d3.extent(modules, ƒ('downloads', addOne)))
.range(c.x.range())
c.y = d3.scaleLog()
.domain(d3.extent(modules, ƒ('githubStars', addOne)))
.range(c.y.range())
c.xAxis.scale(c.x)
c.yAxis.scale(c.y)
c.drawAxis()
var simulation = d3.forceSimulation(modules)
.force('x', d3.forceX(ƒ('downloads', addOne, c.x)).strength(.1))
.force('y', d3.forceY(ƒ('githubStars', addOne, c.y)).strength(.1))
.force('collide', d3.forceCollide(faceRadius))
.force('container', d3.forceContainer([
[faceRadius, faceRadius],
[width - faceRadius*3, height - faceRadius*2.6] ]))
for (var i = 0; i < 400; ++i) simulation.tick()
var color = d3.scaleOrdinal(d3.schemeCategory10)
var moduleSel = c.svg.appendMany(modules, 'g')
.at({
fill: ƒ('author', color),
stroke: ƒ('author', color)
})
.translate(d => [d.x, d.y])
.on('click', d => window.open(d.link, '_blank'))
.st({cursor: 'pointer'})
modules.forEach(function(d){
delete d.x
delete d.y
delete d.vx
delete d.vy
delete d.index
})
moduleSel.call(d3.attachTooltip)
moduleSel.append('circle').at({r: faceRadius})
moduleSel.append('g.face')
.call(chernoff)
.at({transform: function(d){
var s = 80/faceRadius
return ['scale(', 1/s , ') ', 'translate(', -faceRadius*3.5, -faceRadius*4, ')'].join(' ')
} })
var swoopy = d3.swoopyDrag()
.x(d => 0)
.y(d => 0)
.draggable(0)
.annotations(annotations)
var swoopySel = c.svg.append('g.swoopy').call(swoopy)
swoopySel.selectAll('path').attr('marker-end', 'url(#arrow)')
c.svg.append('marker')
.attr('id', 'arrow')
.attr('viewBox', '-10 -10 20 20')
.attr('markerWidth', 20)
.attr('markerHeight', 20)
.attr('orient', 'auto')
.append('path')
.attr('d', 'M-6.75,-6.75 L 0,0 L -6.75,6.75')
swoopySel.selectAll('text')
.each(function(d){
d3.select(this)
.text('')
.tspans(d3.wordwrap(d.text, 22))
})
})
function addOne(d){ return d + 1 }
[
{
"path": "M 764,400 A 37.76 37.76 0 0 1 759,330",
"text": "Modules Mike included in the default d3 build have the most stars and downloads",
"textOffset": [
773,
414
]
},
{
"path": "M 811,39 A 48.376 48.376 0 0 0 907,50",
"text": "The most downloaded, d3-queue, predates d3v4",
"textOffset": [
696,
10
]
},
{
"path": "M 455,75 A 60.466 60.466 0 0 0 547,87",
"text": "Susie's legend generator is the most popular module not in the default build",
"textOffset": [
369,
35
]
},
{
"path": "M 432,358 A 35.487 35.487 0 0 1 394,314",
"text": "All three of Peter's modules have about the same number of downloads",
"textOffset": [
445,
359
]
},
{
"path": "M 133,277 A 99.156 99.156 0 0 0 56,194",
"text": "I just put swoopy-drag and force-container on npm",
"textOffset": [
38,
310
]
},
{
"path": "M 134,339 A 82.601 82.601 0 0 1 49,432",
"text": "",
"textOffset": [
38,
310
]
}
]
function sign(num) {
if(num > 0) {
return 1;
} else if(num < 0) {
return -1;
} else {
return 0;
}
}
function d3_chernoff() {
var facef = 0.5, // 0 - 1
hairf = 0, // -1 - 1
mouthf = 0, // -1 - 1
nosehf = 0.5, // 0 - 1
nosewf = 0.5, // 0 - 1
eyehf = 0.5, // 0 - 1
eyewf = 0.5, // 0 - 1
browf = 0, // -1 - 1
line = d3.line()
.curve(d3.curveCardinalClosed)
.x(function(d) { return d.x; })
.y(function(d) { return d.y; }),
bline = d3.line()
.curve(d3.curveBasisClosed)
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
function chernoff(a) {
if(true || a instanceof Array) {
a.each(__chernoff);
} else {
d3.select(this).each(__chernoff);
}
}
function __chernoff(d) {
var ele = d3.select(this),
facevar = (typeof(facef) === "function" ? facef(d) : facef) * 30,
hairvar = (typeof(hairf) === "function" ? hairf(d) : hairf) * 80,
mouthvar = (typeof(mouthf) === "function" ? mouthf(d) : mouthf) * 7,
nosehvar = (typeof(nosehf) === "function" ? nosehf(d) : nosehf) * 10,
nosewvar = (typeof(nosewf) === "function" ? nosewf(d) : nosewf) * 10,
eyehvar = (typeof(eyehf) === "function" ? eyehf(d) : eyehf) * 10,
eyewvar = (typeof(eyewf) === "function" ? eyewf(d) : eyewf) * 10,
browvar = (typeof(browf) === "function" ? browf(d) : browf) * 3;
var face = [{x: 70, y: 60}, {x: 120, y: 80},
{x: 120-facevar, y: 110}, {x: 120-facevar, y: 160},
{x: 20+facevar, y: 160}, {x: 20+facevar, y: 110},
{x: 20, y: 80}];
ele.selectAll("path.face").data([face]).enter()
.append("svg:path")
.attr("class", "face")
.attr("d", bline);
var hair = [{x: 70, y: 60}, {x: 120, y: 80},
{x: 140, y: 45-hairvar}, {x: 120, y: 45},
{x: 70, y: 30}, {x: 20, y: 45},
{x: 0, y: 45-hairvar}, {x: 20, y: 80}];
ele.selectAll("path.hair").data([hair]).enter()
.append("svg:path")
.attr("class", "hair")
.attr("d", bline);
var mouth = [{x: 70, y: 130+mouthvar},
{x: 110-facevar, y: 135-mouthvar},
{x: 70, y: 140+mouthvar},
{x: 30+facevar, y: 135-mouthvar}];
ele.selectAll("path.mouth").data([mouth]).enter()
.append("svg:path")
.attr("class", "mouth")
.attr("d", line);
var nose = [{x: 70, y: 110-nosehvar},
{x: 70+nosewvar, y: 110+nosehvar},
{x: 70-nosewvar, y: 110+nosehvar}];
ele.selectAll("path.nose").data([nose]).enter()
.append("svg:path")
.attr("class", "nose")
.attr("d", line);
var leye = [{x: 55, y: 90-eyehvar}, {x: 55+eyewvar, y: 90},
{x: 55, y: 90+eyehvar}, {x: 55-eyewvar, y: 90}];
var reye = [{x: 85, y: 90-eyehvar}, {x: 85+eyewvar, y: 90},
{x: 85, y: 90+eyehvar}, {x: 85-eyewvar, y: 90}];
ele.selectAll("path.leye").data([leye]).enter()
.append("svg:path")
.attr("class", "leye")
.attr("d", bline);
ele.selectAll("path.reye").data([reye]).enter()
.append("svg:path")
.attr("class", "reye")
.attr("d", bline);
ele.append("svg:path")
.attr("class", "lbrow")
.attr("d", "M" + (55-eyewvar/1.7-sign(browvar)) + "," +
(87-eyehvar+browvar) + " " +
(55+eyewvar/1.7-sign(browvar)) + "," +
(87-eyehvar-browvar));
ele.append("svg:path")
.attr("class", "rbrow")
.attr("d", "M" + (85-eyewvar/1.7+sign(browvar)) + "," +
(87-eyehvar-browvar) + " " +
(85+eyewvar/1.7+sign(browvar)) + "," +
(87-eyehvar+browvar));
}
chernoff.face = function(x) {
if(!arguments.length) return facef;
facef = x;
return chernoff;
};
chernoff.hair = function(x) {
if(!arguments.length) return hairf;
hairf = x;
return chernoff;
};
chernoff.mouth = function(x) {
if(!arguments.length) return mouthf;
mouthf = x;
return chernoff;
};
chernoff.noseh = function(x) {
if(!arguments.length) return nosehf;
nosehf = x;
return chernoff;
};
chernoff.nosew = function(x) {
if(!arguments.length) return nosewf;
nosewf = x;
return chernoff;
};
chernoff.eyeh = function(x) {
if(!arguments.length) return eyehf;
eyehf = x;
return chernoff;
};
chernoff.eyew = function(x) {
if(!arguments.length) return eyewf;
eyewf = x;
return chernoff;
};
chernoff.brow = function(x) {
if(!arguments.length) return browf;
browf = x;
return chernoff;
};
return chernoff;
}
d3.chernoff = function() {
return d3_chernoff(Object);
};
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, function (exports) { 'use strict';
function forceContainer (bbox){
var nodes, strength = 1;;
if (!bbox || bbox.length < 2) bbox = [[0, 0], [100, 100]]
function force(alpha) {
var i,
n = nodes.length,
node,
x = 0,
y = 0;
for (i = 0; i < n; ++i) {
node = nodes[i], x = node.x, y = node.y;
if (x < bbox[0][0]) node.vx += (bbox[0][0] - x)*alpha
if (y < bbox[0][1]) node.vy += (bbox[0][1] - y)*alpha
if (x > bbox[1][0]) node.vx += (bbox[1][0] - x)*alpha
if (y > bbox[1][1]) node.vy += (bbox[1][1] - y)*alpha
}
}
force.initialize = function(_){
nodes = _;
};
force.bbox = function(_){
return arguments.length ? (bbox = +_, force) : bbox;
};
force.strength = function(_){
return arguments.length ? (strength = +_, force) : strength;
}
return force;
}
exports.forceContainer = forceContainer;
Object.defineProperty(exports, '__esModule', { value: true });
}));
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.d3 = global.d3 || {})));
}(this, function (exports) { 'use strict';
function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function bisector(compare) {
if (compare.length === 1) compare = ascendingComparator(compare);
return {
left: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) < 0) lo = mid + 1;
else hi = mid;
}
return lo;
},
right: function(a, x, lo, hi) {
if (lo == null) lo = 0;
if (hi == null) hi = a.length;
while (lo < hi) {
var mid = lo + hi >>> 1;
if (compare(a[mid], x) > 0) hi = mid;
else lo = mid + 1;
}
return lo;
}
};
}
function ascendingComparator(f) {
return function(d, x) {
return ascending(f(d), x);
};
}
var ascendingBisect = bisector(ascending);
var bisectRight = ascendingBisect.right;
var bisectLeft = ascendingBisect.left;
function descending(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function number(x) {
return x === null ? NaN : +x;
}
function variance(array, f) {
var n = array.length,
m = 0,
a,
d,
s = 0,
i = -1,
j = 0;
if (f == null) {
while (++i < n) {
if (!isNaN(a = number(array[i]))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
else {
while (++i < n) {
if (!isNaN(a = number(f(array[i], i, array)))) {
d = a - m;
m += d / ++j;
s += d * (a - m);
}
}
}
if (j > 1) return s / (j - 1);
}
function deviation(array, f) {
var v = variance(array, f);
return v ? Math.sqrt(v) : v;
}
function extent(array, f) {
var i = -1,
n = array.length,
a,
b,
c;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = c = b; break; }
while (++i < n) if ((b = array[i]) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = c = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null) {
if (a > b) a = b;
if (c < b) c = b;
}
}
return [a, c];
}
var array = Array.prototype;
var slice = array.slice;
var map = array.map;
function constant(x) {
return function() {
return x;
};
}
function identity(x) {
return x;
}
function range(start, stop, step) {
start = +start, stop = +stop, step = (n = arguments.length) < 2 ? (stop = start, start = 0, 1) : n < 3 ? 1 : +step;
var i = -1,
n = Math.max(0, Math.ceil((stop - start) / step)) | 0,
range = new Array(n);
while (++i < n) {
range[i] = start + i * step;
}
return range;
}
var e10 = Math.sqrt(50);
var e5 = Math.sqrt(10);
var e2 = Math.sqrt(2);
function ticks(start, stop, count) {
var step = tickStep(start, stop, count);
return range(
Math.ceil(start / step) * step,
Math.floor(stop / step) * step + step / 2, // inclusive
step
);
}
function tickStep(start, stop, count) {
var step0 = Math.abs(stop - start) / Math.max(0, count),
step1 = Math.pow(10, Math.floor(Math.log(step0) / Math.LN10)),
error = step0 / step1;
if (error >= e10) step1 *= 10;
else if (error >= e5) step1 *= 5;
else if (error >= e2) step1 *= 2;
return stop < start ? -step1 : step1;
}
function sturges(values) {
return Math.ceil(Math.log(values.length) / Math.LN2) + 1;
}
function histogram() {
var value = identity,
domain = extent,
threshold = sturges;
function histogram(data) {
var i,
n = data.length,
x,
values = new Array(n);
for (i = 0; i < n; ++i) {
values[i] = value(data[i], i, data);
}
var xz = domain(values),
x0 = xz[0],
x1 = xz[1],
tz = threshold(values, x0, x1);
// Convert number of thresholds into uniform thresholds.
if (!Array.isArray(tz)) tz = ticks(x0, x1, tz);
// Remove any thresholds outside the domain.
var m = tz.length;
while (tz[0] <= x0) tz.shift(), --m;
while (tz[m - 1] >= x1) tz.pop(), --m;
var bins = new Array(m + 1),
bin;
// Initialize bins.
for (i = 0; i <= m; ++i) {
bin = bins[i] = [];
bin.x0 = i > 0 ? tz[i - 1] : x0;
bin.x1 = i < m ? tz[i] : x1;
}
// Assign data to bins by value, ignoring any outside the domain.
for (i = 0; i < n; ++i) {
x = values[i];
if (x0 <= x && x <= x1) {
bins[bisectRight(tz, x, 0, m)].push(data[i]);
}
}
return bins;
}
histogram.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant(_), histogram) : value;
};
histogram.domain = function(_) {
return arguments.length ? (domain = typeof _ === "function" ? _ : constant([_[0], _[1]]), histogram) : domain;
};
histogram.thresholds = function(_) {
return arguments.length ? (threshold = typeof _ === "function" ? _ : Array.isArray(_) ? constant(slice.call(_)) : constant(_), histogram) : threshold;
};
return histogram;
}
function threshold(array, p, f) {
if (f == null) f = number;
if (!(n = array.length)) return;
if ((p = +p) <= 0 || n < 2) return +f(array[0], 0, array);
if (p >= 1) return +f(array[n - 1], n - 1, array);
var n,
h = (n - 1) * p,
i = Math.floor(h),
a = +f(array[i], i, array),
b = +f(array[i + 1], i + 1, array);
return a + (b - a) * (h - i);
}
function freedmanDiaconis(values, min, max) {
values = map.call(values, number).sort(ascending);
return Math.ceil((max - min) / (2 * (threshold(values, 0.75) - threshold(values, 0.25)) * Math.pow(values.length, -1 / 3)));
}
function scott(values, min, max) {
return Math.ceil((max - min) / (3.5 * deviation(values) * Math.pow(values.length, -1 / 3)));
}
function max(array, f) {
var i = -1,
n = array.length,
a,
b;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = array[i]) != null && b > a) a = b;
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null && b > a) a = b;
}
return a;
}
function mean(array, f) {
var s = 0,
n = array.length,
a,
i = -1,
j = n;
if (f == null) {
while (++i < n) if (!isNaN(a = number(array[i]))) s += a; else --j;
}
else {
while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) s += a; else --j;
}
if (j) return s / j;
}
function median(array, f) {
var numbers = [],
n = array.length,
a,
i = -1;
if (f == null) {
while (++i < n) if (!isNaN(a = number(array[i]))) numbers.push(a);
}
else {
while (++i < n) if (!isNaN(a = number(f(array[i], i, array)))) numbers.push(a);
}
return threshold(numbers.sort(ascending), 0.5);
}
function merge(arrays) {
var n = arrays.length,
m,
i = -1,
j = 0,
merged,
array;
while (++i < n) j += arrays[i].length;
merged = new Array(j);
while (--n >= 0) {
array = arrays[n];
m = array.length;
while (--m >= 0) {
merged[--j] = array[m];
}
}
return merged;
}
function min(array, f) {
var i = -1,
n = array.length,
a,
b;
if (f == null) {
while (++i < n) if ((b = array[i]) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = array[i]) != null && a > b) a = b;
}
else {
while (++i < n) if ((b = f(array[i], i, array)) != null && b >= b) { a = b; break; }
while (++i < n) if ((b = f(array[i], i, array)) != null && a > b) a = b;
}
return a;
}
function pairs(array) {
var i = 0, n = array.length - 1, p = array[0], pairs = new Array(n < 0 ? 0 : n);
while (i < n) pairs[i] = [p, p = array[++i]];
return pairs;
}
function permute(array, indexes) {
var i = indexes.length, permutes = new Array(i);
while (i--) permutes[i] = array[indexes[i]];
return permutes;
}
function scan(array, compare) {
if (!(n = array.length)) return;
var i = 0,
n,
j = 0,
xi,
xj = array[j];
if (!compare) compare = ascending;
while (++i < n) if (compare(xi = array[i], xj) < 0 || compare(xj, xj) !== 0) xj = xi, j = i;
if (compare(xj, xj) === 0) return j;
}
function shuffle(array, i0, i1) {
var m = (i1 == null ? array.length : i1) - (i0 = i0 == null ? 0 : +i0),
t,
i;
while (m) {
i = Math.random() * m-- | 0;
t = array[m + i0];
array[m + i0] = array[i + i0];
array[i + i0] = t;
}
return array;
}
function sum(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (f == null) {
while (++i < n) if (a = +array[i]) s += a; // Note: zero and null are equivalent.
}
else {
while (++i < n) if (a = +f(array[i], i, array)) s += a;
}
return s;
}
function transpose(matrix) {
if (!(n = matrix.length)) return [];
for (var i = -1, m = min(matrix, length), transpose = new Array(m); ++i < m;) {
for (var j = -1, n, row = transpose[i] = new Array(n); ++j < n;) {
row[j] = matrix[j][i];
}
}
return transpose;
}
function length(d) {
return d.length;
}
function zip() {
return transpose(arguments);
}
var prefix = "$";
function Map() {}
Map.prototype = map$1.prototype = {
constructor: Map,
has: function(key) {
return (prefix + key) in this;
},
get: function(key) {
return this[prefix + key];
},
set: function(key, value) {
this[prefix + key] = value;
return this;
},
remove: function(key) {
var property = prefix + key;
return property in this && delete this[property];
},
clear: function() {
for (var property in this) if (property[0] === prefix) delete this[property];
},
keys: function() {
var keys = [];
for (var property in this) if (property[0] === prefix) keys.push(property.slice(1));
return keys;
},
values: function() {
var values = [];
for (var property in this) if (property[0] === prefix) values.push(this[property]);
return values;
},
entries: function() {
var entries = [];
for (var property in this) if (property[0] === prefix) entries.push({key: property.slice(1), value: this[property]});
return entries;
},
size: function() {
var size = 0;
for (var property in this) if (property[0] === prefix) ++size;
return size;
},
empty: function() {
for (var property in this) if (property[0] === prefix) return false;
return true;
},
each: function(f) {
for (var property in this) if (property[0] === prefix) f(this[property], property.slice(1), this);
}
};
function map$1(object, f) {
var map = new Map;
// Copy constructor.
if (object instanceof Map) object.each(function(value, key) { map.set(key, value); });
// Index array by numeric index or specified key function.
else if (Array.isArray(object)) {
var i = -1,
n = object.length,
o;
if (f == null) while (++i < n) map.set(i, object[i]);
else while (++i < n) map.set(f(o = object[i], i, object), o);
}
// Convert object to map.
else if (object) for (var key in object) map.set(key, object[key]);
return map;
}
function nest() {
var keys = [],
sortKeys = [],
sortValues,
rollup,
nest;
function apply(array, depth, createResult, setResult) {
if (depth >= keys.length) return rollup != null
? rollup(array) : (sortValues != null
? array.sort(sortValues)
: array);
var i = -1,
n = array.length,
key = keys[depth++],
keyValue,
value,
valuesByKey = map$1(),
values,
result = createResult();
while (++i < n) {
if (values = valuesByKey.get(keyValue = key(value = array[i]) + "")) {
values.push(value);
} else {
valuesByKey.set(keyValue, [value]);
}
}
valuesByKey.each(function(values, key) {
setResult(result, key, apply(values, depth, createResult, setResult));
});
return result;
}
function entries(map, depth) {
if (++depth > keys.length) return map;
var array, sortKey = sortKeys[depth - 1];
if (rollup != null && depth >= keys.length) array = map.entries();
else array = [], map.each(function(v, k) { array.push({key: k, values: entries(v, depth)}); });
return sortKey != null ? array.sort(function(a, b) { return sortKey(a.key, b.key); }) : array;
}
return nest = {
object: function(array) { return apply(array, 0, createObject, setObject); },
map: function(array) { return apply(array, 0, createMap, setMap); },
entries: function(array) { return entries(apply(array, 0, createMap, setMap), 0); },
key: function(d) { keys.push(d); return nest; },
sortKeys: function(order) { sortKeys[keys.length - 1] = order; return nest; },
sortValues: function(order) { sortValues = order; return nest; },
rollup: function(f) { rollup = f; return nest; }
};
}
function createObject() {
return {};
}
function setObject(object, key, value) {
object[key] = value;
}
function createMap() {
return map$1();
}
function setMap(map, key, value) {
map.set(key, value);
}
function Set() {}
var proto = map$1.prototype;
Set.prototype = set.prototype = {
constructor: Set,
has: proto.has,
add: function(value) {
value += "";
this[prefix + value] = value;
return this;
},
remove: proto.remove,
clear: proto.clear,
values: proto.keys,
size: proto.size,
empty: proto.empty,
each: proto.each
};
function set(object, f) {
var set = new Set;
// Copy constructor.
if (object instanceof Set) object.each(function(value) { set.add(value); });
// Otherwise, assume it’s an array.
else if (object) {
var i = -1, n = object.length;
if (f == null) while (++i < n) set.add(object[i]);
else while (++i < n) set.add(f(object[i], i, object));
}
return set;
}
function d3keys(map) {
var keys = [];
for (var key in map) keys.push(key);
return keys;
}
function values(map) {
var values = [];
for (var key in map) values.push(map[key]);
return values;
}
function entries(map) {
var entries = [];
for (var key in map) entries.push({key: key, value: map[key]});
return entries;
}
function uniform(min, max) {
min = min == null ? 0 : +min;
max = max == null ? 1 : +max;
if (arguments.length === 1) max = min, min = 0;
else max -= min;
return function() {
return Math.random() * max + min;
};
}
function normal(mu, sigma) {
var x, r;
mu = mu == null ? 0 : +mu;
sigma = sigma == null ? 1 : +sigma;
return function() {
var y;
// If available, use the second previously-generated uniform random.
if (x != null) y = x, x = null;
// Otherwise, generate a new x and y.
else do {
x = Math.random() * 2 - 1;
y = Math.random() * 2 - 1;
r = x * x + y * y;
} while (!r || r > 1);
return mu + sigma * y * Math.sqrt(-2 * Math.log(r) / r);
};
}
function logNormal() {
var randomNormal = normal.apply(this, arguments);
return function() {
return Math.exp(randomNormal());
};
}
function irwinHall(n) {
return function() {
for (var sum = 0, i = 0; i < n; ++i) sum += Math.random();
return sum;
};
}
function bates(n) {
var randomIrwinHall = irwinHall(n);
return function() {
return randomIrwinHall() / n;
};
}
function exponential(lambda) {
return function() {
return -Math.log(1 - Math.random()) / lambda;
};
}
function linear(t) {
return +t;
}
function quadIn(t) {
return t * t;
}
function quadOut(t) {
return t * (2 - t);
}
function quadInOut(t) {
return ((t *= 2) <= 1 ? t * t : --t * (2 - t) + 1) / 2;
}
function cubicIn(t) {
return t * t * t;
}
function cubicOut(t) {
return --t * t * t + 1;
}
function easeCubicInOut(t) {
return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
}
var exponent = 3;
var polyIn = (function custom(e) {
e = +e;
function polyIn(t) {
return Math.pow(t, e);
}
polyIn.exponent = custom;
return polyIn;
})(exponent);
var polyOut = (function custom(e) {
e = +e;
function polyOut(t) {
return 1 - Math.pow(1 - t, e);
}
polyOut.exponent = custom;
return polyOut;
})(exponent);
var polyInOut = (function custom(e) {
e = +e;
function polyInOut(t) {
return ((t *= 2) <= 1 ? Math.pow(t, e) : 2 - Math.pow(2 - t, e)) / 2;
}
polyInOut.exponent = custom;
return polyInOut;
})(exponent);
var pi = Math.PI;
var halfPi = pi / 2;
function sinIn(t) {
return 1 - Math.cos(t * halfPi);
}
function sinOut(t) {
return Math.sin(t * halfPi);
}
function sinInOut(t) {
return (1 - Math.cos(pi * t)) / 2;
}
function expIn(t) {
return Math.pow(2, 10 * t - 10);
}
function expOut(t) {
return 1 - Math.pow(2, -10 * t);
}
function expInOut(t) {
return ((t *= 2) <= 1 ? Math.pow(2, 10 * t - 10) : 2 - Math.pow(2, 10 - 10 * t)) / 2;
}
function circleIn(t) {
return 1 - Math.sqrt(1 - t * t);
}
function circleOut(t) {
return Math.sqrt(1 - --t * t);
}
function circleInOut(t) {
return ((t *= 2) <= 1 ? 1 - Math.sqrt(1 - t * t) : Math.sqrt(1 - (t -= 2) * t) + 1) / 2;
}
var b1 = 4 / 11;
var b2 = 6 / 11;
var b3 = 8 / 11;
var b4 = 3 / 4;
var b5 = 9 / 11;
var b6 = 10 / 11;
var b7 = 15 / 16;
var b8 = 21 / 22;
var b9 = 63 / 64;
var b0 = 1 / b1 / b1;
function bounceIn(t) {
return 1 - bounceOut(1 - t);
}
function bounceOut(t) {
return (t = +t) < b1 ? b0 * t * t : t < b3 ? b0 * (t -= b2) * t + b4 : t < b6 ? b0 * (t -= b5) * t + b7 : b0 * (t -= b8) * t + b9;
}
function bounceInOut(t) {
return ((t *= 2) <= 1 ? 1 - bounceOut(1 - t) : bounceOut(t - 1) + 1) / 2;
}
var overshoot = 1.70158;
var backIn = (function custom(s) {
s = +s;
function backIn(t) {
return t * t * ((s + 1) * t - s);
}
backIn.overshoot = custom;
return backIn;
})(overshoot);
var backOut = (function custom(s) {
s = +s;
function backOut(t) {
return --t * t * ((s + 1) * t + s) + 1;
}
backOut.overshoot = custom;
return backOut;
})(overshoot);
var backInOut = (function custom(s) {
s = +s;
function backInOut(t) {
return ((t *= 2) < 1 ? t * t * ((s + 1) * t - s) : (t -= 2) * t * ((s + 1) * t + s) + 2) / 2;
}
backInOut.overshoot = custom;
return backInOut;
})(overshoot);
var tau = 2 * Math.PI;
var amplitude = 1;
var period = 0.3;
var elasticIn = (function custom(a, p) {
var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
function elasticIn(t) {
return a * Math.pow(2, 10 * --t) * Math.sin((s - t) / p);
}
elasticIn.amplitude = function(a) { return custom(a, p * tau); };
elasticIn.period = function(p) { return custom(a, p); };
return elasticIn;
})(amplitude, period);
var elasticOut = (function custom(a, p) {
var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
function elasticOut(t) {
return 1 - a * Math.pow(2, -10 * (t = +t)) * Math.sin((t + s) / p);
}
elasticOut.amplitude = function(a) { return custom(a, p * tau); };
elasticOut.period = function(p) { return custom(a, p); };
return elasticOut;
})(amplitude, period);
var elasticInOut = (function custom(a, p) {
var s = Math.asin(1 / (a = Math.max(1, a))) * (p /= tau);
function elasticInOut(t) {
return ((t = t * 2 - 1) < 0
? a * Math.pow(2, 10 * t) * Math.sin((s - t) / p)
: 2 - a * Math.pow(2, -10 * t) * Math.sin((s + t) / p)) / 2;
}
elasticInOut.amplitude = function(a) { return custom(a, p * tau); };
elasticInOut.period = function(p) { return custom(a, p); };
return elasticInOut;
})(amplitude, period);
function area(polygon) {
var i = -1,
n = polygon.length,
a,
b = polygon[n - 1],
area = 0;
while (++i < n) {
a = b;
b = polygon[i];
area += a[1] * b[0] - a[0] * b[1];
}
return area / 2;
}
function centroid(polygon) {
var i = -1,
n = polygon.length,
x = 0,
y = 0,
a,
b = polygon[n - 1],
c,
k = 0;
while (++i < n) {
a = b;
b = polygon[i];
k += c = a[0] * b[1] - b[0] * a[1];
x += (a[0] + b[0]) * c;
y += (a[1] + b[1]) * c;
}
return k *= 3, [x / k, y / k];
}
// Returns the 2D cross product of AB and AC vectors, i.e., the z-component of
// the 3D cross product in a quadrant I Cartesian coordinate system (+x is
// right, +y is up). Returns a positive value if ABC is counter-clockwise,
// negative if clockwise, and zero if the points are collinear.
function cross(a, b, c) {
return (b[0] - a[0]) * (c[1] - a[1]) - (b[1] - a[1]) * (c[0] - a[0]);
}
function lexicographicOrder(a, b) {
return a[0] - b[0] || a[1] - b[1];
}
// Computes the upper convex hull per the monotone chain algorithm.
// Assumes points.length >= 3, is sorted by x, unique in y.
// Returns an array of indices into points in left-to-right order.
function computeUpperHullIndexes(points) {
var n = points.length,
indexes = [0, 1],
size = 2;
for (var i = 2; i < n; ++i) {
while (size > 1 && cross(points[indexes[size - 2]], points[indexes[size - 1]], points[i]) <= 0) --size;
indexes[size++] = i;
}
return indexes.slice(0, size); // remove popped points
}
function hull(points) {
if ((n = points.length) < 3) return null;
var i,
n,
sortedPoints = new Array(n),
flippedPoints = new Array(n);
for (i = 0; i < n; ++i) sortedPoints[i] = [+points[i][0], +points[i][1], i];
sortedPoints.sort(lexicographicOrder);
for (i = 0; i < n; ++i) flippedPoints[i] = [sortedPoints[i][0], -sortedPoints[i][1]];
var upperIndexes = computeUpperHullIndexes(sortedPoints),
lowerIndexes = computeUpperHullIndexes(flippedPoints);
// Construct the hull polygon, removing possible duplicate endpoints.
var skipLeft = lowerIndexes[0] === upperIndexes[0],
skipRight = lowerIndexes[lowerIndexes.length - 1] === upperIndexes[upperIndexes.length - 1],
hull = [];
// Add upper hull in right-to-l order.
// Then add lower hull in left-to-right order.
for (i = upperIndexes.length - 1; i >= 0; --i) hull.push(points[sortedPoints[upperIndexes[i]][2]]);
for (i = +skipLeft; i < lowerIndexes.length - skipRight; ++i) hull.push(points[sortedPoints[lowerIndexes[i]][2]]);
return hull;
}
function contains(polygon, point) {
var n = polygon.length,
p = polygon[n - 1],
x = point[0], y = point[1],
x0 = p[0], y0 = p[1],
x1, y1,
inside = false;
for (var i = 0; i < n; ++i) {
p = polygon[i], x1 = p[0], y1 = p[1];
if (((y1 > y) !== (y0 > y)) && (x < (x0 - x1) * (y - y1) / (y0 - y1) + x1)) inside = !inside;
x0 = x1, y0 = y1;
}
return inside;
}
function length$1(polygon) {
var i = -1,
n = polygon.length,
b = polygon[n - 1],
xa,
ya,
xb = b[0],
yb = b[1],
perimeter = 0;
while (++i < n) {
xa = xb;
ya = yb;
b = polygon[i];
xb = b[0];
yb = b[1];
xa -= xb;
ya -= yb;
perimeter += Math.sqrt(xa * xa + ya * ya);
}
return perimeter;
}
var pi$1 = Math.PI;
var tau$1 = 2 * pi$1;
var epsilon = 1e-6;
var tauEpsilon = tau$1 - epsilon;
function Path() {
this._x0 = this._y0 = // start of current subpath
this._x1 = this._y1 = null; // end of current subpath
this._ = [];
}
function path() {
return new Path;
}
Path.prototype = path.prototype = {
constructor: Path,
moveTo: function(x, y) {
this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y);
},
closePath: function() {
if (this._x1 !== null) {
this._x1 = this._x0, this._y1 = this._y0;
this._.push("Z");
}
},
lineTo: function(x, y) {
this._.push("L", this._x1 = +x, ",", this._y1 = +y);
},
quadraticCurveTo: function(x1, y1, x, y) {
this._.push("Q", +x1, ",", +y1, ",", this._x1 = +x, ",", this._y1 = +y);
},
bezierCurveTo: function(x1, y1, x2, y2, x, y) {
this._.push("C", +x1, ",", +y1, ",", +x2, ",", +y2, ",", this._x1 = +x, ",", this._y1 = +y);
},
arcTo: function(x1, y1, x2, y2, r) {
x1 = +x1, y1 = +y1, x2 = +x2, y2 = +y2, r = +r;
var x0 = this._x1,
y0 = this._y1,
x21 = x2 - x1,
y21 = y2 - y1,
x01 = x0 - x1,
y01 = y0 - y1,
l01_2 = x01 * x01 + y01 * y01;
// Is the radius negative? Error.
if (r < 0) throw new Error("negative radius: " + r);
// Is this path empty? Move to (x1,y1).
if (this._x1 === null) {
this._.push(
"M", this._x1 = x1, ",", this._y1 = y1
);
}
// Or, is (x1,y1) coincident with (x0,y0)? Do nothing.
else if (!(l01_2 > epsilon));
// Or, are (x0,y0), (x1,y1) and (x2,y2) collinear?
// Equivalently, is (x1,y1) coincident with (x2,y2)?
// Or, is the radius zero? Line to (x1,y1).
else if (!(Math.abs(y01 * x21 - y21 * x01) > epsilon) || !r) {
this._.push(
"L", this._x1 = x1, ",", this._y1 = y1
);
}
// Otherwise, draw an arc!
else {
var x20 = x2 - x0,
y20 = y2 - y0,
l21_2 = x21 * x21 + y21 * y21,
l20_2 = x20 * x20 + y20 * y20,
l21 = Math.sqrt(l21_2),
l01 = Math.sqrt(l01_2),
l = r * Math.tan((pi$1 - Math.acos((l21_2 + l01_2 - l20_2) / (2 * l21 * l01))) / 2),
t01 = l / l01,
t21 = l / l21;
// If the start tangent is not coincident with (x0,y0), line to.
if (Math.abs(t01 - 1) > epsilon) {
this._.push(
"L", x1 + t01 * x01, ",", y1 + t01 * y01
);
}
this._.push(
"A", r, ",", r, ",0,0,", +(y01 * x20 > x01 * y20), ",", this._x1 = x1 + t21 * x21, ",", this._y1 = y1 + t21 * y21
);
}
},
arc: function(x, y, r, a0, a1, ccw) {
x = +x, y = +y, r = +r;
var dx = r * Math.cos(a0),
dy = r * Math.sin(a0),
x0 = x + dx,
y0 = y + dy,
cw = 1 ^ ccw,
da = ccw ? a0 - a1 : a1 - a0;
// Is the radius negative? Error.
if (r < 0) throw new Error("negative radius: " + r);
// Is this path empty? Move to (x0,y0).
if (this._x1 === null) {
this._.push(
"M", x0, ",", y0
);
}
// Or, is (x0,y0) not coincident with the previous point? Line to (x0,y0).
else if (Math.abs(this._x1 - x0) > epsilon || Math.abs(this._y1 - y0) > epsilon) {
this._.push(
"L", x0, ",", y0
);
}
// Is this arc empty? We’re done.
if (!r) return;
// Is this a complete circle? Draw two arcs to complete the circle.
if (da > tauEpsilon) {
this._.push(
"A", r, ",", r, ",0,1,", cw, ",", x - dx, ",", y - dy,
"A", r, ",", r, ",0,1,", cw, ",", this._x1 = x0, ",", this._y1 = y0
);
}
// Otherwise, draw an arc!
else {
if (da < 0) da = da % tau$1 + tau$1;
this._.push(
"A", r, ",", r, ",0,", +(da >= pi$1), ",", cw, ",", this._x1 = x + r * Math.cos(a1), ",", this._y1 = y + r * Math.sin(a1)
);
}
},
rect: function(x, y, w, h) {
this._.push("M", this._x0 = this._x1 = +x, ",", this._y0 = this._y1 = +y, "h", +w, "v", +h, "h", -w, "Z");
},
toString: function() {
return this._.join("");
}
};
function tree_add(d) {
var x = +this._x.call(null, d),
y = +this._y.call(null, d);
return add(this.cover(x, y), x, y, d);
}
function add(tree, x, y, d) {
if (isNaN(x) || isNaN(y)) return tree; // ignore invalid points
var parent,
node = tree._root,
leaf = {data: d},
x0 = tree._x0,
y0 = tree._y0,
x1 = tree._x1,
y1 = tree._y1,
xm,
ym,
xp,
yp,
right,
bottom,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return tree._root = leaf, tree;
// Find the existing leaf for the new point, or add it.
while (node.length) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (parent = node, !(node = node[i = bottom << 1 | right])) return parent[i] = leaf, tree;
}
// Is the new point is exactly coincident with the existing point?
xp = +tree._x.call(null, node.data);
yp = +tree._y.call(null, node.data);
if (x === xp && y === yp) return leaf.next = node, parent ? parent[i] = leaf : tree._root = leaf, tree;
// Otherwise, split the leaf node until the old and new point are separated.
do {
parent = parent ? parent[i] = new Array(4) : tree._root = new Array(4);
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
} while ((i = bottom << 1 | right) === (j = (yp >= ym) << 1 | (xp >= xm)));
return parent[j] = node, parent[i] = leaf, tree;
}
function addAll(data) {
var d, i, n = data.length,
x,
y,
xz = new Array(n),
yz = new Array(n),
x0 = Infinity,
y0 = Infinity,
x1 = -Infinity,
y1 = -Infinity;
// Compute the points and their extent.
for (i = 0; i < n; ++i) {
if (isNaN(x = +this._x.call(null, d = data[i])) || isNaN(y = +this._y.call(null, d))) continue;
xz[i] = x;
yz[i] = y;
if (x < x0) x0 = x;
if (x > x1) x1 = x;
if (y < y0) y0 = y;
if (y > y1) y1 = y;
}
// If there were no (valid) points, inherit the existing extent.
if (x1 < x0) x0 = this._x0, x1 = this._x1;
if (y1 < y0) y0 = this._y0, y1 = this._y1;
// Expand the tree to cover the new points.
this.cover(x0, y0).cover(x1, y1);
// Add the new points.
for (i = 0; i < n; ++i) {
add(this, xz[i], yz[i], data[i]);
}
return this;
}
function tree_cover(x, y) {
if (isNaN(x = +x) || isNaN(y = +y)) return this; // ignore invalid points
var x0 = this._x0,
y0 = this._y0,
x1 = this._x1,
y1 = this._y1;
// If the quadtree has no extent, initialize them.
// Integer extent are necessary so that if we later double the extent,
// the existing quadrant boundaries don’t change due to floating point error!
if (isNaN(x0)) {
x1 = (x0 = Math.floor(x)) + 1;
y1 = (y0 = Math.floor(y)) + 1;
}
// Otherwise, double repeatedly to cover.
else if (x0 > x || x > x1 || y0 > y || y > y1) {
var z = x1 - x0,
node = this._root,
parent,
i;
switch (i = (y < (y0 + y1) / 2) << 1 | (x < (x0 + x1) / 2)) {
case 0: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x1 = x0 + z, y1 = y0 + z, x > x1 || y > y1);
break;
}
case 1: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x0 = x1 - z, y1 = y0 + z, x0 > x || y > y1);
break;
}
case 2: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x1 = x0 + z, y0 = y1 - z, x > x1 || y0 > y);
break;
}
case 3: {
do parent = new Array(4), parent[i] = node, node = parent;
while (z *= 2, x0 = x1 - z, y0 = y1 - z, x0 > x || y0 > y);
break;
}
}
if (this._root && this._root.length) this._root = node;
}
// If the quadtree covers the point already, just return.
else return this;
this._x0 = x0;
this._y0 = y0;
this._x1 = x1;
this._y1 = y1;
return this;
}
function tree_data() {
var data = [];
this.visit(function(node) {
if (!node.length) do data.push(node.data); while (node = node.next)
});
return data;
}
function tree_extent(_) {
return arguments.length
? this.cover(+_[0][0], +_[0][1]).cover(+_[1][0], +_[1][1])
: isNaN(this._x0) ? undefined : [[this._x0, this._y0], [this._x1, this._y1]];
}
function Quad(node, x0, y0, x1, y1) {
this.node = node;
this.x0 = x0;
this.y0 = y0;
this.x1 = x1;
this.y1 = y1;
}
function tree_find(x, y, radius) {
var data,
x0 = this._x0,
y0 = this._y0,
x1,
y1,
x2,
y2,
x3 = this._x1,
y3 = this._y1,
quads = [],
node = this._root,
q,
i;
if (node) quads.push(new Quad(node, x0, y0, x3, y3));
if (radius == null) radius = Infinity;
else {
x0 = x - radius, y0 = y - radius;
x3 = x + radius, y3 = y + radius;
radius *= radius;
}
while (q = quads.pop()) {
// Stop searching if this quadrant can’t contain a closer node.
if (!(node = q.node)
|| (x1 = q.x0) > x3
|| (y1 = q.y0) > y3
|| (x2 = q.x1) < x0
|| (y2 = q.y1) < y0) continue;
// Bisect the current quadrant.
if (node.length) {
var xm = (x1 + x2) / 2,
ym = (y1 + y2) / 2;
quads.push(
new Quad(node[3], xm, ym, x2, y2),
new Quad(node[2], x1, ym, xm, y2),
new Quad(node[1], xm, y1, x2, ym),
new Quad(node[0], x1, y1, xm, ym)
);
// Visit the closest quadrant first.
if (i = (y >= ym) << 1 | (x >= xm)) {
q = quads[quads.length - 1];
quads[quads.length - 1] = quads[quads.length - 1 - i];
quads[quads.length - 1 - i] = q;
}
}
// Visit this point. (Visiting coincident points isn’t necessary!)
else {
var dx = x - +this._x.call(null, node.data),
dy = y - +this._y.call(null, node.data),
d2 = dx * dx + dy * dy;
if (d2 < radius) {
var d = Math.sqrt(radius = d2);
x0 = x - d, y0 = y - d;
x3 = x + d, y3 = y + d;
data = node.data;
}
}
}
return data;
}
function tree_remove(d) {
if (isNaN(x = +this._x.call(null, d)) || isNaN(y = +this._y.call(null, d))) return this; // ignore invalid points
var parent,
node = this._root,
retainer,
previous,
next,
x0 = this._x0,
y0 = this._y0,
x1 = this._x1,
y1 = this._y1,
x,
y,
xm,
ym,
right,
bottom,
i,
j;
// If the tree is empty, initialize the root as a leaf.
if (!node) return this;
// Find the leaf node for the point.
// While descending, also retain the deepest parent with a non-removed sibling.
if (node.length) while (true) {
if (right = x >= (xm = (x0 + x1) / 2)) x0 = xm; else x1 = xm;
if (bottom = y >= (ym = (y0 + y1) / 2)) y0 = ym; else y1 = ym;
if (!(parent = node, node = node[i = bottom << 1 | right])) return this;
if (!node.length) break;
if (parent[(i + 1) & 3] || parent[(i + 2) & 3] || parent[(i + 3) & 3]) retainer = parent, j = i;
}
// Find the point to remove.
while (node.data !== d) if (!(previous = node, node = node.next)) return this;
if (next = node.next) delete node.next;
// If there are multiple coincident points, remove just the point.
if (previous) return (next ? previous.next = next : delete previous.next), this;
// If this is the root point, remove it.
if (!parent) return this._root = next, this;
// Remove this leaf.
next ? parent[i] = next : delete parent[i];
// If the parent now contains exactly one leaf, collapse superfluous parents.
if ((node = parent[0] || parent[1] || parent[2] || parent[3])
&& node === (parent[3] || parent[2] || parent[1] || parent[0])
&& !node.length) {
if (retainer) retainer[j] = node;
else this._root = node;
}
return this;
}
function removeAll(data) {
for (var i = 0, n = data.length; i < n; ++i) this.remove(data[i]);
return this;
}
function tree_root() {
return this._root;
}
function tree_size() {
var size = 0;
this.visit(function(node) {
if (!node.length) do ++size; while (node = node.next)
});
return size;
}
function tree_visit(callback) {
var quads = [], q, node = this._root, child, x0, y0, x1, y1;
if (node) quads.push(new Quad(node, this._x0, this._y0, this._x1, this._y1));
while (q = quads.pop()) {
if (!callback(node = q.node, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1) && node.length) {
var xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
}
}
return this;
}
function tree_visitAfter(callback) {
var quads = [], next = [], q;
if (this._root) quads.push(new Quad(this._root, this._x0, this._y0, this._x1, this._y1));
while (q = quads.pop()) {
var node = q.node;
if (node.length) {
var child, x0 = q.x0, y0 = q.y0, x1 = q.x1, y1 = q.y1, xm = (x0 + x1) / 2, ym = (y0 + y1) / 2;
if (child = node[0]) quads.push(new Quad(child, x0, y0, xm, ym));
if (child = node[1]) quads.push(new Quad(child, xm, y0, x1, ym));
if (child = node[2]) quads.push(new Quad(child, x0, ym, xm, y1));
if (child = node[3]) quads.push(new Quad(child, xm, ym, x1, y1));
}
next.push(q);
}
while (q = next.pop()) {
callback(q.node, q.x0, q.y0, q.x1, q.y1);
}
return this;
}
function defaultX(d) {
return d[0];
}
function tree_x(_) {
return arguments.length ? (this._x = _, this) : this._x;
}
function defaultY(d) {
return d[1];
}
function tree_y(_) {
return arguments.length ? (this._y = _, this) : this._y;
}
function quadtree(nodes, x, y) {
var tree = new Quadtree(x == null ? defaultX : x, y == null ? defaultY : y, NaN, NaN, NaN, NaN);
return nodes == null ? tree : tree.addAll(nodes);
}
function Quadtree(x, y, x0, y0, x1, y1) {
this._x = x;
this._y = y;
this._x0 = x0;
this._y0 = y0;
this._x1 = x1;
this._y1 = y1;
this._root = undefined;
}
function leaf_copy(leaf) {
var copy = {data: leaf.data}, next = copy;
while (leaf = leaf.next) next = next.next = {data: leaf.data};
return copy;
}
var treeProto = quadtree.prototype = Quadtree.prototype;
treeProto.copy = function() {
var copy = new Quadtree(this._x, this._y, this._x0, this._y0, this._x1, this._y1),
node = this._root,
nodes,
child;
if (!node) return copy;
if (!node.length) return copy._root = leaf_copy(node), copy;
nodes = [{source: node, target: copy._root = new Array(4)}];
while (node = nodes.pop()) {
for (var i = 0; i < 4; ++i) {
if (child = node.source[i]) {
if (child.length) nodes.push({source: child, target: node.target[i] = new Array(4)});
else node.target[i] = leaf_copy(child);
}
}
}
return copy;
};
treeProto.add = tree_add;
treeProto.addAll = addAll;
treeProto.cover = tree_cover;
treeProto.data = tree_data;
treeProto.extent = tree_extent;
treeProto.find = tree_find;
treeProto.remove = tree_remove;
treeProto.removeAll = removeAll;
treeProto.root = tree_root;
treeProto.size = tree_size;
treeProto.visit = tree_visit;
treeProto.visitAfter = tree_visitAfter;
treeProto.x = tree_x;
treeProto.y = tree_y;
var slice$1 = [].slice;
var noabort = {};
function Queue(size) {
if (!(size >= 1)) throw new Error;
this._size = size;
this._call =
this._error = null;
this._tasks = [];
this._data = [];
this._waiting =
this._active =
this._ended =
this._start = 0; // inside a synchronous task callback?
}
Queue.prototype = queue.prototype = {
constructor: Queue,
defer: function(callback) {
if (typeof callback !== "function" || this._call) throw new Error;
if (this._error != null) return this;
var t = slice$1.call(arguments, 1);
t.push(callback);
++this._waiting, this._tasks.push(t);
poke(this);
return this;
},
abort: function() {
if (this._error == null) abort(this, new Error("abort"));
return this;
},
await: function(callback) {
if (typeof callback !== "function" || this._call) throw new Error;
this._call = function(error, results) { callback.apply(null, [error].concat(results)); };
maybeNotify(this);
return this;
},
awaitAll: function(callback) {
if (typeof callback !== "function" || this._call) throw new Error;
this._call = callback;
maybeNotify(this);
return this;
}
};
function poke(q) {
if (!q._start) {
try { start(q); } // let the current task complete
catch (e) {
if (q._tasks[q._ended + q._active - 1]) abort(q, e); // task errored synchronously
else if (!q._data) throw e; // await callback errored synchronously
}
}
}
function start(q) {
while (q._start = q._waiting && q._active < q._size) {
var i = q._ended + q._active,
t = q._tasks[i],
j = t.length - 1,
c = t[j];
t[j] = end(q, i);
--q._waiting, ++q._active;
t = c.apply(null, t);
if (!q._tasks[i]) continue; // task finished synchronously
q._tasks[i] = t || noabort;
}
}
function end(q, i) {
return function(e, r) {
if (!q._tasks[i]) return; // ignore multiple callbacks
--q._active, ++q._ended;
q._tasks[i] = null;
if (q._error != null) return; // ignore secondary errors
if (e != null) {
abort(q, e);
} else {
q._data[i] = r;
if (q._waiting) poke(q);
else maybeNotify(q);
}
};
}
function abort(q, e) {
var i = q._tasks.length, t;
q._error = e; // ignore active callbacks
q._data = undefined; // allow gc
q._waiting = NaN; // prevent starting
while (--i >= 0) {
if (t = q._tasks[i]) {
q._tasks[i] = null;
if (t.abort) {
try { t.abort(); }
catch (e) { /* ignore */ }
}
}
}
q._active = NaN; // allow notification
maybeNotify(q);
}
function maybeNotify(q) {
if (!q._active && q._call) {
var d = q._data;
q._data = undefined; // allow gc
q._call(q._error, d);
}
}
function queue(concurrency) {
return new Queue(arguments.length ? +concurrency : Infinity);
}
function constant$1(x) {
return function constant() {
return x;
};
}
var epsilon$1 = 1e-12;
var pi$2 = Math.PI;
var halfPi$1 = pi$2 / 2;
var tau$2 = 2 * pi$2;
function arcInnerRadius(d) {
return d.innerRadius;
}
function arcOuterRadius(d) {
return d.outerRadius;
}
function arcStartAngle(d) {
return d.startAngle;
}
function arcEndAngle(d) {
return d.endAngle;
}
function arcPadAngle(d) {
return d && d.padAngle; // Note: optional!
}
function asin(x) {
return x >= 1 ? halfPi$1 : x <= -1 ? -halfPi$1 : Math.asin(x);
}
function intersect(x0, y0, x1, y1, x2, y2, x3, y3) {
var x10 = x1 - x0, y10 = y1 - y0,
x32 = x3 - x2, y32 = y3 - y2,
t = (x32 * (y0 - y2) - y32 * (x0 - x2)) / (y32 * x10 - x32 * y10);
return [x0 + t * x10, y0 + t * y10];
}
// Compute perpendicular offset line of length rc.
// http://mathworld.wolfram.com/Circle-LineIntersection.html
function cornerTangents(x0, y0, x1, y1, r1, rc, cw) {
var x01 = x0 - x1,
y01 = y0 - y1,
lo = (cw ? rc : -rc) / Math.sqrt(x01 * x01 + y01 * y01),
ox = lo * y01,
oy = -lo * x01,
x11 = x0 + ox,
y11 = y0 + oy,
x10 = x1 + ox,
y10 = y1 + oy,
x00 = (x11 + x10) / 2,
y00 = (y11 + y10) / 2,
dx = x10 - x11,
dy = y10 - y11,
d2 = dx * dx + dy * dy,
r = r1 - rc,
D = x11 * y10 - x10 * y11,
d = (dy < 0 ? -1 : 1) * Math.sqrt(Math.max(0, r * r * d2 - D * D)),
cx0 = (D * dy - dx * d) / d2,
cy0 = (-D * dx - dy * d) / d2,
cx1 = (D * dy + dx * d) / d2,
cy1 = (-D * dx + dy * d) / d2,
dx0 = cx0 - x00,
dy0 = cy0 - y00,
dx1 = cx1 - x00,
dy1 = cy1 - y00;
// Pick the closer of the two intersection points.
// TODO Is there a faster way to determine which intersection to use?
if (dx0 * dx0 + dy0 * dy0 > dx1 * dx1 + dy1 * dy1) cx0 = cx1, cy0 = cy1;
return {
cx: cx0,
cy: cy0,
x01: -ox,
y01: -oy,
x11: cx0 * (r1 / r - 1),
y11: cy0 * (r1 / r - 1)
};
}
function arc() {
var innerRadius = arcInnerRadius,
outerRadius = arcOuterRadius,
cornerRadius = constant$1(0),
padRadius = null,
startAngle = arcStartAngle,
endAngle = arcEndAngle,
padAngle = arcPadAngle,
context = null;
function arc() {
var buffer,
r,
r0 = +innerRadius.apply(this, arguments),
r1 = +outerRadius.apply(this, arguments),
a0 = startAngle.apply(this, arguments) - halfPi$1,
a1 = endAngle.apply(this, arguments) - halfPi$1,
da = Math.abs(a1 - a0),
cw = a1 > a0;
if (!context) context = buffer = path();
// Ensure that the outer radius is always larger than the inner radius.
if (r1 < r0) r = r1, r1 = r0, r0 = r;
// Is it a point?
if (!(r1 > epsilon$1)) context.moveTo(0, 0);
// Or is it a circle or annulus?
else if (da > tau$2 - epsilon$1) {
context.moveTo(r1 * Math.cos(a0), r1 * Math.sin(a0));
context.arc(0, 0, r1, a0, a1, !cw);
if (r0 > epsilon$1) {
context.moveTo(r0 * Math.cos(a1), r0 * Math.sin(a1));
context.arc(0, 0, r0, a1, a0, cw);
}
}
// Or is it a circular or annular sector?
else {
var a01 = a0,
a11 = a1,
a00 = a0,
a10 = a1,
da0 = da,
da1 = da,
ap = padAngle.apply(this, arguments) / 2,
rp = (ap > epsilon$1) && (padRadius ? +padRadius.apply(this, arguments) : Math.sqrt(r0 * r0 + r1 * r1)),
rc = Math.min(Math.abs(r1 - r0) / 2, +cornerRadius.apply(this, arguments)),
rc0 = rc,
rc1 = rc,
t0,
t1;
// Apply padding? Note that since r1 ≥ r0, da1 ≥ da0.
if (rp > epsilon$1) {
var p0 = asin(rp / r0 * Math.sin(ap)),
p1 = asin(rp / r1 * Math.sin(ap));
if ((da0 -= p0 * 2) > epsilon$1) p0 *= (cw ? 1 : -1), a00 += p0, a10 -= p0;
else da0 = 0, a00 = a10 = (a0 + a1) / 2;
if ((da1 -= p1 * 2) > epsilon$1) p1 *= (cw ? 1 : -1), a01 += p1, a11 -= p1;
else da1 = 0, a01 = a11 = (a0 + a1) / 2;
}
var x01 = r1 * Math.cos(a01),
y01 = r1 * Math.sin(a01),
x10 = r0 * Math.cos(a10),
y10 = r0 * Math.sin(a10);
// Apply rounded corners?
if (rc > epsilon$1) {
var x11 = r1 * Math.cos(a11),
y11 = r1 * Math.sin(a11),
x00 = r0 * Math.cos(a00),
y00 = r0 * Math.sin(a00);
// Restrict the corner radius according to the sector angle.
if (da < pi$2) {
var oc = da0 > epsilon$1 ? intersect(x01, y01, x00, y00, x11, y11, x10, y10) : [x10, y10],
ax = x01 - oc[0],
ay = y01 - oc[1],
bx = x11 - oc[0],
by = y11 - oc[1],
kc = 1 / Math.sin(Math.acos((ax * bx + ay * by) / (Math.sqrt(ax * ax + ay * ay) * Math.sqrt(bx * bx + by * by))) / 2),
lc = Math.sqrt(oc[0] * oc[0] + oc[1] * oc[1]);
rc0 = Math.min(rc, (r0 - lc) / (kc - 1));
rc1 = Math.min(rc, (r1 - lc) / (kc + 1));
}
}
// Is the sector collapsed to a line?
if (!(da1 > epsilon$1)) context.moveTo(x01, y01);
// Does the sector’s outer ring have rounded corners?
else if (rc1 > epsilon$1) {
t0 = cornerTangents(x00, y00, x01, y01, r1, rc1, cw);
t1 = cornerTangents(x11, y11, x10, y10, r1, rc1, cw);
context.moveTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc1 < rc) context.arc(t0.cx, t0.cy, rc1, Math.atan2(t0.y01, t0.x01), Math.atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc1, Math.atan2(t0.y01, t0.x01), Math.atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r1, Math.atan2(t0.cy + t0.y11, t0.cx + t0.x11), Math.atan2(t1.cy + t1.y11, t1.cx + t1.x11), !cw);
context.arc(t1.cx, t1.cy, rc1, Math.atan2(t1.y11, t1.x11), Math.atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the outer ring just a circular arc?
else context.moveTo(x01, y01), context.arc(0, 0, r1, a01, a11, !cw);
// Is there no inner ring, and it’s a circular sector?
// Or perhaps it’s an annular sector collapsed due to padding?
if (!(r0 > epsilon$1) || !(da0 > epsilon$1)) context.lineTo(x10, y10);
// Does the sector’s inner ring (or point) have rounded corners?
else if (rc0 > epsilon$1) {
t0 = cornerTangents(x10, y10, x11, y11, r0, -rc0, cw);
t1 = cornerTangents(x01, y01, x00, y00, r0, -rc0, cw);
context.lineTo(t0.cx + t0.x01, t0.cy + t0.y01);
// Have the corners merged?
if (rc0 < rc) context.arc(t0.cx, t0.cy, rc0, Math.atan2(t0.y01, t0.x01), Math.atan2(t1.y01, t1.x01), !cw);
// Otherwise, draw the two corners and the ring.
else {
context.arc(t0.cx, t0.cy, rc0, Math.atan2(t0.y01, t0.x01), Math.atan2(t0.y11, t0.x11), !cw);
context.arc(0, 0, r0, Math.atan2(t0.cy + t0.y11, t0.cx + t0.x11), Math.atan2(t1.cy + t1.y11, t1.cx + t1.x11), cw);
context.arc(t1.cx, t1.cy, rc0, Math.atan2(t1.y11, t1.x11), Math.atan2(t1.y01, t1.x01), !cw);
}
}
// Or is the inner ring just a circular arc?
else context.arc(0, 0, r0, a10, a00, cw);
}
context.closePath();
if (buffer) return context = null, buffer + "" || null;
}
arc.centroid = function() {
var r = (+innerRadius.apply(this, arguments) + +outerRadius.apply(this, arguments)) / 2,
a = (+startAngle.apply(this, arguments) + +endAngle.apply(this, arguments)) / 2 - pi$2 / 2;
return [Math.cos(a) * r, Math.sin(a) * r];
};
arc.innerRadius = function(_) {
return arguments.length ? (innerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : innerRadius;
};
arc.outerRadius = function(_) {
return arguments.length ? (outerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : outerRadius;
};
arc.cornerRadius = function(_) {
return arguments.length ? (cornerRadius = typeof _ === "function" ? _ : constant$1(+_), arc) : cornerRadius;
};
arc.padRadius = function(_) {
return arguments.length ? (padRadius = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), arc) : padRadius;
};
arc.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : startAngle;
};
arc.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : endAngle;
};
arc.padAngle = function(_) {
return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), arc) : padAngle;
};
arc.context = function(_) {
return arguments.length ? ((context = _ == null ? null : _), arc) : context;
};
return arc;
}
function Linear(context) {
this._context = context;
}
Linear.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; // proceed
default: this._context.lineTo(x, y); break;
}
}
};
function curveLinear(context) {
return new Linear(context);
}
function x(p) {
return p[0];
}
function y(p) {
return p[1];
}
function line() {
var x$$ = x,
y$$ = y,
defined = constant$1(true),
context = null,
curve = curveLinear,
output = null;
function line(data) {
var i,
n = data.length,
d,
defined0 = false,
buffer;
if (context == null) output = curve(buffer = path());
for (i = 0; i <= n; ++i) {
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
if (defined0 = !defined0) output.lineStart();
else output.lineEnd();
}
if (defined0) output.point(+x$$(d, i, data), +y$$(d, i, data));
}
if (buffer) return output = null, buffer + "" || null;
}
line.x = function(_) {
return arguments.length ? (x$$ = typeof _ === "function" ? _ : constant$1(+_), line) : x$$;
};
line.y = function(_) {
return arguments.length ? (y$$ = typeof _ === "function" ? _ : constant$1(+_), line) : y$$;
};
line.defined = function(_) {
return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), line) : defined;
};
line.curve = function(_) {
return arguments.length ? (curve = _, context != null && (output = curve(context)), line) : curve;
};
line.context = function(_) {
return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), line) : context;
};
return line;
}
function area$1() {
var x0 = x,
x1 = null,
y0 = constant$1(0),
y1 = y,
defined = constant$1(true),
context = null,
curve = curveLinear,
output = null;
function area(data) {
var i,
j,
k,
n = data.length,
d,
defined0 = false,
buffer,
x0z = new Array(n),
y0z = new Array(n);
if (context == null) output = curve(buffer = path());
for (i = 0; i <= n; ++i) {
if (!(i < n && defined(d = data[i], i, data)) === defined0) {
if (defined0 = !defined0) {
j = i;
output.areaStart();
output.lineStart();
} else {
output.lineEnd();
output.lineStart();
for (k = i - 1; k >= j; --k) {
output.point(x0z[k], y0z[k]);
}
output.lineEnd();
output.areaEnd();
}
}
if (defined0) {
x0z[i] = +x0(d, i, data), y0z[i] = +y0(d, i, data);
output.point(x1 ? +x1(d, i, data) : x0z[i], y1 ? +y1(d, i, data) : y0z[i]);
}
}
if (buffer) return output = null, buffer + "" || null;
}
function arealine() {
return line().defined(defined).curve(curve).context(context);
}
area.x = function(_) {
return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), x1 = null, area) : x0;
};
area.x0 = function(_) {
return arguments.length ? (x0 = typeof _ === "function" ? _ : constant$1(+_), area) : x0;
};
area.x1 = function(_) {
return arguments.length ? (x1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : x1;
};
area.y = function(_) {
return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), y1 = null, area) : y0;
};
area.y0 = function(_) {
return arguments.length ? (y0 = typeof _ === "function" ? _ : constant$1(+_), area) : y0;
};
area.y1 = function(_) {
return arguments.length ? (y1 = _ == null ? null : typeof _ === "function" ? _ : constant$1(+_), area) : y1;
};
area.lineX0 =
area.lineY0 = function() {
return arealine().x(x0).y(y0);
};
area.lineY1 = function() {
return arealine().x(x0).y(y1);
};
area.lineX1 = function() {
return arealine().x(x1).y(y0);
};
area.defined = function(_) {
return arguments.length ? (defined = typeof _ === "function" ? _ : constant$1(!!_), area) : defined;
};
area.curve = function(_) {
return arguments.length ? (curve = _, context != null && (output = curve(context)), area) : curve;
};
area.context = function(_) {
return arguments.length ? (_ == null ? context = output = null : output = curve(context = _), area) : context;
};
return area;
}
function descending$1(a, b) {
return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;
}
function identity$1(d) {
return d;
}
function pie() {
var value = identity$1,
sortValues = descending$1,
sort = null,
startAngle = constant$1(0),
endAngle = constant$1(tau$2),
padAngle = constant$1(0);
function pie(data) {
var i,
n = data.length,
j,
k,
sum = 0,
index = new Array(n),
arcs = new Array(n),
a0 = +startAngle.apply(this, arguments),
da = Math.min(tau$2, Math.max(-tau$2, endAngle.apply(this, arguments) - a0)),
a1,
p = Math.min(Math.abs(da) / n, padAngle.apply(this, arguments)),
pa = p * (da < 0 ? -1 : 1),
v;
for (i = 0; i < n; ++i) {
if ((v = arcs[index[i] = i] = +value(data[i], i, data)) > 0) {
sum += v;
}
}
// Optionally sort the arcs by previously-computed values or by data.
if (sortValues != null) index.sort(function(i, j) { return sortValues(arcs[i], arcs[j]); });
else if (sort != null) index.sort(function(i, j) { return sort(data[i], data[j]); });
// Compute the arcs! They are stored in the original data's order.
for (i = 0, k = sum ? (da - n * pa) / sum : 0; i < n; ++i, a0 = a1) {
j = index[i], v = arcs[j], a1 = a0 + (v > 0 ? v * k : 0) + pa, arcs[j] = {
data: data[j],
index: i,
value: v,
startAngle: a0,
endAngle: a1,
padAngle: p
};
}
return arcs;
}
pie.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), pie) : value;
};
pie.sortValues = function(_) {
return arguments.length ? (sortValues = _, sort = null, pie) : sortValues;
};
pie.sort = function(_) {
return arguments.length ? (sort = _, sortValues = null, pie) : sort;
};
pie.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : startAngle;
};
pie.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : endAngle;
};
pie.padAngle = function(_) {
return arguments.length ? (padAngle = typeof _ === "function" ? _ : constant$1(+_), pie) : padAngle;
};
return pie;
}
var curveRadialLinear = curveRadial(curveLinear);
function Radial(curve) {
this._curve = curve;
}
Radial.prototype = {
areaStart: function() {
this._curve.areaStart();
},
areaEnd: function() {
this._curve.areaEnd();
},
lineStart: function() {
this._curve.lineStart();
},
lineEnd: function() {
this._curve.lineEnd();
},
point: function(a, r) {
this._curve.point(r * Math.sin(a), r * -Math.cos(a));
}
};
function curveRadial(curve) {
function radial(context) {
return new Radial(curve(context));
}
radial._curve = curve;
return radial;
}
function radialLine(l) {
var c = l.curve;
l.angle = l.x, delete l.x;
l.radius = l.y, delete l.y;
l.curve = function(_) {
return arguments.length ? c(curveRadial(_)) : c()._curve;
};
return l;
}
function radialLine$1() {
return radialLine(line().curve(curveRadialLinear));
}
function radialArea() {
var a = area$1().curve(curveRadialLinear),
c = a.curve,
x0 = a.lineX0,
x1 = a.lineX1,
y0 = a.lineY0,
y1 = a.lineY1;
a.angle = a.x, delete a.x;
a.startAngle = a.x0, delete a.x0;
a.endAngle = a.x1, delete a.x1;
a.radius = a.y, delete a.y;
a.innerRadius = a.y0, delete a.y0;
a.outerRadius = a.y1, delete a.y1;
a.lineStartAngle = function() { return radialLine(x0()); }, delete a.lineX0;
a.lineEndAngle = function() { return radialLine(x1()); }, delete a.lineX1;
a.lineInnerRadius = function() { return radialLine(y0()); }, delete a.lineY0;
a.lineOuterRadius = function() { return radialLine(y1()); }, delete a.lineY1;
a.curve = function(_) {
return arguments.length ? c(curveRadial(_)) : c()._curve;
};
return a;
}
var circle = {
draw: function(context, size) {
var r = Math.sqrt(size / pi$2);
context.moveTo(r, 0);
context.arc(0, 0, r, 0, tau$2);
}
};
var cross$1 = {
draw: function(context, size) {
var r = Math.sqrt(size / 5) / 2;
context.moveTo(-3 * r, -r);
context.lineTo(-r, -r);
context.lineTo(-r, -3 * r);
context.lineTo(r, -3 * r);
context.lineTo(r, -r);
context.lineTo(3 * r, -r);
context.lineTo(3 * r, r);
context.lineTo(r, r);
context.lineTo(r, 3 * r);
context.lineTo(-r, 3 * r);
context.lineTo(-r, r);
context.lineTo(-3 * r, r);
context.closePath();
}
};
var tan30 = Math.sqrt(1 / 3);
var tan30_2 = tan30 * 2;
var diamond = {
draw: function(context, size) {
var y = Math.sqrt(size / tan30_2),
x = y * tan30;
context.moveTo(0, -y);
context.lineTo(x, 0);
context.lineTo(0, y);
context.lineTo(-x, 0);
context.closePath();
}
};
var ka = 0.89081309152928522810;
var kr = Math.sin(pi$2 / 10) / Math.sin(7 * pi$2 / 10);
var kx = Math.sin(tau$2 / 10) * kr;
var ky = -Math.cos(tau$2 / 10) * kr;
var star = {
draw: function(context, size) {
var r = Math.sqrt(size * ka),
x = kx * r,
y = ky * r;
context.moveTo(0, -r);
context.lineTo(x, y);
for (var i = 1; i < 5; ++i) {
var a = tau$2 * i / 5,
c = Math.cos(a),
s = Math.sin(a);
context.lineTo(s * r, -c * r);
context.lineTo(c * x - s * y, s * x + c * y);
}
context.closePath();
}
};
var square = {
draw: function(context, size) {
var w = Math.sqrt(size),
x = -w / 2;
context.rect(x, x, w, w);
}
};
var sqrt3 = Math.sqrt(3);
var triangle = {
draw: function(context, size) {
var y = -Math.sqrt(size / (sqrt3 * 3));
context.moveTo(0, y * 2);
context.lineTo(-sqrt3 * y, -y);
context.lineTo(sqrt3 * y, -y);
context.closePath();
}
};
var c = -0.5;
var s = Math.sqrt(3) / 2;
var k = 1 / Math.sqrt(12);
var a = (k / 2 + 1) * 3;
var wye = {
draw: function(context, size) {
var r = Math.sqrt(size / a),
x0 = r / 2,
y0 = r * k,
x1 = x0,
y1 = r * k + r,
x2 = -x1,
y2 = y1;
context.moveTo(x0, y0);
context.lineTo(x1, y1);
context.lineTo(x2, y2);
context.lineTo(c * x0 - s * y0, s * x0 + c * y0);
context.lineTo(c * x1 - s * y1, s * x1 + c * y1);
context.lineTo(c * x2 - s * y2, s * x2 + c * y2);
context.lineTo(c * x0 + s * y0, c * y0 - s * x0);
context.lineTo(c * x1 + s * y1, c * y1 - s * x1);
context.lineTo(c * x2 + s * y2, c * y2 - s * x2);
context.closePath();
}
};
var symbols = [
circle,
cross$1,
diamond,
square,
star,
triangle,
wye
];
function symbol() {
var type = constant$1(circle),
size = constant$1(64),
context = null;
function symbol() {
var buffer;
if (!context) context = buffer = path();
type.apply(this, arguments).draw(context, +size.apply(this, arguments));
if (buffer) return context = null, buffer + "" || null;
}
symbol.type = function(_) {
return arguments.length ? (type = typeof _ === "function" ? _ : constant$1(_), symbol) : type;
};
symbol.size = function(_) {
return arguments.length ? (size = typeof _ === "function" ? _ : constant$1(+_), symbol) : size;
};
symbol.context = function(_) {
return arguments.length ? (context = _ == null ? null : _, symbol) : context;
};
return symbol;
}
function noop() {}
function point(that, x, y) {
that._context.bezierCurveTo(
(2 * that._x0 + that._x1) / 3,
(2 * that._y0 + that._y1) / 3,
(that._x0 + 2 * that._x1) / 3,
(that._y0 + 2 * that._y1) / 3,
(that._x0 + 4 * that._x1 + x) / 6,
(that._y0 + 4 * that._y1 + y) / 6
);
}
function Basis(context) {
this._context = context;
}
Basis.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 3: point(this, this._x1, this._y1); // proceed
case 2: this._context.lineTo(this._x1, this._y1); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; break;
case 2: this._point = 3; this._context.lineTo((5 * this._x0 + this._x1) / 6, (5 * this._y0 + this._y1) / 6); // proceed
default: point(this, x, y); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
}
};
function basis(context) {
return new Basis(context);
}
function BasisClosed(context) {
this._context = context;
}
BasisClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 1: {
this._context.moveTo(this._x2, this._y2);
this._context.closePath();
break;
}
case 2: {
this._context.moveTo((this._x2 + 2 * this._x3) / 3, (this._y2 + 2 * this._y3) / 3);
this._context.lineTo((this._x3 + 2 * this._x2) / 3, (this._y3 + 2 * this._y2) / 3);
this._context.closePath();
break;
}
case 3: {
this.point(this._x2, this._y2);
this.point(this._x3, this._y3);
this.point(this._x4, this._y4);
break;
}
}
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._x2 = x, this._y2 = y; break;
case 1: this._point = 2; this._x3 = x, this._y3 = y; break;
case 2: this._point = 3; this._x4 = x, this._y4 = y; this._context.moveTo((this._x0 + 4 * this._x1 + x) / 6, (this._y0 + 4 * this._y1 + y) / 6); break;
default: point(this, x, y); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
}
};
function basisClosed(context) {
return new BasisClosed(context);
}
function BasisOpen(context) {
this._context = context;
}
BasisOpen.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 = NaN;
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; break;
case 1: this._point = 2; break;
case 2: this._point = 3; var x0 = (this._x0 + 4 * this._x1 + x) / 6, y0 = (this._y0 + 4 * this._y1 + y) / 6; this._line ? this._context.lineTo(x0, y0) : this._context.moveTo(x0, y0); break;
case 3: this._point = 4; // proceed
default: point(this, x, y); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
}
};
function basisOpen(context) {
return new BasisOpen(context);
}
function Bundle(context, beta) {
this._basis = new Basis(context);
this._beta = beta;
}
Bundle.prototype = {
lineStart: function() {
this._x = [];
this._y = [];
this._basis.lineStart();
},
lineEnd: function() {
var x = this._x,
y = this._y,
j = x.length - 1;
if (j > 0) {
var x0 = x[0],
y0 = y[0],
dx = x[j] - x0,
dy = y[j] - y0,
i = -1,
t;
while (++i <= j) {
t = i / j;
this._basis.point(
this._beta * x[i] + (1 - this._beta) * (x0 + t * dx),
this._beta * y[i] + (1 - this._beta) * (y0 + t * dy)
);
}
}
this._x = this._y = null;
this._basis.lineEnd();
},
point: function(x, y) {
this._x.push(+x);
this._y.push(+y);
}
};
var bundle = (function custom(beta) {
function bundle(context) {
return beta === 1 ? new Basis(context) : new Bundle(context, beta);
}
bundle.beta = function(beta) {
return custom(+beta);
};
return bundle;
})(0.85);
function point$1(that, x, y) {
that._context.bezierCurveTo(
that._x1 + that._k * (that._x2 - that._x0),
that._y1 + that._k * (that._y2 - that._y0),
that._x2 + that._k * (that._x1 - x),
that._y2 + that._k * (that._y1 - y),
that._x2,
that._y2
);
}
function Cardinal(context, tension) {
this._context = context;
this._k = (1 - tension) / 6;
}
Cardinal.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 2: this._context.lineTo(this._x2, this._y2); break;
case 3: point$1(this, this._x1, this._y1); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; this._x1 = x, this._y1 = y; break;
case 2: this._point = 3; // proceed
default: point$1(this, x, y); break;
}
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var cardinal = (function custom(tension) {
function cardinal(context) {
return new Cardinal(context, tension);
}
cardinal.tension = function(tension) {
return custom(+tension);
};
return cardinal;
})(0);
function CardinalClosed(context, tension) {
this._context = context;
this._k = (1 - tension) / 6;
}
CardinalClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 1: {
this._context.moveTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 2: {
this._context.lineTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 3: {
this.point(this._x3, this._y3);
this.point(this._x4, this._y4);
this.point(this._x5, this._y5);
break;
}
}
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
default: point$1(this, x, y); break;
}
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var cardinalClosed = (function custom(tension) {
function cardinal(context) {
return new CardinalClosed(context, tension);
}
cardinal.tension = function(tension) {
return custom(+tension);
};
return cardinal;
})(0);
function CardinalOpen(context, tension) {
this._context = context;
this._k = (1 - tension) / 6;
}
CardinalOpen.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; break;
case 1: this._point = 2; break;
case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
case 3: this._point = 4; // proceed
default: point$1(this, x, y); break;
}
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var cardinalOpen = (function custom(tension) {
function cardinal(context) {
return new CardinalOpen(context, tension);
}
cardinal.tension = function(tension) {
return custom(+tension);
};
return cardinal;
})(0);
function point$2(that, x, y) {
var x1 = that._x1,
y1 = that._y1,
x2 = that._x2,
y2 = that._y2;
if (that._l01_a > epsilon$1) {
var a = 2 * that._l01_2a + 3 * that._l01_a * that._l12_a + that._l12_2a,
n = 3 * that._l01_a * (that._l01_a + that._l12_a);
x1 = (x1 * a - that._x0 * that._l12_2a + that._x2 * that._l01_2a) / n;
y1 = (y1 * a - that._y0 * that._l12_2a + that._y2 * that._l01_2a) / n;
}
if (that._l23_a > epsilon$1) {
var b = 2 * that._l23_2a + 3 * that._l23_a * that._l12_a + that._l12_2a,
m = 3 * that._l23_a * (that._l23_a + that._l12_a);
x2 = (x2 * b + that._x1 * that._l23_2a - x * that._l12_2a) / m;
y2 = (y2 * b + that._y1 * that._l23_2a - y * that._l12_2a) / m;
}
that._context.bezierCurveTo(x1, y1, x2, y2, that._x2, that._y2);
}
function CatmullRom(context, alpha) {
this._context = context;
this._alpha = alpha;
}
CatmullRom.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._l01_a = this._l12_a = this._l23_a =
this._l01_2a = this._l12_2a = this._l23_2a =
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 2: this._context.lineTo(this._x2, this._y2); break;
case 3: this.point(this, this._x2, this._y2); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) {
var x23 = this._x2 - x,
y23 = this._y2 - y;
this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
}
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; break;
case 2: this._point = 3; // proceed
default: point$2(this, x, y); break;
}
this._l01_a = this._l12_a, this._l12_a = this._l23_a;
this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var catmullRom = (function custom(alpha) {
function catmullRom(context) {
return alpha ? new CatmullRom(context, alpha) : new Cardinal(context, 0);
}
catmullRom.alpha = function(alpha) {
return custom(+alpha);
};
return catmullRom;
})(0.5);
function CatmullRomClosed(context, alpha) {
this._context = context;
this._alpha = alpha;
}
CatmullRomClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._x0 = this._x1 = this._x2 = this._x3 = this._x4 = this._x5 =
this._y0 = this._y1 = this._y2 = this._y3 = this._y4 = this._y5 = NaN;
this._l01_a = this._l12_a = this._l23_a =
this._l01_2a = this._l12_2a = this._l23_2a =
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 1: {
this._context.moveTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 2: {
this._context.lineTo(this._x3, this._y3);
this._context.closePath();
break;
}
case 3: {
this.point(this._x3, this._y3);
this.point(this._x4, this._y4);
this.point(this._x5, this._y5);
break;
}
}
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) {
var x23 = this._x2 - x,
y23 = this._y2 - y;
this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
}
switch (this._point) {
case 0: this._point = 1; this._x3 = x, this._y3 = y; break;
case 1: this._point = 2; this._context.moveTo(this._x4 = x, this._y4 = y); break;
case 2: this._point = 3; this._x5 = x, this._y5 = y; break;
default: point$2(this, x, y); break;
}
this._l01_a = this._l12_a, this._l12_a = this._l23_a;
this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var catmullRomClosed = (function custom(alpha) {
function catmullRom(context) {
return alpha ? new CatmullRomClosed(context, alpha) : new CardinalClosed(context, 0);
}
catmullRom.alpha = function(alpha) {
return custom(+alpha);
};
return catmullRom;
})(0.5);
function CatmullRomOpen(context, alpha) {
this._context = context;
this._alpha = alpha;
}
CatmullRomOpen.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 = this._x2 =
this._y0 = this._y1 = this._y2 = NaN;
this._l01_a = this._l12_a = this._l23_a =
this._l01_2a = this._l12_2a = this._l23_2a =
this._point = 0;
},
lineEnd: function() {
if (this._line || (this._line !== 0 && this._point === 3)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) {
var x23 = this._x2 - x,
y23 = this._y2 - y;
this._l23_a = Math.sqrt(this._l23_2a = Math.pow(x23 * x23 + y23 * y23, this._alpha));
}
switch (this._point) {
case 0: this._point = 1; break;
case 1: this._point = 2; break;
case 2: this._point = 3; this._line ? this._context.lineTo(this._x2, this._y2) : this._context.moveTo(this._x2, this._y2); break;
case 3: this._point = 4; // proceed
default: point$2(this, x, y); break;
}
this._l01_a = this._l12_a, this._l12_a = this._l23_a;
this._l01_2a = this._l12_2a, this._l12_2a = this._l23_2a;
this._x0 = this._x1, this._x1 = this._x2, this._x2 = x;
this._y0 = this._y1, this._y1 = this._y2, this._y2 = y;
}
};
var catmullRomOpen = (function custom(alpha) {
function catmullRom(context) {
return alpha ? new CatmullRomOpen(context, alpha) : new CardinalOpen(context, 0);
}
catmullRom.alpha = function(alpha) {
return custom(+alpha);
};
return catmullRom;
})(0.5);
function LinearClosed(context) {
this._context = context;
}
LinearClosed.prototype = {
areaStart: noop,
areaEnd: noop,
lineStart: function() {
this._point = 0;
},
lineEnd: function() {
if (this._point) this._context.closePath();
},
point: function(x, y) {
x = +x, y = +y;
if (this._point) this._context.lineTo(x, y);
else this._point = 1, this._context.moveTo(x, y);
}
};
function linearClosed(context) {
return new LinearClosed(context);
}
function sign(x) {
return x < 0 ? -1 : 1;
}
// Calculate the slopes of the tangents (Hermite-type interpolation) based on
// the following paper: Steffen, M. 1990. A Simple Method for Monotonic
// Interpolation in One Dimension. Astronomy and Astrophysics, Vol. 239, NO.
// NOV(II), P. 443, 1990.
function slope3(that, x2, y2) {
var h0 = that._x1 - that._x0,
h1 = x2 - that._x1,
s0 = (that._y1 - that._y0) / (h0 || h1 < 0 && -0),
s1 = (y2 - that._y1) / (h1 || h0 < 0 && -0),
p = (s0 * h1 + s1 * h0) / (h0 + h1);
return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;
}
// Calculate a one-sided slope.
function slope2(that, t) {
var h = that._x1 - that._x0;
return h ? (3 * (that._y1 - that._y0) / h - t) / 2 : t;
}
// According to https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Representations
// "you can express cubic Hermite interpolation in terms of cubic Bézier curves
// with respect to the four values p0, p0 + m0 / 3, p1 - m1 / 3, p1".
function point$3(that, t0, t1) {
var x0 = that._x0,
y0 = that._y0,
x1 = that._x1,
y1 = that._y1,
dx = (x1 - x0) / 3;
that._context.bezierCurveTo(x0 + dx, y0 + dx * t0, x1 - dx, y1 - dx * t1, x1, y1);
}
function MonotoneX(context) {
this._context = context;
}
MonotoneX.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x0 = this._x1 =
this._y0 = this._y1 =
this._t0 = NaN;
this._point = 0;
},
lineEnd: function() {
switch (this._point) {
case 2: this._context.lineTo(this._x1, this._y1); break;
case 3: point$3(this, this._t0, slope2(this, this._t0)); break;
}
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
this._line = 1 - this._line;
},
point: function(x, y) {
var t1 = NaN;
x = +x, y = +y;
if (x === this._x1 && y === this._y1) return; // Ignore coincident points.
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; break;
case 2: this._point = 3; point$3(this, slope2(this, t1 = slope3(this, x, y)), t1); break;
default: point$3(this, this._t0, t1 = slope3(this, x, y)); break;
}
this._x0 = this._x1, this._x1 = x;
this._y0 = this._y1, this._y1 = y;
this._t0 = t1;
}
}
function MonotoneY(context) {
this._context = new ReflectContext(context);
}
(MonotoneY.prototype = Object.create(MonotoneX.prototype)).point = function(x, y) {
MonotoneX.prototype.point.call(this, y, x);
};
function ReflectContext(context) {
this._context = context;
}
ReflectContext.prototype = {
moveTo: function(x, y) { this._context.moveTo(y, x); },
closePath: function() { this._context.closePath(); },
lineTo: function(x, y) { this._context.lineTo(y, x); },
bezierCurveTo: function(x1, y1, x2, y2, x, y) { this._context.bezierCurveTo(y1, x1, y2, x2, y, x); }
};
function monotoneX(context) {
return new MonotoneX(context);
}
function monotoneY(context) {
return new MonotoneY(context);
}
function Natural(context) {
this._context = context;
}
Natural.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x = [];
this._y = [];
},
lineEnd: function() {
var x = this._x,
y = this._y,
n = x.length;
if (n) {
this._line ? this._context.lineTo(x[0], y[0]) : this._context.moveTo(x[0], y[0]);
if (n === 2) {
this._context.lineTo(x[1], y[1]);
} else {
var px = controlPoints(x),
py = controlPoints(y);
for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) {
this._context.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]);
}
}
}
if (this._line || (this._line !== 0 && n === 1)) this._context.closePath();
this._line = 1 - this._line;
this._x = this._y = null;
},
point: function(x, y) {
this._x.push(+x);
this._y.push(+y);
}
};
// See https://www.particleincell.com/2012/bezier-splines/ for derivation.
function controlPoints(x) {
var i,
n = x.length - 1,
m,
a = new Array(n),
b = new Array(n),
r = new Array(n);
a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1];
for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1];
a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n];
for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1];
a[n - 1] = r[n - 1] / b[n - 1];
for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i];
b[n - 1] = (x[n] + a[n - 1]) / 2;
for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1];
return [a, b];
}
function natural(context) {
return new Natural(context);
}
function Step(context, t) {
this._context = context;
this._t = t;
}
Step.prototype = {
areaStart: function() {
this._line = 0;
},
areaEnd: function() {
this._line = NaN;
},
lineStart: function() {
this._x = this._y = NaN;
this._point = 0;
},
lineEnd: function() {
if (0 < this._t && this._t < 1 && this._point === 2) this._context.lineTo(this._x, this._y);
if (this._line || (this._line !== 0 && this._point === 1)) this._context.closePath();
if (this._line >= 0) this._t = 1 - this._t, this._line = 1 - this._line;
},
point: function(x, y) {
x = +x, y = +y;
switch (this._point) {
case 0: this._point = 1; this._line ? this._context.lineTo(x, y) : this._context.moveTo(x, y); break;
case 1: this._point = 2; // proceed
default: {
if (this._t <= 0) {
this._context.lineTo(this._x, y);
this._context.lineTo(x, y);
} else {
var x1 = this._x * (1 - this._t) + x * this._t;
this._context.lineTo(x1, this._y);
this._context.lineTo(x1, y);
}
break;
}
}
this._x = x, this._y = y;
}
};
function step(context) {
return new Step(context, 0.5);
}
function stepBefore(context) {
return new Step(context, 0);
}
function stepAfter(context) {
return new Step(context, 1);
}
var slice$2 = Array.prototype.slice;
function none(series, order) {
if (!((n = series.length) > 1)) return;
for (var i = 1, s0, s1 = series[order[0]], n, m = s1.length; i < n; ++i) {
s0 = s1, s1 = series[order[i]];
for (var j = 0; j < m; ++j) {
s1[j][1] += s1[j][0] = isNaN(s0[j][1]) ? s0[j][0] : s0[j][1];
}
}
}
function none$1(series) {
var n = series.length, o = new Array(n);
while (--n >= 0) o[n] = n;
return o;
}
function stackValue(d, key) {
return d[key];
}
function stack() {
var keys = constant$1([]),
order = none$1,
offset = none,
value = stackValue;
function stack(data) {
var kz = keys.apply(this, arguments),
i,
m = data.length,
n = kz.length,
sz = new Array(n),
oz;
for (i = 0; i < n; ++i) {
for (var ki = kz[i], si = sz[i] = new Array(m), j = 0, sij; j < m; ++j) {
si[j] = sij = [0, +value(data[j], ki, j, data)];
sij.data = data[j];
}
si.key = ki;
}
for (i = 0, oz = order(sz); i < n; ++i) {
sz[oz[i]].index = i;
}
offset(sz, oz);
return sz;
}
stack.keys = function(_) {
return arguments.length ? (keys = typeof _ === "function" ? _ : constant$1(slice$2.call(_)), stack) : keys;
};
stack.value = function(_) {
return arguments.length ? (value = typeof _ === "function" ? _ : constant$1(+_), stack) : value;
};
stack.order = function(_) {
return arguments.length ? (order = _ == null ? none$1 : typeof _ === "function" ? _ : constant$1(slice$2.call(_)), stack) : order;
};
stack.offset = function(_) {
return arguments.length ? (offset = _ == null ? none : _, stack) : offset;
};
return stack;
}
function expand(series, order) {
if (!((n = series.length) > 0)) return;
for (var i, n, j = 0, m = series[0].length, y; j < m; ++j) {
for (y = i = 0; i < n; ++i) y += series[i][j][1] || 0;
if (y) for (i = 0; i < n; ++i) series[i][j][1] /= y;
}
none(series, order);
}
function silhouette(series, order) {
if (!((n = series.length) > 0)) return;
for (var j = 0, s0 = series[order[0]], n, m = s0.length; j < m; ++j) {
for (var i = 0, y = 0; i < n; ++i) y += series[i][j][1] || 0;
s0[j][1] += s0[j][0] = -y / 2;
}
none(series, order);
}
function wiggle(series, order) {
if (!((n = series.length) > 0) || !((m = (s0 = series[order[0]]).length) > 0)) return;
for (var y = 0, j = 1, s0, m, n; j < m; ++j) {
for (var i = 0, s1 = 0, s2 = 0; i < n; ++i) {
var si = series[order[i]],
sij0 = si[j][1] || 0,
sij1 = si[j - 1][1] || 0,
s3 = (sij0 - sij1) / 2;
for (var k = 0; k < i; ++k) {
var sk = series[order[k]],
skj0 = sk[j][1] || 0,
skj1 = sk[j - 1][1] || 0;
s3 += skj0 - skj1;
}
s1 += sij0, s2 += s3 * sij0;
}
s0[j - 1][1] += s0[j - 1][0] = y;
if (s1) y -= s2 / s1;
}
s0[j - 1][1] += s0[j - 1][0] = y;
none(series, order);
}
function ascending$1(series) {
var sums = series.map(sum$1);
return none$1(series).sort(function(a, b) { return sums[a] - sums[b]; });
}
function sum$1(series) {
var s = 0, i = -1, n = series.length, v;
while (++i < n) if (v = +series[i][1]) s += v;
return s;
}
function descending$2(series) {
return ascending$1(series).reverse();
}
function insideOut(series) {
var n = series.length,
i,
j,
sums = series.map(sum$1),
order = none$1(series).sort(function(a, b) { return sums[b] - sums[a]; }),
top = 0,
bottom = 0,
tops = [],
bottoms = [];
for (i = 0; i < n; ++i) {
j = order[i];
if (top < bottom) {
top += sums[j];
tops.push(j);
} else {
bottom += sums[j];
bottoms.push(j);
}
}
return bottoms.reverse().concat(tops);
}
function reverse(series) {
return none$1(series).reverse();
}
function define(constructor, factory, prototype) {
constructor.prototype = factory.prototype = prototype;
prototype.constructor = constructor;
}
function extend(parent, definition) {
var prototype = Object.create(parent.prototype);
for (var key in definition) prototype[key] = definition[key];
return prototype;
}
function Color() {}
var darker = 0.7;
var brighter = 1 / darker;
var reHex3 = /^#([0-9a-f]{3})$/;
var reHex6 = /^#([0-9a-f]{6})$/;
var reRgbInteger = /^rgb\(\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*\)$/;
var reRgbPercent = /^rgb\(\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*\)$/;
var reRgbaInteger = /^rgba\(\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*,\s*([-+]?\d+)\s*,\s*([-+]?\d+(?:\.\d+)?)\s*\)$/;
var reRgbaPercent = /^rgba\(\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)\s*\)$/;
var reHslPercent = /^hsl\(\s*([-+]?\d+(?:\.\d+)?)\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*\)$/;
var reHslaPercent = /^hsla\(\s*([-+]?\d+(?:\.\d+)?)\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)%\s*,\s*([-+]?\d+(?:\.\d+)?)\s*\)$/;
var named = {
aliceblue: 0xf0f8ff,
antiquewhite: 0xfaebd7,
aqua: 0x00ffff,
aquamarine: 0x7fffd4,
azure: 0xf0ffff,
beige: 0xf5f5dc,
bisque: 0xffe4c4,
black: 0x000000,
blanchedalmond: 0xffebcd,
blue: 0x0000ff,
blueviolet: 0x8a2be2,
brown: 0xa52a2a,
burlywood: 0xdeb887,
cadetblue: 0x5f9ea0,
chartreuse: 0x7fff00,
chocolate: 0xd2691e,
coral: 0xff7f50,
cornflowerblue: 0x6495ed,
cornsilk: 0xfff8dc,
crimson: 0xdc143c,
cyan: 0x00ffff,
darkblue: 0x00008b,
darkcyan: 0x008b8b,
darkgoldenrod: 0xb8860b,
darkgray: 0xa9a9a9,
darkgreen: 0x006400,
darkgrey: 0xa9a9a9,
darkkhaki: 0xbdb76b,
darkmagenta: 0x8b008b,
darkolivegreen: 0x556b2f,
darkorange: 0xff8c00,
darkorchid: 0x9932cc,
darkred: 0x8b0000,
darksalmon: 0xe9967a,
darkseagreen: 0x8fbc8f,
darkslateblue: 0x483d8b,
darkslategray: 0x2f4f4f,
darkslategrey: 0x2f4f4f,
darkturquoise: 0x00ced1,
darkviolet: 0x9400d3,
deeppink: 0xff1493,
deepskyblue: 0x00bfff,
dimgray: 0x696969,
dimgrey: 0x696969,
dodgerblue: 0x1e90ff,
firebrick: 0xb22222,
floralwhite: 0xfffaf0,
forestgreen: 0x228b22,
fuchsia: 0xff00ff,
gainsboro: 0xdcdcdc,
ghostwhite: 0xf8f8ff,
gold: 0xffd700,
goldenrod: 0xdaa520,
gray: 0x808080,
green: 0x008000,
greenyellow: 0xadff2f,
grey: 0x808080,
honeydew: 0xf0fff0,
hotpink: 0xff69b4,
indianred: 0xcd5c5c,
indigo: 0x4b0082,
ivory: 0xfffff0,
khaki: 0xf0e68c,
lavender: 0xe6e6fa,
lavenderblush: 0xfff0f5,
lawngreen: 0x7cfc00,
lemonchiffon: 0xfffacd,
lightblue: 0xadd8e6,
lightcoral: 0xf08080,
lightcyan: 0xe0ffff,
lightgoldenrodyellow: 0xfafad2,
lightgray: 0xd3d3d3,
lightgreen: 0x90ee90,
lightgrey: 0xd3d3d3,
lightpink: 0xffb6c1,
lightsalmon: 0xffa07a,
lightseagreen: 0x20b2aa,
lightskyblue: 0x87cefa,
lightslategray: 0x778899,
lightslategrey: 0x778899,
lightsteelblue: 0xb0c4de,
lightyellow: 0xffffe0,
lime: 0x00ff00,
limegreen: 0x32cd32,
linen: 0xfaf0e6,
magenta: 0xff00ff,
maroon: 0x800000,
mediumaquamarine: 0x66cdaa,
mediumblue: 0x0000cd,
mediumorchid: 0xba55d3,
mediumpurple: 0x9370db,
mediumseagreen: 0x3cb371,
mediumslateblue: 0x7b68ee,
mediumspringgreen: 0x00fa9a,
mediumturquoise: 0x48d1cc,
mediumvioletred: 0xc71585,
midnightblue: 0x191970,
mintcream: 0xf5fffa,
mistyrose: 0xffe4e1,
moccasin: 0xffe4b5,
navajowhite: 0xffdead,
navy: 0x000080,
oldlace: 0xfdf5e6,
olive: 0x808000,
olivedrab: 0x6b8e23,
orange: 0xffa500,
orangered: 0xff4500,
orchid: 0xda70d6,
palegoldenrod: 0xeee8aa,
palegreen: 0x98fb98,
paleturquoise: 0xafeeee,
palevioletred: 0xdb7093,
papayawhip: 0xffefd5,
peachpuff: 0xffdab9,
peru: 0xcd853f,
pink: 0xffc0cb,
plum: 0xdda0dd,
powderblue: 0xb0e0e6,
purple: 0x800080,
rebeccapurple: 0x663399,
red: 0xff0000,
rosybrown: 0xbc8f8f,
royalblue: 0x4169e1,
saddlebrown: 0x8b4513,
salmon: 0xfa8072,
sandybrown: 0xf4a460,
seagreen: 0x2e8b57,
seashell: 0xfff5ee,
sienna: 0xa0522d,
silver: 0xc0c0c0,
skyblue: 0x87ceeb,
slateblue: 0x6a5acd,
slategray: 0x708090,
slategrey: 0x708090,
snow: 0xfffafa,
springgreen: 0x00ff7f,
steelblue: 0x4682b4,
tan: 0xd2b48c,
teal: 0x008080,
thistle: 0xd8bfd8,
tomato: 0xff6347,
turquoise: 0x40e0d0,
violet: 0xee82ee,
wheat: 0xf5deb3,
white: 0xffffff,
whitesmoke: 0xf5f5f5,
yellow: 0xffff00,
yellowgreen: 0x9acd32
};
define(Color, color, {
displayable: function() {
return this.rgb().displayable();
},
toString: function() {
return this.rgb() + "";
}
});
function color(format) {
var m;
format = (format + "").trim().toLowerCase();
return (m = reHex3.exec(format)) ? (m = parseInt(m[1], 16), new Rgb((m >> 8 & 0xf) | (m >> 4 & 0x0f0), (m >> 4 & 0xf) | (m & 0xf0), ((m & 0xf) << 4) | (m & 0xf), 1)) // #f00
: (m = reHex6.exec(format)) ? rgbn(parseInt(m[1], 16)) // #ff0000
: (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) // rgb(255, 0, 0)
: (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) // rgb(100%, 0%, 0%)
: (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) // rgba(255, 0, 0, 1)
: (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) // rgb(100%, 0%, 0%, 1)
: (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) // hsl(120, 50%, 50%)
: (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) // hsla(120, 50%, 50%, 1)
: named.hasOwnProperty(format) ? rgbn(named[format])
: format === "transparent" ? new Rgb(NaN, NaN, NaN, 0)
: null;
}
function rgbn(n) {
return new Rgb(n >> 16 & 0xff, n >> 8 & 0xff, n & 0xff, 1);
}
function rgba(r, g, b, a) {
if (a <= 0) r = g = b = NaN;
return new Rgb(r, g, b, a);
}
function rgbConvert(o) {
if (!(o instanceof Color)) o = color(o);
if (!o) return new Rgb;
o = o.rgb();
return new Rgb(o.r, o.g, o.b, o.opacity);
}
function colorRgb(r, g, b, opacity) {
return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
}
function Rgb(r, g, b, opacity) {
this.r = +r;
this.g = +g;
this.b = +b;
this.opacity = +opacity;
}
define(Rgb, colorRgb, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
rgb: function() {
return this;
},
displayable: function() {
return (0 <= this.r && this.r <= 255)
&& (0 <= this.g && this.g <= 255)
&& (0 <= this.b && this.b <= 255)
&& (0 <= this.opacity && this.opacity <= 1);
},
toString: function() {
var a = this.opacity; a = isNaN(a) ? 1 : Math.max(0, Math.min(1, a));
return (a === 1 ? "rgb(" : "rgba(")
+ Math.max(0, Math.min(255, Math.round(this.r) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.g) || 0)) + ", "
+ Math.max(0, Math.min(255, Math.round(this.b) || 0))
+ (a === 1 ? ")" : ", " + a + ")");
}
}));
function hsla(h, s, l, a) {
if (a <= 0) h = s = l = NaN;
else if (l <= 0 || l >= 1) h = s = NaN;
else if (s <= 0) h = NaN;
return new Hsl(h, s, l, a);
}
function hslConvert(o) {
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Color)) o = color(o);
if (!o) return new Hsl;
if (o instanceof Hsl) return o;
o = o.rgb();
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
min = Math.min(r, g, b),
max = Math.max(r, g, b),
h = NaN,
s = max - min,
l = (max + min) / 2;
if (s) {
if (r === max) h = (g - b) / s + (g < b) * 6;
else if (g === max) h = (b - r) / s + 2;
else h = (r - g) / s + 4;
s /= l < 0.5 ? max + min : 2 - max - min;
h *= 60;
} else {
s = l > 0 && l < 1 ? 0 : h;
}
return new Hsl(h, s, l, o.opacity);
}
function colorHsl(h, s, l, opacity) {
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
}
function Hsl(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Hsl, colorHsl, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = this.h % 360 + (this.h < 0) * 360,
s = isNaN(h) || isNaN(this.s) ? 0 : this.s,
l = this.l,
m2 = l + (l < 0.5 ? l : 1 - l) * s,
m1 = 2 * l - m2;
return new Rgb(
hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2),
hsl2rgb(h, m1, m2),
hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2),
this.opacity
);
},
displayable: function() {
return (0 <= this.s && this.s <= 1 || isNaN(this.s))
&& (0 <= this.l && this.l <= 1)
&& (0 <= this.opacity && this.opacity <= 1);
}
}));
/* From FvD 13.37, CSS Color Module Level 3 */
function hsl2rgb(h, m1, m2) {
return (h < 60 ? m1 + (m2 - m1) * h / 60
: h < 180 ? m2
: h < 240 ? m1 + (m2 - m1) * (240 - h) / 60
: m1) * 255;
}
var deg2rad = Math.PI / 180;
var rad2deg = 180 / Math.PI;
var Kn = 18;
var Xn = 0.950470;
var Yn = 1;
var Zn = 1.088830;
var t0 = 4 / 29;
var t1 = 6 / 29;
var t2 = 3 * t1 * t1;
var t3 = t1 * t1 * t1;
function labConvert(o) {
if (o instanceof Lab) return new Lab(o.l, o.a, o.b, o.opacity);
if (o instanceof Hcl) {
var h = o.h * deg2rad;
return new Lab(o.l, Math.cos(h) * o.c, Math.sin(h) * o.c, o.opacity);
}
if (!(o instanceof Rgb)) o = rgbConvert(o);
var b = rgb2xyz(o.r),
a = rgb2xyz(o.g),
l = rgb2xyz(o.b),
x = xyz2lab((0.4124564 * b + 0.3575761 * a + 0.1804375 * l) / Xn),
y = xyz2lab((0.2126729 * b + 0.7151522 * a + 0.0721750 * l) / Yn),
z = xyz2lab((0.0193339 * b + 0.1191920 * a + 0.9503041 * l) / Zn);
return new Lab(116 * y - 16, 500 * (x - y), 200 * (y - z), o.opacity);
}
function lab(l, a, b, opacity) {
return arguments.length === 1 ? labConvert(l) : new Lab(l, a, b, opacity == null ? 1 : opacity);
}
function Lab(l, a, b, opacity) {
this.l = +l;
this.a = +a;
this.b = +b;
this.opacity = +opacity;
}
define(Lab, lab, extend(Color, {
brighter: function(k) {
return new Lab(this.l + Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
darker: function(k) {
return new Lab(this.l - Kn * (k == null ? 1 : k), this.a, this.b, this.opacity);
},
rgb: function() {
var y = (this.l + 16) / 116,
x = isNaN(this.a) ? y : y + this.a / 500,
z = isNaN(this.b) ? y : y - this.b / 200;
y = Yn * lab2xyz(y);
x = Xn * lab2xyz(x);
z = Zn * lab2xyz(z);
return new Rgb(
xyz2rgb( 3.2404542 * x - 1.5371385 * y - 0.4985314 * z), // D65 -> sRGB
xyz2rgb(-0.9692660 * x + 1.8760108 * y + 0.0415560 * z),
xyz2rgb( 0.0556434 * x - 0.2040259 * y + 1.0572252 * z),
this.opacity
);
}
}));
function xyz2lab(t) {
return t > t3 ? Math.pow(t, 1 / 3) : t / t2 + t0;
}
function lab2xyz(t) {
return t > t1 ? t * t * t : t2 * (t - t0);
}
function xyz2rgb(x) {
return 255 * (x <= 0.0031308 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055);
}
function rgb2xyz(x) {
return (x /= 255) <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
}
function hclConvert(o) {
if (o instanceof Hcl) return new Hcl(o.h, o.c, o.l, o.opacity);
if (!(o instanceof Lab)) o = labConvert(o);
var h = Math.atan2(o.b, o.a) * rad2deg;
return new Hcl(h < 0 ? h + 360 : h, Math.sqrt(o.a * o.a + o.b * o.b), o.l, o.opacity);
}
function colorHcl(h, c, l, opacity) {
return arguments.length === 1 ? hclConvert(h) : new Hcl(h, c, l, opacity == null ? 1 : opacity);
}
function Hcl(h, c, l, opacity) {
this.h = +h;
this.c = +c;
this.l = +l;
this.opacity = +opacity;
}
define(Hcl, colorHcl, extend(Color, {
brighter: function(k) {
return new Hcl(this.h, this.c, this.l + Kn * (k == null ? 1 : k), this.opacity);
},
darker: function(k) {
return new Hcl(this.h, this.c, this.l - Kn * (k == null ? 1 : k), this.opacity);
},
rgb: function() {
return labConvert(this).rgb();
}
}));
var A = -0.14861;
var B = +1.78277;
var C = -0.29227;
var D = -0.90649;
var E = +1.97294;
var ED = E * D;
var EB = E * B;
var BC_DA = B * C - D * A;
function cubehelixConvert(o) {
if (o instanceof Cubehelix) return new Cubehelix(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Rgb)) o = rgbConvert(o);
var r = o.r / 255,
g = o.g / 255,
b = o.b / 255,
l = (BC_DA * b + ED * r - EB * g) / (BC_DA + ED - EB),
bl = b - l,
k = (E * (g - l) - C * bl) / D,
s = Math.sqrt(k * k + bl * bl) / (E * l * (1 - l)), // NaN if l=0 or l=1
h = s ? Math.atan2(k, bl) * rad2deg - 120 : NaN;
return new Cubehelix(h < 0 ? h + 360 : h, s, l, o.opacity);
}
function cubehelix(h, s, l, opacity) {
return arguments.length === 1 ? cubehelixConvert(h) : new Cubehelix(h, s, l, opacity == null ? 1 : opacity);
}
function Cubehelix(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define(Cubehelix, cubehelix, extend(Color, {
brighter: function(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
darker: function(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Cubehelix(this.h, this.s, this.l * k, this.opacity);
},
rgb: function() {
var h = isNaN(this.h) ? 0 : (this.h + 120) * deg2rad,
l = +this.l,
a = isNaN(this.s) ? 0 : this.s * l * (1 - l),
cosh = Math.cos(h),
sinh = Math.sin(h);
return new Rgb(
255 * (l + a * (A * cosh + B * sinh)),
255 * (l + a * (C * cosh + D * sinh)),
255 * (l + a * (E * cosh)),
this.opacity
);
}
}));
function basis$1(t1, v0, v1, v2, v3) {
var t2 = t1 * t1, t3 = t2 * t1;
return ((1 - 3 * t1 + 3 * t2 - t3) * v0
+ (4 - 6 * t2 + 3 * t3) * v1
+ (1 + 3 * t1 + 3 * t2 - 3 * t3) * v2
+ t3 * v3) / 6;
}
function basis$2(values) {
var n = values.length - 1;
return function(t) {
var i = t <= 0 ? (t = 0) : t >= 1 ? (t = 1, n - 1) : Math.floor(t * n),
v1 = values[i],
v2 = values[i + 1],
v0 = i > 0 ? values[i - 1] : 2 * v1 - v2,
v3 = i < n - 1 ? values[i + 2] : 2 * v2 - v1;
return basis$1((t - i / n) * n, v0, v1, v2, v3);
};
}
function basisClosed$1(values) {
var n = values.length;
return function(t) {
var i = Math.floor(((t %= 1) < 0 ? ++t : t) * n),
v0 = values[(i + n - 1) % n],
v1 = values[i % n],
v2 = values[(i + 1) % n],
v3 = values[(i + 2) % n];
return basis$1((t - i / n) * n, v0, v1, v2, v3);
};
}
function constant$2(x) {
return function() {
return x;
};
}
function linear$1(a, d) {
return function(t) {
return a + t * d;
};
}
function exponential$1(a, b, y) {
return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
return Math.pow(a + t * b, y);
};
}
function hue(a, b) {
var d = b - a;
return d ? linear$1(a, d > 180 || d < -180 ? d - 360 * Math.round(d / 360) : d) : constant$2(isNaN(a) ? b : a);
}
function gamma(y) {
return (y = +y) === 1 ? nogamma : function(a, b) {
return b - a ? exponential$1(a, b, y) : constant$2(isNaN(a) ? b : a);
};
}
function nogamma(a, b) {
var d = b - a;
return d ? linear$1(a, d) : constant$2(isNaN(a) ? b : a);
}
var interpolateRgb = (function rgbGamma(y) {
var color = gamma(y);
function rgb(start, end) {
var r = color((start = colorRgb(start)).r, (end = colorRgb(end)).r),
g = color(start.g, end.g),
b = color(start.b, end.b),
opacity = color(start.opacity, end.opacity);
return function(t) {
start.r = r(t);
start.g = g(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
rgb.gamma = rgbGamma;
return rgb;
})(1);
function rgbSpline(spline) {
return function(colors) {
var n = colors.length,
r = new Array(n),
g = new Array(n),
b = new Array(n),
i, color;
for (i = 0; i < n; ++i) {
color = colorRgb(colors[i]);
r[i] = color.r || 0;
g[i] = color.g || 0;
b[i] = color.b || 0;
}
r = spline(r);
g = spline(g);
b = spline(b);
color.opacity = 1;
return function(t) {
color.r = r(t);
color.g = g(t);
color.b = b(t);
return color + "";
};
};
}
var rgbBasis = rgbSpline(basis$2);
var rgbBasisClosed = rgbSpline(basisClosed$1);
function array$1(a, b) {
var nb = b ? b.length : 0,
na = a ? Math.min(nb, a.length) : 0,
x = new Array(nb),
c = new Array(nb),
i;
for (i = 0; i < na; ++i) x[i] = interpolate(a[i], b[i]);
for (; i < nb; ++i) c[i] = b[i];
return function(t) {
for (i = 0; i < na; ++i) c[i] = x[i](t);
return c;
};
}
function date(a, b) {
var d = new Date;
return a = +a, b -= a, function(t) {
return d.setTime(a + b * t), d;
};
}
function interpolateNumber(a, b) {
return a = +a, b -= a, function(t) {
return a + b * t;
};
}
function object(a, b) {
var i = {},
c = {},
k;
if (a === null || typeof a !== "object") a = {};
if (b === null || typeof b !== "object") b = {};
for (k in b) {
if (k in a) {
i[k] = interpolate(a[k], b[k]);
} else {
c[k] = b[k];
}
}
return function(t) {
for (k in i) c[k] = i[k](t);
return c;
};
}
var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g;
var reB = new RegExp(reA.source, "g");
function zero(b) {
return function() {
return b;
};
}
function one(b) {
return function(t) {
return b(t) + "";
};
}
function interpolateString(a, b) {
var bi = reA.lastIndex = reB.lastIndex = 0, // scan index for next number in b
am, // current match in a
bm, // current match in b
bs, // string preceding current number in b, if any
i = -1, // index in s
s = [], // string constants and placeholders
q = []; // number interpolators
// Coerce inputs to strings.
a = a + "", b = b + "";
// Interpolate pairs of numbers in a & b.
while ((am = reA.exec(a))
&& (bm = reB.exec(b))) {
if ((bs = bm.index) > bi) { // a string precedes the next number in b
bs = b.slice(bi, bs);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
if ((am = am[0]) === (bm = bm[0])) { // numbers in a & b match
if (s[i]) s[i] += bm; // coalesce with previous string
else s[++i] = bm;
} else { // interpolate non-matching numbers
s[++i] = null;
q.push({i: i, x: interpolateNumber(am, bm)});
}
bi = reB.lastIndex;
}
// Add remains of b.
if (bi < b.length) {
bs = b.slice(bi);
if (s[i]) s[i] += bs; // coalesce with previous string
else s[++i] = bs;
}
// Special optimization for only a single match.
// Otherwise, interpolate each of the numbers and rejoin the string.
return s.length < 2 ? (q[0]
? one(q[0].x)
: zero(b))
: (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
}
function interpolate(a, b) {
var t = typeof b, c;
return b == null || t === "boolean" ? constant$2(b)
: (t === "number" ? interpolateNumber
: t === "string" ? ((c = color(b)) ? (b = c, interpolateRgb) : interpolateString)
: b instanceof color ? interpolateRgb
: b instanceof Date ? date
: Array.isArray(b) ? array$1
: isNaN(b) ? object
: interpolateNumber)(a, b);
}
function interpolateRound(a, b) {
return a = +a, b -= a, function(t) {
return Math.round(a + b * t);
};
}
var degrees = 180 / Math.PI;
var identity$2 = {
translateX: 0,
translateY: 0,
rotate: 0,
skewX: 0,
scaleX: 1,
scaleY: 1
};
function decompose(a, b, c, d, e, f) {
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * degrees,
skewX: Math.atan(skewX) * degrees,
scaleX: scaleX,
scaleY: scaleY
};
}
var cssNode;
var cssRoot;
var cssView;
var svgNode;
function parseCss(value) {
if (value === "none") return identity$2;
if (!cssNode) cssNode = document.createElement("DIV"), cssRoot = document.documentElement, cssView = document.defaultView;
cssNode.style.transform = value;
value = cssView.getComputedStyle(cssRoot.appendChild(cssNode), null).getPropertyValue("transform");
cssRoot.removeChild(cssNode);
value = value.slice(7, -1).split(",");
return decompose(+value[0], +value[1], +value[2], +value[3], +value[4], +value[5]);
}
function parseSvg(value) {
if (value == null) return identity$2;
if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
svgNode.setAttribute("transform", value);
if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
value = value.matrix;
return decompose(value.a, value.b, value.c, value.d, value.e, value.f);
}
function interpolateTransform(parse, pxComma, pxParen, degParen) {
function pop(s) {
return s.length ? s.pop() + " " : "";
}
function translate(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push("translate(", null, pxComma, null, pxParen);
q.push({i: i - 4, x: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(ya, yb)});
} else if (xb || yb) {
s.push("translate(" + xb + pxComma + yb + pxParen);
}
}
function rotate(a, b, s, q) {
if (a !== b) {
if (a - b > 180) b += 360; else if (b - a > 180) a += 360; // shortest path
q.push({i: s.push(pop(s) + "rotate(", null, degParen) - 2, x: interpolateNumber(a, b)});
} else if (b) {
s.push(pop(s) + "rotate(" + b + degParen);
}
}
function skewX(a, b, s, q) {
if (a !== b) {
q.push({i: s.push(pop(s) + "skewX(", null, degParen) - 2, x: interpolateNumber(a, b)});
} else if (b) {
s.push(pop(s) + "skewX(" + b + degParen);
}
}
function scale(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push(pop(s) + "scale(", null, ",", null, ")");
q.push({i: i - 4, x: interpolateNumber(xa, xb)}, {i: i - 2, x: interpolateNumber(ya, yb)});
} else if (xb !== 1 || yb !== 1) {
s.push(pop(s) + "scale(" + xb + "," + yb + ")");
}
}
return function(a, b) {
var s = [], // string constants and placeholders
q = []; // number interpolators
a = parse(a), b = parse(b);
translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
rotate(a.rotate, b.rotate, s, q);
skewX(a.skewX, b.skewX, s, q);
scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
a = b = null; // gc
return function(t) {
var i = -1, n = q.length, o;
while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
};
}
var interpolateTransform$1 = interpolateTransform(parseCss, "px, ", "px)", "deg)");
var interpolateTransform$2 = interpolateTransform(parseSvg, ", ", ")", ")");
var rho = Math.SQRT2;
var rho2 = 2;
var rho4 = 4;
var epsilon2 = 1e-12;
function cosh(x) {
return ((x = Math.exp(x)) + 1 / x) / 2;
}
function sinh(x) {
return ((x = Math.exp(x)) - 1 / x) / 2;
}
function tanh(x) {
return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
// p0 = [ux0, uy0, w0]
// p1 = [ux1, uy1, w1]
function interpolateZoom(p0, p1) {
var ux0 = p0[0], uy0 = p0[1], w0 = p0[2],
ux1 = p1[0], uy1 = p1[1], w1 = p1[2],
dx = ux1 - ux0,
dy = uy1 - uy0,
d2 = dx * dx + dy * dy,
i,
S;
// Special case for u0 ≅ u1.
if (d2 < epsilon2) {
S = Math.log(w1 / w0) / rho;
i = function(t) {
return [
ux0 + t * dx,
uy0 + t * dy,
w0 * Math.exp(rho * t * S)
];
}
}
// General case.
else {
var d1 = Math.sqrt(d2),
b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1),
b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1),
r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0),
r1 = Math.log(Math.sqrt(b1 * b1 + 1) - b1);
S = (r1 - r0) / rho;
i = function(t) {
var s = t * S,
coshr0 = cosh(r0),
u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
return [
ux0 + u * dx,
uy0 + u * dy,
w0 * coshr0 / cosh(rho * s + r0)
];
}
}
i.duration = S * 1000;
return i;
}
function hsl(hue) {
return function(start, end) {
var h = hue((start = colorHsl(start)).h, (end = colorHsl(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hsl$1 = hsl(hue);
var hslLong = hsl(nogamma);
function lab$1(start, end) {
var l = nogamma((start = lab(start)).l, (end = lab(end)).l),
a = nogamma(start.a, end.a),
b = nogamma(start.b, end.b),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.l = l(t);
start.a = a(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
function hcl(hue) {
return function(start, end) {
var h = hue((start = colorHcl(start)).h, (end = colorHcl(end)).h),
c = nogamma(start.c, end.c),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.c = c(t);
start.l = l(t);
start.opacity = opacity(t);
return start + "";
};
}
}
var hcl$1 = hcl(hue);
var hclLong = hcl(nogamma);
function cubehelix$1(hue) {
return (function cubehelixGamma(y) {
y = +y;
function cubehelix$$(start, end) {
var h = hue((start = cubehelix(start)).h, (end = cubehelix(end)).h),
s = nogamma(start.s, end.s),
l = nogamma(start.l, end.l),
opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.h = h(t);
start.s = s(t);
start.l = l(Math.pow(t, y));
start.opacity = opacity(t);
return start + "";
};
}
cubehelix$$.gamma = cubehelixGamma;
return cubehelix$$;
})(1);
}
var cubehelix$2 = cubehelix$1(hue);
var interpolateCubehelixLong = cubehelix$1(nogamma);
function quantize(interpolator, n) {
var samples = new Array(n);
for (var i = 0; i < n; ++i) samples[i] = interpolator(i / (n - 1));
return samples;
}
var noop$1 = {value: function() {}};
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || (t in _)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {type: t, name: name};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._,
T = parseTypenames(typename + "", _),
t,
i = -1,
n = T.length;
// If no callback was specified, return the callback of the given type and name.
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get(_[t], typename.name))) return t;
return;
}
// If a type was specified, set the callback for the given type and name.
// Otherwise, if a null callback was specified, remove callbacks of the given name.
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) {
if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null);
}
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) {
if ((c = type[i]).name === name) {
return c.value;
}
}
}
function set$1(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) {
if (type[i].name === name) {
type[i] = noop$1, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
}
if (callback != null) type.push({name: name, value: callback});
return type;
}
function objectConverter(columns) {
return new Function("d", "return {" + columns.map(function(name, i) {
return JSON.stringify(name) + ": d[" + i + "]";
}).join(",") + "}");
}
function customConverter(columns, f) {
var object = objectConverter(columns);
return function(row, i) {
return f(object(row), i, columns);
};
}
// Compute unique columns in order of discovery.
function inferColumns(rows) {
var columnSet = Object.create(null),
columns = [];
rows.forEach(function(row) {
for (var column in row) {
if (!(column in columnSet)) {
columns.push(columnSet[column] = column);
}
}
});
return columns;
}
function dsv(delimiter) {
var reFormat = new RegExp("[\"" + delimiter + "\n]"),
delimiterCode = delimiter.charCodeAt(0);
function parse(text, f) {
var convert, columns, rows = parseRows(text, function(row, i) {
if (convert) return convert(row, i - 1);
columns = row, convert = f ? customConverter(row, f) : objectConverter(row);
});
rows.columns = columns;
return rows;
}
function parseRows(text, f) {
var EOL = {}, // sentinel value for end-of-line
EOF = {}, // sentinel value for end-of-file
rows = [], // output rows
N = text.length,
I = 0, // current character index
n = 0, // the current line number
t, // the current token
eol; // is the current token followed by EOL?
function token() {
if (I >= N) return EOF; // special case: end of file
if (eol) return eol = false, EOL; // special case: end of line
// special case: quotes
var j = I, c;
if (text.charCodeAt(j) === 34) {
var i = j;
while (i++ < N) {
if (text.charCodeAt(i) === 34) {
if (text.charCodeAt(i + 1) !== 34) break;
++i;
}
}
I = i + 2;
c = text.charCodeAt(i + 1);
if (c === 13) {
eol = true;
if (text.charCodeAt(i + 2) === 10) ++I;
} else if (c === 10) {
eol = true;
}
return text.slice(j + 1, i).replace(/""/g, "\"");
}
// common case: find next delimiter or newline
while (I < N) {
var k = 1;
c = text.charCodeAt(I++);
if (c === 10) eol = true; // \n
else if (c === 13) { eol = true; if (text.charCodeAt(I) === 10) ++I, ++k; } // \r|\r\n
else if (c !== delimiterCode) continue;
return text.slice(j, I - k);
}
// special case: last token before EOF
return text.slice(j);
}
while ((t = token()) !== EOF) {
var a = [];
while (t !== EOL && t !== EOF) {
a.push(t);
t = token();
}
if (f && (a = f(a, n++)) == null) continue;
rows.push(a);
}
return rows;
}
function format(rows, columns) {
if (columns == null) columns = inferColumns(rows);
return [columns.map(formatValue).join(delimiter)].concat(rows.map(function(row) {
return columns.map(function(column) {
return formatValue(row[column]);
}).join(delimiter);
})).join("\n");
}
function formatRows(rows) {
return rows.map(formatRow).join("\n");
}
function formatRow(row) {
return row.map(formatValue).join(delimiter);
}
function formatValue(text) {
return text == null ? ""
: reFormat.test(text += "") ? "\"" + text.replace(/\"/g, "\"\"") + "\""
: text;
}
return {
parse: parse,
parseRows: parseRows,
format: format,
formatRows: formatRows
};
}
var csv = dsv(",");
var csvParse = csv.parse;
var csvParseRows = csv.parseRows;
var csvFormat = csv.format;
var csvFormatRows = csv.formatRows;
var tsv = dsv("\t");
var tsvParse = tsv.parse;
var tsvParseRows = tsv.parseRows;
var tsvFormat = tsv.format;
var tsvFormatRows = tsv.formatRows;
function request(url, callback) {
var request,
event = dispatch("beforesend", "progress", "load", "error"),
mimeType,
headers = map$1(),
xhr = new XMLHttpRequest,
user = null,
password = null,
response,
responseType,
timeout = 0;
// If IE does not support CORS, use XDomainRequest.
if (typeof XDomainRequest !== "undefined"
&& !("withCredentials" in xhr)
&& /^(http(s)?:)?\/\//.test(url)) xhr = new XDomainRequest;
"onload" in xhr
? xhr.onload = xhr.onerror = xhr.ontimeout = respond
: xhr.onreadystatechange = function(o) { xhr.readyState > 3 && respond(o); };
function respond(o) {
var status = xhr.status, result;
if (!status && hasResponse(xhr)
|| status >= 200 && status < 300
|| status === 304) {
if (response) {
try {
result = response.call(request, xhr);
} catch (e) {
event.call("error", request, e);
return;
}
} else {
result = xhr;
}
event.call("load", request, result);
} else {
event.call("error", request, o);
}
}
xhr.onprogress = function(e) {
event.call("progress", request, e);
};
request = {
header: function(name, value) {
name = (name + "").toLowerCase();
if (arguments.length < 2) return headers.get(name);
if (value == null) headers.remove(name);
else headers.set(name, value + "");
return request;
},
// If mimeType is non-null and no Accept header is set, a default is used.
mimeType: function(value) {
if (!arguments.length) return mimeType;
mimeType = value == null ? null : value + "";
return request;
},
// Specifies what type the response value should take;
// for instance, arraybuffer, blob, document, or text.
responseType: function(value) {
if (!arguments.length) return responseType;
responseType = value;
return request;
},
timeout: function(value) {
if (!arguments.length) return timeout;
timeout = +value;
return request;
},
user: function(value) {
return arguments.length < 1 ? user : (user = value == null ? null : value + "", request);
},
password: function(value) {
return arguments.length < 1 ? password : (password = value == null ? null : value + "", request);
},
// Specify how to convert the response content to a specific type;
// changes the callback value on "load" events.
response: function(value) {
response = value;
return request;
},
// Alias for send("GET", …).
get: function(data, callback) {
return request.send("GET", data, callback);
},
// Alias for send("POST", …).
post: function(data, callback) {
return request.send("POST", data, callback);
},
// If callback is non-null, it will be used for error and load events.
send: function(method, data, callback) {
xhr.open(method, url, true, user, password);
if (mimeType != null && !headers.has("accept")) headers.set("accept", mimeType + ",*/*");
if (xhr.setRequestHeader) headers.each(function(value, name) { xhr.setRequestHeader(name, value); });
if (mimeType != null && xhr.overrideMimeType) xhr.overrideMimeType(mimeType);
if (responseType != null) xhr.responseType = responseType;
if (timeout > 0) xhr.timeout = timeout;
if (callback == null && typeof data === "function") callback = data, data = null;
if (callback != null && callback.length === 1) callback = fixCallback(callback);
if (callback != null) request.on("error", callback).on("load", function(xhr) { callback(null, xhr); });
event.call("beforesend", request, xhr);
xhr.send(data == null ? null : data);
return request;
},
abort: function() {
xhr.abort();
return request;
},
on: function() {
var value = event.on.apply(event, arguments);
return value === event ? request : value;
}
};
if (callback != null) {
if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
return request.get(callback);
}
return request;
}
function fixCallback(callback) {
return function(error, xhr) {
callback(error == null ? xhr : null);
};
}
function hasResponse(xhr) {
var type = xhr.responseType;
return type && type !== "text"
? xhr.response // null on error
: xhr.responseText; // "" on error
}
function type(defaultMimeType, response) {
return function(url, callback) {
var r = request(url).mimeType(defaultMimeType).response(response);
if (callback != null) {
if (typeof callback !== "function") throw new Error("invalid callback: " + callback);
return r.get(callback);
}
return r;
};
}
var html = type("text/html", function(xhr) {
return document.createRange().createContextualFragment(xhr.responseText);
});
var json = type("application/json", function(xhr) {
return JSON.parse(xhr.responseText);
});
var text = type("text/plain", function(xhr) {
return xhr.responseText;
});
var xml = type("application/xml", function(xhr) {
var xml = xhr.responseXML;
if (!xml) throw new Error("parse error");
return xml;
});
function dsv$1(defaultMimeType, parse) {
return function(url, row, callback) {
if (arguments.length < 3) callback = row, row = null;
var r = request(url).mimeType(defaultMimeType);
r.row = function(_) { return arguments.length ? r.response(responseOf(parse, row = _)) : row; };
r.row(row);
return callback ? r.get(callback) : r;
};
}
function responseOf(parse, row) {
return function(request) {
return parse(request.responseText, row);
};
}
var csv$1 = dsv$1("text/csv", csvParse);
var tsv$1 = dsv$1("text/tab-separated-values", tsvParse);
var frame = 0;
var timeout = 0;
var interval = 0;
var pokeDelay = 1000;
var taskHead;
var taskTail;
var clockLast = 0;
var clockNow = 0;
var clockSkew = 0;
var clock = typeof performance === "object" && performance.now ? performance : Date;
var setFrame = typeof requestAnimationFrame === "function"
? (clock === Date ? function(f) { requestAnimationFrame(function() { f(clock.now()); }); } : requestAnimationFrame)
: function(f) { setTimeout(f, 17); };
function now() {
return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
}
function clearNow() {
clockNow = 0;
}
function Timer() {
this._call =
this._time =
this._next = null;
}
Timer.prototype = timer.prototype = {
constructor: Timer,
restart: function(callback, delay, time) {
if (typeof callback !== "function") throw new TypeError("callback is not a function");
time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
if (!this._next && taskTail !== this) {
if (taskTail) taskTail._next = this;
else taskHead = this;
taskTail = this;
}
this._call = callback;
this._time = time;
sleep();
},
stop: function() {
if (this._call) {
this._call = null;
this._time = Infinity;
sleep();
}
}
};
function timer(callback, delay, time) {
var t = new Timer;
t.restart(callback, delay, time);
return t;
}
function timerFlush() {
now(); // Get the current time, if not already set.
++frame; // Pretend we’ve set an alarm, if we haven’t already.
var t = taskHead, e;
while (t) {
if ((e = clockNow - t._time) >= 0) t._call.call(null, e);
t = t._next;
}
--frame;
}
function wake(time) {
clockNow = (clockLast = time || clock.now()) + clockSkew;
frame = timeout = 0;
try {
timerFlush();
} finally {
frame = 0;
nap();
clockNow = 0;
}
}
function poke$1() {
var now = clock.now(), delay = now - clockLast;
if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
}
function nap() {
var t0, t1 = taskHead, t2, time = Infinity;
while (t1) {
if (t1._call) {
if (time > t1._time) time = t1._time;
t0 = t1, t1 = t1._next;
} else {
t2 = t1._next, t1._next = null;
t1 = t0 ? t0._next = t2 : taskHead = t2;
}
}
taskTail = t0;
sleep(time);
}
function sleep(time) {
if (frame) return; // Soonest alarm already set, or will be.
if (timeout) timeout = clearTimeout(timeout);
var delay = time - clockNow;
if (delay > 24) {
if (time < Infinity) timeout = setTimeout(wake, delay);
if (interval) interval = clearInterval(interval);
} else {
if (!interval) interval = setInterval(poke$1, pokeDelay);
frame = 1, setFrame(wake);
}
}
function timeout$1(callback, delay, time) {
var t = new Timer;
delay = delay == null ? 0 : +delay;
t.restart(function(elapsed) {
t.stop();
callback(elapsed + delay);
}, delay, time);
return t;
}
function interval$1(callback, delay, time) {
var t = new Timer, total = delay;
if (delay == null) return t.restart(callback, delay, time), t;
delay = +delay, time = time == null ? now() : +time;
t.restart(function tick(elapsed) {
elapsed += total;
t.restart(tick, total += delay, time);
callback(elapsed);
}, delay, time);
return t;
}
var t0$1 = new Date;
var t1$1 = new Date;
function newInterval(floori, offseti, count, field) {
function interval(date) {
return floori(date = new Date(+date)), date;
}
interval.floor = interval;
interval.ceil = function(date) {
return floori(date = new Date(date - 1)), offseti(date, 1), floori(date), date;
};
interval.round = function(date) {
var d0 = interval(date),
d1 = interval.ceil(date);
return date - d0 < d1 - date ? d0 : d1;
};
interval.offset = function(date, step) {
return offseti(date = new Date(+date), step == null ? 1 : Math.floor(step)), date;
};
interval.range = function(start, stop, step) {
var range = [];
start = interval.ceil(start);
step = step == null ? 1 : Math.floor(step);
if (!(start < stop) || !(step > 0)) return range; // also handles Invalid Date
do range.push(new Date(+start)); while (offseti(start, step), floori(start), start < stop)
return range;
};
interval.filter = function(test) {
return newInterval(function(date) {
while (floori(date), !test(date)) date.setTime(date - 1);
}, function(date, step) {
while (--step >= 0) while (offseti(date, 1), !test(date));
});
};
if (count) {
interval.count = function(start, end) {
t0$1.setTime(+start), t1$1.setTime(+end);
floori(t0$1), floori(t1$1);
return Math.floor(count(t0$1, t1$1));
};
interval.every = function(step) {
step = Math.floor(step);
return !isFinite(step) || !(step > 0) ? null
: !(step > 1) ? interval
: interval.filter(field
? function(d) { return field(d) % step === 0; }
: function(d) { return interval.count(0, d) % step === 0; });
};
}
return interval;
}
var millisecond = newInterval(function() {
// noop
}, function(date, step) {
date.setTime(+date + step);
}, function(start, end) {
return end - start;
});
// An optimized implementation for this simple case.
millisecond.every = function(k) {
k = Math.floor(k);
if (!isFinite(k) || !(k > 0)) return null;
if (!(k > 1)) return millisecond;
return newInterval(function(date) {
date.setTime(Math.floor(date / k) * k);
}, function(date, step) {
date.setTime(+date + step * k);
}, function(start, end) {
return (end - start) / k;
});
};
var milliseconds = millisecond.range;
var durationSecond = 1e3;
var durationMinute = 6e4;
var durationHour = 36e5;
var durationDay = 864e5;
var durationWeek = 6048e5;
var second = newInterval(function(date) {
date.setTime(Math.floor(date / durationSecond) * durationSecond);
}, function(date, step) {
date.setTime(+date + step * durationSecond);
}, function(start, end) {
return (end - start) / durationSecond;
}, function(date) {
return date.getUTCSeconds();
});
var seconds = second.range;
var minute = newInterval(function(date) {
date.setTime(Math.floor(date / durationMinute) * durationMinute);
}, function(date, step) {
date.setTime(+date + step * durationMinute);
}, function(start, end) {
return (end - start) / durationMinute;
}, function(date) {
return date.getMinutes();
});
var minutes = minute.range;
var hour = newInterval(function(date) {
var offset = date.getTimezoneOffset() * durationMinute % durationHour;
if (offset < 0) offset += durationHour;
date.setTime(Math.floor((+date - offset) / durationHour) * durationHour + offset);
}, function(date, step) {
date.setTime(+date + step * durationHour);
}, function(start, end) {
return (end - start) / durationHour;
}, function(date) {
return date.getHours();
});
var hours = hour.range;
var day = newInterval(function(date) {
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setDate(date.getDate() + step);
}, function(start, end) {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationDay;
}, function(date) {
return date.getDate() - 1;
});
var days = day.range;
function weekday(i) {
return newInterval(function(date) {
date.setDate(date.getDate() - (date.getDay() + 7 - i) % 7);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setDate(date.getDate() + step * 7);
}, function(start, end) {
return (end - start - (end.getTimezoneOffset() - start.getTimezoneOffset()) * durationMinute) / durationWeek;
});
}
var timeWeek = weekday(0);
var timeMonday = weekday(1);
var tuesday = weekday(2);
var wednesday = weekday(3);
var thursday = weekday(4);
var friday = weekday(5);
var saturday = weekday(6);
var sundays = timeWeek.range;
var mondays = timeMonday.range;
var tuesdays = tuesday.range;
var wednesdays = wednesday.range;
var thursdays = thursday.range;
var fridays = friday.range;
var saturdays = saturday.range;
var month = newInterval(function(date) {
date.setDate(1);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setMonth(date.getMonth() + step);
}, function(start, end) {
return end.getMonth() - start.getMonth() + (end.getFullYear() - start.getFullYear()) * 12;
}, function(date) {
return date.getMonth();
});
var months = month.range;
var year = newInterval(function(date) {
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setFullYear(date.getFullYear() + step);
}, function(start, end) {
return end.getFullYear() - start.getFullYear();
}, function(date) {
return date.getFullYear();
});
// An optimized implementation for this simple case.
year.every = function(k) {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
date.setFullYear(Math.floor(date.getFullYear() / k) * k);
date.setMonth(0, 1);
date.setHours(0, 0, 0, 0);
}, function(date, step) {
date.setFullYear(date.getFullYear() + step * k);
});
};
var years = year.range;
var utcMinute = newInterval(function(date) {
date.setUTCSeconds(0, 0);
}, function(date, step) {
date.setTime(+date + step * durationMinute);
}, function(start, end) {
return (end - start) / durationMinute;
}, function(date) {
return date.getUTCMinutes();
});
var utcMinutes = utcMinute.range;
var utcHour = newInterval(function(date) {
date.setUTCMinutes(0, 0, 0);
}, function(date, step) {
date.setTime(+date + step * durationHour);
}, function(start, end) {
return (end - start) / durationHour;
}, function(date) {
return date.getUTCHours();
});
var utcHours = utcHour.range;
var utcDay = newInterval(function(date) {
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCDate(date.getUTCDate() + step);
}, function(start, end) {
return (end - start) / durationDay;
}, function(date) {
return date.getUTCDate() - 1;
});
var utcDays = utcDay.range;
function utcWeekday(i) {
return newInterval(function(date) {
date.setUTCDate(date.getUTCDate() - (date.getUTCDay() + 7 - i) % 7);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCDate(date.getUTCDate() + step * 7);
}, function(start, end) {
return (end - start) / durationWeek;
});
}
var utcWeek = utcWeekday(0);
var utcMonday = utcWeekday(1);
var utcTuesday = utcWeekday(2);
var utcWednesday = utcWeekday(3);
var utcThursday = utcWeekday(4);
var utcFriday = utcWeekday(5);
var utcSaturday = utcWeekday(6);
var utcSundays = utcWeek.range;
var utcMondays = utcMonday.range;
var utcTuesdays = utcTuesday.range;
var utcWednesdays = utcWednesday.range;
var utcThursdays = utcThursday.range;
var utcFridays = utcFriday.range;
var utcSaturdays = utcSaturday.range;
var utcMonth = newInterval(function(date) {
date.setUTCDate(1);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCMonth(date.getUTCMonth() + step);
}, function(start, end) {
return end.getUTCMonth() - start.getUTCMonth() + (end.getUTCFullYear() - start.getUTCFullYear()) * 12;
}, function(date) {
return date.getUTCMonth();
});
var utcMonths = utcMonth.range;
var utcYear = newInterval(function(date) {
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCFullYear(date.getUTCFullYear() + step);
}, function(start, end) {
return end.getUTCFullYear() - start.getUTCFullYear();
}, function(date) {
return date.getUTCFullYear();
});
// An optimized implementation for this simple case.
utcYear.every = function(k) {
return !isFinite(k = Math.floor(k)) || !(k > 0) ? null : newInterval(function(date) {
date.setUTCFullYear(Math.floor(date.getUTCFullYear() / k) * k);
date.setUTCMonth(0, 1);
date.setUTCHours(0, 0, 0, 0);
}, function(date, step) {
date.setUTCFullYear(date.getUTCFullYear() + step * k);
});
};
var utcYears = utcYear.range;
// Computes the decimal coefficient and exponent of the specified number x with
// significant digits p, where x is positive and p is in [1, 21] or undefined.
// For example, formatDecimal(1.23) returns ["123", 0].
function formatDecimal(x, p) {
if ((i = (x = p ? x.toExponential(p - 1) : x.toExponential()).indexOf("e")) < 0) return null; // NaN, ±Infinity
var i, coefficient = x.slice(0, i);
// The string returned by toExponential either has the form \d\.\d+e[-+]\d+
// (e.g., 1.2e+3) or the form \de[-+]\d+ (e.g., 1e+3).
return [
coefficient.length > 1 ? coefficient[0] + coefficient.slice(2) : coefficient,
+x.slice(i + 1)
];
}
function exponent$1(x) {
return x = formatDecimal(Math.abs(x)), x ? x[1] : NaN;
}
function formatGroup(grouping, thousands) {
return function(value, width) {
var i = value.length,
t = [],
j = 0,
g = grouping[0],
length = 0;
while (i > 0 && g > 0) {
if (length + g + 1 > width) g = Math.max(1, width - length);
t.push(value.substring(i -= g, i + g));
if ((length += g + 1) > width) break;
g = grouping[j = (j + 1) % grouping.length];
}
return t.reverse().join(thousands);
};
}
function formatDefault(x, p) {
x = x.toPrecision(p);
out: for (var n = x.length, i = 1, i0 = -1, i1; i < n; ++i) {
switch (x[i]) {
case ".": i0 = i1 = i; break;
case "0": if (i0 === 0) i0 = i; i1 = i; break;
case "e": break out;
default: if (i0 > 0) i0 = 0; break;
}
}
return i0 > 0 ? x.slice(0, i0) + x.slice(i1 + 1) : x;
}
var prefixExponent;
function formatPrefixAuto(x, p) {
var d = formatDecimal(x, p);
if (!d) return x + "";
var coefficient = d[0],
exponent = d[1],
i = exponent - (prefixExponent = Math.max(-8, Math.min(8, Math.floor(exponent / 3))) * 3) + 1,
n = coefficient.length;
return i === n ? coefficient
: i > n ? coefficient + new Array(i - n + 1).join("0")
: i > 0 ? coefficient.slice(0, i) + "." + coefficient.slice(i)
: "0." + new Array(1 - i).join("0") + formatDecimal(x, Math.max(0, p + i - 1))[0]; // less than 1y!
}
function formatRounded(x, p) {
var d = formatDecimal(x, p);
if (!d) return x + "";
var coefficient = d[0],
exponent = d[1];
return exponent < 0 ? "0." + new Array(-exponent).join("0") + coefficient
: coefficient.length > exponent + 1 ? coefficient.slice(0, exponent + 1) + "." + coefficient.slice(exponent + 1)
: coefficient + new Array(exponent - coefficient.length + 2).join("0");
}
var formatTypes = {
"": formatDefault,
"%": function(x, p) { return (x * 100).toFixed(p); },
"b": function(x) { return Math.round(x).toString(2); },
"c": function(x) { return x + ""; },
"d": function(x) { return Math.round(x).toString(10); },
"e": function(x, p) { return x.toExponential(p); },
"f": function(x, p) { return x.toFixed(p); },
"g": function(x, p) { return x.toPrecision(p); },
"o": function(x) { return Math.round(x).toString(8); },
"p": function(x, p) { return formatRounded(x * 100, p); },
"r": formatRounded,
"s": formatPrefixAuto,
"X": function(x) { return Math.round(x).toString(16).toUpperCase(); },
"x": function(x) { return Math.round(x).toString(16); }
};
// [[fill]align][sign][symbol][0][width][,][.precision][type]
var re = /^(?:(.)?([<>=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;
function formatSpecifier(specifier) {
return new FormatSpecifier(specifier);
}
function FormatSpecifier(specifier) {
if (!(match = re.exec(specifier))) throw new Error("invalid format: " + specifier);
var match,
fill = match[1] || " ",
align = match[2] || ">",
sign = match[3] || "-",
symbol = match[4] || "",
zero = !!match[5],
width = match[6] && +match[6],
comma = !!match[7],
precision = match[8] && +match[8].slice(1),
type = match[9] || "";
// The "n" type is an alias for ",g".
if (type === "n") comma = true, type = "g";
// Map invalid types to the default format.
else if (!formatTypes[type]) type = "";
// If zero fill is specified, padding goes after sign and before digits.
if (zero || (fill === "0" && align === "=")) zero = true, fill = "0", align = "=";
this.fill = fill;
this.align = align;
this.sign = sign;
this.symbol = symbol;
this.zero = zero;
this.width = width;
this.comma = comma;
this.precision = precision;
this.type = type;
}
FormatSpecifier.prototype.toString = function() {
return this.fill
+ this.align
+ this.sign
+ this.symbol
+ (this.zero ? "0" : "")
+ (this.width == null ? "" : Math.max(1, this.width | 0))
+ (this.comma ? "," : "")
+ (this.precision == null ? "" : "." + Math.max(0, this.precision | 0))
+ this.type;
};
var prefixes = ["y","z","a","f","p","n","\xB5","m","","k","M","G","T","P","E","Z","Y"];
function identity$3(x) {
return x;
}
function formatLocale(locale) {
var group = locale.grouping && locale.thousands ? formatGroup(locale.grouping, locale.thousands) : identity$3,
currency = locale.currency,
decimal = locale.decimal;
function newFormat(specifier) {
specifier = formatSpecifier(specifier);
var fill = specifier.fill,
align = specifier.align,
sign = specifier.sign,
symbol = specifier.symbol,
zero = specifier.zero,
width = specifier.width,
comma = specifier.comma,
precision = specifier.precision,
type = specifier.type;
// Compute the prefix and suffix.
// For SI-prefix, the suffix is lazily computed.
var prefix = symbol === "$" ? currency[0] : symbol === "#" && /[boxX]/.test(type) ? "0" + type.toLowerCase() : "",
suffix = symbol === "$" ? currency[1] : /[%p]/.test(type) ? "%" : "";
// What format function should we use?
// Is this an integer type?
// Can this type generate exponential notation?
var formatType = formatTypes[type],
maybeSuffix = !type || /[defgprs%]/.test(type);
// Set the default precision if not specified,
// or clamp the specified precision to the supported range.
// For significant precision, it must be in [1, 21].
// For fixed precision, it must be in [0, 20].
precision = precision == null ? (type ? 6 : 12)
: /[gprs]/.test(type) ? Math.max(1, Math.min(21, precision))
: Math.max(0, Math.min(20, precision));
function format(value) {
var valuePrefix = prefix,
valueSuffix = suffix,
i, n, c;
if (type === "c") {
valueSuffix = formatType(value) + valueSuffix;
value = "";
} else {
value = +value;
// Convert negative to positive, and compute the prefix.
// Note that -0 is not less than 0, but 1 / -0 is!
var valueNegative = (value < 0 || 1 / value < 0) && (value *= -1, true);
// Perform the initial formatting.
value = formatType(value, precision);
// If the original value was negative, it may be rounded to zero during
// formatting; treat this as (positive) zero.
if (valueNegative) {
i = -1, n = value.length;
valueNegative = false;
while (++i < n) {
if (c = value.charCodeAt(i), (48 < c && c < 58)
|| (type === "x" && 96 < c && c < 103)
|| (type === "X" && 64 < c && c < 71)) {
valueNegative = true;
break;
}
}
}
// Compute the prefix and suffix.
valuePrefix = (valueNegative ? (sign === "(" ? sign : "-") : sign === "-" || sign === "(" ? "" : sign) + valuePrefix;
valueSuffix = valueSuffix + (type === "s" ? prefixes[8 + prefixExponent / 3] : "") + (valueNegative && sign === "(" ? ")" : "");
// Break the formatted value into the integer “value” part that can be
// grouped, and fractional or exponential “suffix” part that is not.
if (maybeSuffix) {
i = -1, n = value.length;
while (++i < n) {
if (c = value.charCodeAt(i), 48 > c || c > 57) {
valueSuffix = (c === 46 ? decimal + value.slice(i + 1) : value.slice(i)) + valueSuffix;
value = value.slice(0, i);
break;
}
}
}
}
// If the fill character is not "0", grouping is applied before padding.
if (comma && !zero) value = group(value, Infinity);
// Compute the padding.
var length = valuePrefix.length + value.length + valueSuffix.length,
padding = length < width ? new Array(width - length + 1).join(fill) : "";
// If the fill character is "0", grouping is applied after padding.
if (comma && zero) value = group(padding + value, padding.length ? width - valueSuffix.length : Infinity), padding = "";
// Reconstruct the final output based on the desired alignment.
switch (align) {
case "<": return valuePrefix + value + valueSuffix + padding;
case "=": return valuePrefix + padding + value + valueSuffix;
case "^": return padding.slice(0, length = padding.length >> 1) + valuePrefix + value + valueSuffix + padding.slice(length);
}
return padding + valuePrefix + value + valueSuffix;
}
format.toString = function() {
return specifier + "";
};
return format;
}
function formatPrefix(specifier, value) {
var f = newFormat((specifier = formatSpecifier(specifier), specifier.type = "f", specifier)),
e = Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3,
k = Math.pow(10, -e),
prefix = prefixes[8 + e / 3];
return function(value) {
return f(k * value) + prefix;
};
}
return {
format: newFormat,
formatPrefix: formatPrefix
};
}
var locale;
exports.format;
exports.formatPrefix;
defaultLocale({
decimal: ".",
thousands: ",",
grouping: [3],
currency: ["$", ""]
});
function defaultLocale(definition) {
locale = formatLocale(definition);
exports.format = locale.format;
exports.formatPrefix = locale.formatPrefix;
return locale;
}
function precisionFixed(step) {
return Math.max(0, -exponent$1(Math.abs(step)));
}
function precisionPrefix(step, value) {
return Math.max(0, Math.max(-8, Math.min(8, Math.floor(exponent$1(value) / 3))) * 3 - exponent$1(Math.abs(step)));
}
function precisionRound(step, max) {
step = Math.abs(step), max = Math.abs(max) - step;
return Math.max(0, exponent$1(max) - exponent$1(step)) + 1;
}
function localDate(d) {
if (0 <= d.y && d.y < 100) {
var date = new Date(-1, d.m, d.d, d.H, d.M, d.S, d.L);
date.setFullYear(d.y);
return date;
}
return new Date(d.y, d.m, d.d, d.H, d.M, d.S, d.L);
}
function utcDate(d) {
if (0 <= d.y && d.y < 100) {
var date = new Date(Date.UTC(-1, d.m, d.d, d.H, d.M, d.S, d.L));
date.setUTCFullYear(d.y);
return date;
}
return new Date(Date.UTC(d.y, d.m, d.d, d.H, d.M, d.S, d.L));
}
function newYear(y) {
return {y: y, m: 0, d: 1, H: 0, M: 0, S: 0, L: 0};
}
function formatLocale$1(locale) {
var locale_dateTime = locale.dateTime,
locale_date = locale.date,
locale_time = locale.time,
locale_periods = locale.periods,
locale_weekdays = locale.days,
locale_shortWeekdays = locale.shortDays,
locale_months = locale.months,
locale_shortMonths = locale.shortMonths;
var periodRe = formatRe(locale_periods),
periodLookup = formatLookup(locale_periods),
weekdayRe = formatRe(locale_weekdays),
weekdayLookup = formatLookup(locale_weekdays),
shortWeekdayRe = formatRe(locale_shortWeekdays),
shortWeekdayLookup = formatLookup(locale_shortWeekdays),
monthRe = formatRe(locale_months),
monthLookup = formatLookup(locale_months),
shortMonthRe = formatRe(locale_shortMonths),
shortMonthLookup = formatLookup(locale_shortMonths);
var formats = {
"a": formatShortWeekday,
"A": formatWeekday,
"b": formatShortMonth,
"B": formatMonth,
"c": null,
"d": formatDayOfMonth,
"e": formatDayOfMonth,
"H": formatHour24,
"I": formatHour12,
"j": formatDayOfYear,
"L": formatMilliseconds,
"m": formatMonthNumber,
"M": formatMinutes,
"p": formatPeriod,
"S": formatSeconds,
"U": formatWeekNumberSunday,
"w": formatWeekdayNumber,
"W": formatWeekNumberMonday,
"x": null,
"X": null,
"y": formatYear,
"Y": formatFullYear,
"Z": formatZone,
"%": formatLiteralPercent
};
var utcFormats = {
"a": formatUTCShortWeekday,
"A": formatUTCWeekday,
"b": formatUTCShortMonth,
"B": formatUTCMonth,
"c": null,
"d": formatUTCDayOfMonth,
"e": formatUTCDayOfMonth,
"H": formatUTCHour24,
"I": formatUTCHour12,
"j": formatUTCDayOfYear,
"L": formatUTCMilliseconds,
"m": formatUTCMonthNumber,
"M": formatUTCMinutes,
"p": formatUTCPeriod,
"S": formatUTCSeconds,
"U": formatUTCWeekNumberSunday,
"w": formatUTCWeekdayNumber,
"W": formatUTCWeekNumberMonday,
"x": null,
"X": null,
"y": formatUTCYear,
"Y": formatUTCFullYear,
"Z": formatUTCZone,
"%": formatLiteralPercent
};
var parses = {
"a": parseShortWeekday,
"A": parseWeekday,
"b": parseShortMonth,
"B": parseMonth,
"c": parseLocaleDateTime,
"d": parseDayOfMonth,
"e": parseDayOfMonth,
"H": parseHour24,
"I": parseHour24,
"j": parseDayOfYear,
"L": parseMilliseconds,
"m": parseMonthNumber,
"M": parseMinutes,
"p": parsePeriod,
"S": parseSeconds,
"U": parseWeekNumberSunday,
"w": parseWeekdayNumber,
"W": parseWeekNumberMonday,
"x": parseLocaleDate,
"X": parseLocaleTime,
"y": parseYear,
"Y": parseFullYear,
"Z": parseZone,
"%": parseLiteralPercent
};
// These recursive directive definitions must be deferred.
formats.x = newFormat(locale_date, formats);
formats.X = newFormat(locale_time, formats);
formats.c = newFormat(locale_dateTime, formats);
utcFormats.x = newFormat(locale_date, utcFormats);
utcFormats.X = newFormat(locale_time, utcFormats);
utcFormats.c = newFormat(locale_dateTime, utcFormats);
function newFormat(specifier, formats) {
return function(date) {
var string = [],
i = -1,
j = 0,
n = specifier.length,
c,
pad,
format;
if (!(date instanceof Date)) date = new Date(+date);
while (++i < n) {
if (specifier.charCodeAt(i) === 37) {
string.push(specifier.slice(j, i));
if ((pad = pads[c = specifier.charAt(++i)]) != null) c = specifier.charAt(++i);
else pad = c === "e" ? " " : "0";
if (format = formats[c]) c = format(date, pad);
string.push(c);
j = i + 1;
}
}
string.push(specifier.slice(j, i));
return string.join("");
};
}
function newParse(specifier, newDate) {
return function(string) {
var d = newYear(1900),
i = parseSpecifier(d, specifier, string += "", 0);
if (i != string.length) return null;
// The am-pm flag is 0 for AM, and 1 for PM.
if ("p" in d) d.H = d.H % 12 + d.p * 12;
// Convert day-of-week and week-of-year to day-of-year.
if ("W" in d || "U" in d) {
if (!("w" in d)) d.w = "W" in d ? 1 : 0;
var day = "Z" in d ? utcDate(newYear(d.y)).getUTCDay() : newDate(newYear(d.y)).getDay();
d.m = 0;
d.d = "W" in d ? (d.w + 6) % 7 + d.W * 7 - (day + 5) % 7 : d.w + d.U * 7 - (day + 6) % 7;
}
// If a time zone is specified, all fields are interpreted as UTC and then
// offset according to the specified time zone.
if ("Z" in d) {
d.H += d.Z / 100 | 0;
d.M += d.Z % 100;
return utcDate(d);
}
// Otherwise, all fields are in local time.
return newDate(d);
};
}
function parseSpecifier(d, specifier, string, j) {
var i = 0,
n = specifier.length,
m = string.length,
c,
parse;
while (i < n) {
if (j >= m) return -1;
c = specifier.charCodeAt(i++);
if (c === 37) {
c = specifier.charAt(i++);
parse = parses[c in pads ? specifier.charAt(i++) : c];
if (!parse || ((j = parse(d, string, j)) < 0)) return -1;
} else if (c != string.charCodeAt(j++)) {
return -1;
}
}
return j;
}
function parsePeriod(d, string, i) {
var n = periodRe.exec(string.slice(i));
return n ? (d.p = periodLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseShortWeekday(d, string, i) {
var n = shortWeekdayRe.exec(string.slice(i));
return n ? (d.w = shortWeekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseWeekday(d, string, i) {
var n = weekdayRe.exec(string.slice(i));
return n ? (d.w = weekdayLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseShortMonth(d, string, i) {
var n = shortMonthRe.exec(string.slice(i));
return n ? (d.m = shortMonthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseMonth(d, string, i) {
var n = monthRe.exec(string.slice(i));
return n ? (d.m = monthLookup[n[0].toLowerCase()], i + n[0].length) : -1;
}
function parseLocaleDateTime(d, string, i) {
return parseSpecifier(d, locale_dateTime, string, i);
}
function parseLocaleDate(d, string, i) {
return parseSpecifier(d, locale_date, string, i);
}
function parseLocaleTime(d, string, i) {
return parseSpecifier(d, locale_time, string, i);
}
function formatShortWeekday(d) {
return locale_shortWeekdays[d.getDay()];
}
function formatWeekday(d) {
return locale_weekdays[d.getDay()];
}
function formatShortMonth(d) {
return locale_shortMonths[d.getMonth()];
}
function formatMonth(d) {
return locale_months[d.getMonth()];
}
function formatPeriod(d) {
return locale_periods[+(d.getHours() >= 12)];
}
function formatUTCShortWeekday(d) {
return locale_shortWeekdays[d.getUTCDay()];
}
function formatUTCWeekday(d) {
return locale_weekdays[d.getUTCDay()];
}
function formatUTCShortMonth(d) {
return locale_shortMonths[d.getUTCMonth()];
}
function formatUTCMonth(d) {
return locale_months[d.getUTCMonth()];
}
function formatUTCPeriod(d) {
return locale_periods[+(d.getUTCHours() >= 12)];
}
return {
format: function(specifier) {
var f = newFormat(specifier += "", formats);
f.toString = function() { return specifier; };
return f;
},
parse: function(specifier) {
var p = newParse(specifier += "", localDate);
p.toString = function() { return specifier; };
return p;
},
utcFormat: function(specifier) {
var f = newFormat(specifier += "", utcFormats);
f.toString = function() { return specifier; };
return f;
},
utcParse: function(specifier) {
var p = newParse(specifier, utcDate);
p.toString = function() { return specifier; };
return p;
}
};
}
var pads = {"-": "", "_": " ", "0": "0"};
var numberRe = /^\s*\d+/;
var percentRe = /^%/;
var requoteRe = /[\\\^\$\*\+\?\|\[\]\(\)\.\{\}]/g;
function pad(value, fill, width) {
var sign = value < 0 ? "-" : "",
string = (sign ? -value : value) + "",
length = string.length;
return sign + (length < width ? new Array(width - length + 1).join(fill) + string : string);
}
function requote(s) {
return s.replace(requoteRe, "\\$&");
}
function formatRe(names) {
return new RegExp("^(?:" + names.map(requote).join("|") + ")", "i");
}
function formatLookup(names) {
var map = {}, i = -1, n = names.length;
while (++i < n) map[names[i].toLowerCase()] = i;
return map;
}
function parseWeekdayNumber(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 1));
return n ? (d.w = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberSunday(d, string, i) {
var n = numberRe.exec(string.slice(i));
return n ? (d.U = +n[0], i + n[0].length) : -1;
}
function parseWeekNumberMonday(d, string, i) {
var n = numberRe.exec(string.slice(i));
return n ? (d.W = +n[0], i + n[0].length) : -1;
}
function parseFullYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 4));
return n ? (d.y = +n[0], i + n[0].length) : -1;
}
function parseYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.y = +n[0] + (+n[0] > 68 ? 1900 : 2000), i + n[0].length) : -1;
}
function parseZone(d, string, i) {
var n = /^(Z)|([+-]\d\d)(?:\:?(\d\d))?/.exec(string.slice(i, i + 6));
return n ? (d.Z = n[1] ? 0 : -(n[2] + (n[3] || "00")), i + n[0].length) : -1;
}
function parseMonthNumber(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.m = n[0] - 1, i + n[0].length) : -1;
}
function parseDayOfMonth(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.d = +n[0], i + n[0].length) : -1;
}
function parseDayOfYear(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 3));
return n ? (d.m = 0, d.d = +n[0], i + n[0].length) : -1;
}
function parseHour24(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.H = +n[0], i + n[0].length) : -1;
}
function parseMinutes(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.M = +n[0], i + n[0].length) : -1;
}
function parseSeconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 2));
return n ? (d.S = +n[0], i + n[0].length) : -1;
}
function parseMilliseconds(d, string, i) {
var n = numberRe.exec(string.slice(i, i + 3));
return n ? (d.L = +n[0], i + n[0].length) : -1;
}
function parseLiteralPercent(d, string, i) {
var n = percentRe.exec(string.slice(i, i + 1));
return n ? i + n[0].length : -1;
}
function formatDayOfMonth(d, p) {
return pad(d.getDate(), p, 2);
}
function formatHour24(d, p) {
return pad(d.getHours(), p, 2);
}
function formatHour12(d, p) {
return pad(d.getHours() % 12 || 12, p, 2);
}
function formatDayOfYear(d, p) {
return pad(1 + day.count(year(d), d), p, 3);
}
function formatMilliseconds(d, p) {
return pad(d.getMilliseconds(), p, 3);
}
function formatMonthNumber(d, p) {
return pad(d.getMonth() + 1, p, 2);
}
function formatMinutes(d, p) {
return pad(d.getMinutes(), p, 2);
}
function formatSeconds(d, p) {
return pad(d.getSeconds(), p, 2);
}
function formatWeekNumberSunday(d, p) {
return pad(timeWeek.count(year(d), d), p, 2);
}
function formatWeekdayNumber(d) {
return d.getDay();
}
function formatWeekNumberMonday(d, p) {
return pad(timeMonday.count(year(d), d), p, 2);
}
function formatYear(d, p) {
return pad(d.getFullYear() % 100, p, 2);
}
function formatFullYear(d, p) {
return pad(d.getFullYear() % 10000, p, 4);
}
function formatZone(d) {
var z = d.getTimezoneOffset();
return (z > 0 ? "-" : (z *= -1, "+"))
+ pad(z / 60 | 0, "0", 2)
+ pad(z % 60, "0", 2);
}
function formatUTCDayOfMonth(d, p) {
return pad(d.getUTCDate(), p, 2);
}
function formatUTCHour24(d, p) {
return pad(d.getUTCHours(), p, 2);
}
function formatUTCHour12(d, p) {
return pad(d.getUTCHours() % 12 || 12, p, 2);
}
function formatUTCDayOfYear(d, p) {
return pad(1 + utcDay.count(utcYear(d), d), p, 3);
}
function formatUTCMilliseconds(d, p) {
return pad(d.getUTCMilliseconds(), p, 3);
}
function formatUTCMonthNumber(d, p) {
return pad(d.getUTCMonth() + 1, p, 2);
}
function formatUTCMinutes(d, p) {
return pad(d.getUTCMinutes(), p, 2);
}
function formatUTCSeconds(d, p) {
return pad(d.getUTCSeconds(), p, 2);
}
function formatUTCWeekNumberSunday(d, p) {
return pad(utcWeek.count(utcYear(d), d), p, 2);
}
function formatUTCWeekdayNumber(d) {
return d.getUTCDay();
}
function formatUTCWeekNumberMonday(d, p) {
return pad(utcMonday.count(utcYear(d), d), p, 2);
}
function formatUTCYear(d, p) {
return pad(d.getUTCFullYear() % 100, p, 2);
}
function formatUTCFullYear(d, p) {
return pad(d.getUTCFullYear() % 10000, p, 4);
}
function formatUTCZone() {
return "+0000";
}
function formatLiteralPercent() {
return "%";
}
var locale$1;
exports.timeFormat;
exports.timeParse;
exports.utcFormat;
exports.utcParse;
defaultLocale$1({
dateTime: "%x, %X",
date: "%-m/%-d/%Y",
time: "%-I:%M:%S %p",
periods: ["AM", "PM"],
days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
shortDays: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
shortMonths: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
});
function defaultLocale$1(definition) {
locale$1 = formatLocale$1(definition);
exports.timeFormat = locale$1.format;
exports.timeParse = locale$1.parse;
exports.utcFormat = locale$1.utcFormat;
exports.utcParse = locale$1.utcParse;
return locale$1;
}
var isoSpecifier = "%Y-%m-%dT%H:%M:%S.%LZ";
function formatIsoNative(date) {
return date.toISOString();
}
var formatIso = Date.prototype.toISOString
? formatIsoNative
: exports.utcFormat(isoSpecifier);
function parseIsoNative(string) {
var date = new Date(string);
return isNaN(date) ? null : date;
}
var parseIso = +new Date("2000-01-01T00:00:00.000Z")
? parseIsoNative
: exports.utcParse(isoSpecifier);
var array$2 = Array.prototype;
var map$2 = array$2.map;
var slice$3 = array$2.slice;
var implicit = {name: "implicit"};
function ordinal(range) {
var index = map$1(),
domain = [],
unknown = implicit;
range = range == null ? [] : slice$3.call(range);
function scale(d) {
var key = d + "", i = index.get(key);
if (!i) {
if (unknown !== implicit) return unknown;
index.set(key, i = domain.push(d));
}
return range[(i - 1) % range.length];
}
scale.domain = function(_) {
if (!arguments.length) return domain.slice();
domain = [], index = map$1();
var i = -1, n = _.length, d, key;
while (++i < n) if (!index.has(key = (d = _[i]) + "")) index.set(key, domain.push(d));
return scale;
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), scale) : range.slice();
};
scale.unknown = function(_) {
return arguments.length ? (unknown = _, scale) : unknown;
};
scale.copy = function() {
return ordinal()
.domain(domain)
.range(range)
.unknown(unknown);
};
return scale;
}
function band() {
var scale = ordinal().unknown(undefined),
domain = scale.domain,
ordinalRange = scale.range,
range$$ = [0, 1],
step,
bandwidth,
round = false,
paddingInner = 0,
paddingOuter = 0,
align = 0.5;
delete scale.unknown;
function rescale() {
var n = domain().length,
reverse = range$$[1] < range$$[0],
start = range$$[reverse - 0],
stop = range$$[1 - reverse];
step = (stop - start) / Math.max(1, n - paddingInner + paddingOuter * 2);
if (round) step = Math.floor(step);
start += (stop - start - step * (n - paddingInner)) * align;
bandwidth = step * (1 - paddingInner);
if (round) start = Math.round(start), bandwidth = Math.round(bandwidth);
var values = range(n).map(function(i) { return start + step * i; });
return ordinalRange(reverse ? values.reverse() : values);
}
scale.domain = function(_) {
return arguments.length ? (domain(_), rescale()) : domain();
};
scale.range = function(_) {
return arguments.length ? (range$$ = [+_[0], +_[1]], rescale()) : range$$.slice();
};
scale.rangeRound = function(_) {
return range$$ = [+_[0], +_[1]], round = true, rescale();
};
scale.bandwidth = function() {
return bandwidth;
};
scale.step = function() {
return step;
};
scale.round = function(_) {
return arguments.length ? (round = !!_, rescale()) : round;
};
scale.padding = function(_) {
return arguments.length ? (paddingInner = paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
};
scale.paddingInner = function(_) {
return arguments.length ? (paddingInner = Math.max(0, Math.min(1, _)), rescale()) : paddingInner;
};
scale.paddingOuter = function(_) {
return arguments.length ? (paddingOuter = Math.max(0, Math.min(1, _)), rescale()) : paddingOuter;
};
scale.align = function(_) {
return arguments.length ? (align = Math.max(0, Math.min(1, _)), rescale()) : align;
};
scale.copy = function() {
return band()
.domain(domain())
.range(range$$)
.round(round)
.paddingInner(paddingInner)
.paddingOuter(paddingOuter)
.align(align);
};
return rescale();
}
function pointish(scale) {
var copy = scale.copy;
scale.padding = scale.paddingOuter;
delete scale.paddingInner;
delete scale.paddingOuter;
scale.copy = function() {
return pointish(copy());
};
return scale;
}
function point$4() {
return pointish(band().paddingInner(1));
}
function constant$3(x) {
return function() {
return x;
};
}
function number$1(x) {
return +x;
}
var unit = [0, 1];
function deinterpolate(a, b) {
return (b -= (a = +a))
? function(x) { return (x - a) / b; }
: constant$3(b);
}
function deinterpolateClamp(deinterpolate) {
return function(a, b) {
var d = deinterpolate(a = +a, b = +b);
return function(x) { return x <= a ? 0 : x >= b ? 1 : d(x); };
};
}
function reinterpolateClamp(reinterpolate) {
return function(a, b) {
var r = reinterpolate(a = +a, b = +b);
return function(t) { return t <= 0 ? a : t >= 1 ? b : r(t); };
};
}
function bimap(domain, range, deinterpolate, reinterpolate) {
var d0 = domain[0], d1 = domain[1], r0 = range[0], r1 = range[1];
if (d1 < d0) d0 = deinterpolate(d1, d0), r0 = reinterpolate(r1, r0);
else d0 = deinterpolate(d0, d1), r0 = reinterpolate(r0, r1);
return function(x) { return r0(d0(x)); };
}
function polymap(domain, range, deinterpolate, reinterpolate) {
var j = Math.min(domain.length, range.length) - 1,
d = new Array(j),
r = new Array(j),
i = -1;
// Reverse descending domains.
if (domain[j] < domain[0]) {
domain = domain.slice().reverse();
range = range.slice().reverse();
}
while (++i < j) {
d[i] = deinterpolate(domain[i], domain[i + 1]);
r[i] = reinterpolate(range[i], range[i + 1]);
}
return function(x) {
var i = bisectRight(domain, x, 1, j) - 1;
return r[i](d[i](x));
};
}
function copy(source, target) {
return target
.domain(source.domain())
.range(source.range())
.interpolate(source.interpolate())
.clamp(source.clamp());
}
// deinterpolate(a, b)(x) takes a domain value x in [a,b] and returns the corresponding parameter t in [0,1].
// reinterpolate(a, b)(t) takes a parameter t in [0,1] and returns the corresponding domain value x in [a,b].
function continuous(deinterpolate$$, reinterpolate) {
var domain = unit,
range = unit,
interpolate$$ = interpolate,
clamp = false,
piecewise,
output,
input;
function rescale() {
piecewise = Math.min(domain.length, range.length) > 2 ? polymap : bimap;
output = input = null;
return scale;
}
function scale(x) {
return (output || (output = piecewise(domain, range, clamp ? deinterpolateClamp(deinterpolate$$) : deinterpolate$$, interpolate$$)))(+x);
}
scale.invert = function(y) {
return (input || (input = piecewise(range, domain, deinterpolate, clamp ? reinterpolateClamp(reinterpolate) : reinterpolate)))(+y);
};
scale.domain = function(_) {
return arguments.length ? (domain = map$2.call(_, number$1), rescale()) : domain.slice();
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), rescale()) : range.slice();
};
scale.rangeRound = function(_) {
return range = slice$3.call(_), interpolate$$ = interpolateRound, rescale();
};
scale.clamp = function(_) {
return arguments.length ? (clamp = !!_, rescale()) : clamp;
};
scale.interpolate = function(_) {
return arguments.length ? (interpolate$$ = _, rescale()) : interpolate$$;
};
return rescale();
}
function tickFormat(domain, count, specifier) {
var start = domain[0],
stop = domain[domain.length - 1],
step = tickStep(start, stop, count == null ? 10 : count),
precision;
specifier = formatSpecifier(specifier == null ? ",f" : specifier);
switch (specifier.type) {
case "s": {
var value = Math.max(Math.abs(start), Math.abs(stop));
if (specifier.precision == null && !isNaN(precision = precisionPrefix(step, value))) specifier.precision = precision;
return exports.formatPrefix(specifier, value);
}
case "":
case "e":
case "g":
case "p":
case "r": {
if (specifier.precision == null && !isNaN(precision = precisionRound(step, Math.max(Math.abs(start), Math.abs(stop))))) specifier.precision = precision - (specifier.type === "e");
break;
}
case "f":
case "%": {
if (specifier.precision == null && !isNaN(precision = precisionFixed(step))) specifier.precision = precision - (specifier.type === "%") * 2;
break;
}
}
return exports.format(specifier);
}
function linearish(scale) {
var domain = scale.domain;
scale.ticks = function(count) {
var d = domain();
return ticks(d[0], d[d.length - 1], count == null ? 10 : count);
};
scale.tickFormat = function(count, specifier) {
return tickFormat(domain(), count, specifier);
};
scale.nice = function(count) {
var d = domain(),
i = d.length - 1,
n = count == null ? 10 : count,
start = d[0],
stop = d[i],
step = tickStep(start, stop, n);
if (step) {
step = tickStep(Math.floor(start / step) * step, Math.ceil(stop / step) * step, n);
d[0] = Math.floor(start / step) * step;
d[i] = Math.ceil(stop / step) * step;
domain(d);
}
return scale;
};
return scale;
}
function linear$2() {
var scale = continuous(deinterpolate, interpolateNumber);
scale.copy = function() {
return copy(scale, linear$2());
};
return linearish(scale);
}
function identity$4() {
var domain = [0, 1];
function scale(x) {
return +x;
}
scale.invert = scale;
scale.domain = scale.range = function(_) {
return arguments.length ? (domain = map$2.call(_, number$1), scale) : domain.slice();
};
scale.copy = function() {
return identity$4().domain(domain);
};
return linearish(scale);
}
function nice(domain, interval) {
domain = domain.slice();
var i0 = 0,
i1 = domain.length - 1,
x0 = domain[i0],
x1 = domain[i1],
t;
if (x1 < x0) {
t = i0, i0 = i1, i1 = t;
t = x0, x0 = x1, x1 = t;
}
domain[i0] = interval.floor(x0);
domain[i1] = interval.ceil(x1);
return domain;
}
function deinterpolate$1(a, b) {
return (b = Math.log(b / a))
? function(x) { return Math.log(x / a) / b; }
: constant$3(b);
}
function reinterpolate(a, b) {
return a < 0
? function(t) { return -Math.pow(-b, t) * Math.pow(-a, 1 - t); }
: function(t) { return Math.pow(b, t) * Math.pow(a, 1 - t); };
}
function pow10(x) {
return isFinite(x) ? +("1e" + x) : x < 0 ? 0 : x;
}
function powp(base) {
return base === 10 ? pow10
: base === Math.E ? Math.exp
: function(x) { return Math.pow(base, x); };
}
function logp(base) {
return base === Math.E ? Math.log
: base === 10 && Math.log10
|| base === 2 && Math.log2
|| (base = Math.log(base), function(x) { return Math.log(x) / base; });
}
function reflect(f) {
return function(x) {
return -f(-x);
};
}
function log() {
var scale = continuous(deinterpolate$1, reinterpolate).domain([1, 10]),
domain = scale.domain,
base = 10,
logs = logp(10),
pows = powp(10);
function rescale() {
logs = logp(base), pows = powp(base);
if (domain()[0] < 0) logs = reflect(logs), pows = reflect(pows);
return scale;
}
scale.base = function(_) {
return arguments.length ? (base = +_, rescale()) : base;
};
scale.domain = function(_) {
return arguments.length ? (domain(_), rescale()) : domain();
};
scale.ticks = function(count) {
var d = domain(),
u = d[0],
v = d[d.length - 1],
r;
if (r = v < u) i = u, u = v, v = i;
var i = logs(u),
j = logs(v),
p,
k,
t,
n = count == null ? 10 : +count,
z = [];
if (!(base % 1) && j - i < n) {
i = Math.round(i) - 1, j = Math.round(j) + 1;
if (u > 0) for (; i < j; ++i) {
for (k = 1, p = pows(i); k < base; ++k) {
t = p * k;
if (t < u) continue;
if (t > v) break;
z.push(t);
}
} else for (; i < j; ++i) {
for (k = base - 1, p = pows(i); k >= 1; --k) {
t = p * k;
if (t < u) continue;
if (t > v) break;
z.push(t);
}
}
} else {
z = ticks(i, j, Math.min(j - i, n)).map(pows);
}
return r ? z.reverse() : z;
};
scale.tickFormat = function(count, specifier) {
if (specifier == null) specifier = base === 10 ? ".0e" : ",";
if (typeof specifier !== "function") specifier = exports.format(specifier);
if (count === Infinity) return specifier;
if (count == null) count = 10;
var k = Math.max(1, base * count / scale.ticks().length); // TODO fast estimate?
return function(d) {
var i = d / pows(Math.round(logs(d)));
if (i * base < base - 0.5) i *= base;
return i <= k ? specifier(d) : "";
};
};
scale.nice = function() {
return domain(nice(domain(), {
floor: function(x) { return pows(Math.floor(logs(x))); },
ceil: function(x) { return pows(Math.ceil(logs(x))); }
}));
};
scale.copy = function() {
return copy(scale, log().base(base));
};
return scale;
}
function raise(x, exponent) {
return x < 0 ? -Math.pow(-x, exponent) : Math.pow(x, exponent);
}
function pow() {
var exponent = 1,
scale = continuous(deinterpolate, reinterpolate),
domain = scale.domain;
function deinterpolate(a, b) {
return (b = raise(b, exponent) - (a = raise(a, exponent)))
? function(x) { return (raise(x, exponent) - a) / b; }
: constant$3(b);
}
function reinterpolate(a, b) {
b = raise(b, exponent) - (a = raise(a, exponent));
return function(t) { return raise(a + b * t, 1 / exponent); };
}
scale.exponent = function(_) {
return arguments.length ? (exponent = +_, domain(domain())) : exponent;
};
scale.copy = function() {
return copy(scale, pow().exponent(exponent));
};
return linearish(scale);
}
function sqrt() {
return pow().exponent(0.5);
}
function quantile() {
var domain = [],
range = [],
thresholds = [];
function rescale() {
var i = 0, n = Math.max(1, range.length);
thresholds = new Array(n - 1);
while (++i < n) thresholds[i - 1] = threshold(domain, i / n);
return scale;
}
function scale(x) {
if (!isNaN(x = +x)) return range[bisectRight(thresholds, x)];
}
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return i < 0 ? [NaN, NaN] : [
i > 0 ? thresholds[i - 1] : domain[0],
i < thresholds.length ? thresholds[i] : domain[domain.length - 1]
];
};
scale.domain = function(_) {
if (!arguments.length) return domain.slice();
domain = [];
for (var i = 0, n = _.length, d; i < n; ++i) if (d = _[i], d != null && !isNaN(d = +d)) domain.push(d);
domain.sort(ascending);
return rescale();
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), rescale()) : range.slice();
};
scale.quantiles = function() {
return thresholds.slice();
};
scale.copy = function() {
return quantile()
.domain(domain)
.range(range);
};
return scale;
}
function quantize$1() {
var x0 = 0,
x1 = 1,
n = 1,
domain = [0.5],
range = [0, 1];
function scale(x) {
if (x <= x) return range[bisectRight(domain, x, 0, n)];
}
function rescale() {
var i = -1;
domain = new Array(n);
while (++i < n) domain[i] = ((i + 1) * x1 - (i - n) * x0) / (n + 1);
return scale;
}
scale.domain = function(_) {
return arguments.length ? (x0 = +_[0], x1 = +_[1], rescale()) : [x0, x1];
};
scale.range = function(_) {
return arguments.length ? (n = (range = slice$3.call(_)).length - 1, rescale()) : range.slice();
};
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return i < 0 ? [NaN, NaN]
: i < 1 ? [x0, domain[0]]
: i >= n ? [domain[n - 1], x1]
: [domain[i - 1], domain[i]];
};
scale.copy = function() {
return quantize$1()
.domain([x0, x1])
.range(range);
};
return linearish(scale);
}
function threshold$1() {
var domain = [0.5],
range = [0, 1],
n = 1;
function scale(x) {
if (x <= x) return range[bisectRight(domain, x, 0, n)];
}
scale.domain = function(_) {
return arguments.length ? (domain = slice$3.call(_), n = Math.min(domain.length, range.length - 1), scale) : domain.slice();
};
scale.range = function(_) {
return arguments.length ? (range = slice$3.call(_), n = Math.min(domain.length, range.length - 1), scale) : range.slice();
};
scale.invertExtent = function(y) {
var i = range.indexOf(y);
return [domain[i - 1], domain[i]];
};
scale.copy = function() {
return threshold$1()
.domain(domain)
.range(range);
};
return scale;
}
var durationSecond$1 = 1000;
var durationMinute$1 = durationSecond$1 * 60;
var durationHour$1 = durationMinute$1 * 60;
var durationDay$1 = durationHour$1 * 24;
var durationWeek$1 = durationDay$1 * 7;
var durationMonth = durationDay$1 * 30;
var durationYear = durationDay$1 * 365;
function date$1(t) {
return new Date(t);
}
function number$2(t) {
return t instanceof Date ? +t : +new Date(+t);
}
function calendar(year, month, week, day, hour, minute, second, millisecond, format) {
var scale = continuous(deinterpolate, interpolateNumber),
invert = scale.invert,
domain = scale.domain;
var formatMillisecond = format(".%L"),
formatSecond = format(":%S"),
formatMinute = format("%I:%M"),
formatHour = format("%I %p"),
formatDay = format("%a %d"),
formatWeek = format("%b %d"),
formatMonth = format("%B"),
formatYear = format("%Y");
var tickIntervals = [
[second, 1, durationSecond$1],
[second, 5, 5 * durationSecond$1],
[second, 15, 15 * durationSecond$1],
[second, 30, 30 * durationSecond$1],
[minute, 1, durationMinute$1],
[minute, 5, 5 * durationMinute$1],
[minute, 15, 15 * durationMinute$1],
[minute, 30, 30 * durationMinute$1],
[ hour, 1, durationHour$1 ],
[ hour, 3, 3 * durationHour$1 ],
[ hour, 6, 6 * durationHour$1 ],
[ hour, 12, 12 * durationHour$1 ],
[ day, 1, durationDay$1 ],
[ day, 2, 2 * durationDay$1 ],
[ week, 1, durationWeek$1 ],
[ month, 1, durationMonth ],
[ month, 3, 3 * durationMonth ],
[ year, 1, durationYear ]
];
function tickFormat(date) {
return (second(date) < date ? formatMillisecond
: minute(date) < date ? formatSecond
: hour(date) < date ? formatMinute
: day(date) < date ? formatHour
: month(date) < date ? (week(date) < date ? formatDay : formatWeek)
: year(date) < date ? formatMonth
: formatYear)(date);
}
function tickInterval(interval, start, stop, step) {
if (interval == null) interval = 10;
// If a desired tick count is specified, pick a reasonable tick interval
// based on the extent of the domain and a rough estimate of tick size.
// Otherwise, assume interval is already a time interval and use it.
if (typeof interval === "number") {
var target = Math.abs(stop - start) / interval,
i = bisector(function(i) { return i[2]; }).right(tickIntervals, target);
if (i === tickIntervals.length) {
step = tickStep(start / durationYear, stop / durationYear, interval);
interval = year;
} else if (i) {
i = tickIntervals[target / tickIntervals[i - 1][2] < tickIntervals[i][2] / target ? i - 1 : i];
step = i[1];
interval = i[0];
} else {
step = tickStep(start, stop, interval);
interval = millisecond;
}
}
return step == null ? interval : interval.every(step);
}
scale.invert = function(y) {
return new Date(invert(y));
};
scale.domain = function(_) {
return arguments.length ? domain(map$2.call(_, number$2)) : domain().map(date$1);
};
scale.ticks = function(interval, step) {
var d = domain(),
t0 = d[0],
t1 = d[d.length - 1],
r = t1 < t0,
t;
if (r) t = t0, t0 = t1, t1 = t;
t = tickInterval(interval, t0, t1, step);
t = t ? t.range(t0, t1 + 1) : []; // inclusive stop
return r ? t.reverse() : t;
};
scale.tickFormat = function(count, specifier) {
return specifier == null ? tickFormat : format(specifier);
};
scale.nice = function(interval, step) {
var d = domain();
return (interval = tickInterval(interval, d[0], d[d.length - 1], step))
? domain(nice(d, interval))
: scale;
};
scale.copy = function() {
return copy(scale, calendar(year, month, week, day, hour, minute, second, millisecond, format));
};
return scale;
}
function time() {
return calendar(year, month, timeWeek, day, hour, minute, second, millisecond, exports.timeFormat).domain([new Date(2000, 0, 1), new Date(2000, 0, 2)]);
}
function utcTime() {
return calendar(utcYear, utcMonth, utcWeek, utcDay, utcHour, utcMinute, second, millisecond, exports.utcFormat).domain([Date.UTC(2000, 0, 1), Date.UTC(2000, 0, 2)]);
}
function colors(s) {
return s.match(/.{6}/g).map(function(x) {
return "#" + x;
});
}
var category10 = colors("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf");
var category20b = colors("393b795254a36b6ecf9c9ede6379398ca252b5cf6bcedb9c8c6d31bd9e39e7ba52e7cb94843c39ad494ad6616be7969c7b4173a55194ce6dbdde9ed6");
var category20c = colors("3182bd6baed69ecae1c6dbefe6550dfd8d3cfdae6bfdd0a231a35474c476a1d99bc7e9c0756bb19e9ac8bcbddcdadaeb636363969696bdbdbdd9d9d9");
var category20 = colors("1f77b4aec7e8ff7f0effbb782ca02c98df8ad62728ff98969467bdc5b0d58c564bc49c94e377c2f7b6d27f7f7fc7c7c7bcbd22dbdb8d17becf9edae5");
var cubehelix$3 = interpolateCubehelixLong(cubehelix(300, 0.5, 0.0), cubehelix(-240, 0.5, 1.0));
var warm = interpolateCubehelixLong(cubehelix(-100, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
var cool = interpolateCubehelixLong(cubehelix(260, 0.75, 0.35), cubehelix(80, 1.50, 0.8));
var rainbow = cubehelix();
function rainbow$1(t) {
if (t < 0 || t > 1) t -= Math.floor(t);
var ts = Math.abs(t - 0.5);
rainbow.h = 360 * t - 100;
rainbow.s = 1.5 - 1.5 * ts;
rainbow.l = 0.8 - 0.9 * ts;
return rainbow + "";
}
function ramp(range) {
var n = range.length;
return function(t) {
return range[Math.max(0, Math.min(n - 1, Math.floor(t * n)))];
};
}
var viridis = ramp(colors("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725"));
var magma = ramp(colors("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf"));
var inferno = ramp(colors("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4"));
var plasma = ramp(colors("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));
function sequential(interpolator) {
var x0 = 0,
x1 = 1,
clamp = false;
function scale(x) {
var t = (x - x0) / (x1 - x0);
return interpolator(clamp ? Math.max(0, Math.min(1, t)) : t);
}
scale.domain = function(_) {
return arguments.length ? (x0 = +_[0], x1 = +_[1], scale) : [x0, x1];
};
scale.clamp = function(_) {
return arguments.length ? (clamp = !!_, scale) : clamp;
};
scale.interpolator = function(_) {
return arguments.length ? (interpolator = _, scale) : interpolator;
};
scale.copy = function() {
return sequential(interpolator).domain([x0, x1]).clamp(clamp);
};
return linearish(scale);
}
var xhtml = "http://www.w3.org/1999/xhtml";
var namespaces = {
svg: "http://www.w3.org/2000/svg",
xhtml: xhtml,
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
function namespace(name) {
var prefix = name += "", i = prefix.indexOf(":");
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name;
}
function creatorInherit(name) {
return function() {
var document = this.ownerDocument,
uri = this.namespaceURI;
return uri === xhtml && document.documentElement.namespaceURI === xhtml
? document.createElement(name)
: document.createElementNS(uri, name);
};
}
function creatorFixed(fullname) {
return function() {
return this.ownerDocument.createElementNS(fullname.space, fullname.local);
};
}
function creator(name) {
var fullname = namespace(name);
return (fullname.local
? creatorFixed
: creatorInherit)(fullname);
}
var nextId = 0;
function local() {
return new Local;
}
function Local() {
this._ = "@" + (++nextId).toString(36);
}
Local.prototype = local.prototype = {
constructor: Local,
get: function(node) {
var id = this._;
while (!(id in node)) if (!(node = node.parentNode)) return;
return node[id];
},
set: function(node, value) {
return node[this._] = value;
},
remove: function(node) {
return this._ in node && delete node[this._];
},
toString: function() {
return this._;
}
};
var matcher = function(selector) {
return function() {
return this.matches(selector);
};
};
if (typeof document !== "undefined") {
var element = document.documentElement;
if (!element.matches) {
var vendorMatches = element.webkitMatchesSelector
|| element.msMatchesSelector
|| element.mozMatchesSelector
|| element.oMatchesSelector;
matcher = function(selector) {
return function() {
return vendorMatches.call(this, selector);
};
};
}
}
var matcher$1 = matcher;
var filterEvents = {};
exports.event = null;
if (typeof document !== "undefined") {
var element$1 = document.documentElement;
if (!("onmouseenter" in element$1)) {
filterEvents = {mouseenter: "mouseover", mouseleave: "mouseout"};
}
}
function filterContextListener(listener, index, group) {
listener = contextListener(listener, index, group);
return function(event) {
var related = event.relatedTarget;
if (!related || (related !== this && !(related.compareDocumentPosition(this) & 8))) {
listener.call(this, event);
}
};
}
function contextListener(listener, index, group) {
return function(event1) {
var event0 = exports.event; // Events can be reentrant (e.g., focus).
exports.event = event1;
try {
listener.call(this, this.__data__, index, group);
} finally {
exports.event = event0;
}
};
}
function parseTypenames$1(typenames) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
return {type: t, name: name};
});
}
function onRemove(typename) {
return function() {
var on = this.__on;
if (!on) return;
for (var j = 0, i = -1, m = on.length, o; j < m; ++j) {
if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.capture);
} else {
on[++i] = o;
}
}
if (++i) on.length = i;
else delete this.__on;
};
}
function onAdd(typename, value, capture) {
var wrap = filterEvents.hasOwnProperty(typename.type) ? filterContextListener : contextListener;
return function(d, i, group) {
var on = this.__on, o, listener = wrap(value, i, group);
if (on) for (var j = 0, m = on.length; j < m; ++j) {
if ((o = on[j]).type === typename.type && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.capture);
this.addEventListener(o.type, o.listener = listener, o.capture = capture);
o.value = value;
return;
}
}
this.addEventListener(typename.type, listener, capture);
o = {type: typename.type, name: typename.name, value: value, listener: listener, capture: capture};
if (!on) this.__on = [o];
else on.push(o);
};
}
function selection_on(typename, value, capture) {
var typenames = parseTypenames$1(typename + ""), i, n = typenames.length, t;
if (arguments.length < 2) {
var on = this.node().__on;
if (on) for (var j = 0, m = on.length, o; j < m; ++j) {
for (i = 0, o = on[j]; i < n; ++i) {
if ((t = typenames[i]).type === o.type && t.name === o.name) {
return o.value;
}
}
}
return;
}
on = value ? onAdd : onRemove;
if (capture == null) capture = false;
for (i = 0; i < n; ++i) this.each(on(typenames[i], value, capture));
return this;
}
function customEvent(event1, listener, that, args) {
var event0 = exports.event;
event1.sourceEvent = exports.event;
exports.event = event1;
try {
return listener.apply(that, args);
} finally {
exports.event = event0;
}
}
function sourceEvent() {
var current = exports.event, source;
while (source = current.sourceEvent) current = source;
return current;
}
function point$5(node, event) {
var svg = node.ownerSVGElement || node;
if (svg.createSVGPoint) {
var point = svg.createSVGPoint();
point.x = event.clientX, point.y = event.clientY;
point = point.matrixTransform(node.getScreenCTM().inverse());
return [point.x, point.y];
}
var rect = node.getBoundingClientRect();
return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
}
function mouse(node) {
var event = sourceEvent();
if (event.changedTouches) event = event.changedTouches[0];
return point$5(node, event);
}
function none$2() {}
function selector(selector) {
return selector == null ? none$2 : function() {
return this.querySelector(selector);
};
}
function selection_select(select) {
if (typeof select !== "function") select = selector(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
}
}
}
return new Selection(subgroups, this._parents);
}
function empty() {
return [];
}
function selectorAll(selector) {
return selector == null ? empty : function() {
return this.querySelectorAll(selector);
};
}
function selection_selectAll(select) {
if (typeof select !== "function") select = selectorAll(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
subgroups.push(select.call(node, node.__data__, i, group));
parents.push(node);
}
}
}
return new Selection(subgroups, parents);
}
function selection_filter(match) {
if (typeof match !== "function") match = matcher$1(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
subgroup.push(node);
}
}
}
return new Selection(subgroups, this._parents);
}
function sparse(update) {
return new Array(update.length);
}
function selection_enter() {
return new Selection(this._enter || this._groups.map(sparse), this._parents);
}
function EnterNode(parent, datum) {
this.ownerDocument = parent.ownerDocument;
this.namespaceURI = parent.namespaceURI;
this._next = null;
this._parent = parent;
this.__data__ = datum;
}
EnterNode.prototype = {
constructor: EnterNode,
appendChild: function(child) { return this._parent.insertBefore(child, this._next); },
insertBefore: function(child, next) { return this._parent.insertBefore(child, next); },
querySelector: function(selector) { return this._parent.querySelector(selector); },
querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); }
};
function constant$4(x) {
return function() {
return x;
};
}
var keyPrefix = "$"; // Protect against keys like “__proto__”.
function bindIndex(parent, group, enter, update, exit, data) {
var i = 0,
node,
groupLength = group.length,
dataLength = data.length;
// Put any non-null nodes that fit into update.
// Put any null nodes into enter.
// Put any remaining data into enter.
for (; i < dataLength; ++i) {
if (node = group[i]) {
node.__data__ = data[i];
update[i] = node;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
// Put any non-null nodes that don’t fit into exit.
for (; i < groupLength; ++i) {
if (node = group[i]) {
exit[i] = node;
}
}
}
function bindKey(parent, group, enter, update, exit, data, key) {
var i,
node,
nodeByKeyValue = {},
groupLength = group.length,
dataLength = data.length,
keyValues = new Array(groupLength),
keyValue;
// Compute the key for each node.
// If multiple nodes have the same key, the duplicates are added to exit.
for (i = 0; i < groupLength; ++i) {
if (node = group[i]) {
keyValues[i] = keyValue = keyPrefix + key.call(node, node.__data__, i, group);
if (keyValue in nodeByKeyValue) {
exit[i] = node;
} else {
nodeByKeyValue[keyValue] = node;
}
}
}
// Compute the key for each datum.
// If there a node associated with this key, join and add it to update.
// If there is not (or the key is a duplicate), add it to enter.
for (i = 0; i < dataLength; ++i) {
keyValue = keyPrefix + key.call(parent, data[i], i, data);
if (node = nodeByKeyValue[keyValue]) {
update[i] = node;
node.__data__ = data[i];
nodeByKeyValue[keyValue] = null;
} else {
enter[i] = new EnterNode(parent, data[i]);
}
}
// Add any remaining nodes that were not bound to data to exit.
for (i = 0; i < groupLength; ++i) {
if ((node = group[i]) && (nodeByKeyValue[keyValues[i]] === node)) {
exit[i] = node;
}
}
}
function selection_data(value, key) {
if (!value) {
data = new Array(this.size()), j = -1;
this.each(function(d) { data[++j] = d; });
return data;
}
var bind = key ? bindKey : bindIndex,
parents = this._parents,
groups = this._groups;
if (typeof value !== "function") value = constant$4(value);
for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
var parent = parents[j],
group = groups[j],
groupLength = group.length,
data = value.call(parent, parent && parent.__data__, j, parents),
dataLength = data.length,
enterGroup = enter[j] = new Array(dataLength),
updateGroup = update[j] = new Array(dataLength),
exitGroup = exit[j] = new Array(groupLength);
bind(parent, group, enterGroup, updateGroup, exitGroup, data, key);
// Now connect the enter nodes to their following update node, such that
// appendChild can insert the materialized enter node before this node,
// rather than at the end of the parent node.
for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) {
if (previous = enterGroup[i0]) {
if (i0 >= i1) i1 = i0 + 1;
while (!(next = updateGroup[i1]) && ++i1 < dataLength);
previous._next = next || null;
}
}
}
update = new Selection(update, parents);
update._enter = enter;
update._exit = exit;
return update;
}
function selection_exit() {
return new Selection(this._exit || this._groups.map(sparse), this._parents);
}
function selection_merge(selection) {
for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group0[i] || group1[i]) {
merge[i] = node;
}
}
}
for (; j < m0; ++j) {
merges[j] = groups0[j];
}
return new Selection(merges, this._parents);
}
function selection_order() {
for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) {
for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) {
if (node = group[i]) {
if (next && next !== node.nextSibling) next.parentNode.insertBefore(node, next);
next = node;
}
}
}
return this;
}
function selection_sort(compare) {
if (!compare) compare = ascending$2;
function compareNode(a, b) {
return a && b ? compare(a.__data__, b.__data__) : !a - !b;
}
for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group[i]) {
sortgroup[i] = node;
}
}
sortgroup.sort(compareNode);
}
return new Selection(sortgroups, this._parents).order();
}
function ascending$2(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
function selection_call() {
var callback = arguments[0];
arguments[0] = this;
callback.apply(null, arguments);
return this;
}
function selection_nodes() {
var nodes = new Array(this.size()), i = -1;
this.each(function() { nodes[++i] = this; });
return nodes;
}
function selection_node() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
var node = group[i];
if (node) return node;
}
}
return null;
}
function selection_size() {
var size = 0;
this.each(function() { ++size; });
return size;
}
function selection_empty() {
return !this.node();
}
function selection_each(callback) {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) {
for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) {
if (node = group[i]) callback.call(node, node.__data__, i, group);
}
}
return this;
}
function attrRemove(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant(name, value) {
return function() {
this.setAttribute(name, value);
};
}
function attrConstantNS(fullname, value) {
return function() {
this.setAttributeNS(fullname.space, fullname.local, value);
};
}
function attrFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttribute(name);
else this.setAttribute(name, v);
};
}
function attrFunctionNS(fullname, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
else this.setAttributeNS(fullname.space, fullname.local, v);
};
}
function selection_attr(name, value) {
var fullname = namespace(name);
if (arguments.length < 2) {
var node = this.node();
return fullname.local
? node.getAttributeNS(fullname.space, fullname.local)
: node.getAttribute(fullname);
}
return this.each((value == null
? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function"
? (fullname.local ? attrFunctionNS : attrFunction)
: (fullname.local ? attrConstantNS : attrConstant)))(fullname, value));
}
function window$1(node) {
return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node
|| (node.document && node) // node is a Window
|| node.defaultView; // node is a Document
}
function styleRemove(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant(name, value, priority) {
return function() {
this.style.setProperty(name, value, priority);
};
}
function styleFunction(name, value, priority) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.style.removeProperty(name);
else this.style.setProperty(name, v, priority);
};
}
function selection_style(name, value, priority) {
var node;
return arguments.length > 1
? this.each((value == null
? styleRemove : typeof value === "function"
? styleFunction
: styleConstant)(name, value, priority == null ? "" : priority))
: window$1(node = this.node())
.getComputedStyle(node, null)
.getPropertyValue(name);
}
function propertyRemove(name) {
return function() {
delete this[name];
};
}
function propertyConstant(name, value) {
return function() {
this[name] = value;
};
}
function propertyFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) delete this[name];
else this[name] = v;
};
}
function selection_property(name, value) {
return arguments.length > 1
? this.each((value == null
? propertyRemove : typeof value === "function"
? propertyFunction
: propertyConstant)(name, value))
: this.node()[name];
}
function classArray(string) {
return string.trim().split(/^|\s+/);
}
function classList(node) {
return node.classList || new ClassList(node);
}
function ClassList(node) {
this._node = node;
this._names = classArray(node.getAttribute("class") || "");
}
ClassList.prototype = {
add: function(name) {
var i = this._names.indexOf(name);
if (i < 0) {
this._names.push(name);
this._node.setAttribute("class", this._names.join(" "));
}
},
remove: function(name) {
var i = this._names.indexOf(name);
if (i >= 0) {
this._names.splice(i, 1);
this._node.setAttribute("class", this._names.join(" "));
}
},
contains: function(name) {
return this._names.indexOf(name) >= 0;
}
};
function classedAdd(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.add(names[i]);
}
function classedRemove(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.remove(names[i]);
}
function classedTrue(names) {
return function() {
classedAdd(this, names);
};
}
function classedFalse(names) {
return function() {
classedRemove(this, names);
};
}
function classedFunction(names, value) {
return function() {
(value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
};
}
function selection_classed(name, value) {
var names = classArray(name + "");
if (arguments.length < 2) {
var list = classList(this.node()), i = -1, n = names.length;
while (++i < n) if (!list.contains(names[i])) return false;
return true;
}
return this.each((typeof value === "function"
? classedFunction : value
? classedTrue
: classedFalse)(names, value));
}
function textRemove() {
this.textContent = "";
}
function textConstant(value) {
return function() {
this.textContent = value;
};
}
function textFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v;
};
}
function selection_text(value) {
return arguments.length
? this.each(value == null
? textRemove : (typeof value === "function"
? textFunction
: textConstant)(value))
: this.node().textContent;
}
function htmlRemove() {
this.innerHTML = "";
}
function htmlConstant(value) {
return function() {
this.innerHTML = value;
};
}
function htmlFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v;
};
}
function selection_html(value) {
return arguments.length
? this.each(value == null
? htmlRemove : (typeof value === "function"
? htmlFunction
: htmlConstant)(value))
: this.node().innerHTML;
}
function raise$1() {
if (this.nextSibling) this.parentNode.appendChild(this);
}
function selection_raise() {
return this.each(raise$1);
}
function lower() {
if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
}
function selection_lower() {
return this.each(lower);
}
function selection_append(name) {
var create = typeof name === "function" ? name : creator(name);
return this.select(function() {
return this.appendChild(create.apply(this, arguments));
});
}
function constantNull() {
return null;
}
function selection_insert(name, before) {
var create = typeof name === "function" ? name : creator(name),
select = before == null ? constantNull : typeof before === "function" ? before : selector(before);
return this.select(function() {
return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
});
}
function remove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
function selection_remove() {
return this.each(remove);
}
function selection_datum(value) {
return arguments.length
? this.property("__data__", value)
: this.node().__data__;
}
function dispatchEvent(node, type, params) {
var window = window$1(node),
event = window.CustomEvent;
if (event) {
event = new event(type, params);
} else {
event = window.document.createEvent("Event");
if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
else event.initEvent(type, false, false);
}
node.dispatchEvent(event);
}
function dispatchConstant(type, params) {
return function() {
return dispatchEvent(this, type, params);
};
}
function dispatchFunction(type, params) {
return function() {
return dispatchEvent(this, type, params.apply(this, arguments));
};
}
function selection_dispatch(type, params) {
return this.each((typeof params === "function"
? dispatchFunction
: dispatchConstant)(type, params));
}
var root = [null];
function Selection(groups, parents) {
this._groups = groups;
this._parents = parents;
}
function selection() {
return new Selection([[document.documentElement]], root);
}
Selection.prototype = selection.prototype = {
constructor: Selection,
select: selection_select,
selectAll: selection_selectAll,
filter: selection_filter,
data: selection_data,
enter: selection_enter,
exit: selection_exit,
merge: selection_merge,
order: selection_order,
sort: selection_sort,
call: selection_call,
nodes: selection_nodes,
node: selection_node,
size: selection_size,
empty: selection_empty,
each: selection_each,
attr: selection_attr,
style: selection_style,
property: selection_property,
classed: selection_classed,
text: selection_text,
html: selection_html,
raise: selection_raise,
lower: selection_lower,
append: selection_append,
insert: selection_insert,
remove: selection_remove,
datum: selection_datum,
on: selection_on,
dispatch: selection_dispatch
};
function select(selector) {
return typeof selector === "string"
? new Selection([[document.querySelector(selector)]], [document.documentElement])
: new Selection([[selector]], root);
}
function selectAll(selector) {
return typeof selector === "string"
? new Selection([document.querySelectorAll(selector)], [document.documentElement])
: new Selection([selector == null ? [] : selector], root);
}
function touch(node, touches, identifier) {
if (arguments.length < 3) identifier = touches, touches = sourceEvent().changedTouches;
for (var i = 0, n = touches ? touches.length : 0, touch; i < n; ++i) {
if ((touch = touches[i]).identifier === identifier) {
return point$5(node, touch);
}
}
return null;
}
function touches(node, touches) {
if (touches == null) touches = sourceEvent().touches;
for (var i = 0, n = touches ? touches.length : 0, points = new Array(n); i < n; ++i) {
points[i] = point$5(node, touches[i]);
}
return points;
}
var emptyOn = dispatch("start", "end", "interrupt");
var emptyTween = [];
var CREATED = 0;
var SCHEDULED = 1;
var STARTING = 2;
var STARTED = 3;
var ENDING = 4;
var ENDED = 5;
function schedule(node, name, id, index, group, timing) {
var schedules = node.__transition;
if (!schedules) node.__transition = {};
else if (id in schedules) return;
create(node, id, {
name: name,
index: index, // For context during callback.
group: group, // For context during callback.
on: emptyOn,
tween: emptyTween,
time: timing.time,
delay: timing.delay,
duration: timing.duration,
ease: timing.ease,
timer: null,
state: CREATED
});
}
function init(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id]) || schedule.state > CREATED) throw new Error("too late");
return schedule;
}
function set$2(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id]) || schedule.state > STARTING) throw new Error("too late");
return schedule;
}
function get$1(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id])) throw new Error("too late");
return schedule;
}
function create(node, id, self) {
var schedules = node.__transition,
tween;
// Initialize the self timer when the transition is created.
// Note the actual delay is not known until the first callback!
schedules[id] = self;
self.timer = timer(schedule, 0, self.time);
// If the delay is greater than this first sleep, sleep some more;
// otherwise, start immediately.
function schedule(elapsed) {
self.state = SCHEDULED;
if (self.delay <= elapsed) start(elapsed - self.delay);
else self.timer.restart(start, self.delay, self.time);
}
function start(elapsed) {
var i, j, n, o;
for (i in schedules) {
o = schedules[i];
if (o.name !== self.name) continue;
// Interrupt the active transition, if any.
// Dispatch the interrupt event.
if (o.state === STARTED) {
o.state = ENDED;
o.timer.stop();
o.on.call("interrupt", node, node.__data__, o.index, o.group);
delete schedules[i];
}
// Cancel any pre-empted transitions. No interrupt event is dispatched
// because the cancelled transitions never started. Note that this also
// removes this transition from the pending list!
else if (+i < id) {
o.state = ENDED;
o.timer.stop();
delete schedules[i];
}
}
// Defer the first tick to end of the current frame; see mbostock/d3#1576.
// Note the transition may be canceled after start and before the first tick!
// Note this must be scheduled before the start event; see d3/d3-transition#16!
// Assuming this is successful, subsequent callbacks go straight to tick.
timeout$1(function() {
if (self.state === STARTED) {
self.timer.restart(tick, self.delay, self.time);
tick(elapsed);
}
});
// Dispatch the start event.
// Note this must be done before the tween are initialized.
self.state = STARTING;
self.on.call("start", node, node.__data__, self.index, self.group);
if (self.state !== STARTING) return; // interrupted
self.state = STARTED;
// Initialize the tween, deleting null tween.
tween = new Array(n = self.tween.length);
for (i = 0, j = -1; i < n; ++i) {
if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) {
tween[++j] = o;
}
}
tween.length = j + 1;
}
function tick(elapsed) {
var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.state = ENDING, 1),
i = -1,
n = tween.length;
while (++i < n) {
tween[i].call(null, t);
}
// Dispatch the end event.
if (self.state === ENDING) {
self.state = ENDED;
self.timer.stop();
self.on.call("end", node, node.__data__, self.index, self.group);
for (i in schedules) if (+i !== id) return void delete schedules[id];
delete node.__transition;
}
}
}
function interrupt(node, name) {
var schedules = node.__transition,
schedule,
active,
empty = true,
i;
if (!schedules) return;
name = name == null ? null : name + "";
for (i in schedules) {
if ((schedule = schedules[i]).name !== name) { empty = false; continue; }
active = schedule.state === STARTED;
schedule.state = ENDED;
schedule.timer.stop();
if (active) schedule.on.call("interrupt", node, node.__data__, schedule.index, schedule.group);
delete schedules[i];
}
if (empty) delete node.__transition;
}
function selection_interrupt(name) {
return this.each(function() {
interrupt(this, name);
});
}
function tweenRemove(id, name) {
var tween0, tween1;
return function() {
var schedule = set$2(this, id),
tween = schedule.tween;
// If this node shared tween with the previous node,
// just assign the updated shared tween and we’re done!
// Otherwise, copy-on-write.
if (tween !== tween0) {
tween1 = tween0 = tween;
for (var i = 0, n = tween1.length; i < n; ++i) {
if (tween1[i].name === name) {
tween1 = tween1.slice();
tween1.splice(i, 1);
break;
}
}
}
schedule.tween = tween1;
};
}
function tweenFunction(id, name, value) {
var tween0, tween1;
if (typeof value !== "function") throw new Error;
return function() {
var schedule = set$2(this, id),
tween = schedule.tween;
// If this node shared tween with the previous node,
// just assign the updated shared tween and we’re done!
// Otherwise, copy-on-write.
if (tween !== tween0) {
tween1 = (tween0 = tween).slice();
for (var t = {name: name, value: value}, i = 0, n = tween1.length; i < n; ++i) {
if (tween1[i].name === name) {
tween1[i] = t;
break;
}
}
if (i === n) tween1.push(t);
}
schedule.tween = tween1;
};
}
function transition_tween(name, value) {
var id = this._id;
name += "";
if (arguments.length < 2) {
var tween = get$1(this.node(), id).tween;
for (var i = 0, n = tween.length, t; i < n; ++i) {
if ((t = tween[i]).name === name) {
return t.value;
}
}
return null;
}
return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
}
function tweenValue(transition, name, value) {
var id = transition._id;
transition.each(function() {
var schedule = set$2(this, id);
(schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
});
return function(node) {
return get$1(node, id).value[name];
};
}
function interpolate$1(a, b) {
var c;
return (typeof b === "number" ? interpolateNumber
: b instanceof color ? interpolateRgb
: (c = color(b)) ? (b = c, interpolateRgb)
: interpolateString)(a, b);
}
function attrRemove$1(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS$1(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant$1(name, interpolate, value1) {
var value00,
interpolate0;
return function() {
var value0 = this.getAttribute(name);
return value0 === value1 ? null
: value0 === value00 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value1);
};
}
function attrConstantNS$1(fullname, interpolate, value1) {
var value00,
interpolate0;
return function() {
var value0 = this.getAttributeNS(fullname.space, fullname.local);
return value0 === value1 ? null
: value0 === value00 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value1);
};
}
function attrFunction$1(name, interpolate, value) {
var value00,
value10,
interpolate0;
return function() {
var value0, value1 = value(this);
if (value1 == null) return void this.removeAttribute(name);
value0 = this.getAttribute(name);
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function attrFunctionNS$1(fullname, interpolate, value) {
var value00,
value10,
interpolate0;
return function() {
var value0, value1 = value(this);
if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
value0 = this.getAttributeNS(fullname.space, fullname.local);
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function transition_attr(name, value) {
var fullname = namespace(name), i = fullname === "transform" ? interpolateTransform$2 : interpolate$1;
return this.attrTween(name, typeof value === "function"
? (fullname.local ? attrFunctionNS$1 : attrFunction$1)(fullname, i, tweenValue(this, "attr." + name, value))
: value == null ? (fullname.local ? attrRemoveNS$1 : attrRemove$1)(fullname)
: (fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, i, value));
}
function attrTweenNS(fullname, value) {
function tween() {
var node = this, i = value.apply(node, arguments);
return i && function(t) {
node.setAttributeNS(fullname.space, fullname.local, i(t));
};
}
tween._value = value;
return tween;
}
function attrTween(name, value) {
function tween() {
var node = this, i = value.apply(node, arguments);
return i && function(t) {
node.setAttribute(name, i(t));
};
}
tween._value = value;
return tween;
}
function transition_attrTween(name, value) {
var key = "attr." + name;
if (arguments.length < 2) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error;
var fullname = namespace(name);
return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
}
function delayFunction(id, value) {
return function() {
init(this, id).delay = +value.apply(this, arguments);
};
}
function delayConstant(id, value) {
return value = +value, function() {
init(this, id).delay = value;
};
}
function transition_delay(value) {
var id = this._id;
return arguments.length
? this.each((typeof value === "function"
? delayFunction
: delayConstant)(id, value))
: get$1(this.node(), id).delay;
}
function durationFunction(id, value) {
return function() {
set$2(this, id).duration = +value.apply(this, arguments);
};
}
function durationConstant(id, value) {
return value = +value, function() {
set$2(this, id).duration = value;
};
}
function transition_duration(value) {
var id = this._id;
return arguments.length
? this.each((typeof value === "function"
? durationFunction
: durationConstant)(id, value))
: get$1(this.node(), id).duration;
}
function easeConstant(id, value) {
if (typeof value !== "function") throw new Error;
return function() {
set$2(this, id).ease = value;
};
}
function transition_ease(value) {
var id = this._id;
return arguments.length
? this.each(easeConstant(id, value))
: get$1(this.node(), id).ease;
}
function transition_filter(match) {
if (typeof match !== "function") match = matcher$1(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) {
if ((node = group[i]) && match.call(node, node.__data__, i, group)) {
subgroup.push(node);
}
}
}
return new Transition(subgroups, this._parents, this._name, this._id);
}
function transition_merge(transition) {
if (transition._id !== this._id) throw new Error;
for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) {
for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) {
if (node = group0[i] || group1[i]) {
merge[i] = node;
}
}
}
for (; j < m0; ++j) {
merges[j] = groups0[j];
}
return new Transition(merges, this._parents, this._name, this._id);
}
function start$1(name) {
return (name + "").trim().split(/^|\s+/).every(function(t) {
var i = t.indexOf(".");
if (i >= 0) t = t.slice(0, i);
return !t || t === "start";
});
}
function onFunction(id, name, listener) {
var on0, on1, sit = start$1(name) ? init : set$2;
return function() {
var schedule = sit(this, id),
on = schedule.on;
// If this node shared a dispatch with the previous node,
// just assign the updated shared dispatch and we’re done!
// Otherwise, copy-on-write.
if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
schedule.on = on1;
};
}
function transition_on(name, listener) {
var id = this._id;
return arguments.length < 2
? get$1(this.node(), id).on.on(name)
: this.each(onFunction(id, name, listener));
}
function removeFunction(id) {
return function() {
var parent = this.parentNode;
for (var i in this.__transition) if (+i !== id) return;
if (parent) parent.removeChild(this);
};
}
function transition_remove() {
return this.on("end.remove", removeFunction(this._id));
}
function transition_select(select) {
var name = this._name,
id = this._id;
if (typeof select !== "function") select = selector(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) {
if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
schedule(subgroup[i], name, id, i, subgroup, get$1(node, id));
}
}
}
return new Transition(subgroups, this._parents, name, id);
}
function transition_selectAll(select) {
var name = this._name,
id = this._id;
if (typeof select !== "function") select = selectorAll(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
for (var children = select.call(node, node.__data__, i, group), child, inherit = get$1(node, id), k = 0, l = children.length; k < l; ++k) {
if (child = children[k]) {
schedule(child, name, id, k, children, inherit);
}
}
subgroups.push(children);
parents.push(node);
}
}
}
return new Transition(subgroups, parents, name, id);
}
var Selection$1 = selection.prototype.constructor;
function transition_selection() {
return new Selection$1(this._groups, this._parents);
}
function styleRemove$1(name, interpolate) {
var value00,
value10,
interpolate0;
return function() {
var style = window$1(this).getComputedStyle(this, null),
value0 = style.getPropertyValue(name),
value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function styleRemoveEnd(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant$1(name, interpolate, value1) {
var value00,
interpolate0;
return function() {
var value0 = window$1(this).getComputedStyle(this, null).getPropertyValue(name);
return value0 === value1 ? null
: value0 === value00 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value1);
};
}
function styleFunction$1(name, interpolate, value) {
var value00,
value10,
interpolate0;
return function() {
var style = window$1(this).getComputedStyle(this, null),
value0 = style.getPropertyValue(name),
value1 = value(this);
if (value1 == null) value1 = (this.style.removeProperty(name), style.getPropertyValue(name));
return value0 === value1 ? null
: value0 === value00 && value1 === value10 ? interpolate0
: interpolate0 = interpolate(value00 = value0, value10 = value1);
};
}
function transition_style(name, value, priority) {
var i = (name += "") === "transform" ? interpolateTransform$1 : interpolate$1;
return value == null ? this
.styleTween(name, styleRemove$1(name, i))
.on("end.style." + name, styleRemoveEnd(name))
: this.styleTween(name, typeof value === "function"
? styleFunction$1(name, i, tweenValue(this, "style." + name, value))
: styleConstant$1(name, i, value), priority);
}
function styleTween(name, value, priority) {
function tween() {
var node = this, i = value.apply(node, arguments);
return i && function(t) {
node.style.setProperty(name, i(t), priority);
};
}
tween._value = value;
return tween;
}
function transition_styleTween(name, value, priority) {
var key = "style." + (name += "");
if (arguments.length < 2) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error;
return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
}
function textConstant$1(value) {
return function() {
this.textContent = value;
};
}
function textFunction$1(value) {
return function() {
var value1 = value(this);
this.textContent = value1 == null ? "" : value1;
};
}
function transition_text(value) {
return this.tween("text", typeof value === "function"
? textFunction$1(tweenValue(this, "text", value))
: textConstant$1(value == null ? "" : value + ""));
}
function transition_transition() {
var name = this._name,
id0 = this._id,
id1 = newId();
for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
var inherit = get$1(node, id0);
schedule(node, name, id1, i, group, {
time: inherit.time + inherit.delay + inherit.duration,
delay: 0,
duration: inherit.duration,
ease: inherit.ease
});
}
}
}
return new Transition(groups, this._parents, name, id1);
}
var id = 0;
function Transition(groups, parents, name, id) {
this._groups = groups;
this._parents = parents;
this._name = name;
this._id = id;
}
function transition(name) {
return selection().transition(name);
}
function newId() {
return ++id;
}
var selection_prototype = selection.prototype;
Transition.prototype = transition.prototype = {
constructor: Transition,
select: transition_select,
selectAll: transition_selectAll,
filter: transition_filter,
merge: transition_merge,
selection: transition_selection,
transition: transition_transition,
call: selection_prototype.call,
nodes: selection_prototype.nodes,
node: selection_prototype.node,
size: selection_prototype.size,
empty: selection_prototype.empty,
each: selection_prototype.each,
on: transition_on,
attr: transition_attr,
attrTween: transition_attrTween,
style: transition_style,
styleTween: transition_styleTween,
text: transition_text,
remove: transition_remove,
tween: transition_tween,
delay: transition_delay,
duration: transition_duration,
ease: transition_ease
};
var defaultTiming = {
time: null, // Set on use.
delay: 0,
duration: 250,
ease: easeCubicInOut
};
function inherit(node, id) {
var timing;
while (!(timing = node.__transition) || !(timing = timing[id])) {
if (!(node = node.parentNode)) {
return defaultTiming.time = now(), defaultTiming;
}
}
return timing;
}
function selection_transition(name) {
var id,
timing;
if (name instanceof Transition) {
id = name._id, name = name._name;
} else {
id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
}
for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) {
if (node = group[i]) {
schedule(node, name, id, i, group, timing || inherit(node, id));
}
}
}
return new Transition(groups, this._parents, name, id);
}
selection.prototype.interrupt = selection_interrupt;
selection.prototype.transition = selection_transition;
var root$1 = [null];
function active(node, name) {
var schedules = node.__transition,
schedule,
i;
if (schedules) {
name = name == null ? null : name + "";
for (i in schedules) {
if ((schedule = schedules[i]).state > SCHEDULED && schedule.name === name) {
return new Transition([[node]], root$1, name, +i);
}
}
}
return null;
}
var slice$4 = Array.prototype.slice;
function identity$5(x) {
return x;
}
var top = 1;
var right = 2;
var bottom = 3;
var left = 4;
var epsilon$2 = 1e-6;
function translateX(scale0, scale1, d) {
var x = scale0(d);
return "translate(" + (isFinite(x) ? x : scale1(d)) + ",0)";
}
function translateY(scale0, scale1, d) {
var y = scale0(d);
return "translate(0," + (isFinite(y) ? y : scale1(d)) + ")";
}
function center(scale) {
var offset = scale.bandwidth() / 2;
if (scale.round()) offset = Math.round(offset);
return function(d) {
return scale(d) + offset;
};
}
function entering() {
return !this.__axis;
}
function axis(orient, scale) {
var tickArguments = [],
tickValues = null,
tickFormat = null,
tickSizeInner = 6,
tickSizeOuter = 6,
tickPadding = 3;
function axis(context) {
var values = tickValues == null ? (scale.ticks ? scale.ticks.apply(scale, tickArguments) : scale.domain()) : tickValues,
format = tickFormat == null ? (scale.tickFormat ? scale.tickFormat.apply(scale, tickArguments) : identity$5) : tickFormat,
spacing = Math.max(tickSizeInner, 0) + tickPadding,
transform = orient === top || orient === bottom ? translateX : translateY,
range = scale.range(),
range0 = range[0] + 0.5,
range1 = range[range.length - 1] + 0.5,
position = (scale.bandwidth ? center : identity$5)(scale.copy()),
selection = context.selection ? context.selection() : context,
path = selection.selectAll(".domain").data([null]),
tick = selection.selectAll(".tick").data(values, scale).order(),
tickExit = tick.exit(),
tickEnter = tick.enter().append("g").attr("class", "tick"),
line = tick.select("line"),
text = tick.select("text"),
k = orient === top || orient === left ? -1 : 1,
x, y = orient === left || orient === right ? (x = "x", "y") : (x = "y", "x");
path = path.merge(path.enter().insert("path", ".tick")
.attr("class", "domain")
.attr("stroke", "#000"));
tick = tick.merge(tickEnter);
line = line.merge(tickEnter.append("line")
.attr("stroke", "#000")
.attr(x + "2", k * tickSizeInner)
.attr(y + "1", 0.5)
.attr(y + "2", 0.5));
text = text.merge(tickEnter.append("text")
.attr("fill", "#000")
.attr(x, k * spacing)
.attr(y, 0.5)
.attr("dy", orient === top ? "0em" : orient === bottom ? "0.71em" : "0.32em"));
if (context !== selection) {
path = path.transition(context);
tick = tick.transition(context);
line = line.transition(context);
text = text.transition(context);
tickExit = tickExit.transition(context)
.attr("opacity", epsilon$2)
.attr("transform", function(d) { return transform(position, this.parentNode.__axis || position, d); });
tickEnter
.attr("opacity", epsilon$2)
.attr("transform", function(d) { return transform(this.parentNode.__axis || position, position, d); });
}
tickExit.remove();
path
.attr("d", orient === left || orient == right
? "M" + k * tickSizeOuter + "," + range0 + "H0.5V" + range1 + "H" + k * tickSizeOuter
: "M" + range0 + "," + k * tickSizeOuter + "V0.5H" + range1 + "V" + k * tickSizeOuter);
tick
.attr("opacity", 1)
.attr("transform", function(d) { return transform(position, position, d); });
line
.attr(x + "2", k * tickSizeInner);
text
.attr(x, k * spacing)
.text(format);
selection.filter(entering)
.attr("fill", "none")
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.attr("text-anchor", orient === right ? "start" : orient === left ? "end" : "middle");
selection
.each(function() { this.__axis = position; });
}
axis.scale = function(_) {
return arguments.length ? (scale = _, axis) : scale;
};
axis.ticks = function() {
return tickArguments = slice$4.call(arguments), axis;
};
axis.tickArguments = function(_) {
return arguments.length ? (tickArguments = _ == null ? [] : slice$4.call(_), axis) : tickArguments.slice();
};
axis.tickValues = function(_) {
return arguments.length ? (tickValues = _ == null ? null : slice$4.call(_), axis) : tickValues && tickValues.slice();
};
axis.tickFormat = function(_) {
return arguments.length ? (tickFormat = _, axis) : tickFormat;
};
axis.tickSize = function(_) {
return arguments.length ? (tickSizeInner = tickSizeOuter = +_, axis) : tickSizeInner;
};
axis.tickSizeInner = function(_) {
return arguments.length ? (tickSizeInner = +_, axis) : tickSizeInner;
};
axis.tickSizeOuter = function(_) {
return arguments.length ? (tickSizeOuter = +_, axis) : tickSizeOuter;
};
axis.tickPadding = function(_) {
return arguments.length ? (tickPadding = +_, axis) : tickPadding;
};
return axis;
}
function axisTop(scale) {
return axis(top, scale);
}
function axisRight(scale) {
return axis(right, scale);
}
function axisBottom(scale) {
return axis(bottom, scale);
}
function axisLeft(scale) {
return axis(left, scale);
}
function defaultSeparation(a, b) {
return a.parent === b.parent ? 1 : 2;
}
function meanX(children) {
return children.reduce(meanXReduce, 0) / children.length;
}
function meanXReduce(x, c) {
return x + c.x;
}
function maxY(children) {
return 1 + children.reduce(maxYReduce, 0);
}
function maxYReduce(y, c) {
return Math.max(y, c.y);
}
function leafLeft(node) {
var children;
while (children = node.children) node = children[0];
return node;
}
function leafRight(node) {
var children;
while (children = node.children) node = children[children.length - 1];
return node;
}
function cluster() {
var separation = defaultSeparation,
dx = 1,
dy = 1,
nodeSize = false;
function cluster(root) {
var previousNode,
x = 0;
// First walk, computing the initial x & y values.
root.eachAfter(function(node) {
var children = node.children;
if (children) {
node.x = meanX(children);
node.y = maxY(children);
} else {
node.x = previousNode ? x += separation(node, previousNode) : 0;
node.y = 0;
previousNode = node;
}
});
var left = leafLeft(root),
right = leafRight(root),
x0 = left.x - separation(left, right) / 2,
x1 = right.x + separation(right, left) / 2;
// Second walk, normalizing x & y to the desired size.
return root.eachAfter(nodeSize ? function(node) {
node.x = (node.x - root.x) * dx;
node.y = (root.y - node.y) * dy;
} : function(node) {
node.x = (node.x - x0) / (x1 - x0) * dx;
node.y = (1 - (root.y ? node.y / root.y : 1)) * dy;
});
}
cluster.separation = function(x) {
return arguments.length ? (separation = x, cluster) : separation;
};
cluster.size = function(x) {
return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? null : [dx, dy]);
};
cluster.nodeSize = function(x) {
return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], cluster) : (nodeSize ? [dx, dy] : null);
};
return cluster;
}
function node_each(callback) {
var node = this, current, next = [node], children, i, n;
do {
current = next.reverse(), next = [];
while (node = current.pop()) {
callback(node), children = node.children;
if (children) for (i = 0, n = children.length; i < n; ++i) {
next.push(children[i]);
}
}
} while (next.length);
return this;
}
function node_eachBefore(callback) {
var node = this, nodes = [node], children, i;
while (node = nodes.pop()) {
callback(node), children = node.children;
if (children) for (i = children.length - 1; i >= 0; --i) {
nodes.push(children[i]);
}
}
return this;
}
function node_eachAfter(callback) {
var node = this, nodes = [node], next = [], children, i, n;
while (node = nodes.pop()) {
next.push(node), children = node.children;
if (children) for (i = 0, n = children.length; i < n; ++i) {
nodes.push(children[i]);
}
}
while (node = next.pop()) {
callback(node);
}
return this;
}
function node_sum(value) {
return this.eachAfter(function(node) {
var sum = +value(node.data) || 0,
children = node.children,
i = children && children.length;
while (--i >= 0) sum += children[i].value;
node.value = sum;
});
}
function node_sort(compare) {
return this.eachBefore(function(node) {
if (node.children) {
node.children.sort(compare);
}
});
}
function node_path(end) {
var start = this,
ancestor = leastCommonAncestor(start, end),
nodes = [start];
while (start !== ancestor) {
start = start.parent;
nodes.push(start);
}
var k = nodes.length;
while (end !== ancestor) {
nodes.splice(k, 0, end);
end = end.parent;
}
return nodes;
}
function leastCommonAncestor(a, b) {
if (a === b) return a;
var aNodes = a.ancestors(),
bNodes = b.ancestors(),
c = null;
a = aNodes.pop();
b = bNodes.pop();
while (a === b) {
c = a;
a = aNodes.pop();
b = bNodes.pop();
}
return c;
}
function node_ancestors() {
var node = this, nodes = [node];
while (node = node.parent) {
nodes.push(node);
}
return nodes;
}
function node_descendants() {
var nodes = [];
this.each(function(node) {
nodes.push(node);
});
return nodes;
}
function node_leaves() {
var leaves = [];
this.eachBefore(function(node) {
if (!node.children) {
leaves.push(node);
}
});
return leaves;
}
function node_links() {
var root = this, links = [];
root.each(function(node) {
if (node !== root) { // Don’t include the root’s parent, if any.
links.push({source: node.parent, target: node});
}
});
return links;
}
function hierarchy(data, children) {
var root = new Node(data),
valued = +data.value && (root.value = data.value),
node,
nodes = [root],
child,
childs,
i,
n;
if (children == null) children = defaultChildren;
while (node = nodes.pop()) {
if (valued) node.value = +node.data.value;
if ((childs = children(node.data)) && (n = childs.length)) {
node.children = new Array(n);
for (i = n - 1; i >= 0; --i) {
nodes.push(child = node.children[i] = new Node(childs[i]));
child.parent = node;
child.depth = node.depth + 1;
}
}
}
return root.eachBefore(computeHeight);
}
function node_copy() {
return hierarchy(this).eachBefore(copyData);
}
function defaultChildren(d) {
return d.children;
}
function copyData(node) {
node.data = node.data.data;
}
function computeHeight(node) {
var height = 0;
do node.height = height;
while ((node = node.parent) && (node.height < ++height));
}
function Node(data) {
this.data = data;
this.depth =
this.height = 0;
this.parent = null;
}
Node.prototype = hierarchy.prototype = {
constructor: Node,
each: node_each,
eachAfter: node_eachAfter,
eachBefore: node_eachBefore,
sum: node_sum,
sort: node_sort,
path: node_path,
ancestors: node_ancestors,
descendants: node_descendants,
leaves: node_leaves,
links: node_links,
copy: node_copy
};
function Node$2(value) {
this._ = value;
this.next = null;
}
function shuffle$1(array) {
var i,
n = (array = array.slice()).length,
head = null,
node = head;
while (n) {
var next = new Node$2(array[n - 1]);
if (node) node = node.next = next;
else node = head = next;
array[i] = array[--n];
}
return {
head: head,
tail: node
};
}
function enclose(circles) {
return encloseN(shuffle$1(circles), []);
}
function encloses(a, b) {
var dx = b.x - a.x,
dy = b.y - a.y,
dr = a.r - b.r;
return dr * dr + 1e-6 > dx * dx + dy * dy;
}
// Returns the smallest circle that contains circles L and intersects circles B.
function encloseN(L, B) {
var circle,
l0 = null,
l1 = L.head,
l2,
p1;
switch (B.length) {
case 1: circle = enclose1(B[0]); break;
case 2: circle = enclose2(B[0], B[1]); break;
case 3: circle = enclose3(B[0], B[1], B[2]); break;
}
while (l1) {
p1 = l1._, l2 = l1.next;
if (!circle || !encloses(circle, p1)) {
// Temporarily truncate L before l1.
if (l0) L.tail = l0, l0.next = null;
else L.head = L.tail = null;
B.push(p1);
circle = encloseN(L, B); // Note: reorders L!
B.pop();
// Move l1 to the front of L and reconnect the truncated list L.
if (L.head) l1.next = L.head, L.head = l1;
else l1.next = null, L.head = L.tail = l1;
l0 = L.tail, l0.next = l2;
} else {
l0 = l1;
}
l1 = l2;
}
L.tail = l0;
return circle;
}
function enclose1(a) {
return {
x: a.x,
y: a.y,
r: a.r
};
}
function enclose2(a, b) {
var x1 = a.x, y1 = a.y, r1 = a.r,
x2 = b.x, y2 = b.y, r2 = b.r,
x21 = x2 - x1, y21 = y2 - y1, r21 = r2 - r1,
l = Math.sqrt(x21 * x21 + y21 * y21);
return {
x: (x1 + x2 + x21 / l * r21) / 2,
y: (y1 + y2 + y21 / l * r21) / 2,
r: (l + r1 + r2) / 2
};
}
function enclose3(a, b, c) {
var x1 = a.x, y1 = a.y, r1 = a.r,
x2 = b.x, y2 = b.y, r2 = b.r,
x3 = c.x, y3 = c.y, r3 = c.r,
a2 = 2 * (x1 - x2),
b2 = 2 * (y1 - y2),
c2 = 2 * (r2 - r1),
d2 = x1 * x1 + y1 * y1 - r1 * r1 - x2 * x2 - y2 * y2 + r2 * r2,
a3 = 2 * (x1 - x3),
b3 = 2 * (y1 - y3),
c3 = 2 * (r3 - r1),
d3 = x1 * x1 + y1 * y1 - r1 * r1 - x3 * x3 - y3 * y3 + r3 * r3,
ab = a3 * b2 - a2 * b3,
xa = (b2 * d3 - b3 * d2) / ab - x1,
xb = (b3 * c2 - b2 * c3) / ab,
ya = (a3 * d2 - a2 * d3) / ab - y1,
yb = (a2 * c3 - a3 * c2) / ab,
A = xb * xb + yb * yb - 1,
B = 2 * (xa * xb + ya * yb + r1),
C = xa * xa + ya * ya - r1 * r1,
r = (-B - Math.sqrt(B * B - 4 * A * C)) / (2 * A);
return {
x: xa + xb * r + x1,
y: ya + yb * r + y1,
r: r
};
}
function place(a, b, c) {
var ax = a.x,
ay = a.y,
da = b.r + c.r,
db = a.r + c.r,
dx = b.x - ax,
dy = b.y - ay,
dc = dx * dx + dy * dy;
if (dc) {
var x = 0.5 + ((db *= db) - (da *= da)) / (2 * dc),
y = Math.sqrt(Math.max(0, 2 * da * (db + dc) - (db -= dc) * db - da * da)) / (2 * dc);
c.x = ax + x * dx + y * dy;
c.y = ay + x * dy - y * dx;
} else {
c.x = ax + db;
c.y = ay;
}
}
function intersects(a, b) {
var dx = b.x - a.x,
dy = b.y - a.y,
dr = a.r + b.r;
return dr * dr > dx * dx + dy * dy;
}
function distance2(circle, x, y) {
var dx = circle.x - x,
dy = circle.y - y;
return dx * dx + dy * dy;
}
function Node$1(circle) {
this._ = circle;
this.next = null;
this.previous = null;
}
function packEnclose(circles) {
if (!(n = circles.length)) return 0;
var a, b, c, n;
// Place the first circle.
a = circles[0], a.x = 0, a.y = 0;
if (!(n > 1)) return a.r;
// Place the second circle.
b = circles[1], a.x = -b.r, b.x = a.r, b.y = 0;
if (!(n > 2)) return a.r + b.r;
// Place the third circle.
place(b, a, c = circles[2]);
// Initialize the weighted centroid.
var aa = a.r * a.r,
ba = b.r * b.r,
ca = c.r * c.r,
oa = aa + ba + ca,
ox = aa * a.x + ba * b.x + ca * c.x,
oy = aa * a.y + ba * b.y + ca * c.y,
cx, cy, i, j, k, sj, sk;
// Initialize the front-chain using the first three circles a, b and c.
a = new Node$1(a), b = new Node$1(b), c = new Node$1(c);
a.next = c.previous = b;
b.next = a.previous = c;
c.next = b.previous = a;
// Attempt to place each remaining circle…
pack: for (i = 3; i < n; ++i) {
place(a._, b._, c = circles[i]), c = new Node$1(c);
// If there are only three elements in the front-chain…
if ((k = a.previous) === (j = b.next)) {
// If the new circle intersects the third circle,
// rotate the front chain to try the next position.
if (intersects(j._, c._)) {
a = b, b = j, --i;
continue pack;
}
}
// Find the closest intersecting circle on the front-chain, if any.
else {
sj = j._.r, sk = k._.r;
do {
if (sj <= sk) {
if (intersects(j._, c._)) {
b = j, a.next = b, b.previous = a, --i;
continue pack;
}
j = j.next, sj += j._.r;
} else {
if (intersects(k._, c._)) {
a = k, a.next = b, b.previous = a, --i;
continue pack;
}
k = k.previous, sk += k._.r;
}
} while (j !== k.next);
}
// Success! Insert the new circle c between a and b.
c.previous = a, c.next = b, a.next = b.previous = b = c;
// Update the weighted centroid.
oa += ca = c._.r * c._.r;
ox += ca * c._.x;
oy += ca * c._.y;
// Compute the new closest circle a to centroid.
aa = distance2(a._, cx = ox / oa, cy = oy / oa);
while ((c = c.next) !== b) {
if ((ca = distance2(c._, cx, cy)) < aa) {
a = c, aa = ca;
}
}
b = a.next;
}
// Compute the enclosing circle of the front chain.
a = [b._], c = b; while ((c = c.next) !== b) a.push(c._); c = enclose(a);
// Translate the circles to put the enclosing circle around the origin.
for (i = 0; i < n; ++i) a = circles[i], a.x -= c.x, a.y -= c.y;
return c.r;
}
function siblings(circles) {
packEnclose(circles);
return circles;
}
function optional(f) {
return f == null ? null : required(f);
}
function required(f) {
if (typeof f !== "function") throw new Error;
return f;
}
function constantZero() {
return 0;
}
function constant$5(x) {
return function() {
return x;
};
}
function defaultRadius(d) {
return Math.sqrt(d.value);
}
function index() {
var radius = null,
dx = 1,
dy = 1,
padding = constantZero;
function pack(root) {
root.x = dx / 2, root.y = dy / 2;
if (radius) {
root.eachBefore(radiusLeaf(radius))
.eachAfter(packChildren(padding, 0.5))
.eachBefore(translateChild(1));
} else {
root.eachBefore(radiusLeaf(defaultRadius))
.eachAfter(packChildren(constantZero, 1))
.eachAfter(packChildren(padding, root.r / Math.min(dx, dy)))
.eachBefore(translateChild(Math.min(dx, dy) / (2 * root.r)));
}
return root;
}
pack.radius = function(x) {
return arguments.length ? (radius = optional(x), pack) : radius;
};
pack.size = function(x) {
return arguments.length ? (dx = +x[0], dy = +x[1], pack) : [dx, dy];
};
pack.padding = function(x) {
return arguments.length ? (padding = typeof x === "function" ? x : constant$5(+x), pack) : padding;
};
return pack;
}
function radiusLeaf(radius) {
return function(node) {
if (!node.children) {
node.r = Math.max(0, +radius(node) || 0);
}
};
}
function packChildren(padding, k) {
return function(node) {
if (children = node.children) {
var children,
i,
n = children.length,
r = padding(node) * k || 0,
e;
if (r) for (i = 0; i < n; ++i) children[i].r += r;
e = packEnclose(children);
if (r) for (i = 0; i < n; ++i) children[i].r -= r;
node.r = e + r;
}
};
}
function translateChild(k) {
return function(node) {
var parent = node.parent;
node.r *= k;
if (parent) {
node.x = parent.x + k * node.x;
node.y = parent.y + k * node.y;
}
};
}
function roundNode(node) {
node.x0 = Math.round(node.x0);
node.y0 = Math.round(node.y0);
node.x1 = Math.round(node.x1);
node.y1 = Math.round(node.y1);
}
function treemapDice(parent, x0, y0, x1, y1) {
var nodes = parent.children,
node,
i = -1,
n = nodes.length,
k = parent.value && (x1 - x0) / parent.value;
while (++i < n) {
node = nodes[i], node.y0 = y0, node.y1 = y1;
node.x0 = x0, node.x1 = x0 += node.value * k;
}
}
function partition() {
var dx = 1,
dy = 1,
padding = 0,
round = false;
function partition(root) {
var n = root.height + 1;
root.x0 =
root.y0 = padding;
root.x1 = dx;
root.y1 = dy / n;
root.eachBefore(positionNode(dy, n));
if (round) root.eachBefore(roundNode);
return root;
}
function positionNode(dy, n) {
return function(node) {
if (node.children) {
treemapDice(node, node.x0, dy * (node.depth + 1) / n, node.x1, dy * (node.depth + 2) / n);
}
var x0 = node.x0,
y0 = node.y0,
x1 = node.x1 - padding,
y1 = node.y1 - padding;
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
node.x0 = x0;
node.y0 = y0;
node.x1 = x1;
node.y1 = y1;
};
}
partition.round = function(x) {
return arguments.length ? (round = !!x, partition) : round;
};
partition.size = function(x) {
return arguments.length ? (dx = +x[0], dy = +x[1], partition) : [dx, dy];
};
partition.padding = function(x) {
return arguments.length ? (padding = +x, partition) : padding;
};
return partition;
}
var keyPrefix$1 = "$";
var preroot = {depth: -1};
var ambiguous = {};
function defaultId(d) {
return d.id;
}
function defaultParentId(d) {
return d.parentId;
}
function stratify() {
var id = defaultId,
parentId = defaultParentId;
function stratify(data) {
var d,
i,
n = data.length,
root,
parent,
node,
nodes = new Array(n),
nodeId,
nodeKey,
nodeByKey = {};
for (i = 0; i < n; ++i) {
d = data[i], node = nodes[i] = new Node(d);
if ((nodeId = id(d, i, data)) != null && (nodeId += "")) {
nodeKey = keyPrefix$1 + (node.id = nodeId);
nodeByKey[nodeKey] = nodeKey in nodeByKey ? ambiguous : node;
}
}
for (i = 0; i < n; ++i) {
node = nodes[i], nodeId = parentId(data[i], i, data);
if (nodeId == null || !(nodeId += "")) {
if (root) throw new Error("multiple roots");
root = node;
} else {
parent = nodeByKey[keyPrefix$1 + nodeId];
if (!parent) throw new Error("missing: " + nodeId);
if (parent === ambiguous) throw new Error("ambiguous: " + nodeId);
if (parent.children) parent.children.push(node);
else parent.children = [node];
node.parent = parent;
}
}
if (!root) throw new Error("no root");
root.parent = preroot;
root.eachBefore(function(node) { node.depth = node.parent.depth + 1; --n; }).eachBefore(computeHeight);
root.parent = null;
if (n > 0) throw new Error("cycle");
return root;
}
stratify.id = function(x) {
return arguments.length ? (id = required(x), stratify) : id;
};
stratify.parentId = function(x) {
return arguments.length ? (parentId = required(x), stratify) : parentId;
};
return stratify;
}
function defaultSeparation$1(a, b) {
return a.parent === b.parent ? 1 : 2;
}
// function radialSeparation(a, b) {
// return (a.parent === b.parent ? 1 : 2) / a.depth;
// }
// This function is used to traverse the left contour of a subtree (or
// subforest). It returns the successor of v on this contour. This successor is
// either given by the leftmost child of v or by the thread of v. The function
// returns null if and only if v is on the highest level of its subtree.
function nextLeft(v) {
var children = v.children;
return children ? children[0] : v.t;
}
// This function works analogously to nextLeft.
function nextRight(v) {
var children = v.children;
return children ? children[children.length - 1] : v.t;
}
// Shifts the current subtree rooted at w+. This is done by increasing
// prelim(w+) and mod(w+) by shift.
function moveSubtree(wm, wp, shift) {
var change = shift / (wp.i - wm.i);
wp.c -= change;
wp.s += shift;
wm.c += change;
wp.z += shift;
wp.m += shift;
}
// All other shifts, applied to the smaller subtrees between w- and w+, are
// performed by this function. To prepare the shifts, we have to adjust
// change(w+), shift(w+), and change(w-).
function executeShifts(v) {
var shift = 0,
change = 0,
children = v.children,
i = children.length,
w;
while (--i >= 0) {
w = children[i];
w.z += shift;
w.m += shift;
shift += w.s + (change += w.c);
}
}
// If vi-’s ancestor is a sibling of v, returns vi-’s ancestor. Otherwise,
// returns the specified (default) ancestor.
function nextAncestor(vim, v, ancestor) {
return vim.a.parent === v.parent ? vim.a : ancestor;
}
function TreeNode(node, i) {
this._ = node;
this.parent = null;
this.children = null;
this.A = null; // default ancestor
this.a = this; // ancestor
this.z = 0; // prelim
this.m = 0; // mod
this.c = 0; // change
this.s = 0; // shift
this.t = null; // thread
this.i = i; // number
}
TreeNode.prototype = Object.create(Node.prototype);
function treeRoot(root) {
var tree = new TreeNode(root, 0),
node,
nodes = [tree],
child,
children,
i,
n;
while (node = nodes.pop()) {
if (children = node._.children) {
node.children = new Array(n = children.length);
for (i = n - 1; i >= 0; --i) {
nodes.push(child = node.children[i] = new TreeNode(children[i], i));
child.parent = node;
}
}
}
(tree.parent = new TreeNode(null, 0)).children = [tree];
return tree;
}
// Node-link tree diagram using the Reingold-Tilford "tidy" algorithm
function tree() {
var separation = defaultSeparation$1,
dx = 1,
dy = 1,
nodeSize = null;
function tree(root) {
var t = treeRoot(root);
// Compute the layout using Buchheim et al.’s algorithm.
t.eachAfter(firstWalk), t.parent.m = -t.z;
t.eachBefore(secondWalk);
// If a fixed node size is specified, scale x and y.
if (nodeSize) root.eachBefore(sizeNode);
// If a fixed tree size is specified, scale x and y based on the extent.
// Compute the left-most, right-most, and depth-most nodes for extents.
else {
var left = root,
right = root,
bottom = root;
root.eachBefore(function(node) {
if (node.x < left.x) left = node;
if (node.x > right.x) right = node;
if (node.depth > bottom.depth) bottom = node;
});
var s = left === right ? 1 : separation(left, right) / 2,
tx = s - left.x,
kx = dx / (right.x + s + tx),
ky = dy / (bottom.depth || 1);
root.eachBefore(function(node) {
node.x = (node.x + tx) * kx;
node.y = node.depth * ky;
});
}
return root;
}
// Computes a preliminary x-coordinate for v. Before that, FIRST WALK is
// applied recursively to the children of v, as well as the function
// APPORTION. After spacing out the children by calling EXECUTE SHIFTS, the
// node v is placed to the midpoint of its outermost children.
function firstWalk(v) {
var children = v.children,
siblings = v.parent.children,
w = v.i ? siblings[v.i - 1] : null;
if (children) {
executeShifts(v);
var midpoint = (children[0].z + children[children.length - 1].z) / 2;
if (w) {
v.z = w.z + separation(v._, w._);
v.m = v.z - midpoint;
} else {
v.z = midpoint;
}
} else if (w) {
v.z = w.z + separation(v._, w._);
}
v.parent.A = apportion(v, w, v.parent.A || siblings[0]);
}
// Computes all real x-coordinates by summing up the modifiers recursively.
function secondWalk(v) {
v._.x = v.z + v.parent.m;
v.m += v.parent.m;
}
// The core of the algorithm. Here, a new subtree is combined with the
// previous subtrees. Threads are used to traverse the inside and outside
// contours of the left and right subtree up to the highest common level. The
// vertices used for the traversals are vi+, vi-, vo-, and vo+, where the
// superscript o means outside and i means inside, the subscript - means left
// subtree and + means right subtree. For summing up the modifiers along the
// contour, we use respective variables si+, si-, so-, and so+. Whenever two
// nodes of the inside contours conflict, we compute the left one of the
// greatest uncommon ancestors using the function ANCESTOR and call MOVE
// SUBTREE to shift the subtree and prepare the shifts of smaller subtrees.
// Finally, we add a new thread (if necessary).
function apportion(v, w, ancestor) {
if (w) {
var vip = v,
vop = v,
vim = w,
vom = vip.parent.children[0],
sip = vip.m,
sop = vop.m,
sim = vim.m,
som = vom.m,
shift;
while (vim = nextRight(vim), vip = nextLeft(vip), vim && vip) {
vom = nextLeft(vom);
vop = nextRight(vop);
vop.a = v;
shift = vim.z + sim - vip.z - sip + separation(vim._, vip._);
if (shift > 0) {
moveSubtree(nextAncestor(vim, v, ancestor), v, shift);
sip += shift;
sop += shift;
}
sim += vim.m;
sip += vip.m;
som += vom.m;
sop += vop.m;
}
if (vim && !nextRight(vop)) {
vop.t = vim;
vop.m += sim - sop;
}
if (vip && !nextLeft(vom)) {
vom.t = vip;
vom.m += sip - som;
ancestor = v;
}
}
return ancestor;
}
function sizeNode(node) {
node.x *= dx;
node.y = node.depth * dy;
}
tree.separation = function(x) {
return arguments.length ? (separation = x, tree) : separation;
};
tree.size = function(x) {
return arguments.length ? (nodeSize = false, dx = +x[0], dy = +x[1], tree) : (nodeSize ? null : [dx, dy]);
};
tree.nodeSize = function(x) {
return arguments.length ? (nodeSize = true, dx = +x[0], dy = +x[1], tree) : (nodeSize ? [dx, dy] : null);
};
return tree;
}
function treemapSlice(parent, x0, y0, x1, y1) {
var nodes = parent.children,
node,
i = -1,
n = nodes.length,
k = parent.value && (y1 - y0) / parent.value;
while (++i < n) {
node = nodes[i], node.x0 = x0, node.x1 = x1;
node.y0 = y0, node.y1 = y0 += node.value * k;
}
}
var phi = (1 + Math.sqrt(5)) / 2;
function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
var rows = [],
nodes = parent.children,
row,
nodeValue,
i0 = 0,
i1,
n = nodes.length,
dx, dy,
value = parent.value,
sumValue,
minValue,
maxValue,
newRatio,
minRatio,
alpha,
beta;
while (i0 < n) {
dx = x1 - x0, dy = y1 - y0;
minValue = maxValue = sumValue = nodes[i0].value;
alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
beta = sumValue * sumValue * alpha;
minRatio = Math.max(maxValue / beta, beta / minValue);
// Keep adding nodes while the aspect ratio maintains or improves.
for (i1 = i0 + 1; i1 < n; ++i1) {
sumValue += nodeValue = nodes[i1].value;
if (nodeValue < minValue) minValue = nodeValue;
if (nodeValue > maxValue) maxValue = nodeValue;
beta = sumValue * sumValue * alpha;
newRatio = Math.max(maxValue / beta, beta / minValue);
if (newRatio > minRatio) { sumValue -= nodeValue; break; }
minRatio = newRatio;
}
// Position and record the row orientation.
rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
value -= sumValue, i0 = i1;
}
return rows;
}
var squarify = (function custom(ratio) {
function squarify(parent, x0, y0, x1, y1) {
squarifyRatio(ratio, parent, x0, y0, x1, y1);
}
squarify.ratio = function(x) {
return custom((x = +x) > 1 ? x : 1);
};
return squarify;
})(phi);
function index$1() {
var tile = squarify,
round = false,
dx = 1,
dy = 1,
paddingStack = [0],
paddingInner = constantZero,
paddingTop = constantZero,
paddingRight = constantZero,
paddingBottom = constantZero,
paddingLeft = constantZero;
function treemap(root) {
root.x0 =
root.y0 = 0;
root.x1 = dx;
root.y1 = dy;
root.eachBefore(positionNode);
paddingStack = [0];
if (round) root.eachBefore(roundNode);
return root;
}
function positionNode(node) {
var p = paddingStack[node.depth],
x0 = node.x0 + p,
y0 = node.y0 + p,
x1 = node.x1 - p,
y1 = node.y1 - p;
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
node.x0 = x0;
node.y0 = y0;
node.x1 = x1;
node.y1 = y1;
if (node.children) {
p = paddingStack[node.depth + 1] = paddingInner(node) / 2;
x0 += paddingLeft(node) - p;
y0 += paddingTop(node) - p;
x1 -= paddingRight(node) - p;
y1 -= paddingBottom(node) - p;
if (x1 < x0) x0 = x1 = (x0 + x1) / 2;
if (y1 < y0) y0 = y1 = (y0 + y1) / 2;
tile(node, x0, y0, x1, y1);
}
}
treemap.round = function(x) {
return arguments.length ? (round = !!x, treemap) : round;
};
treemap.size = function(x) {
return arguments.length ? (dx = +x[0], dy = +x[1], treemap) : [dx, dy];
};
treemap.tile = function(x) {
return arguments.length ? (tile = required(x), treemap) : tile;
};
treemap.padding = function(x) {
return arguments.length ? treemap.paddingInner(x).paddingOuter(x) : treemap.paddingInner();
};
treemap.paddingInner = function(x) {
return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$5(+x), treemap) : paddingInner;
};
treemap.paddingOuter = function(x) {
return arguments.length ? treemap.paddingTop(x).paddingRight(x).paddingBottom(x).paddingLeft(x) : treemap.paddingTop();
};
treemap.paddingTop = function(x) {
return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$5(+x), treemap) : paddingTop;
};
treemap.paddingRight = function(x) {
return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$5(+x), treemap) : paddingRight;
};
treemap.paddingBottom = function(x) {
return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$5(+x), treemap) : paddingBottom;
};
treemap.paddingLeft = function(x) {
return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$5(+x), treemap) : paddingLeft;
};
return treemap;
}
function binary(parent, x0, y0, x1, y1) {
var nodes = parent.children,
i, n = nodes.length,
sum, sums = new Array(n + 1);
for (sums[0] = sum = i = 0; i < n; ++i) {
sums[i + 1] = sum += nodes[i].value;
}
partition(0, n, parent.value, x0, y0, x1, y1);
function partition(i, j, value, x0, y0, x1, y1) {
if (i >= j - 1) {
var node = nodes[i];
node.x0 = x0, node.y0 = y0;
node.x1 = x1, node.y1 = y1;
return;
}
var valueOffset = sums[i],
valueTarget = (value / 2) + valueOffset,
k = i + 1,
hi = j - 1;
while (k < hi) {
var mid = k + hi >>> 1;
if (sums[mid] < valueTarget) k = mid + 1;
else hi = mid;
}
var valueLeft = sums[k] - valueOffset,
valueRight = value - valueLeft;
if ((y1 - y0) > (x1 - x0)) {
var yk = (y0 * valueRight + y1 * valueLeft) / value;
partition(i, k, valueLeft, x0, y0, x1, yk);
partition(k, j, valueRight, x0, yk, x1, y1);
} else {
var xk = (x0 * valueRight + x1 * valueLeft) / value;
partition(i, k, valueLeft, x0, y0, xk, y1);
partition(k, j, valueRight, xk, y0, x1, y1);
}
}
}
function sliceDice(parent, x0, y0, x1, y1) {
(parent.depth & 1 ? treemapSlice : treemapDice)(parent, x0, y0, x1, y1);
}
var resquarify = (function custom(ratio) {
function resquarify(parent, x0, y0, x1, y1) {
if ((rows = parent._squarify) && (rows.ratio === ratio)) {
var rows,
row,
nodes,
i,
j = -1,
n,
m = rows.length,
value = parent.value;
while (++j < m) {
row = rows[j], nodes = row.children;
for (i = row.value = 0, n = nodes.length; i < n; ++i) row.value += nodes[i].value;
if (row.dice) treemapDice(row, x0, y0, x1, y0 += (y1 - y0) * row.value / value);
else treemapSlice(row, x0, y0, x0 += (x1 - x0) * row.value / value, y1);
value -= row.value;
}
} else {
parent._squarify = rows = squarifyRatio(ratio, parent, x0, y0, x1, y1);
rows.ratio = ratio;
}
}
resquarify.ratio = function(x) {
return custom((x = +x) > 1 ? x : 1);
};
return resquarify;
})(phi);
function center$1(x, y) {
var nodes;
if (x == null) x = 0;
if (y == null) y = 0;
function force() {
var i,
n = nodes.length,
node,
sx = 0,
sy = 0;
for (i = 0; i < n; ++i) {
node = nodes[i], sx += node.x, sy += node.y;
}
for (sx = sx / n - x, sy = sy / n - y, i = 0; i < n; ++i) {
node = nodes[i], node.x -= sx, node.y -= sy;
}
}
force.initialize = function(_) {
nodes = _;
};
force.x = function(_) {
return arguments.length ? (x = +_, force) : x;
};
force.y = function(_) {
return arguments.length ? (y = +_, force) : y;
};
return force;
}
function constant$6(x) {
return function() {
return x;
};
}
function jiggle() {
return (Math.random() - 0.5) * 1e-6;
}
function x$1(d) {
return d.x + d.vx;
}
function y$1(d) {
return d.y + d.vy;
}
function collide(radius) {
var nodes,
radii,
strength = 1,
iterations = 1;
if (typeof radius !== "function") radius = constant$6(radius == null ? 1 : +radius);
function force() {
var i, n = nodes.length,
tree,
node,
xi,
yi,
ri,
ri2;
for (var k = 0; k < iterations; ++k) {
tree = quadtree(nodes, x$1, y$1).visitAfter(prepare);
for (i = 0; i < n; ++i) {
node = nodes[i];
ri = radii[i], ri2 = ri * ri;
xi = node.x + node.vx;
yi = node.y + node.vy;
tree.visit(apply);
}
}
function apply(quad, x0, y0, x1, y1) {
var data = quad.data, rj = quad.r, r = ri + rj;
if (data) {
if (data.index > i) {
var x = xi - data.x - data.vx,
y = yi - data.y - data.vy,
l = x * x + y * y;
if (l < r * r) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
l = (r - (l = Math.sqrt(l))) / l * strength;
node.vx += (x *= l) * (r = (rj *= rj) / (ri2 + rj));
node.vy += (y *= l) * r;
data.vx -= x * (r = 1 - r);
data.vy -= y * r;
}
}
return;
}
return x0 > xi + r || x1 < xi - r || y0 > yi + r || y1 < yi - r;
}
}
function prepare(quad) {
if (quad.data) return quad.r = radii[quad.data.index];
for (var i = quad.r = 0; i < 4; ++i) {
if (quad[i] && quad[i].r > quad.r) {
quad.r = quad[i].r;
}
}
}
force.initialize = function(_) {
var i, n = (nodes = _).length; radii = new Array(n);
for (i = 0; i < n; ++i) radii[i] = +radius(nodes[i], i, nodes);
};
force.iterations = function(_) {
return arguments.length ? (iterations = +_, force) : iterations;
};
force.strength = function(_) {
return arguments.length ? (strength = +_, force) : strength;
};
force.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$6(+_), force) : radius;
};
return force;
}
function index$2(d, i) {
return i;
}
function link(links) {
var id = index$2,
strength = defaultStrength,
strengths,
distance = constant$6(30),
distances,
nodes,
count,
bias,
iterations = 1;
if (links == null) links = [];
function defaultStrength(link) {
return 1 / Math.min(count[link.source.index], count[link.target.index]);
}
function force(alpha) {
for (var k = 0, n = links.length; k < iterations; ++k) {
for (var i = 0, link, source, target, x, y, l, b; i < n; ++i) {
link = links[i], source = link.source, target = link.target;
x = target.x + target.vx - source.x - source.vx || jiggle();
y = target.y + target.vy - source.y - source.vy || jiggle();
l = Math.sqrt(x * x + y * y);
l = (l - distances[i]) / l * alpha * strengths[i];
x *= l, y *= l;
target.vx -= x * (b = bias[i]);
target.vy -= y * b;
source.vx += x * (b = 1 - b);
source.vy += y * b;
}
}
}
function initialize() {
if (!nodes) return;
var i,
n = nodes.length,
m = links.length,
nodeById = map$1(nodes, id),
link;
for (i = 0, count = new Array(n); i < n; ++i) {
count[i] = 0;
}
for (i = 0; i < m; ++i) {
link = links[i], link.index = i;
if (typeof link.source !== "object") link.source = nodeById.get(link.source);
if (typeof link.target !== "object") link.target = nodeById.get(link.target);
++count[link.source.index], ++count[link.target.index];
}
for (i = 0, bias = new Array(m); i < m; ++i) {
link = links[i], bias[i] = count[link.source.index] / (count[link.source.index] + count[link.target.index]);
}
strengths = new Array(m), initializeStrength();
distances = new Array(m), initializeDistance();
}
function initializeStrength() {
if (!nodes) return;
for (var i = 0, n = links.length; i < n; ++i) {
strengths[i] = +strength(links[i], i, links);
}
}
function initializeDistance() {
if (!nodes) return;
for (var i = 0, n = links.length; i < n; ++i) {
distances[i] = +distance(links[i], i, links);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.links = function(_) {
return arguments.length ? (links = _, initialize(), force) : links;
};
force.id = function(_) {
return arguments.length ? (id = _, force) : id;
};
force.iterations = function(_) {
return arguments.length ? (iterations = +_, force) : iterations;
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initializeStrength(), force) : strength;
};
force.distance = function(_) {
return arguments.length ? (distance = typeof _ === "function" ? _ : constant$6(+_), initializeDistance(), force) : distance;
};
return force;
}
function x$2(d) {
return d.x;
}
function y$2(d) {
return d.y;
}
var initialRadius = 10;
var initialAngle = Math.PI * (3 - Math.sqrt(5));
function simulation(nodes) {
var simulation,
alpha = 1,
alphaMin = 0.001,
alphaDecay = 1 - Math.pow(alphaMin, 1 / 300),
alphaTarget = 0,
velocityDecay = 0.6,
forces = map$1(),
stepper = timer(step),
event = dispatch("tick", "end");
if (nodes == null) nodes = [];
function step() {
tick();
event.call("tick", simulation);
if (alpha < alphaMin) {
stepper.stop();
event.call("end", simulation);
}
}
function tick() {
var i, n = nodes.length, node;
alpha += (alphaTarget - alpha) * alphaDecay;
forces.each(function(force) {
force(alpha);
});
for (i = 0; i < n; ++i) {
node = nodes[i];
if (node.fx == null) node.x += node.vx *= velocityDecay;
else node.x = node.fx, node.vx = 0;
if (node.fy == null) node.y += node.vy *= velocityDecay;
else node.y = node.fy, node.vy = 0;
}
}
function initializeNodes() {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.index = i;
if (isNaN(node.x) || isNaN(node.y)) {
var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
node.x = radius * Math.cos(angle);
node.y = radius * Math.sin(angle);
}
if (isNaN(node.vx) || isNaN(node.vy)) {
node.vx = node.vy = 0;
}
}
}
function initializeForce(force) {
if (force.initialize) force.initialize(nodes);
return force;
}
initializeNodes();
return simulation = {
tick: tick,
restart: function() {
return stepper.restart(step), simulation;
},
stop: function() {
return stepper.stop(), simulation;
},
nodes: function(_) {
return arguments.length ? (nodes = _, initializeNodes(), forces.each(initializeForce), simulation) : nodes;
},
alpha: function(_) {
return arguments.length ? (alpha = +_, simulation) : alpha;
},
alphaMin: function(_) {
return arguments.length ? (alphaMin = +_, simulation) : alphaMin;
},
alphaDecay: function(_) {
return arguments.length ? (alphaDecay = +_, simulation) : +alphaDecay;
},
alphaTarget: function(_) {
return arguments.length ? (alphaTarget = +_, simulation) : alphaTarget;
},
velocityDecay: function(_) {
return arguments.length ? (velocityDecay = 1 - _, simulation) : 1 - velocityDecay;
},
force: function(name, _) {
return arguments.length > 1 ? ((_ == null ? forces.remove(name) : forces.set(name, initializeForce(_))), simulation) : forces.get(name);
},
find: function(x, y, radius) {
var i = 0,
n = nodes.length,
dx,
dy,
d2,
node,
closest;
if (radius == null) radius = Infinity;
else radius *= radius;
for (i = 0; i < n; ++i) {
node = nodes[i];
dx = x - node.x;
dy = y - node.y;
d2 = dx * dx + dy * dy;
if (d2 < radius) closest = node, radius = d2;
}
return closest;
},
on: function(name, _) {
return arguments.length > 1 ? (event.on(name, _), simulation) : event.on(name);
}
};
}
function manyBody() {
var nodes,
node,
alpha,
strength = constant$6(-30),
strengths,
distanceMin2 = 1,
distanceMax2 = Infinity,
theta2 = 0.81;
function force(_) {
var i, n = nodes.length, tree = quadtree(nodes, x$2, y$2).visitAfter(accumulate);
for (alpha = _, i = 0; i < n; ++i) node = nodes[i], tree.visit(apply);
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
for (i = 0; i < n; ++i) strengths[i] = +strength(nodes[i], i, nodes);
}
function accumulate(quad) {
var strength = 0, q, c, x, y, i;
// For internal nodes, accumulate forces from child quadrants.
if (quad.length) {
for (x = y = i = 0; i < 4; ++i) {
if ((q = quad[i]) && (c = q.value)) {
strength += c, x += c * q.x, y += c * q.y;
}
}
quad.x = x / strength;
quad.y = y / strength;
}
// For leaf nodes, accumulate forces from coincident quadrants.
else {
q = quad;
q.x = q.data.x;
q.y = q.data.y;
do strength += strengths[q.data.index];
while (q = q.next);
}
quad.value = strength;
}
function apply(quad, x1, _, x2) {
if (!quad.value) return true;
var x = quad.x - node.x,
y = quad.y - node.y,
w = x2 - x1,
l = x * x + y * y;
// Apply the Barnes-Hut approximation if possible.
// Limit forces for very close nodes; randomize direction if coincident.
if (w * w / theta2 < l) {
if (l < distanceMax2) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
node.vx += x * quad.value * alpha / l;
node.vy += y * quad.value * alpha / l;
}
return true;
}
// Otherwise, process points directly.
else if (quad.length || l >= distanceMax2) return;
// Limit forces for very close nodes; randomize direction if coincident.
if (quad.data !== node || quad.next) {
if (x === 0) x = jiggle(), l += x * x;
if (y === 0) y = jiggle(), l += y * y;
if (l < distanceMin2) l = Math.sqrt(distanceMin2 * l);
}
do if (quad.data !== node) {
w = strengths[quad.data.index] * alpha / l;
node.vx += x * w;
node.vy += y * w;
} while (quad = quad.next);
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
};
force.distanceMin = function(_) {
return arguments.length ? (distanceMin2 = _ * _, force) : Math.sqrt(distanceMin2);
};
force.distanceMax = function(_) {
return arguments.length ? (distanceMax2 = _ * _, force) : Math.sqrt(distanceMax2);
};
force.theta = function(_) {
return arguments.length ? (theta2 = _ * _, force) : Math.sqrt(theta2);
};
return force;
}
function x$3(x) {
var strength = constant$6(0.1),
nodes,
strengths,
xz;
if (typeof x !== "function") x = constant$6(x == null ? 0 : +x);
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.vx += (xz[i] - node.x) * strengths[i] * alpha;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
xz = new Array(n);
for (i = 0; i < n; ++i) {
strengths[i] = isNaN(xz[i] = +x(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
};
force.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : x;
};
return force;
}
function y$3(y) {
var strength = constant$6(0.1),
nodes,
strengths,
yz;
if (typeof y !== "function") y = constant$6(y == null ? 0 : +y);
function force(alpha) {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.vy += (yz[i] - node.y) * strengths[i] * alpha;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
yz = new Array(n);
for (i = 0; i < n; ++i) {
strengths[i] = isNaN(yz[i] = +y(nodes[i], i, nodes)) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _;
initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : strength;
};
force.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant$6(+_), initialize(), force) : y;
};
return force;
}
function nopropagation() {
exports.event.stopImmediatePropagation();
}
function noevent() {
exports.event.preventDefault();
exports.event.stopImmediatePropagation();
}
function dragDisable(view) {
var root = view.document.documentElement,
selection = select(view).on("dragstart.drag", noevent, true);
if ("onselectstart" in root) {
selection.on("selectstart.drag", noevent, true);
} else {
root.__noselect = root.style.MozUserSelect;
root.style.MozUserSelect = "none";
}
}
function dragEnable(view, noclick) {
var root = view.document.documentElement,
selection = select(view).on("dragstart.drag", null);
if (noclick) {
selection.on("click.drag", noevent, true);
setTimeout(function() { selection.on("click.drag", null); }, 0);
}
if ("onselectstart" in root) {
selection.on("selectstart.drag", null);
} else {
root.style.MozUserSelect = root.__noselect;
delete root.__noselect;
}
}
function constant$7(x) {
return function() {
return x;
};
}
function DragEvent(target, type, subject, id, active, x, y, dx, dy, dispatch) {
this.target = target;
this.type = type;
this.subject = subject;
this.identifier = id;
this.active = active;
this.x = x;
this.y = y;
this.dx = dx;
this.dy = dy;
this._ = dispatch;
}
DragEvent.prototype.on = function() {
var value = this._.on.apply(this._, arguments);
return value === this._ ? this : value;
};
// Ignore right-click, since that should open the context menu.
function defaultFilter() {
return !exports.event.button;
}
function defaultContainer() {
return this.parentNode;
}
function defaultSubject(d) {
return d == null ? {x: exports.event.x, y: exports.event.y} : d;
}
function drag() {
var filter = defaultFilter,
container = defaultContainer,
subject = defaultSubject,
gestures = {},
listeners = dispatch("start", "drag", "end"),
active = 0,
mousemoving,
touchending;
function drag(selection) {
selection
.on("mousedown.drag", mousedowned)
.on("touchstart.drag", touchstarted)
.on("touchmove.drag", touchmoved)
.on("touchend.drag touchcancel.drag", touchended)
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
}
function mousedowned() {
if (touchending || !filter.apply(this, arguments)) return;
var gesture = beforestart("mouse", container.apply(this, arguments), mouse, this, arguments);
if (!gesture) return;
select(exports.event.view).on("mousemove.drag", mousemoved, true).on("mouseup.drag", mouseupped, true);
dragDisable(exports.event.view);
nopropagation();
mousemoving = false;
gesture("start");
}
function mousemoved() {
noevent();
mousemoving = true;
gestures.mouse("drag");
}
function mouseupped() {
select(exports.event.view).on("mousemove.drag mouseup.drag", null);
dragEnable(exports.event.view, mousemoving);
noevent();
gestures.mouse("end");
}
function touchstarted() {
if (!filter.apply(this, arguments)) return;
var touches = exports.event.changedTouches,
c = container.apply(this, arguments),
n = touches.length, i, gesture;
for (i = 0; i < n; ++i) {
if (gesture = beforestart(touches[i].identifier, c, touch, this, arguments)) {
nopropagation();
gesture("start");
}
}
}
function touchmoved() {
var touches = exports.event.changedTouches,
n = touches.length, i, gesture;
for (i = 0; i < n; ++i) {
if (gesture = gestures[touches[i].identifier]) {
noevent();
gesture("drag");
}
}
}
function touchended() {
var touches = exports.event.changedTouches,
n = touches.length, i, gesture;
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
for (i = 0; i < n; ++i) {
if (gesture = gestures[touches[i].identifier]) {
nopropagation();
gesture("end");
}
}
}
function beforestart(id, container, point, that, args) {
var p = point(container, id), s, dx, dy,
sublisteners = listeners.copy();
if (!customEvent(new DragEvent(drag, "beforestart", s, id, active, p[0], p[1], 0, 0, sublisteners), function() {
if ((exports.event.subject = s = subject.apply(that, args)) == null) return false;
dx = s.x - p[0] || 0;
dy = s.y - p[1] || 0;
return true;
})) return;
return function gesture(type) {
var p0 = p, n;
switch (type) {
case "start": gestures[id] = gesture, n = active++; break;
case "end": delete gestures[id], --active; // nobreak
case "drag": p = point(container, id), n = active; break;
}
customEvent(new DragEvent(drag, type, s, id, n, p[0] + dx, p[1] + dy, p[0] - p0[0], p[1] - p0[1], sublisteners), sublisteners.apply, sublisteners, [type, that, args]);
};
}
drag.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$7(!!_), drag) : filter;
};
drag.container = function(_) {
return arguments.length ? (container = typeof _ === "function" ? _ : constant$7(_), drag) : container;
};
drag.subject = function(_) {
return arguments.length ? (subject = typeof _ === "function" ? _ : constant$7(_), drag) : subject;
};
drag.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? drag : value;
};
return drag;
}
function constant$8(x) {
return function() {
return x;
};
}
function x$4(d) {
return d[0];
}
function y$4(d) {
return d[1];
}
function RedBlackTree() {
this._ = null; // root node
}
function RedBlackNode(node) {
node.U = // parent node
node.C = // color - true for red, false for black
node.L = // left node
node.R = // right node
node.P = // previous node
node.N = null; // next node
}
RedBlackTree.prototype = {
constructor: RedBlackTree,
insert: function(after, node) {
var parent, grandpa, uncle;
if (after) {
node.P = after;
node.N = after.N;
if (after.N) after.N.P = node;
after.N = node;
if (after.R) {
after = after.R;
while (after.L) after = after.L;
after.L = node;
} else {
after.R = node;
}
parent = after;
} else if (this._) {
after = RedBlackFirst(this._);
node.P = null;
node.N = after;
after.P = after.L = node;
parent = after;
} else {
node.P = node.N = null;
this._ = node;
parent = null;
}
node.L = node.R = null;
node.U = parent;
node.C = true;
after = node;
while (parent && parent.C) {
grandpa = parent.U;
if (parent === grandpa.L) {
uncle = grandpa.R;
if (uncle && uncle.C) {
parent.C = uncle.C = false;
grandpa.C = true;
after = grandpa;
} else {
if (after === parent.R) {
RedBlackRotateLeft(this, parent);
after = parent;
parent = after.U;
}
parent.C = false;
grandpa.C = true;
RedBlackRotateRight(this, grandpa);
}
} else {
uncle = grandpa.L;
if (uncle && uncle.C) {
parent.C = uncle.C = false;
grandpa.C = true;
after = grandpa;
} else {
if (after === parent.L) {
RedBlackRotateRight(this, parent);
after = parent;
parent = after.U;
}
parent.C = false;
grandpa.C = true;
RedBlackRotateLeft(this, grandpa);
}
}
parent = after.U;
}
this._.C = false;
},
remove: function(node) {
if (node.N) node.N.P = node.P;
if (node.P) node.P.N = node.N;
node.N = node.P = null;
var parent = node.U,
sibling,
left = node.L,
right = node.R,
next,
red;
if (!left) next = right;
else if (!right) next = left;
else next = RedBlackFirst(right);
if (parent) {
if (parent.L === node) parent.L = next;
else parent.R = next;
} else {
this._ = next;
}
if (left && right) {
red = next.C;
next.C = node.C;
next.L = left;
left.U = next;
if (next !== right) {
parent = next.U;
next.U = node.U;
node = next.R;
parent.L = node;
next.R = right;
right.U = next;
} else {
next.U = parent;
parent = next;
node = next.R;
}
} else {
red = node.C;
node = next;
}
if (node) node.U = parent;
if (red) return;
if (node && node.C) { node.C = false; return; }
do {
if (node === this._) break;
if (node === parent.L) {
sibling = parent.R;
if (sibling.C) {
sibling.C = false;
parent.C = true;
RedBlackRotateLeft(this, parent);
sibling = parent.R;
}
if ((sibling.L && sibling.L.C)
|| (sibling.R && sibling.R.C)) {
if (!sibling.R || !sibling.R.C) {
sibling.L.C = false;
sibling.C = true;
RedBlackRotateRight(this, sibling);
sibling = parent.R;
}
sibling.C = parent.C;
parent.C = sibling.R.C = false;
RedBlackRotateLeft(this, parent);
node = this._;
break;
}
} else {
sibling = parent.L;
if (sibling.C) {
sibling.C = false;
parent.C = true;
RedBlackRotateRight(this, parent);
sibling = parent.L;
}
if ((sibling.L && sibling.L.C)
|| (sibling.R && sibling.R.C)) {
if (!sibling.L || !sibling.L.C) {
sibling.R.C = false;
sibling.C = true;
RedBlackRotateLeft(this, sibling);
sibling = parent.L;
}
sibling.C = parent.C;
parent.C = sibling.L.C = false;
RedBlackRotateRight(this, parent);
node = this._;
break;
}
}
sibling.C = true;
node = parent;
parent = parent.U;
} while (!node.C);
if (node) node.C = false;
}
};
function RedBlackRotateLeft(tree, node) {
var p = node,
q = node.R,
parent = p.U;
if (parent) {
if (parent.L === p) parent.L = q;
else parent.R = q;
} else {
tree._ = q;
}
q.U = parent;
p.U = q;
p.R = q.L;
if (p.R) p.R.U = p;
q.L = p;
}
function RedBlackRotateRight(tree, node) {
var p = node,
q = node.L,
parent = p.U;
if (parent) {
if (parent.L === p) parent.L = q;
else parent.R = q;
} else {
tree._ = q;
}
q.U = parent;
p.U = q;
p.L = q.R;
if (p.L) p.L.U = p;
q.R = p;
}
function RedBlackFirst(node) {
while (node.L) node = node.L;
return node;
}
function createEdge(left, right, v0, v1) {
var edge = [null, null],
index = edges.push(edge) - 1;
edge.left = left;
edge.right = right;
if (v0) setEdgeEnd(edge, left, right, v0);
if (v1) setEdgeEnd(edge, right, left, v1);
cells[left.index].halfedges.push(index);
cells[right.index].halfedges.push(index);
return edge;
}
function createBorderEdge(left, v0, v1) {
var edge = [v0, v1];
edge.left = left;
return edge;
}
function setEdgeEnd(edge, left, right, vertex) {
if (!edge[0] && !edge[1]) {
edge[0] = vertex;
edge.left = left;
edge.right = right;
} else if (edge.left === right) {
edge[1] = vertex;
} else {
edge[0] = vertex;
}
}
// Liang–Barsky line clipping.
function clipEdge(edge, x0, y0, x1, y1) {
var a = edge[0],
b = edge[1],
ax = a[0],
ay = a[1],
bx = b[0],
by = b[1],
t0 = 0,
t1 = 1,
dx = bx - ax,
dy = by - ay,
r;
r = x0 - ax;
if (!dx && r > 0) return;
r /= dx;
if (dx < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dx > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = x1 - ax;
if (!dx && r < 0) return;
r /= dx;
if (dx < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dx > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
r = y0 - ay;
if (!dy && r > 0) return;
r /= dy;
if (dy < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dy > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = y1 - ay;
if (!dy && r < 0) return;
r /= dy;
if (dy < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dy > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
if (!(t0 > 0) && !(t1 < 1)) return true; // TODO Better check?
if (t0 > 0) edge[0] = [ax + t0 * dx, ay + t0 * dy];
if (t1 < 1) edge[1] = [ax + t1 * dx, ay + t1 * dy];
return true;
}
function connectEdge(edge, x0, y0, x1, y1) {
var v1 = edge[1];
if (v1) return true;
var v0 = edge[0],
left = edge.left,
right = edge.right,
lx = left[0],
ly = left[1],
rx = right[0],
ry = right[1],
fx = (lx + rx) / 2,
fy = (ly + ry) / 2,
fm,
fb;
if (ry === ly) {
if (fx < x0 || fx >= x1) return;
if (lx > rx) {
if (!v0) v0 = [fx, y0];
else if (v0[1] >= y1) return;
v1 = [fx, y1];
} else {
if (!v0) v0 = [fx, y1];
else if (v0[1] < y0) return;
v1 = [fx, y0];
}
} else {
fm = (lx - rx) / (ry - ly);
fb = fy - fm * fx;
if (fm < -1 || fm > 1) {
if (lx > rx) {
if (!v0) v0 = [(y0 - fb) / fm, y0];
else if (v0[1] >= y1) return;
v1 = [(y1 - fb) / fm, y1];
} else {
if (!v0) v0 = [(y1 - fb) / fm, y1];
else if (v0[1] < y0) return;
v1 = [(y0 - fb) / fm, y0];
}
} else {
if (ly < ry) {
if (!v0) v0 = [x0, fm * x0 + fb];
else if (v0[0] >= x1) return;
v1 = [x1, fm * x1 + fb];
} else {
if (!v0) v0 = [x1, fm * x1 + fb];
else if (v0[0] < x0) return;
v1 = [x0, fm * x0 + fb];
}
}
}
edge[0] = v0;
edge[1] = v1;
return true;
}
function clipEdges(x0, y0, x1, y1) {
var i = edges.length,
edge;
while (i--) {
if (!connectEdge(edge = edges[i], x0, y0, x1, y1)
|| !clipEdge(edge, x0, y0, x1, y1)
|| !(Math.abs(edge[0][0] - edge[1][0]) > epsilon$3
|| Math.abs(edge[0][1] - edge[1][1]) > epsilon$3)) {
delete edges[i];
}
}
}
function createCell(site) {
return cells[site.index] = {
site: site,
halfedges: []
};
}
function cellHalfedgeAngle(cell, edge) {
var site = cell.site,
va = edge.left,
vb = edge.right;
if (site === vb) vb = va, va = site;
if (vb) return Math.atan2(vb[1] - va[1], vb[0] - va[0]);
if (site === va) va = edge[1], vb = edge[0];
else va = edge[0], vb = edge[1];
return Math.atan2(va[0] - vb[0], vb[1] - va[1]);
}
function cellHalfedgeStart(cell, edge) {
return edge[+(edge.left !== cell.site)];
}
function cellHalfedgeEnd(cell, edge) {
return edge[+(edge.left === cell.site)];
}
function sortCellHalfedges() {
for (var i = 0, n = cells.length, cell, halfedges, j, m; i < n; ++i) {
if ((cell = cells[i]) && (m = (halfedges = cell.halfedges).length)) {
var index = new Array(m),
array = new Array(m);
for (j = 0; j < m; ++j) index[j] = j, array[j] = cellHalfedgeAngle(cell, edges[halfedges[j]]);
index.sort(function(i, j) { return array[j] - array[i]; });
for (j = 0; j < m; ++j) array[j] = halfedges[index[j]];
for (j = 0; j < m; ++j) halfedges[j] = array[j];
}
}
}
function clipCells(x0, y0, x1, y1) {
var nCells = cells.length,
iCell,
cell,
site,
iHalfedge,
halfedges,
nHalfedges,
start,
startX,
startY,
end,
endX,
endY,
cover = true;
for (iCell = 0; iCell < nCells; ++iCell) {
if (cell = cells[iCell]) {
site = cell.site;
halfedges = cell.halfedges;
iHalfedge = halfedges.length;
// Remove any dangling clipped edges.
while (iHalfedge--) {
if (!edges[halfedges[iHalfedge]]) {
halfedges.splice(iHalfedge, 1);
}
}
// Insert any border edges as necessary.
iHalfedge = 0, nHalfedges = halfedges.length;
while (iHalfedge < nHalfedges) {
end = cellHalfedgeEnd(cell, edges[halfedges[iHalfedge]]), endX = end[0], endY = end[1];
start = cellHalfedgeStart(cell, edges[halfedges[++iHalfedge % nHalfedges]]), startX = start[0], startY = start[1];
if (Math.abs(endX - startX) > epsilon$3 || Math.abs(endY - startY) > epsilon$3) {
halfedges.splice(iHalfedge, 0, edges.push(createBorderEdge(site, end,
Math.abs(endX - x0) < epsilon$3 && y1 - endY > epsilon$3 ? [x0, Math.abs(startX - x0) < epsilon$3 ? startY : y1]
: Math.abs(endY - y1) < epsilon$3 && x1 - endX > epsilon$3 ? [Math.abs(startY - y1) < epsilon$3 ? startX : x1, y1]
: Math.abs(endX - x1) < epsilon$3 && endY - y0 > epsilon$3 ? [x1, Math.abs(startX - x1) < epsilon$3 ? startY : y0]
: Math.abs(endY - y0) < epsilon$3 && endX - x0 > epsilon$3 ? [Math.abs(startY - y0) < epsilon$3 ? startX : x0, y0]
: null)) - 1);
++nHalfedges;
}
}
if (nHalfedges) cover = false;
}
}
// If there weren’t any edges, have the closest site cover the extent.
// It doesn’t matter which corner of the extent we measure!
if (cover) {
var dx, dy, d2, dc = Infinity;
for (iCell = 0, cover = null; iCell < nCells; ++iCell) {
if (cell = cells[iCell]) {
site = cell.site;
dx = site[0] - x0;
dy = site[1] - y0;
d2 = dx * dx + dy * dy;
if (d2 < dc) dc = d2, cover = cell;
}
}
if (cover) {
var v00 = [x0, y0], v01 = [x0, y1], v11 = [x1, y1], v10 = [x1, y0];
cover.halfedges.push(
edges.push(createBorderEdge(site = cover.site, v00, v01)) - 1,
edges.push(createBorderEdge(site, v01, v11)) - 1,
edges.push(createBorderEdge(site, v11, v10)) - 1,
edges.push(createBorderEdge(site, v10, v00)) - 1
);
}
}
// Lastly delete any cells with no edges; these were entirely clipped.
for (iCell = 0; iCell < nCells; ++iCell) {
if (cell = cells[iCell]) {
if (!cell.halfedges.length) {
delete cells[iCell];
}
}
}
}
var circlePool = [];
var firstCircle;
function Circle() {
RedBlackNode(this);
this.x =
this.y =
this.arc =
this.site =
this.cy = null;
}
function attachCircle(arc) {
var lArc = arc.P,
rArc = arc.N;
if (!lArc || !rArc) return;
var lSite = lArc.site,
cSite = arc.site,
rSite = rArc.site;
if (lSite === rSite) return;
var bx = cSite[0],
by = cSite[1],
ax = lSite[0] - bx,
ay = lSite[1] - by,
cx = rSite[0] - bx,
cy = rSite[1] - by;
var d = 2 * (ax * cy - ay * cx);
if (d >= -epsilon2$1) return;
var ha = ax * ax + ay * ay,
hc = cx * cx + cy * cy,
x = (cy * ha - ay * hc) / d,
y = (ax * hc - cx * ha) / d;
var circle = circlePool.pop() || new Circle;
circle.arc = arc;
circle.site = cSite;
circle.x = x + bx;
circle.y = (circle.cy = y + by) + Math.sqrt(x * x + y * y); // y bottom
arc.circle = circle;
var before = null,
node = circles._;
while (node) {
if (circle.y < node.y || (circle.y === node.y && circle.x <= node.x)) {
if (node.L) node = node.L;
else { before = node.P; break; }
} else {
if (node.R) node = node.R;
else { before = node; break; }
}
}
circles.insert(before, circle);
if (!before) firstCircle = circle;
}
function detachCircle(arc) {
var circle = arc.circle;
if (circle) {
if (!circle.P) firstCircle = circle.N;
circles.remove(circle);
circlePool.push(circle);
RedBlackNode(circle);
arc.circle = null;
}
}
var beachPool = [];
function Beach() {
RedBlackNode(this);
this.edge =
this.site =
this.circle = null;
}
function createBeach(site) {
var beach = beachPool.pop() || new Beach;
beach.site = site;
return beach;
}
function detachBeach(beach) {
detachCircle(beach);
beaches.remove(beach);
beachPool.push(beach);
RedBlackNode(beach);
}
function removeBeach(beach) {
var circle = beach.circle,
x = circle.x,
y = circle.cy,
vertex = [x, y],
previous = beach.P,
next = beach.N,
disappearing = [beach];
detachBeach(beach);
var lArc = previous;
while (lArc.circle
&& Math.abs(x - lArc.circle.x) < epsilon$3
&& Math.abs(y - lArc.circle.cy) < epsilon$3) {
previous = lArc.P;
disappearing.unshift(lArc);
detachBeach(lArc);
lArc = previous;
}
disappearing.unshift(lArc);
detachCircle(lArc);
var rArc = next;
while (rArc.circle
&& Math.abs(x - rArc.circle.x) < epsilon$3
&& Math.abs(y - rArc.circle.cy) < epsilon$3) {
next = rArc.N;
disappearing.push(rArc);
detachBeach(rArc);
rArc = next;
}
disappearing.push(rArc);
detachCircle(rArc);
var nArcs = disappearing.length,
iArc;
for (iArc = 1; iArc < nArcs; ++iArc) {
rArc = disappearing[iArc];
lArc = disappearing[iArc - 1];
setEdgeEnd(rArc.edge, lArc.site, rArc.site, vertex);
}
lArc = disappearing[0];
rArc = disappearing[nArcs - 1];
rArc.edge = createEdge(lArc.site, rArc.site, null, vertex);
attachCircle(lArc);
attachCircle(rArc);
}
function addBeach(site) {
var x = site[0],
directrix = site[1],
lArc,
rArc,
dxl,
dxr,
node = beaches._;
while (node) {
dxl = leftBreakPoint(node, directrix) - x;
if (dxl > epsilon$3) node = node.L; else {
dxr = x - rightBreakPoint(node, directrix);
if (dxr > epsilon$3) {
if (!node.R) {
lArc = node;
break;
}
node = node.R;
} else {
if (dxl > -epsilon$3) {
lArc = node.P;
rArc = node;
} else if (dxr > -epsilon$3) {
lArc = node;
rArc = node.N;
} else {
lArc = rArc = node;
}
break;
}
}
}
createCell(site);
var newArc = createBeach(site);
beaches.insert(lArc, newArc);
if (!lArc && !rArc) return;
if (lArc === rArc) {
detachCircle(lArc);
rArc = createBeach(lArc.site);
beaches.insert(newArc, rArc);
newArc.edge = rArc.edge = createEdge(lArc.site, newArc.site);
attachCircle(lArc);
attachCircle(rArc);
return;
}
if (!rArc) { // && lArc
newArc.edge = createEdge(lArc.site, newArc.site);
return;
}
// else lArc !== rArc
detachCircle(lArc);
detachCircle(rArc);
var lSite = lArc.site,
ax = lSite[0],
ay = lSite[1],
bx = site[0] - ax,
by = site[1] - ay,
rSite = rArc.site,
cx = rSite[0] - ax,
cy = rSite[1] - ay,
d = 2 * (bx * cy - by * cx),
hb = bx * bx + by * by,
hc = cx * cx + cy * cy,
vertex = [(cy * hb - by * hc) / d + ax, (bx * hc - cx * hb) / d + ay];
setEdgeEnd(rArc.edge, lSite, rSite, vertex);
newArc.edge = createEdge(lSite, site, null, vertex);
rArc.edge = createEdge(site, rSite, null, vertex);
attachCircle(lArc);
attachCircle(rArc);
}
function leftBreakPoint(arc, directrix) {
var site = arc.site,
rfocx = site[0],
rfocy = site[1],
pby2 = rfocy - directrix;
if (!pby2) return rfocx;
var lArc = arc.P;
if (!lArc) return -Infinity;
site = lArc.site;
var lfocx = site[0],
lfocy = site[1],
plby2 = lfocy - directrix;
if (!plby2) return lfocx;
var hl = lfocx - rfocx,
aby2 = 1 / pby2 - 1 / plby2,
b = hl / plby2;
if (aby2) return (-b + Math.sqrt(b * b - 2 * aby2 * (hl * hl / (-2 * plby2) - lfocy + plby2 / 2 + rfocy - pby2 / 2))) / aby2 + rfocx;
return (rfocx + lfocx) / 2;
}
function rightBreakPoint(arc, directrix) {
var rArc = arc.N;
if (rArc) return leftBreakPoint(rArc, directrix);
var site = arc.site;
return site[1] === directrix ? site[0] : Infinity;
}
var epsilon$3 = 1e-6;
var epsilon2$1 = 1e-12;
var beaches;
var cells;
var circles;
var edges;
function triangleArea(a, b, c) {
return (a[0] - c[0]) * (b[1] - a[1]) - (a[0] - b[0]) * (c[1] - a[1]);
}
function lexicographic(a, b) {
return b[1] - a[1]
|| b[0] - a[0];
}
function Diagram(sites, extent) {
var site = sites.sort(lexicographic).pop(),
x,
y,
circle;
edges = [];
cells = new Array(sites.length);
beaches = new RedBlackTree;
circles = new RedBlackTree;
while (true) {
circle = firstCircle;
if (site && (!circle || site[1] < circle.y || (site[1] === circle.y && site[0] < circle.x))) {
if (site[0] !== x || site[1] !== y) {
addBeach(site);
x = site[0], y = site[1];
}
site = sites.pop();
} else if (circle) {
removeBeach(circle.arc);
} else {
break;
}
}
sortCellHalfedges();
if (extent) {
var x0 = +extent[0][0],
y0 = +extent[0][1],
x1 = +extent[1][0],
y1 = +extent[1][1];
clipEdges(x0, y0, x1, y1);
clipCells(x0, y0, x1, y1);
}
this.edges = edges;
this.cells = cells;
beaches =
circles =
edges =
cells = null;
}
Diagram.prototype = {
constructor: Diagram,
polygons: function() {
var edges = this.edges;
return this.cells.map(function(cell) {
var polygon = cell.halfedges.map(function(i) { return cellHalfedgeStart(cell, edges[i]); });
polygon.data = cell.site.data;
return polygon;
});
},
triangles: function() {
var triangles = [],
edges = this.edges;
this.cells.forEach(function(cell, i) {
var site = cell.site,
halfedges = cell.halfedges,
j = -1,
m = halfedges.length,
s0,
e1 = edges[halfedges[m - 1]],
s1 = e1.left === site ? e1.right : e1.left;
while (++j < m) {
s0 = s1;
e1 = edges[halfedges[j]];
s1 = e1.left === site ? e1.right : e1.left;
if (i < s0.index && i < s1.index && triangleArea(site, s0, s1) < 0) {
triangles.push([site.data, s0.data, s1.data]);
}
}
});
return triangles;
},
links: function() {
return this.edges.filter(function(edge) {
return edge.right;
}).map(function(edge) {
return {
source: edge.left.data,
target: edge.right.data
};
});
}
}
function voronoi() {
var x = x$4,
y = y$4,
extent = null;
function voronoi(data) {
return new Diagram(data.map(function(d, i) {
var s = [Math.round(x(d, i, data) / epsilon$3) * epsilon$3, Math.round(y(d, i, data) / epsilon$3) * epsilon$3];
s.index = i;
s.data = d;
return s;
}), extent);
}
voronoi.polygons = function(data) {
return voronoi(data).polygons();
};
voronoi.links = function(data) {
return voronoi(data).links();
};
voronoi.triangles = function(data) {
return voronoi(data).triangles();
};
voronoi.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant$8(+_), voronoi) : x;
};
voronoi.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant$8(+_), voronoi) : y;
};
voronoi.extent = function(_) {
return arguments.length ? (extent = _ == null ? null : [[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]], voronoi) : extent && [[extent[0][0], extent[0][1]], [extent[1][0], extent[1][1]]];
};
voronoi.size = function(_) {
return arguments.length ? (extent = _ == null ? null : [[0, 0], [+_[0], +_[1]]], voronoi) : extent && [extent[1][0] - extent[0][0], extent[1][1] - extent[0][1]];
};
return voronoi;
}
function constant$9(x) {
return function() {
return x;
};
}
function ZoomEvent(target, type, transform) {
this.target = target;
this.type = type;
this.transform = transform;
}
function Transform(k, x, y) {
this.k = k;
this.x = x;
this.y = y;
}
Transform.prototype = {
constructor: Transform,
scale: function(k) {
return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
},
translate: function(x, y) {
return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
},
apply: function(point) {
return [point[0] * this.k + this.x, point[1] * this.k + this.y];
},
applyX: function(x) {
return x * this.k + this.x;
},
applyY: function(y) {
return y * this.k + this.y;
},
invert: function(location) {
return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
},
invertX: function(x) {
return (x - this.x) / this.k;
},
invertY: function(y) {
return (y - this.y) / this.k;
},
rescaleX: function(x) {
return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
},
rescaleY: function(y) {
return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
},
toString: function() {
return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
}
};
var identity$6 = new Transform(1, 0, 0);
transform.prototype = Transform.prototype;
function transform(node) {
return node.__zoom || identity$6;
}
function nopropagation$1() {
exports.event.stopImmediatePropagation();
}
function noevent$1() {
exports.event.preventDefault();
exports.event.stopImmediatePropagation();
}
// Ignore right-click, since that should open the context menu.
function defaultFilter$1() {
return !exports.event.button;
}
function defaultExtent() {
var e = this, w, h;
if (e instanceof SVGElement) {
e = e.ownerSVGElement || e;
w = e.width.baseVal.value;
h = e.height.baseVal.value;
} else {
w = e.clientWidth;
h = e.clientHeight;
}
return [[0, 0], [w, h]];
}
function defaultTransform() {
return this.__zoom || identity$6;
}
function zoom() {
var filter = defaultFilter$1,
extent = defaultExtent,
k0 = 0,
k1 = Infinity,
x0 = -k1,
x1 = k1,
y0 = x0,
y1 = x1,
duration = 250,
gestures = [],
listeners = dispatch("start", "zoom", "end"),
touchstarting,
touchending,
touchDelay = 500,
wheelDelay = 150;
function zoom(selection) {
selection
.on("wheel.zoom", wheeled)
.on("mousedown.zoom", mousedowned)
.on("dblclick.zoom", dblclicked)
.on("touchstart.zoom", touchstarted)
.on("touchmove.zoom", touchmoved)
.on("touchend.zoom touchcancel.zoom", touchended)
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
.property("__zoom", defaultTransform);
}
zoom.transform = function(collection, transform) {
var selection = collection.selection ? collection.selection() : collection;
selection.property("__zoom", defaultTransform);
if (collection !== selection) {
schedule(collection, transform);
} else {
selection.interrupt().each(function() {
gesture(this, arguments)
.start()
.zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform)
.end();
});
}
};
zoom.scaleBy = function(selection, k) {
zoom.scaleTo(selection, function() {
var k0 = this.__zoom.k,
k1 = typeof k === "function" ? k.apply(this, arguments) : k;
return k0 * k1;
});
};
zoom.scaleTo = function(selection, k) {
zoom.transform(selection, function() {
var e = extent.apply(this, arguments),
t0 = this.__zoom,
p0 = centroid(e),
p1 = t0.invert(p0),
k1 = typeof k === "function" ? k.apply(this, arguments) : k;
return constrain(translate(scale(t0, k1), p0, p1), e);
});
};
zoom.translateBy = function(selection, x, y) {
zoom.transform(selection, function() {
return constrain(this.__zoom.translate(
typeof x === "function" ? x.apply(this, arguments) : x,
typeof y === "function" ? y.apply(this, arguments) : y
), extent.apply(this, arguments));
});
};
function scale(transform, k) {
k = Math.max(k0, Math.min(k1, k));
return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
}
function translate(transform, p0, p1) {
var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k;
return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
}
function constrain(transform, extent) {
var dx = Math.min(0, transform.invertX(extent[0][0]) - x0) || Math.max(0, transform.invertX(extent[1][0]) - x1),
dy = Math.min(0, transform.invertY(extent[0][1]) - y0) || Math.max(0, transform.invertY(extent[1][1]) - y1);
return dx || dy ? transform.translate(dx, dy) : transform;
}
function centroid(extent) {
return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
}
function schedule(transition, transform, center) {
transition
.on("start.zoom", function() { gesture(this, arguments).start(); })
.on("interrupt.zoom end.zoom", function() { gesture(this, arguments).end(); })
.tween("zoom", function() {
var that = this,
args = arguments,
g = gesture(that, args),
e = extent.apply(that, args),
p = center || centroid(e),
w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]),
a = that.__zoom,
b = typeof transform === "function" ? transform.apply(that, args) : transform,
i = interpolateZoom(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
return function(t) {
if (t === 1) t = b; // Avoid rounding error on end.
else { var l = i(t), k = w / l[2]; t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k); }
g.zoom(null, t);
};
});
}
function gesture(that, args) {
for (var i = 0, n = gestures.length, g; i < n; ++i) {
if ((g = gestures[i]).that === that) {
return g;
}
}
return new Gesture(that, args);
}
function Gesture(that, args) {
this.that = that;
this.args = args;
this.index = -1;
this.active = 0;
this.extent = extent.apply(that, args);
}
Gesture.prototype = {
start: function() {
if (++this.active === 1) {
this.index = gestures.push(this) - 1;
this.emit("start");
}
return this;
},
zoom: function(key, transform) {
if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
this.that.__zoom = transform;
this.emit("zoom");
return this;
},
end: function() {
if (--this.active === 0) {
gestures.splice(this.index, 1);
this.index = -1;
this.emit("end");
}
return this;
},
emit: function(type) {
customEvent(new ZoomEvent(zoom, type, this.that.__zoom), listeners.apply, listeners, [type, this.that, this.args]);
}
};
function wheeled() {
if (!filter.apply(this, arguments)) return;
var g = gesture(this, arguments),
t = this.__zoom,
k = Math.max(k0, Math.min(k1, t.k * Math.pow(2, -exports.event.deltaY * (exports.event.deltaMode ? 120 : 1) / 500))),
p = mouse(this);
// If the mouse is in the same location as before, reuse it.
// If there were recent wheel events, reset the wheel idle timeout.
if (g.wheel) {
if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) {
g.mouse[1] = t.invert(g.mouse[0] = p);
}
clearTimeout(g.wheel);
}
// If this wheel event won’t trigger a transform change, ignore it.
else if (t.k === k) return;
// Otherwise, capture the mouse point and location at the start.
else {
g.mouse = [p, t.invert(p)];
interrupt(this);
g.start();
}
noevent$1();
g.wheel = setTimeout(wheelidled, wheelDelay);
g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent));
function wheelidled() {
g.wheel = null;
g.end();
}
}
function mousedowned() {
if (touchending || !filter.apply(this, arguments)) return;
var g = gesture(this, arguments),
v = select(exports.event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true),
p = mouse(this);
dragDisable(exports.event.view);
nopropagation$1();
g.mouse = [p, this.__zoom.invert(p)];
interrupt(this);
g.start();
function mousemoved() {
noevent$1();
g.moved = true;
g.zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = mouse(g.that), g.mouse[1]), g.extent));
}
function mouseupped() {
v.on("mousemove.zoom mouseup.zoom", null);
dragEnable(exports.event.view, g.moved);
noevent$1();
g.end();
}
}
function dblclicked() {
if (!filter.apply(this, arguments)) return;
var t0 = this.__zoom,
p0 = mouse(this),
p1 = t0.invert(p0),
k1 = t0.k * (exports.event.shiftKey ? 0.5 : 2),
t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, arguments));
noevent$1();
if (duration > 0) select(this).transition().duration(duration).call(schedule, t1, p0);
else select(this).call(zoom.transform, t1);
}
function touchstarted() {
if (!filter.apply(this, arguments)) return;
var g = gesture(this, arguments),
touches = exports.event.changedTouches,
n = touches.length, i, t, p;
nopropagation$1();
for (i = 0; i < n; ++i) {
t = touches[i], p = touch(this, touches, t.identifier);
p = [p, this.__zoom.invert(p), t.identifier];
if (!g.touch0) g.touch0 = p;
else if (!g.touch1) g.touch1 = p;
}
if (touchstarting) {
touchstarting = clearTimeout(touchstarting);
if (!g.touch1) return g.end(), dblclicked.apply(this, arguments);
}
if (exports.event.touches.length === n) {
touchstarting = setTimeout(function() { touchstarting = null; }, touchDelay);
interrupt(this);
g.start();
}
}
function touchmoved() {
var g = gesture(this, arguments),
touches = exports.event.changedTouches,
n = touches.length, i, t, p, l;
noevent$1();
if (touchstarting) touchstarting = clearTimeout(touchstarting);
for (i = 0; i < n; ++i) {
t = touches[i], p = touch(this, touches, t.identifier);
if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
}
t = g.that.__zoom;
if (g.touch1) {
var p0 = g.touch0[0], l0 = g.touch0[1],
p1 = g.touch1[0], l1 = g.touch1[1],
dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp,
dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
t = scale(t, Math.sqrt(dp / dl));
p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
}
else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
else return;
g.zoom("touch", constrain(translate(t, p, l), g.extent));
}
function touchended() {
var g = gesture(this, arguments),
touches = exports.event.changedTouches,
n = touches.length, i, t;
nopropagation$1();
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, touchDelay);
for (i = 0; i < n; ++i) {
t = touches[i];
if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
}
if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
if (!g.touch0) g.end();
}
zoom.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$9(!!_), zoom) : filter;
};
zoom.extent = function(_) {
return arguments.length ? (extent = typeof _ === "function" ? _ : constant$9([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
};
zoom.scaleExtent = function(_) {
return arguments.length ? (k0 = +_[0], k1 = +_[1], zoom) : [k0, k1];
};
zoom.translateExtent = function(_) {
return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], zoom) : [[x0, y0], [x1, y1]];
};
zoom.duration = function(_) {
return arguments.length ? (duration = +_, zoom) : duration;
};
zoom.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? zoom : value;
};
return zoom;
}
function constant$10(x) {
return function() {
return x;
};
}
function BrushEvent(target, type, selection) {
this.target = target;
this.type = type;
this.selection = selection;
}
function nopropagation$2() {
exports.event.stopImmediatePropagation();
}
function noevent$2() {
exports.event.preventDefault();
exports.event.stopImmediatePropagation();
}
var MODE_DRAG = {name: "drag"};
var MODE_SPACE = {name: "space"};
var MODE_HANDLE = {name: "handle"};
var MODE_CENTER = {name: "center"};
var X = {
name: "x",
handles: ["e", "w"].map(type$1),
input: function(x, e) { return x && [[x[0], e[0][1]], [x[1], e[1][1]]]; },
output: function(xy) { return xy && [xy[0][0], xy[1][0]]; }
};
var Y = {
name: "y",
handles: ["n", "s"].map(type$1),
input: function(y, e) { return y && [[e[0][0], y[0]], [e[1][0], y[1]]]; },
output: function(xy) { return xy && [xy[0][1], xy[1][1]]; }
};
var XY = {
name: "xy",
handles: ["n", "e", "s", "w", "nw", "ne", "se", "sw"].map(type$1),
input: function(xy) { return xy; },
output: function(xy) { return xy; }
};
var cursors = {
overlay: "crosshair",
selection: "move",
n: "ns-resize",
e: "ew-resize",
s: "ns-resize",
w: "ew-resize",
nw: "nwse-resize",
ne: "nesw-resize",
se: "nwse-resize",
sw: "nesw-resize"
};
var flipX = {
e: "w",
w: "e",
nw: "ne",
ne: "nw",
se: "sw",
sw: "se"
};
var flipY = {
n: "s",
s: "n",
nw: "sw",
ne: "se",
se: "ne",
sw: "nw"
};
var signsX = {
overlay: +1,
selection: +1,
n: null,
e: +1,
s: null,
w: -1,
nw: -1,
ne: +1,
se: +1,
sw: -1
};
var signsY = {
overlay: +1,
selection: +1,
n: -1,
e: null,
s: +1,
w: null,
nw: -1,
ne: -1,
se: +1,
sw: +1
};
function type$1(t) {
return {type: t};
}
// Ignore right-click, since that should open the context menu.
function defaultFilter$2() {
return !exports.event.button;
}
function defaultExtent$1() {
var svg = this.ownerSVGElement || this;
return [[0, 0], [svg.width.baseVal.value, svg.height.baseVal.value]];
}
// Like d3.local, but with the name “__brush” rather than auto-generated.
function local$1(node) {
while (!node.__brush) if (!(node = node.parentNode)) return;
return node.__brush;
}
function empty$1(extent) {
return extent[0][0] === extent[1][0]
|| extent[0][1] === extent[1][1];
}
function brushSelection(node) {
var state = node.__brush;
return state ? state.dim.output(state.selection) : null;
}
function brushX() {
return brush$1(X);
}
function brushY() {
return brush$1(Y);
}
function brush() {
return brush$1(XY);
}
function brush$1(dim) {
var extent = defaultExtent$1,
filter = defaultFilter$2,
listeners = dispatch(brush, "start", "brush", "end"),
handleSize = 6,
touchending;
function brush(group) {
var overlay = group
.property("__brush", initialize)
.selectAll(".overlay")
.data([type$1("overlay")]);
overlay.enter().append("rect")
.attr("class", "overlay")
.attr("pointer-events", "all")
.attr("cursor", cursors.overlay)
.merge(overlay)
.each(function() {
var extent = local$1(this).extent;
select(this)
.attr("x", extent[0][0])
.attr("y", extent[0][1])
.attr("width", extent[1][0] - extent[0][0])
.attr("height", extent[1][1] - extent[0][1]);
});
group.selectAll(".selection")
.data([type$1("selection")])
.enter().append("rect")
.attr("class", "selection")
.attr("cursor", cursors.selection)
.attr("fill", "#777")
.attr("fill-opacity", 0.3)
.attr("stroke", "#fff")
.attr("shape-rendering", "crispEdges");
var handle = group.selectAll(".handle")
.data(dim.handles, function(d) { return d.type; });
handle.exit().remove();
handle.enter().append("rect")
.attr("class", function(d) { return "handle handle--" + d.type; })
.attr("cursor", function(d) { return cursors[d.type]; });
group
.each(redraw)
.attr("fill", "none")
.attr("pointer-events", "all")
.style("-webkit-tap-highlight-color", "rgba(0,0,0,0)")
.on("mousedown.brush touchstart.brush", started);
}
brush.move = function(group, selection) {
if (group.selection) {
group
.on("start.brush", function() { emitter(this, arguments).beforestart().start(); })
.on("interrupt.brush end.brush", function() { emitter(this, arguments).end(); })
.tween("brush", function() {
var that = this,
state = that.__brush,
emit = emitter(that, arguments),
selection0 = state.selection,
selection1 = dim.input(typeof selection === "function" ? selection.apply(this, arguments) : selection, state.extent),
i = interpolate(selection0, selection1);
function tween(t) {
state.selection = t === 1 && empty$1(selection1) ? null : i(t);
redraw.call(that);
emit.brush();
}
return selection0 && selection1 ? tween : tween(1);
});
} else {
group
.each(function() {
var that = this,
args = arguments,
state = that.__brush,
selection1 = dim.input(typeof selection === "function" ? selection.apply(that, args) : selection, state.extent),
emit = emitter(that, args).beforestart();
interrupt(that);
state.selection = selection1 == null || empty$1(selection1) ? null : selection1;
redraw.call(that);
emit.start().brush().end();
});
}
};
function redraw() {
var group = select(this),
selection = local$1(this).selection;
if (selection) {
group.selectAll(".selection")
.style("display", null)
.attr("x", selection[0][0])
.attr("y", selection[0][1])
.attr("width", selection[1][0] - selection[0][0])
.attr("height", selection[1][1] - selection[0][1]);
group.selectAll(".handle")
.style("display", null)
.attr("x", function(d) { return d.type[d.type.length - 1] === "e" ? selection[1][0] - handleSize / 2 : selection[0][0] - handleSize / 2; })
.attr("y", function(d) { return d.type[0] === "s" ? selection[1][1] - handleSize / 2 : selection[0][1] - handleSize / 2; })
.attr("width", function(d) { return d.type === "n" || d.type === "s" ? selection[1][0] - selection[0][0] + handleSize : handleSize; })
.attr("height", function(d) { return d.type === "e" || d.type === "w" ? selection[1][1] - selection[0][1] + handleSize : handleSize; });
}
else {
group.selectAll(".selection,.handle")
.style("display", "none")
.attr("x", null)
.attr("y", null)
.attr("width", null)
.attr("height", null);
}
}
function emitter(that, args) {
return that.__brush.emitter || new Emitter(that, args);
}
function Emitter(that, args) {
this.that = that;
this.args = args;
this.state = that.__brush;
this.active = 0;
}
Emitter.prototype = {
beforestart: function() {
if (++this.active === 1) this.state.emitter = this, this.starting = true;
return this;
},
start: function() {
if (this.starting) this.starting = false, this.emit("start");
return this;
},
brush: function() {
this.emit("brush");
return this;
},
end: function() {
if (--this.active === 0) delete this.state.emitter, this.emit("end");
return this;
},
emit: function(type) {
customEvent(new BrushEvent(brush, type, dim.output(this.state.selection)), listeners.apply, listeners, [type, this.that, this.args]);
}
};
function started() {
if (exports.event.touches) { if (exports.event.changedTouches.length < exports.event.touches.length) return noevent$2(); }
else if (touchending) return;
if (!filter.apply(this, arguments)) return;
var that = this,
type = exports.event.target.__data__.type,
mode = (exports.event.metaKey ? type = "overlay" : type) === "selection" ? MODE_DRAG : (exports.event.altKey ? MODE_CENTER : MODE_HANDLE),
signX = dim === Y ? null : signsX[type],
signY = dim === X ? null : signsY[type],
state = local$1(that),
extent = state.extent,
selection = state.selection,
W = extent[0][0], w0, w1,
N = extent[0][1], n0, n1,
E = extent[1][0], e0, e1,
S = extent[1][1], s0, s1,
dx,
dy,
moving,
shifting = signX && signY && exports.event.shiftKey,
lockX,
lockY,
point0 = mouse(that),
point = point0,
emit = emitter(that, arguments).beforestart();
if (type === "overlay") {
state.selection = selection = [
[w0 = dim === Y ? W : point0[0], n0 = dim === X ? N : point0[1]],
[e0 = dim === Y ? E : w0, s0 = dim === X ? S : n0]
];
} else {
w0 = selection[0][0];
n0 = selection[0][1];
e0 = selection[1][0];
s0 = selection[1][1];
}
w1 = w0;
n1 = n0;
e1 = e0;
s1 = s0;
var group = select(that)
.attr("pointer-events", "none");
var overlay = group.selectAll(".overlay")
.attr("cursor", cursors[type]);
if (exports.event.touches) {
group
.on("touchmove.brush", moved, true)
.on("touchend.brush touchcancel.brush", ended, true);
} else {
var view = select(exports.event.view)
.on("keydown.brush", keydowned, true)
.on("keyup.brush", keyupped, true)
.on("mousemove.brush", moved, true)
.on("mouseup.brush", ended, true);
dragDisable(exports.event.view);
}
nopropagation$2();
interrupt(that);
redraw.call(that);
emit.start();
function moved() {
var point1 = mouse(that);
if (shifting && !lockX && !lockY) {
if (Math.abs(point1[0] - point[0]) > Math.abs(point1[1] - point[1])) lockY = true;
else lockX = true;
}
point = point1;
moving = true;
noevent$2();
move();
}
function move() {
var t;
dx = point[0] - point0[0];
dy = point[1] - point0[1];
switch (mode) {
case MODE_SPACE:
case MODE_DRAG: {
if (signX) dx = Math.max(W - w0, Math.min(E - e0, dx)), w1 = w0 + dx, e1 = e0 + dx;
if (signY) dy = Math.max(N - n0, Math.min(S - s0, dy)), n1 = n0 + dy, s1 = s0 + dy;
break;
}
case MODE_HANDLE: {
if (signX < 0) dx = Math.max(W - w0, Math.min(E - w0, dx)), w1 = w0 + dx, e1 = e0;
else if (signX > 0) dx = Math.max(W - e0, Math.min(E - e0, dx)), w1 = w0, e1 = e0 + dx;
if (signY < 0) dy = Math.max(N - n0, Math.min(S - n0, dy)), n1 = n0 + dy, s1 = s0;
else if (signY > 0) dy = Math.max(N - s0, Math.min(S - s0, dy)), n1 = n0, s1 = s0 + dy;
break;
}
case MODE_CENTER: {
if (signX) w1 = Math.max(W, Math.min(E, w0 - dx * signX)), e1 = Math.max(W, Math.min(E, e0 + dx * signX));
if (signY) n1 = Math.max(N, Math.min(S, n0 - dy * signY)), s1 = Math.max(N, Math.min(S, s0 + dy * signY));
break;
}
}
if (e1 < w1) {
signX *= -1;
t = w0, w0 = e0, e0 = t;
t = w1, w1 = e1, e1 = t;
if (type in flipX) overlay.attr("cursor", cursors[type = flipX[type]]);
}
if (s1 < n1) {
signY *= -1;
t = n0, n0 = s0, s0 = t;
t = n1, n1 = s1, s1 = t;
if (type in flipY) overlay.attr("cursor", cursors[type = flipY[type]]);
}
selection = state.selection; // May be set by brush.move!
if (lockX) w1 = selection[0][0], e1 = selection[1][0];
if (lockY) n1 = selection[0][1], s1 = selection[1][1];
if (selection[0][0] !== w1
|| selection[0][1] !== n1
|| selection[1][0] !== e1
|| selection[1][1] !== s1) {
state.selection = [[w1, n1], [e1, s1]];
redraw.call(that);
emit.brush();
}
}
function ended() {
nopropagation$2();
if (exports.event.touches) {
if (exports.event.touches.length) return;
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() { touchending = null; }, 500); // Ghost clicks are delayed!
group.on("touchmove.brush touchend.brush touchcancel.brush", null);
} else {
dragEnable(exports.event.view, moving);
view.on("keydown.brush keyup.brush mousemove.brush mouseup.brush", null);
}
group.attr("pointer-events", "all");
overlay.attr("cursor", cursors.overlay);
if (empty$1(selection)) state.selection = null, redraw.call(that);
emit.end();
}
function keydowned() {
switch (exports.event.keyCode) {
case 16: { // SHIFT
shifting = signX && signY;
break;
}
case 18: { // ALT
if (mode === MODE_HANDLE) {
if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
mode = MODE_CENTER;
move();
}
break;
}
case 32: { // SPACE; takes priority over ALT
if (mode === MODE_HANDLE || mode === MODE_CENTER) {
if (signX < 0) e0 = e1 - dx; else if (signX > 0) w0 = w1 - dx;
if (signY < 0) s0 = s1 - dy; else if (signY > 0) n0 = n1 - dy;
mode = MODE_SPACE;
overlay.attr("cursor", cursors.selection);
move();
}
break;
}
default: return;
}
noevent$2();
}
function keyupped() {
switch (exports.event.keyCode) {
case 16: { // SHIFT
if (shifting) {
lockX = lockY = shifting = false;
move();
}
break;
}
case 18: { // ALT
if (mode === MODE_CENTER) {
if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
mode = MODE_HANDLE;
move();
}
break;
}
case 32: { // SPACE
if (mode === MODE_SPACE) {
if (exports.event.altKey) {
if (signX) e0 = e1 - dx * signX, w0 = w1 + dx * signX;
if (signY) s0 = s1 - dy * signY, n0 = n1 + dy * signY;
mode = MODE_CENTER;
} else {
if (signX < 0) e0 = e1; else if (signX > 0) w0 = w1;
if (signY < 0) s0 = s1; else if (signY > 0) n0 = n1;
mode = MODE_HANDLE;
}
overlay.attr("cursor", cursors[type]);
move();
}
break;
}
default: return;
}
noevent$2();
}
}
function initialize() {
var state = this.__brush || {selection: null};
state.extent = extent.apply(this, arguments);
state.dim = dim;
return state;
}
brush.extent = function(_) {
return arguments.length ? (extent = typeof _ === "function" ? _ : constant$10([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), brush) : extent;
};
brush.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant$10(!!_), brush) : filter;
};
brush.handleSize = function(_) {
return arguments.length ? (handleSize = +_, brush) : handleSize;
};
brush.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? brush : value;
};
return brush;
}
// Adds floating point numbers with twice the normal precision.
// Reference: J. R. Shewchuk, Adaptive Precision Floating-Point Arithmetic and
// Fast Robust Geometric Predicates, Discrete & Computational Geometry 18(3)
// 305–363 (1997).
// Code adapted from GeographicLib by Charles F. F. Karney,
// http://geographiclib.sourceforge.net/
function adder() {
return new Adder;
}
function Adder() {
this.reset();
}
Adder.prototype = {
constructor: Adder,
reset: function() {
this.s = // rounded value
this.t = 0; // exact error
},
add: function(y) {
add$1(temp, y, this.t);
add$1(this, temp.s, this.s);
if (this.s) this.t += temp.t;
else this.s = temp.t;
},
valueOf: function() {
return this.s;
}
};
var temp = new Adder;
function add$1(adder, a, b) {
var x = adder.s = a + b,
bv = x - a,
av = x - bv;
adder.t = (a - av) + (b - bv);
}
var epsilon$4 = 1e-6;
var epsilon2$2 = 1e-12;
var pi$3 = Math.PI;
var halfPi$2 = pi$3 / 2;
var quarterPi = pi$3 / 4;
var tau$3 = pi$3 * 2;
var degrees$1 = 180 / pi$3;
var radians = pi$3 / 180;
var abs = Math.abs;
var atan = Math.atan;
var atan2 = Math.atan2;
var cos = Math.cos;
var ceil = Math.ceil;
var exp = Math.exp;
var log$1 = Math.log;
var pow$1 = Math.pow;
var sin = Math.sin;
var sign$1 = Math.sign || function(x) { return x > 0 ? 1 : x < 0 ? -1 : 0; };
var sqrt$1 = Math.sqrt;
var tan = Math.tan;
function acos(x) {
return x > 1 ? 0 : x < -1 ? pi$3 : Math.acos(x);
}
function asin$1(x) {
return x > 1 ? halfPi$2 : x < -1 ? -halfPi$2 : Math.asin(x);
}
function haversin(x) {
return (x = sin(x / 2)) * x;
}
function noop$2() {}
function streamGeometry(geometry, stream) {
if (geometry && streamGeometryType.hasOwnProperty(geometry.type)) {
streamGeometryType[geometry.type](geometry, stream);
}
}
var streamObjectType = {
Feature: function(feature, stream) {
streamGeometry(feature.geometry, stream);
},
FeatureCollection: function(object, stream) {
var features = object.features, i = -1, n = features.length;
while (++i < n) streamGeometry(features[i].geometry, stream);
}
};
var streamGeometryType = {
Sphere: function(object, stream) {
stream.sphere();
},
Point: function(object, stream) {
object = object.coordinates;
stream.point(object[0], object[1], object[2]);
},
MultiPoint: function(object, stream) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) object = coordinates[i], stream.point(object[0], object[1], object[2]);
},
LineString: function(object, stream) {
streamLine(object.coordinates, stream, 0);
},
MultiLineString: function(object, stream) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) streamLine(coordinates[i], stream, 0);
},
Polygon: function(object, stream) {
streamPolygon(object.coordinates, stream);
},
MultiPolygon: function(object, stream) {
var coordinates = object.coordinates, i = -1, n = coordinates.length;
while (++i < n) streamPolygon(coordinates[i], stream);
},
GeometryCollection: function(object, stream) {
var geometries = object.geometries, i = -1, n = geometries.length;
while (++i < n) streamGeometry(geometries[i], stream);
}
};
function streamLine(coordinates, stream, closed) {
var i = -1, n = coordinates.length - closed, coordinate;
stream.lineStart();
while (++i < n) coordinate = coordinates[i], stream.point(coordinate[0], coordinate[1], coordinate[2]);
stream.lineEnd();
}
function streamPolygon(coordinates, stream) {
var i = -1, n = coordinates.length;
stream.polygonStart();
while (++i < n) streamLine(coordinates[i], stream, 1);
stream.polygonEnd();
}
function geoStream(object, stream) {
if (object && streamObjectType.hasOwnProperty(object.type)) {
streamObjectType[object.type](object, stream);
} else {
streamGeometry(object, stream);
}
}
var areaRingSum = adder();
var areaSum = adder();
var lambda00;
var phi00;
var lambda0;
var cosPhi0;
var sinPhi0;
var areaStream = {
point: noop$2,
lineStart: noop$2,
lineEnd: noop$2,
polygonStart: function() {
areaRingSum.reset();
areaStream.lineStart = areaRingStart;
areaStream.lineEnd = areaRingEnd;
},
polygonEnd: function() {
var areaRing = +areaRingSum;
areaSum.add(areaRing < 0 ? tau$3 + areaRing : areaRing);
this.lineStart = this.lineEnd = this.point = noop$2;
},
sphere: function() {
areaSum.add(tau$3);
}
};
function areaRingStart() {
areaStream.point = areaPointFirst;
}
function areaRingEnd() {
areaPoint(lambda00, phi00);
}
function areaPointFirst(lambda, phi) {
areaStream.point = areaPoint;
lambda00 = lambda, phi00 = phi;
lambda *= radians, phi *= radians;
lambda0 = lambda, cosPhi0 = cos(phi = phi / 2 + quarterPi), sinPhi0 = sin(phi);
}
function areaPoint(lambda, phi) {
lambda *= radians, phi *= radians;
phi = phi / 2 + quarterPi; // half the angular distance from south pole
// Spherical excess E for a spherical triangle with vertices: south pole,
// previous point, current point. Uses a formula derived from Cagnoli’s
// theorem. See Todhunter, Spherical Trig. (1871), Sec. 103, Eq. (2).
var dLambda = lambda - lambda0,
sdLambda = dLambda >= 0 ? 1 : -1,
adLambda = sdLambda * dLambda,
cosPhi = cos(phi),
sinPhi = sin(phi),
k = sinPhi0 * sinPhi,
u = cosPhi0 * cosPhi + k * cos(adLambda),
v = k * sdLambda * sin(adLambda);
areaRingSum.add(atan2(v, u));
// Advance the previous points.
lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
}
function area$2(object) {
areaSum.reset();
geoStream(object, areaStream);
return areaSum * 2;
}
function spherical(cartesian) {
return [atan2(cartesian[1], cartesian[0]), asin$1(cartesian[2])];
}
function cartesian(spherical) {
var lambda = spherical[0], phi = spherical[1], cosPhi = cos(phi);
return [cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi)];
}
function cartesianDot(a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
function cartesianCross(a, b) {
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
}
// TODO return a
function cartesianAddInPlace(a, b) {
a[0] += b[0], a[1] += b[1], a[2] += b[2];
}
function cartesianScale(vector, k) {
return [vector[0] * k, vector[1] * k, vector[2] * k];
}
// TODO return d
function cartesianNormalizeInPlace(d) {
var l = sqrt$1(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
d[0] /= l, d[1] /= l, d[2] /= l;
}
var lambda0$1;
var phi0;
var lambda1;
var phi1;
var lambda2;
var lambda00$1;
var phi00$1;
var p0;
var deltaSum = adder();
var ranges;
var range$1;
var boundsStream = {
point: boundsPoint,
lineStart: boundsLineStart,
lineEnd: boundsLineEnd,
polygonStart: function() {
boundsStream.point = boundsRingPoint;
boundsStream.lineStart = boundsRingStart;
boundsStream.lineEnd = boundsRingEnd;
deltaSum.reset();
areaStream.polygonStart();
},
polygonEnd: function() {
areaStream.polygonEnd();
boundsStream.point = boundsPoint;
boundsStream.lineStart = boundsLineStart;
boundsStream.lineEnd = boundsLineEnd;
if (areaRingSum < 0) lambda0$1 = -(lambda1 = 180), phi0 = -(phi1 = 90);
else if (deltaSum > epsilon$4) phi1 = 90;
else if (deltaSum < -epsilon$4) phi0 = -90;
range$1[0] = lambda0$1, range$1[1] = lambda1;
}
};
function boundsPoint(lambda, phi) {
ranges.push(range$1 = [lambda0$1 = lambda, lambda1 = lambda]);
if (phi < phi0) phi0 = phi;
if (phi > phi1) phi1 = phi;
}
function linePoint(lambda, phi) {
var p = cartesian([lambda * radians, phi * radians]);
if (p0) {
var normal = cartesianCross(p0, p),
equatorial = [normal[1], -normal[0], 0],
inflection = cartesianCross(equatorial, normal);
cartesianNormalizeInPlace(inflection);
inflection = spherical(inflection);
var delta = lambda - lambda2,
sign = delta > 0 ? 1 : -1,
lambdai = inflection[0] * degrees$1 * sign,
phii,
antimeridian = abs(delta) > 180;
if (antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
phii = inflection[1] * degrees$1;
if (phii > phi1) phi1 = phii;
} else if (lambdai = (lambdai + 360) % 360 - 180, antimeridian ^ (sign * lambda2 < lambdai && lambdai < sign * lambda)) {
phii = -inflection[1] * degrees$1;
if (phii < phi0) phi0 = phii;
} else {
if (phi < phi0) phi0 = phi;
if (phi > phi1) phi1 = phi;
}
if (antimeridian) {
if (lambda < lambda2) {
if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
} else {
if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
}
} else {
if (lambda1 >= lambda0$1) {
if (lambda < lambda0$1) lambda0$1 = lambda;
if (lambda > lambda1) lambda1 = lambda;
} else {
if (lambda > lambda2) {
if (angle(lambda0$1, lambda) > angle(lambda0$1, lambda1)) lambda1 = lambda;
} else {
if (angle(lambda, lambda1) > angle(lambda0$1, lambda1)) lambda0$1 = lambda;
}
}
}
} else {
boundsPoint(lambda, phi);
}
p0 = p, lambda2 = lambda;
}
function boundsLineStart() {
boundsStream.point = linePoint;
}
function boundsLineEnd() {
range$1[0] = lambda0$1, range$1[1] = lambda1;
boundsStream.point = boundsPoint;
p0 = null;
}
function boundsRingPoint(lambda, phi) {
if (p0) {
var delta = lambda - lambda2;
deltaSum.add(abs(delta) > 180 ? delta + (delta > 0 ? 360 : -360) : delta);
} else {
lambda00$1 = lambda, phi00$1 = phi;
}
areaStream.point(lambda, phi);
linePoint(lambda, phi);
}
function boundsRingStart() {
areaStream.lineStart();
}
function boundsRingEnd() {
boundsRingPoint(lambda00$1, phi00$1);
areaStream.lineEnd();
if (abs(deltaSum) > epsilon$4) lambda0$1 = -(lambda1 = 180);
range$1[0] = lambda0$1, range$1[1] = lambda1;
p0 = null;
}
// Finds the left-right distance between two longitudes.
// This is almost the same as (lambda1 - lambda0 + 360°) % 360°, except that we want
// the distance between ±180° to be 360°.
function angle(lambda0, lambda1) {
return (lambda1 -= lambda0) < 0 ? lambda1 + 360 : lambda1;
}
function rangeCompare(a, b) {
return a[0] - b[0];
}
function rangeContains(range, x) {
return range[0] <= range[1] ? range[0] <= x && x <= range[1] : x < range[0] || range[1] < x;
}
function bounds(feature) {
var i, n, a, b, merged, deltaMax, delta;
phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
ranges = [];
geoStream(feature, boundsStream);
// First, sort ranges by their minimum longitudes.
if (n = ranges.length) {
ranges.sort(rangeCompare);
// Then, merge any ranges that overlap.
for (i = 1, a = ranges[0], merged = [a]; i < n; ++i) {
b = ranges[i];
if (rangeContains(a, b[0]) || rangeContains(a, b[1])) {
if (angle(a[0], b[1]) > angle(a[0], a[1])) a[1] = b[1];
if (angle(b[0], a[1]) > angle(a[0], a[1])) a[0] = b[0];
} else {
merged.push(a = b);
}
}
// Finally, find the largest gap between the merged ranges.
// The final bounding box will be the inverse of this gap.
for (deltaMax = -Infinity, n = merged.length - 1, i = 0, a = merged[n]; i <= n; a = b, ++i) {
b = merged[i];
if ((delta = angle(a[1], b[0])) > deltaMax) deltaMax = delta, lambda0$1 = b[0], lambda1 = a[1];
}
}
ranges = range$1 = null;
return lambda0$1 === Infinity || phi0 === Infinity
? [[NaN, NaN], [NaN, NaN]]
: [[lambda0$1, phi0], [lambda1, phi1]];
}
var W0;
var W1;
var X0;
var Y0;
var Z0;
var X1;
var Y1;
var Z1;
var X2;
var Y2;
var Z2;
var lambda00$2;
var phi00$2;
var x0;
var y0;
var z0;
// previous point
var centroidStream = {
sphere: noop$2,
point: centroidPoint,
lineStart: centroidLineStart,
lineEnd: centroidLineEnd,
polygonStart: function() {
centroidStream.lineStart = centroidRingStart;
centroidStream.lineEnd = centroidRingEnd;
},
polygonEnd: function() {
centroidStream.lineStart = centroidLineStart;
centroidStream.lineEnd = centroidLineEnd;
}
};
// Arithmetic mean of Cartesian vectors.
function centroidPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos(phi);
centroidPointCartesian(cosPhi * cos(lambda), cosPhi * sin(lambda), sin(phi));
}
function centroidPointCartesian(x, y, z) {
++W0;
X0 += (x - X0) / W0;
Y0 += (y - Y0) / W0;
Z0 += (z - Z0) / W0;
}
function centroidLineStart() {
centroidStream.point = centroidLinePointFirst;
}
function centroidLinePointFirst(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos(phi);
x0 = cosPhi * cos(lambda);
y0 = cosPhi * sin(lambda);
z0 = sin(phi);
centroidStream.point = centroidLinePoint;
centroidPointCartesian(x0, y0, z0);
}
function centroidLinePoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos(phi),
x = cosPhi * cos(lambda),
y = cosPhi * sin(lambda),
z = sin(phi),
w = atan2(sqrt$1((w = y0 * z - z0 * y) * w + (w = z0 * x - x0 * z) * w + (w = x0 * y - y0 * x) * w), x0 * x + y0 * y + z0 * z);
W1 += w;
X1 += w * (x0 + (x0 = x));
Y1 += w * (y0 + (y0 = y));
Z1 += w * (z0 + (z0 = z));
centroidPointCartesian(x0, y0, z0);
}
function centroidLineEnd() {
centroidStream.point = centroidPoint;
}
// See J. E. Brock, The Inertia Tensor for a Spherical Triangle,
// J. Applied Mechanics 42, 239 (1975).
function centroidRingStart() {
centroidStream.point = centroidRingPointFirst;
}
function centroidRingEnd() {
centroidRingPoint(lambda00$2, phi00$2);
centroidStream.point = centroidPoint;
}
function centroidRingPointFirst(lambda, phi) {
lambda00$2 = lambda, phi00$2 = phi;
lambda *= radians, phi *= radians;
centroidStream.point = centroidRingPoint;
var cosPhi = cos(phi);
x0 = cosPhi * cos(lambda);
y0 = cosPhi * sin(lambda);
z0 = sin(phi);
centroidPointCartesian(x0, y0, z0);
}
function centroidRingPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos(phi),
x = cosPhi * cos(lambda),
y = cosPhi * sin(lambda),
z = sin(phi),
cx = y0 * z - z0 * y,
cy = z0 * x - x0 * z,
cz = x0 * y - y0 * x,
m = sqrt$1(cx * cx + cy * cy + cz * cz),
u = x0 * x + y0 * y + z0 * z,
v = m && -acos(u) / m, // area weight
w = atan2(m, u); // line weight
X2 += v * cx;
Y2 += v * cy;
Z2 += v * cz;
W1 += w;
X1 += w * (x0 + (x0 = x));
Y1 += w * (y0 + (y0 = y));
Z1 += w * (z0 + (z0 = z));
centroidPointCartesian(x0, y0, z0);
}
function centroid$1(object) {
W0 = W1 =
X0 = Y0 = Z0 =
X1 = Y1 = Z1 =
X2 = Y2 = Z2 = 0;
geoStream(object, centroidStream);
var x = X2,
y = Y2,
z = Z2,
m = x * x + y * y + z * z;
// If the area-weighted ccentroid is undefined, fall back to length-weighted ccentroid.
if (m < epsilon2$2) {
x = X1, y = Y1, z = Z1;
// If the feature has zero length, fall back to arithmetic mean of point vectors.
if (W1 < epsilon$4) x = X0, y = Y0, z = Z0;
m = x * x + y * y + z * z;
// If the feature still has an undefined ccentroid, then return.
if (m < epsilon2$2) return [NaN, NaN];
}
return [atan2(y, x) * degrees$1, asin$1(z / sqrt$1(m)) * degrees$1];
}
function constant$11(x) {
return function() {
return x;
};
}
function compose(a, b) {
function compose(x, y) {
return x = a(x, y), b(x[0], x[1]);
}
if (a.invert && b.invert) compose.invert = function(x, y) {
return x = b.invert(x, y), x && a.invert(x[0], x[1]);
};
return compose;
}
function rotationIdentity(lambda, phi) {
return [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
}
rotationIdentity.invert = rotationIdentity;
function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
return (deltaLambda %= tau$3) ? (deltaPhi || deltaGamma ? compose(rotationLambda(deltaLambda), rotationPhiGamma(deltaPhi, deltaGamma))
: rotationLambda(deltaLambda))
: (deltaPhi || deltaGamma ? rotationPhiGamma(deltaPhi, deltaGamma)
: rotationIdentity);
}
function forwardRotationLambda(deltaLambda) {
return function(lambda, phi) {
return lambda += deltaLambda, [lambda > pi$3 ? lambda - tau$3 : lambda < -pi$3 ? lambda + tau$3 : lambda, phi];
};
}
function rotationLambda(deltaLambda) {
var rotation = forwardRotationLambda(deltaLambda);
rotation.invert = forwardRotationLambda(-deltaLambda);
return rotation;
}
function rotationPhiGamma(deltaPhi, deltaGamma) {
var cosDeltaPhi = cos(deltaPhi),
sinDeltaPhi = sin(deltaPhi),
cosDeltaGamma = cos(deltaGamma),
sinDeltaGamma = sin(deltaGamma);
function rotation(lambda, phi) {
var cosPhi = cos(phi),
x = cos(lambda) * cosPhi,
y = sin(lambda) * cosPhi,
z = sin(phi),
k = z * cosDeltaPhi + x * sinDeltaPhi;
return [
atan2(y * cosDeltaGamma - k * sinDeltaGamma, x * cosDeltaPhi - z * sinDeltaPhi),
asin$1(k * cosDeltaGamma + y * sinDeltaGamma)
];
}
rotation.invert = function(lambda, phi) {
var cosPhi = cos(phi),
x = cos(lambda) * cosPhi,
y = sin(lambda) * cosPhi,
z = sin(phi),
k = z * cosDeltaGamma - y * sinDeltaGamma;
return [
atan2(y * cosDeltaGamma + z * sinDeltaGamma, x * cosDeltaPhi + k * sinDeltaPhi),
asin$1(k * cosDeltaPhi - x * sinDeltaPhi)
];
};
return rotation;
}
function rotation(rotate) {
rotate = rotateRadians(rotate[0] * radians, rotate[1] * radians, rotate.length > 2 ? rotate[2] * radians : 0);
function forward(coordinates) {
coordinates = rotate(coordinates[0] * radians, coordinates[1] * radians);
return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
}
forward.invert = function(coordinates) {
coordinates = rotate.invert(coordinates[0] * radians, coordinates[1] * radians);
return coordinates[0] *= degrees$1, coordinates[1] *= degrees$1, coordinates;
};
return forward;
}
// Generates a circle centered at [0°, 0°], with a given radius and precision.
function circleStream(stream, radius, delta, direction, t0, t1) {
if (!delta) return;
var cosRadius = cos(radius),
sinRadius = sin(radius),
step = direction * delta;
if (t0 == null) {
t0 = radius + direction * tau$3;
t1 = radius - step / 2;
} else {
t0 = circleRadius(cosRadius, t0);
t1 = circleRadius(cosRadius, t1);
if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$3;
}
for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
point = spherical([cosRadius, -sinRadius * cos(t), -sinRadius * sin(t)]);
stream.point(point[0], point[1]);
}
}
// Returns the signed angle of a cartesian point relative to [cosRadius, 0, 0].
function circleRadius(cosRadius, point) {
point = cartesian(point), point[0] -= cosRadius;
cartesianNormalizeInPlace(point);
var radius = acos(-point[1]);
return ((-point[2] < 0 ? -radius : radius) + tau$3 - epsilon$4) % tau$3;
}
function circle$1() {
var center = constant$11([0, 0]),
radius = constant$11(90),
precision = constant$11(6),
ring,
rotate,
stream = {point: point};
function point(x, y) {
ring.push(x = rotate(x, y));
x[0] *= degrees$1, x[1] *= degrees$1;
}
function circle() {
var c = center.apply(this, arguments),
r = radius.apply(this, arguments) * radians,
p = precision.apply(this, arguments) * radians;
ring = [];
rotate = rotateRadians(-c[0] * radians, -c[1] * radians, 0).invert;
circleStream(stream, r, p, 1);
c = {type: "Polygon", coordinates: [ring]};
ring = rotate = null;
return c;
}
circle.center = function(_) {
return arguments.length ? (center = typeof _ === "function" ? _ : constant$11([+_[0], +_[1]]), circle) : center;
};
circle.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$11(+_), circle) : radius;
};
circle.precision = function(_) {
return arguments.length ? (precision = typeof _ === "function" ? _ : constant$11(+_), circle) : precision;
};
return circle;
}
function clipBuffer() {
var lines = [],
line;
return {
point: function(x, y) {
line.push([x, y]);
},
lineStart: function() {
lines.push(line = []);
},
lineEnd: noop$2,
rejoin: function() {
if (lines.length > 1) lines.push(lines.pop().concat(lines.shift()));
},
result: function() {
var result = lines;
lines = [];
line = null;
return result;
}
};
}
function clipLine(a, b, x0, y0, x1, y1) {
var ax = a[0],
ay = a[1],
bx = b[0],
by = b[1],
t0 = 0,
t1 = 1,
dx = bx - ax,
dy = by - ay,
r;
r = x0 - ax;
if (!dx && r > 0) return;
r /= dx;
if (dx < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dx > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = x1 - ax;
if (!dx && r < 0) return;
r /= dx;
if (dx < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dx > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
r = y0 - ay;
if (!dy && r > 0) return;
r /= dy;
if (dy < 0) {
if (r < t0) return;
if (r < t1) t1 = r;
} else if (dy > 0) {
if (r > t1) return;
if (r > t0) t0 = r;
}
r = y1 - ay;
if (!dy && r < 0) return;
r /= dy;
if (dy < 0) {
if (r > t1) return;
if (r > t0) t0 = r;
} else if (dy > 0) {
if (r < t0) return;
if (r < t1) t1 = r;
}
if (t0 > 0) a[0] = ax + t0 * dx, a[1] = ay + t0 * dy;
if (t1 < 1) b[0] = ax + t1 * dx, b[1] = ay + t1 * dy;
return true;
}
function pointEqual(a, b) {
return abs(a[0] - b[0]) < epsilon$4 && abs(a[1] - b[1]) < epsilon$4;
}
function Intersection(point, points, other, entry) {
this.x = point;
this.z = points;
this.o = other; // another intersection
this.e = entry; // is an entry?
this.v = false; // visited
this.n = this.p = null; // next & previous
}
// A generalized polygon clipping algorithm: given a polygon that has been cut
// into its visible line segments, and rejoins the segments by interpolating
// along the clip edge.
function clipPolygon(segments, compareIntersection, startInside, interpolate, stream) {
var subject = [],
clip = [],
i,
n;
segments.forEach(function(segment) {
if ((n = segment.length - 1) <= 0) return;
var n, p0 = segment[0], p1 = segment[n], x;
// If the first and last points of a segment are coincident, then treat as a
// closed ring. TODO if all rings are closed, then the winding order of the
// exterior ring should be checked.
if (pointEqual(p0, p1)) {
stream.lineStart();
for (i = 0; i < n; ++i) stream.point((p0 = segment[i])[0], p0[1]);
stream.lineEnd();
return;
}
subject.push(x = new Intersection(p0, segment, null, true));
clip.push(x.o = new Intersection(p0, null, x, false));
subject.push(x = new Intersection(p1, segment, null, false));
clip.push(x.o = new Intersection(p1, null, x, true));
});
if (!subject.length) return;
clip.sort(compareIntersection);
link$1(subject);
link$1(clip);
for (i = 0, n = clip.length; i < n; ++i) {
clip[i].e = startInside = !startInside;
}
var start = subject[0],
points,
point;
while (1) {
// Find first unvisited intersection.
var current = start,
isSubject = true;
while (current.v) if ((current = current.n) === start) return;
points = current.z;
stream.lineStart();
do {
current.v = current.o.v = true;
if (current.e) {
if (isSubject) {
for (i = 0, n = points.length; i < n; ++i) stream.point((point = points[i])[0], point[1]);
} else {
interpolate(current.x, current.n.x, 1, stream);
}
current = current.n;
} else {
if (isSubject) {
points = current.p.z;
for (i = points.length - 1; i >= 0; --i) stream.point((point = points[i])[0], point[1]);
} else {
interpolate(current.x, current.p.x, -1, stream);
}
current = current.p;
}
current = current.o;
points = current.z;
isSubject = !isSubject;
} while (!current.v);
stream.lineEnd();
}
}
function link$1(array) {
if (!(n = array.length)) return;
var n,
i = 0,
a = array[0],
b;
while (++i < n) {
a.n = b = array[i];
b.p = a;
a = b;
}
a.n = b = array[0];
b.p = a;
}
var clipMax = 1e9;
var clipMin = -clipMax;
// TODO Use d3-polygon’s polygonContains here for the ring check?
// TODO Eliminate duplicate buffering in clipBuffer and polygon.push?
function clipExtent(x0, y0, x1, y1) {
function visible(x, y) {
return x0 <= x && x <= x1 && y0 <= y && y <= y1;
}
function interpolate(from, to, direction, stream) {
var a = 0, a1 = 0;
if (from == null
|| (a = corner(from, direction)) !== (a1 = corner(to, direction))
|| comparePoint(from, to) < 0 ^ direction > 0) {
do stream.point(a === 0 || a === 3 ? x0 : x1, a > 1 ? y1 : y0);
while ((a = (a + direction + 4) % 4) !== a1);
} else {
stream.point(to[0], to[1]);
}
}
function corner(p, direction) {
return abs(p[0] - x0) < epsilon$4 ? direction > 0 ? 0 : 3
: abs(p[0] - x1) < epsilon$4 ? direction > 0 ? 2 : 1
: abs(p[1] - y0) < epsilon$4 ? direction > 0 ? 1 : 0
: direction > 0 ? 3 : 2; // abs(p[1] - y1) < epsilon
}
function compareIntersection(a, b) {
return comparePoint(a.x, b.x);
}
function comparePoint(a, b) {
var ca = corner(a, 1),
cb = corner(b, 1);
return ca !== cb ? ca - cb
: ca === 0 ? b[1] - a[1]
: ca === 1 ? a[0] - b[0]
: ca === 2 ? a[1] - b[1]
: b[0] - a[0];
}
return function(stream) {
var activeStream = stream,
bufferStream = clipBuffer(),
segments,
polygon,
ring,
x__, y__, v__, // first point
x_, y_, v_, // previous point
first,
clean;
var clipStream = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: polygonStart,
polygonEnd: polygonEnd
};
function point(x, y) {
if (visible(x, y)) activeStream.point(x, y);
}
function polygonInside() {
var winding = 0;
for (var i = 0, n = polygon.length; i < n; ++i) {
for (var ring = polygon[i], j = 1, m = ring.length, point = ring[0], a0, a1, b0 = point[0], b1 = point[1]; j < m; ++j) {
a0 = b0, a1 = b1, point = ring[j], b0 = point[0], b1 = point[1];
if (a1 <= y1) { if (b1 > y1 && (b0 - a0) * (y1 - a1) > (b1 - a1) * (x0 - a0)) ++winding; }
else { if (b1 <= y1 && (b0 - a0) * (y1 - a1) < (b1 - a1) * (x0 - a0)) --winding; }
}
}
return winding;
}
// Buffer geometry within a polygon and then clip it en masse.
function polygonStart() {
activeStream = bufferStream, segments = [], polygon = [], clean = true;
}
function polygonEnd() {
var startInside = polygonInside(),
cleanInside = clean && startInside,
visible = (segments = merge(segments)).length;
if (cleanInside || visible) {
stream.polygonStart();
if (cleanInside) {
stream.lineStart();
interpolate(null, null, 1, stream);
stream.lineEnd();
}
if (visible) {
clipPolygon(segments, compareIntersection, startInside, interpolate, stream);
}
stream.polygonEnd();
}
activeStream = stream, segments = polygon = ring = null;
}
function lineStart() {
clipStream.point = linePoint;
if (polygon) polygon.push(ring = []);
first = true;
v_ = false;
x_ = y_ = NaN;
}
// TODO rather than special-case polygons, simply handle them separately.
// Ideally, coincident intersection points should be jittered to avoid
// clipping issues.
function lineEnd() {
if (segments) {
linePoint(x__, y__);
if (v__ && v_) bufferStream.rejoin();
segments.push(bufferStream.result());
}
clipStream.point = point;
if (v_) activeStream.lineEnd();
}
function linePoint(x, y) {
var v = visible(x, y);
if (polygon) ring.push([x, y]);
if (first) {
x__ = x, y__ = y, v__ = v;
first = false;
if (v) {
activeStream.lineStart();
activeStream.point(x, y);
}
} else {
if (v && v_) activeStream.point(x, y);
else {
var a = [x_ = Math.max(clipMin, Math.min(clipMax, x_)), y_ = Math.max(clipMin, Math.min(clipMax, y_))],
b = [x = Math.max(clipMin, Math.min(clipMax, x)), y = Math.max(clipMin, Math.min(clipMax, y))];
if (clipLine(a, b, x0, y0, x1, y1)) {
if (!v_) {
activeStream.lineStart();
activeStream.point(a[0], a[1]);
}
activeStream.point(b[0], b[1]);
if (!v) activeStream.lineEnd();
clean = false;
} else if (v) {
activeStream.lineStart();
activeStream.point(x, y);
clean = false;
}
}
}
x_ = x, y_ = y, v_ = v;
}
return clipStream;
};
}
function extent$1() {
var x0 = 0,
y0 = 0,
x1 = 960,
y1 = 500,
cache,
cacheStream,
clip;
return clip = {
stream: function(stream) {
return cache && cacheStream === stream ? cache : cache = clipExtent(x0, y0, x1, y1)(cacheStream = stream);
},
extent: function(_) {
return arguments.length ? (x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1], cache = cacheStream = null, clip) : [[x0, y0], [x1, y1]];
}
};
}
var lengthSum = adder();
var lambda0$2;
var sinPhi0$1;
var cosPhi0$1;
var lengthStream = {
sphere: noop$2,
point: noop$2,
lineStart: lengthLineStart,
lineEnd: noop$2,
polygonStart: noop$2,
polygonEnd: noop$2
};
function lengthLineStart() {
lengthStream.point = lengthPointFirst;
lengthStream.lineEnd = lengthLineEnd;
}
function lengthLineEnd() {
lengthStream.point = lengthStream.lineEnd = noop$2;
}
function lengthPointFirst(lambda, phi) {
lambda *= radians, phi *= radians;
lambda0$2 = lambda, sinPhi0$1 = sin(phi), cosPhi0$1 = cos(phi);
lengthStream.point = lengthPoint;
}
function lengthPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var sinPhi = sin(phi),
cosPhi = cos(phi),
delta = abs(lambda - lambda0$2),
cosDelta = cos(delta),
sinDelta = sin(delta),
x = cosPhi * sinDelta,
y = cosPhi0$1 * sinPhi - sinPhi0$1 * cosPhi * cosDelta,
z = sinPhi0$1 * sinPhi + cosPhi0$1 * cosPhi * cosDelta;
lengthSum.add(atan2(sqrt$1(x * x + y * y), z));
lambda0$2 = lambda, sinPhi0$1 = sinPhi, cosPhi0$1 = cosPhi;
}
function length$2(object) {
lengthSum.reset();
geoStream(object, lengthStream);
return +lengthSum;
}
var coordinates = [null, null];
var object$1 = {type: "LineString", coordinates: coordinates};
function distance(a, b) {
coordinates[0] = a;
coordinates[1] = b;
return length$2(object$1);
}
function graticuleX(y0, y1, dy) {
var y = range(y0, y1 - epsilon$4, dy).concat(y1);
return function(x) { return y.map(function(y) { return [x, y]; }); };
}
function graticuleY(x0, x1, dx) {
var x = range(x0, x1 - epsilon$4, dx).concat(x1);
return function(y) { return x.map(function(x) { return [x, y]; }); };
}
function graticule() {
var x1, x0, X1, X0,
y1, y0, Y1, Y0,
dx = 10, dy = dx, DX = 90, DY = 360,
x, y, X, Y,
precision = 2.5;
function graticule() {
return {type: "MultiLineString", coordinates: lines()};
}
function lines() {
return range(ceil(X0 / DX) * DX, X1, DX).map(X)
.concat(range(ceil(Y0 / DY) * DY, Y1, DY).map(Y))
.concat(range(ceil(x0 / dx) * dx, x1, dx).filter(function(x) { return abs(x % DX) > epsilon$4; }).map(x))
.concat(range(ceil(y0 / dy) * dy, y1, dy).filter(function(y) { return abs(y % DY) > epsilon$4; }).map(y));
}
graticule.lines = function() {
return lines().map(function(coordinates) { return {type: "LineString", coordinates: coordinates}; });
};
graticule.outline = function() {
return {
type: "Polygon",
coordinates: [
X(X0).concat(
Y(Y1).slice(1),
X(X1).reverse().slice(1),
Y(Y0).reverse().slice(1))
]
};
};
graticule.extent = function(_) {
if (!arguments.length) return graticule.extentMinor();
return graticule.extentMajor(_).extentMinor(_);
};
graticule.extentMajor = function(_) {
if (!arguments.length) return [[X0, Y0], [X1, Y1]];
X0 = +_[0][0], X1 = +_[1][0];
Y0 = +_[0][1], Y1 = +_[1][1];
if (X0 > X1) _ = X0, X0 = X1, X1 = _;
if (Y0 > Y1) _ = Y0, Y0 = Y1, Y1 = _;
return graticule.precision(precision);
};
graticule.extentMinor = function(_) {
if (!arguments.length) return [[x0, y0], [x1, y1]];
x0 = +_[0][0], x1 = +_[1][0];
y0 = +_[0][1], y1 = +_[1][1];
if (x0 > x1) _ = x0, x0 = x1, x1 = _;
if (y0 > y1) _ = y0, y0 = y1, y1 = _;
return graticule.precision(precision);
};
graticule.step = function(_) {
if (!arguments.length) return graticule.stepMinor();
return graticule.stepMajor(_).stepMinor(_);
};
graticule.stepMajor = function(_) {
if (!arguments.length) return [DX, DY];
DX = +_[0], DY = +_[1];
return graticule;
};
graticule.stepMinor = function(_) {
if (!arguments.length) return [dx, dy];
dx = +_[0], dy = +_[1];
return graticule;
};
graticule.precision = function(_) {
if (!arguments.length) return precision;
precision = +_;
x = graticuleX(y0, y1, 90);
y = graticuleY(x0, x1, precision);
X = graticuleX(Y0, Y1, 90);
Y = graticuleY(X0, X1, precision);
return graticule;
};
return graticule
.extentMajor([[-180, -90 + epsilon$4], [180, 90 - epsilon$4]])
.extentMinor([[-180, -80 - epsilon$4], [180, 80 + epsilon$4]]);
}
function interpolate$2(a, b) {
var x0 = a[0] * radians,
y0 = a[1] * radians,
x1 = b[0] * radians,
y1 = b[1] * radians,
cy0 = cos(y0),
sy0 = sin(y0),
cy1 = cos(y1),
sy1 = sin(y1),
kx0 = cy0 * cos(x0),
ky0 = cy0 * sin(x0),
kx1 = cy1 * cos(x1),
ky1 = cy1 * sin(x1),
d = 2 * asin$1(sqrt$1(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
k = sin(d);
var interpolate = d ? function(t) {
var B = sin(t *= d) / k,
A = sin(d - t) / k,
x = A * kx0 + B * kx1,
y = A * ky0 + B * ky1,
z = A * sy0 + B * sy1;
return [
atan2(y, x) * degrees$1,
atan2(z, sqrt$1(x * x + y * y)) * degrees$1
];
} : function() {
return [x0 * degrees$1, y0 * degrees$1];
};
interpolate.distance = d;
return interpolate;
}
function identity$7(x) {
return x;
}
var areaSum$1 = adder();
var areaRingSum$1 = adder();
var x00;
var y00;
var x0$1;
var y0$1;
var areaStream$1 = {
point: noop$2,
lineStart: noop$2,
lineEnd: noop$2,
polygonStart: function() {
areaStream$1.lineStart = areaRingStart$1;
areaStream$1.lineEnd = areaRingEnd$1;
},
polygonEnd: function() {
areaStream$1.lineStart = areaStream$1.lineEnd = areaStream$1.point = noop$2;
areaSum$1.add(abs(areaRingSum$1));
areaRingSum$1.reset();
},
result: function() {
var area = areaSum$1 / 2;
areaSum$1.reset();
return area;
}
};
function areaRingStart$1() {
areaStream$1.point = areaPointFirst$1;
}
function areaPointFirst$1(x, y) {
areaStream$1.point = areaPoint$1;
x00 = x0$1 = x, y00 = y0$1 = y;
}
function areaPoint$1(x, y) {
areaRingSum$1.add(y0$1 * x - x0$1 * y);
x0$1 = x, y0$1 = y;
}
function areaRingEnd$1() {
areaPoint$1(x00, y00);
}
var x0$2 = Infinity;
var y0$2 = x0$2;
var x1 = -x0$2;
var y1 = x1;
var boundsStream$1 = {
point: boundsPoint$1,
lineStart: noop$2,
lineEnd: noop$2,
polygonStart: noop$2,
polygonEnd: noop$2,
result: function() {
var bounds = [[x0$2, y0$2], [x1, y1]];
x1 = y1 = -(y0$2 = x0$2 = Infinity);
return bounds;
}
};
function boundsPoint$1(x, y) {
if (x < x0$2) x0$2 = x;
if (x > x1) x1 = x;
if (y < y0$2) y0$2 = y;
if (y > y1) y1 = y;
}
var X0$1 = 0;
var Y0$1 = 0;
var Z0$1 = 0;
var X1$1 = 0;
var Y1$1 = 0;
var Z1$1 = 0;
var X2$1 = 0;
var Y2$1 = 0;
var Z2$1 = 0;
var x00$1;
var y00$1;
var x0$3;
var y0$3;
var centroidStream$1 = {
point: centroidPoint$1,
lineStart: centroidLineStart$1,
lineEnd: centroidLineEnd$1,
polygonStart: function() {
centroidStream$1.lineStart = centroidRingStart$1;
centroidStream$1.lineEnd = centroidRingEnd$1;
},
polygonEnd: function() {
centroidStream$1.point = centroidPoint$1;
centroidStream$1.lineStart = centroidLineStart$1;
centroidStream$1.lineEnd = centroidLineEnd$1;
},
result: function() {
var centroid = Z2$1 ? [X2$1 / Z2$1, Y2$1 / Z2$1]
: Z1$1 ? [X1$1 / Z1$1, Y1$1 / Z1$1]
: Z0$1 ? [X0$1 / Z0$1, Y0$1 / Z0$1]
: [NaN, NaN];
X0$1 = Y0$1 = Z0$1 =
X1$1 = Y1$1 = Z1$1 =
X2$1 = Y2$1 = Z2$1 = 0;
return centroid;
}
};
function centroidPoint$1(x, y) {
X0$1 += x;
Y0$1 += y;
++Z0$1;
}
function centroidLineStart$1() {
centroidStream$1.point = centroidPointFirstLine;
}
function centroidPointFirstLine(x, y) {
centroidStream$1.point = centroidPointLine;
centroidPoint$1(x0$3 = x, y0$3 = y);
}
function centroidPointLine(x, y) {
var dx = x - x0$3, dy = y - y0$3, z = sqrt$1(dx * dx + dy * dy);
X1$1 += z * (x0$3 + x) / 2;
Y1$1 += z * (y0$3 + y) / 2;
Z1$1 += z;
centroidPoint$1(x0$3 = x, y0$3 = y);
}
function centroidLineEnd$1() {
centroidStream$1.point = centroidPoint$1;
}
function centroidRingStart$1() {
centroidStream$1.point = centroidPointFirstRing;
}
function centroidRingEnd$1() {
centroidPointRing(x00$1, y00$1);
}
function centroidPointFirstRing(x, y) {
centroidStream$1.point = centroidPointRing;
centroidPoint$1(x00$1 = x0$3 = x, y00$1 = y0$3 = y);
}
function centroidPointRing(x, y) {
var dx = x - x0$3,
dy = y - y0$3,
z = sqrt$1(dx * dx + dy * dy);
X1$1 += z * (x0$3 + x) / 2;
Y1$1 += z * (y0$3 + y) / 2;
Z1$1 += z;
z = y0$3 * x - x0$3 * y;
X2$1 += z * (x0$3 + x);
Y2$1 += z * (y0$3 + y);
Z2$1 += z * 3;
centroidPoint$1(x0$3 = x, y0$3 = y);
}
function PathContext(context) {
var pointRadius = 4.5;
var stream = {
point: point,
// While inside a line, override point to moveTo then lineTo.
lineStart: function() { stream.point = pointLineStart; },
lineEnd: lineEnd,
// While inside a polygon, override lineEnd to closePath.
polygonStart: function() { stream.lineEnd = lineEndPolygon; },
polygonEnd: function() { stream.lineEnd = lineEnd; stream.point = point; },
pointRadius: function(_) {
pointRadius = _;
return stream;
},
result: noop$2
};
function point(x, y) {
context.moveTo(x + pointRadius, y);
context.arc(x, y, pointRadius, 0, tau$3);
}
function pointLineStart(x, y) {
context.moveTo(x, y);
stream.point = pointLine;
}
function pointLine(x, y) {
context.lineTo(x, y);
}
function lineEnd() {
stream.point = point;
}
function lineEndPolygon() {
context.closePath();
}
return stream;
}
function PathString() {
var pointCircle = circle$2(4.5),
string = [];
var stream = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
stream.lineEnd = lineEndPolygon;
},
polygonEnd: function() {
stream.lineEnd = lineEnd;
stream.point = point;
},
pointRadius: function(_) {
pointCircle = circle$2(_);
return stream;
},
result: function() {
if (string.length) {
var result = string.join("");
string = [];
return result;
}
}
};
function point(x, y) {
string.push("M", x, ",", y, pointCircle);
}
function pointLineStart(x, y) {
string.push("M", x, ",", y);
stream.point = pointLine;
}
function pointLine(x, y) {
string.push("L", x, ",", y);
}
function lineStart() {
stream.point = pointLineStart;
}
function lineEnd() {
stream.point = point;
}
function lineEndPolygon() {
string.push("Z");
}
return stream;
}
function circle$2(radius) {
return "m0," + radius
+ "a" + radius + "," + radius + " 0 1,1 0," + -2 * radius
+ "a" + radius + "," + radius + " 0 1,1 0," + 2 * radius
+ "z";
}
function index$3() {
var pointRadius = 4.5,
projection,
projectionStream,
context,
contextStream;
function path(object) {
if (object) {
if (typeof pointRadius === "function") contextStream.pointRadius(+pointRadius.apply(this, arguments));
geoStream(object, projectionStream(contextStream));
}
return contextStream.result();
}
path.area = function(object) {
geoStream(object, projectionStream(areaStream$1));
return areaStream$1.result();
};
path.bounds = function(object) {
geoStream(object, projectionStream(boundsStream$1));
return boundsStream$1.result();
};
path.centroid = function(object) {
geoStream(object, projectionStream(centroidStream$1));
return centroidStream$1.result();
};
path.projection = function(_) {
return arguments.length ? (projectionStream = (projection = _) == null ? identity$7 : _.stream, path) : projection;
};
path.context = function(_) {
if (!arguments.length) return context;
contextStream = (context = _) == null ? new PathString : new PathContext(_);
if (typeof pointRadius !== "function") contextStream.pointRadius(pointRadius);
return path;
};
path.pointRadius = function(_) {
if (!arguments.length) return pointRadius;
pointRadius = typeof _ === "function" ? _ : (contextStream.pointRadius(+_), +_);
return path;
};
return path.projection(null).context(null);
}
var sum$2 = adder();
function polygonContains(polygon, point) {
var lambda = point[0],
phi = point[1],
normal = [sin(lambda), -cos(lambda), 0],
angle = 0,
winding = 0;
sum$2.reset();
for (var i = 0, n = polygon.length; i < n; ++i) {
if (!(m = (ring = polygon[i]).length)) continue;
var ring,
m,
point0 = ring[m - 1],
lambda0 = point0[0],
phi0 = point0[1] / 2 + quarterPi,
sinPhi0 = sin(phi0),
cosPhi0 = cos(phi0);
for (var j = 0; j < m; ++j, lambda0 = lambda1, sinPhi0 = sinPhi1, cosPhi0 = cosPhi1, point0 = point1) {
var point1 = ring[j],
lambda1 = point1[0],
phi1 = point1[1] / 2 + quarterPi,
sinPhi1 = sin(phi1),
cosPhi1 = cos(phi1),
delta = lambda1 - lambda0,
sign = delta >= 0 ? 1 : -1,
absDelta = sign * delta,
antimeridian = absDelta > pi$3,
k = sinPhi0 * sinPhi1;
sum$2.add(atan2(k * sign * sin(absDelta), cosPhi0 * cosPhi1 + k * cos(absDelta)));
angle += antimeridian ? delta + sign * tau$3 : delta;
// Are the longitudes either side of the point’s meridian (lambda),
// and are the latitudes smaller than the parallel (phi)?
if (antimeridian ^ lambda0 >= lambda ^ lambda1 >= lambda) {
var arc = cartesianCross(cartesian(point0), cartesian(point1));
cartesianNormalizeInPlace(arc);
var intersection = cartesianCross(normal, arc);
cartesianNormalizeInPlace(intersection);
var phiArc = (antimeridian ^ delta >= 0 ? -1 : 1) * asin$1(intersection[2]);
if (phi > phiArc || phi === phiArc && (arc[0] || arc[1])) {
winding += antimeridian ^ delta >= 0 ? 1 : -1;
}
}
}
}
// First, determine whether the South pole is inside or outside:
//
// It is inside if:
// * the polygon winds around it in a clockwise direction.
// * the polygon does not (cumulatively) wind around it, but has a negative
// (counter-clockwise) area.
//
// Second, count the (signed) number of times a segment crosses a lambda
// from the point to the South pole. If it is zero, then the point is the
// same side as the South pole.
return (angle < -epsilon$4 || angle < epsilon$4 && sum$2 < -epsilon$4) ^ (winding & 1);
}
function clip(pointVisible, clipLine, interpolate, start) {
return function(rotate, sink) {
var line = clipLine(sink),
rotatedStart = rotate.invert(start[0], start[1]),
ringBuffer = clipBuffer(),
ringSink = clipLine(ringBuffer),
polygonStarted = false,
polygon,
segments,
ring;
var clip = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() {
clip.point = pointRing;
clip.lineStart = ringStart;
clip.lineEnd = ringEnd;
segments = [];
polygon = [];
},
polygonEnd: function() {
clip.point = point;
clip.lineStart = lineStart;
clip.lineEnd = lineEnd;
segments = merge(segments);
var startInside = polygonContains(polygon, rotatedStart);
if (segments.length) {
if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
clipPolygon(segments, compareIntersection, startInside, interpolate, sink);
} else if (startInside) {
if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
sink.lineStart();
interpolate(null, null, 1, sink);
sink.lineEnd();
}
if (polygonStarted) sink.polygonEnd(), polygonStarted = false;
segments = polygon = null;
},
sphere: function() {
sink.polygonStart();
sink.lineStart();
interpolate(null, null, 1, sink);
sink.lineEnd();
sink.polygonEnd();
}
};
function point(lambda, phi) {
var point = rotate(lambda, phi);
if (pointVisible(lambda = point[0], phi = point[1])) sink.point(lambda, phi);
}
function pointLine(lambda, phi) {
var point = rotate(lambda, phi);
line.point(point[0], point[1]);
}
function lineStart() {
clip.point = pointLine;
line.lineStart();
}
function lineEnd() {
clip.point = point;
line.lineEnd();
}
function pointRing(lambda, phi) {
ring.push([lambda, phi]);
var point = rotate(lambda, phi);
ringSink.point(point[0], point[1]);
}
function ringStart() {
ringSink.lineStart();
ring = [];
}
function ringEnd() {
pointRing(ring[0][0], ring[0][1]);
ringSink.lineEnd();
var clean = ringSink.clean(),
ringSegments = ringBuffer.result(),
i, n = ringSegments.length, m,
segment,
point;
ring.pop();
polygon.push(ring);
ring = null;
if (!n) return;
// No intersections.
if (clean & 1) {
segment = ringSegments[0];
if ((m = segment.length - 1) > 0) {
if (!polygonStarted) sink.polygonStart(), polygonStarted = true;
sink.lineStart();
for (i = 0; i < m; ++i) sink.point((point = segment[i])[0], point[1]);
sink.lineEnd();
}
return;
}
// Rejoin connected segments.
// TODO reuse ringBuffer.rejoin()?
if (n > 1 && clean & 2) ringSegments.push(ringSegments.pop().concat(ringSegments.shift()));
segments.push(ringSegments.filter(validSegment));
}
return clip;
};
}
function validSegment(segment) {
return segment.length > 1;
}
// Intersections are sorted along the clip edge. For both antimeridian cutting
// and circle clipping, the same comparison is used.
function compareIntersection(a, b) {
return ((a = a.x)[0] < 0 ? a[1] - halfPi$2 - epsilon$4 : halfPi$2 - a[1])
- ((b = b.x)[0] < 0 ? b[1] - halfPi$2 - epsilon$4 : halfPi$2 - b[1]);
}
var clipAntimeridian = clip(
function() { return true; },
clipAntimeridianLine,
clipAntimeridianInterpolate,
[-pi$3, -halfPi$2]
);
// Takes a line and cuts into visible segments. Return values: 0 - there were
// intersections or the line was empty; 1 - no intersections; 2 - there were
// intersections, and the first and last segments should be rejoined.
function clipAntimeridianLine(stream) {
var lambda0 = NaN,
phi0 = NaN,
sign0 = NaN,
clean; // no intersections
return {
lineStart: function() {
stream.lineStart();
clean = 1;
},
point: function(lambda1, phi1) {
var sign1 = lambda1 > 0 ? pi$3 : -pi$3,
delta = abs(lambda1 - lambda0);
if (abs(delta - pi$3) < epsilon$4) { // line crosses a pole
stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$2 : -halfPi$2);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
stream.point(lambda1, phi0);
clean = 0;
} else if (sign0 !== sign1 && delta >= pi$3) { // line crosses antimeridian
if (abs(lambda0 - sign0) < epsilon$4) lambda0 -= sign0 * epsilon$4; // handle degeneracies
if (abs(lambda1 - sign1) < epsilon$4) lambda1 -= sign1 * epsilon$4;
phi0 = clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
clean = 0;
}
stream.point(lambda0 = lambda1, phi0 = phi1);
sign0 = sign1;
},
lineEnd: function() {
stream.lineEnd();
lambda0 = phi0 = NaN;
},
clean: function() {
return 2 - clean; // if intersections, rejoin first and last segments
}
};
}
function clipAntimeridianIntersect(lambda0, phi0, lambda1, phi1) {
var cosPhi0,
cosPhi1,
sinLambda0Lambda1 = sin(lambda0 - lambda1);
return abs(sinLambda0Lambda1) > epsilon$4
? atan((sin(phi0) * (cosPhi1 = cos(phi1)) * sin(lambda1)
- sin(phi1) * (cosPhi0 = cos(phi0)) * sin(lambda0))
/ (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
: (phi0 + phi1) / 2;
}
function clipAntimeridianInterpolate(from, to, direction, stream) {
var phi;
if (from == null) {
phi = direction * halfPi$2;
stream.point(-pi$3, phi);
stream.point(0, phi);
stream.point(pi$3, phi);
stream.point(pi$3, 0);
stream.point(pi$3, -phi);
stream.point(0, -phi);
stream.point(-pi$3, -phi);
stream.point(-pi$3, 0);
stream.point(-pi$3, phi);
} else if (abs(from[0] - to[0]) > epsilon$4) {
var lambda = from[0] < to[0] ? pi$3 : -pi$3;
phi = direction * lambda / 2;
stream.point(-lambda, phi);
stream.point(0, phi);
stream.point(lambda, phi);
} else {
stream.point(to[0], to[1]);
}
}
function clipCircle(radius, delta) {
var cr = cos(radius),
smallRadius = cr > 0,
notHemisphere = abs(cr) > epsilon$4; // TODO optimise for this common case
function interpolate(from, to, direction, stream) {
circleStream(stream, radius, delta, direction, from, to);
}
function visible(lambda, phi) {
return cos(lambda) * cos(phi) > cr;
}
// Takes a line and cuts into visible segments. Return values used for polygon
// clipping: 0 - there were intersections or the line was empty; 1 - no
// intersections 2 - there were intersections, and the first and last segments
// should be rejoined.
function clipLine(stream) {
var point0, // previous point
c0, // code for previous point
v0, // visibility of previous point
v00, // visibility of first point
clean; // no intersections
return {
lineStart: function() {
v00 = v0 = false;
clean = 1;
},
point: function(lambda, phi) {
var point1 = [lambda, phi],
point2,
v = visible(lambda, phi),
c = smallRadius
? v ? 0 : code(lambda, phi)
: v ? code(lambda + (lambda < 0 ? pi$3 : -pi$3), phi) : 0;
if (!point0 && (v00 = v0 = v)) stream.lineStart();
// Handle degeneracies.
// TODO ignore if not clipping polygons.
if (v !== v0) {
point2 = intersect(point0, point1);
if (pointEqual(point0, point2) || pointEqual(point1, point2)) {
point1[0] += epsilon$4;
point1[1] += epsilon$4;
v = visible(point1[0], point1[1]);
}
}
if (v !== v0) {
clean = 0;
if (v) {
// outside going in
stream.lineStart();
point2 = intersect(point1, point0);
stream.point(point2[0], point2[1]);
} else {
// inside going out
point2 = intersect(point0, point1);
stream.point(point2[0], point2[1]);
stream.lineEnd();
}
point0 = point2;
} else if (notHemisphere && point0 && smallRadius ^ v) {
var t;
// If the codes for two points are different, or are both zero,
// and there this segment intersects with the small circle.
if (!(c & c0) && (t = intersect(point1, point0, true))) {
clean = 0;
if (smallRadius) {
stream.lineStart();
stream.point(t[0][0], t[0][1]);
stream.point(t[1][0], t[1][1]);
stream.lineEnd();
} else {
stream.point(t[1][0], t[1][1]);
stream.lineEnd();
stream.lineStart();
stream.point(t[0][0], t[0][1]);
}
}
}
if (v && (!point0 || !pointEqual(point0, point1))) {
stream.point(point1[0], point1[1]);
}
point0 = point1, v0 = v, c0 = c;
},
lineEnd: function() {
if (v0) stream.lineEnd();
point0 = null;
},
// Rejoin first and last segments if there were intersections and the first
// and last points were visible.
clean: function() {
return clean | ((v00 && v0) << 1);
}
};
}
// Intersects the great circle between a and b with the clip circle.
function intersect(a, b, two) {
var pa = cartesian(a),
pb = cartesian(b);
// We have two planes, n1.p = d1 and n2.p = d2.
// Find intersection line p(t) = c1 n1 + c2 n2 + t (n1 ⨯ n2).
var n1 = [1, 0, 0], // normal
n2 = cartesianCross(pa, pb),
n2n2 = cartesianDot(n2, n2),
n1n2 = n2[0], // cartesianDot(n1, n2),
determinant = n2n2 - n1n2 * n1n2;
// Two polar points.
if (!determinant) return !two && a;
var c1 = cr * n2n2 / determinant,
c2 = -cr * n1n2 / determinant,
n1xn2 = cartesianCross(n1, n2),
A = cartesianScale(n1, c1),
B = cartesianScale(n2, c2);
cartesianAddInPlace(A, B);
// Solve |p(t)|^2 = 1.
var u = n1xn2,
w = cartesianDot(A, u),
uu = cartesianDot(u, u),
t2 = w * w - uu * (cartesianDot(A, A) - 1);
if (t2 < 0) return;
var t = sqrt$1(t2),
q = cartesianScale(u, (-w - t) / uu);
cartesianAddInPlace(q, A);
q = spherical(q);
if (!two) return q;
// Two intersection points.
var lambda0 = a[0],
lambda1 = b[0],
phi0 = a[1],
phi1 = b[1],
z;
if (lambda1 < lambda0) z = lambda0, lambda0 = lambda1, lambda1 = z;
var delta = lambda1 - lambda0,
polar = abs(delta - pi$3) < epsilon$4,
meridian = polar || delta < epsilon$4;
if (!polar && phi1 < phi0) z = phi0, phi0 = phi1, phi1 = z;
// Check that the first point is between a and b.
if (meridian
? polar
? phi0 + phi1 > 0 ^ q[1] < (abs(q[0] - lambda0) < epsilon$4 ? phi0 : phi1)
: phi0 <= q[1] && q[1] <= phi1
: delta > pi$3 ^ (lambda0 <= q[0] && q[0] <= lambda1)) {
var q1 = cartesianScale(u, (-w + t) / uu);
cartesianAddInPlace(q1, A);
return [q, spherical(q1)];
}
}
// Generates a 4-bit vector representing the location of a point relative to
// the small circle's bounding box.
function code(lambda, phi) {
var r = smallRadius ? radius : pi$3 - radius,
code = 0;
if (lambda < -r) code |= 1; // left
else if (lambda > r) code |= 2; // right
if (phi < -r) code |= 4; // below
else if (phi > r) code |= 8; // above
return code;
}
return clip(visible, clipLine, interpolate, smallRadius ? [0, -radius] : [-pi$3, radius - pi$3]);
}
function transform$1(prototype) {
return {
stream: transform$2(prototype)
};
}
function transform$2(prototype) {
function T() {}
var p = T.prototype = Object.create(Transform$1.prototype);
for (var k in prototype) p[k] = prototype[k];
return function(stream) {
var t = new T;
t.stream = stream;
return t;
};
}
function Transform$1() {}
Transform$1.prototype = {
point: function(x, y) { this.stream.point(x, y); },
sphere: function() { this.stream.sphere(); },
lineStart: function() { this.stream.lineStart(); },
lineEnd: function() { this.stream.lineEnd(); },
polygonStart: function() { this.stream.polygonStart(); },
polygonEnd: function() { this.stream.polygonEnd(); }
};
function fit(project, extent, object) {
var w = extent[1][0] - extent[0][0],
h = extent[1][1] - extent[0][1],
clip = project.clipExtent && project.clipExtent();
project
.scale(150)
.translate([0, 0]);
if (clip != null) project.clipExtent(null);
geoStream(object, project.stream(boundsStream$1));
var b = boundsStream$1.result(),
k = Math.min(w / (b[1][0] - b[0][0]), h / (b[1][1] - b[0][1])),
x = +extent[0][0] + (w - k * (b[1][0] + b[0][0])) / 2,
y = +extent[0][1] + (h - k * (b[1][1] + b[0][1])) / 2;
if (clip != null) project.clipExtent(clip);
return project
.scale(k * 150)
.translate([x, y]);
}
function fitSize(project) {
return function(size, object) {
return fit(project, [[0, 0], size], object);
};
}
function fitExtent(project) {
return function(extent, object) {
return fit(project, extent, object);
};
}
var maxDepth = 16;
var cosMinDistance = cos(30 * radians);
// cos(minimum angular distance)
function resample(project, delta2) {
return +delta2 ? resample$1(project, delta2) : resampleNone(project);
}
function resampleNone(project) {
return transform$2({
point: function(x, y) {
x = project(x, y);
this.stream.point(x[0], x[1]);
}
});
}
function resample$1(project, delta2) {
function resampleLineTo(x0, y0, lambda0, a0, b0, c0, x1, y1, lambda1, a1, b1, c1, depth, stream) {
var dx = x1 - x0,
dy = y1 - y0,
d2 = dx * dx + dy * dy;
if (d2 > 4 * delta2 && depth--) {
var a = a0 + a1,
b = b0 + b1,
c = c0 + c1,
m = sqrt$1(a * a + b * b + c * c),
phi2 = asin$1(c /= m),
lambda2 = abs(abs(c) - 1) < epsilon$4 || abs(lambda0 - lambda1) < epsilon$4 ? (lambda0 + lambda1) / 2 : atan2(b, a),
p = project(lambda2, phi2),
x2 = p[0],
y2 = p[1],
dx2 = x2 - x0,
dy2 = y2 - y0,
dz = dy * dx2 - dx * dy2;
if (dz * dz / d2 > delta2 // perpendicular projected distance
|| abs((dx * dx2 + dy * dy2) / d2 - 0.5) > 0.3 // midpoint close to an end
|| a0 * a1 + b0 * b1 + c0 * c1 < cosMinDistance) { // angular distance
resampleLineTo(x0, y0, lambda0, a0, b0, c0, x2, y2, lambda2, a /= m, b /= m, c, depth, stream);
stream.point(x2, y2);
resampleLineTo(x2, y2, lambda2, a, b, c, x1, y1, lambda1, a1, b1, c1, depth, stream);
}
}
}
return function(stream) {
var lambda00, x00, y00, a00, b00, c00, // first point
lambda0, x0, y0, a0, b0, c0; // previous point
var resampleStream = {
point: point,
lineStart: lineStart,
lineEnd: lineEnd,
polygonStart: function() { stream.polygonStart(); resampleStream.lineStart = ringStart; },
polygonEnd: function() { stream.polygonEnd(); resampleStream.lineStart = lineStart; }
};
function point(x, y) {
x = project(x, y);
stream.point(x[0], x[1]);
}
function lineStart() {
x0 = NaN;
resampleStream.point = linePoint;
stream.lineStart();
}
function linePoint(lambda, phi) {
var c = cartesian([lambda, phi]), p = project(lambda, phi);
resampleLineTo(x0, y0, lambda0, a0, b0, c0, x0 = p[0], y0 = p[1], lambda0 = lambda, a0 = c[0], b0 = c[1], c0 = c[2], maxDepth, stream);
stream.point(x0, y0);
}
function lineEnd() {
resampleStream.point = point;
stream.lineEnd();
}
function ringStart() {
lineStart();
resampleStream.point = ringPoint;
resampleStream.lineEnd = ringEnd;
}
function ringPoint(lambda, phi) {
linePoint(lambda00 = lambda, phi), x00 = x0, y00 = y0, a00 = a0, b00 = b0, c00 = c0;
resampleStream.point = linePoint;
}
function ringEnd() {
resampleLineTo(x0, y0, lambda0, a0, b0, c0, x00, y00, lambda00, a00, b00, c00, maxDepth, stream);
resampleStream.lineEnd = lineEnd;
lineEnd();
}
return resampleStream;
};
}
var transformRadians = transform$2({
point: function(x, y) {
this.stream.point(x * radians, y * radians);
}
});
function projection(project) {
return projectionMutator(function() { return project; })();
}
function projectionMutator(projectAt) {
var project,
k = 150, // scale
x = 480, y = 250, // translate
dx, dy, lambda = 0, phi = 0, // center
deltaLambda = 0, deltaPhi = 0, deltaGamma = 0, rotate, projectRotate, // rotate
theta = null, preclip = clipAntimeridian, // clip angle
x0 = null, y0, x1, y1, postclip = identity$7, // clip extent
delta2 = 0.5, projectResample = resample(projectTransform, delta2), // precision
cache,
cacheStream;
function projection(point) {
point = projectRotate(point[0] * radians, point[1] * radians);
return [point[0] * k + dx, dy - point[1] * k];
}
function invert(point) {
point = projectRotate.invert((point[0] - dx) / k, (dy - point[1]) / k);
return point && [point[0] * degrees$1, point[1] * degrees$1];
}
function projectTransform(x, y) {
return x = project(x, y), [x[0] * k + dx, dy - x[1] * k];
}
projection.stream = function(stream) {
return cache && cacheStream === stream ? cache : cache = transformRadians(preclip(rotate, projectResample(postclip(cacheStream = stream))));
};
projection.clipAngle = function(_) {
return arguments.length ? (preclip = +_ ? clipCircle(theta = _ * radians, 6 * radians) : (theta = null, clipAntimeridian), reset()) : theta * degrees$1;
};
projection.clipExtent = function(_) {
return arguments.length ? (postclip = _ == null ? (x0 = y0 = x1 = y1 = null, identity$7) : clipExtent(x0 = +_[0][0], y0 = +_[0][1], x1 = +_[1][0], y1 = +_[1][1]), reset()) : x0 == null ? null : [[x0, y0], [x1, y1]];
};
projection.scale = function(_) {
return arguments.length ? (k = +_, recenter()) : k;
};
projection.translate = function(_) {
return arguments.length ? (x = +_[0], y = +_[1], recenter()) : [x, y];
};
projection.center = function(_) {
return arguments.length ? (lambda = _[0] % 360 * radians, phi = _[1] % 360 * radians, recenter()) : [lambda * degrees$1, phi * degrees$1];
};
projection.rotate = function(_) {
return arguments.length ? (deltaLambda = _[0] % 360 * radians, deltaPhi = _[1] % 360 * radians, deltaGamma = _.length > 2 ? _[2] % 360 * radians : 0, recenter()) : [deltaLambda * degrees$1, deltaPhi * degrees$1, deltaGamma * degrees$1];
};
projection.precision = function(_) {
return arguments.length ? (projectResample = resample(projectTransform, delta2 = _ * _), reset()) : sqrt$1(delta2);
};
projection.fitExtent = fitExtent(projection);
projection.fitSize = fitSize(projection);
function recenter() {
projectRotate = compose(rotate = rotateRadians(deltaLambda, deltaPhi, deltaGamma), project);
var center = project(lambda, phi);
dx = x - center[0] * k;
dy = y + center[1] * k;
return reset();
}
function reset() {
cache = cacheStream = null;
return projection;
}
return function() {
project = projectAt.apply(this, arguments);
projection.invert = project.invert && invert;
return recenter();
};
}
function conicProjection(projectAt) {
var phi0 = 0,
phi1 = pi$3 / 3,
m = projectionMutator(projectAt),
p = m(phi0, phi1);
p.parallels = function(_) {
return arguments.length ? m(phi0 = _[0] * radians, phi1 = _[1] * radians) : [phi0 * degrees$1, phi1 * degrees$1];
};
return p;
}
function conicEqualAreaRaw(y0, y1) {
var sy0 = sin(y0),
n = (sy0 + sin(y1)) / 2,
c = 1 + sy0 * (2 * n - sy0),
r0 = sqrt$1(c) / n;
function project(x, y) {
var r = sqrt$1(c - 2 * n * sin(y)) / n;
return [r * sin(x *= n), r0 - r * cos(x)];
}
project.invert = function(x, y) {
var r0y = r0 - y;
return [atan2(x, r0y) / n, asin$1((c - (x * x + r0y * r0y) * n * n) / (2 * n))];
};
return project;
}
function conicEqualArea() {
return conicProjection(conicEqualAreaRaw)
.scale(155.424)
.center([0, 33.6442]);
}
function albers() {
return conicEqualArea()
.parallels([29.5, 45.5])
.scale(1070)
.translate([480, 250])
.rotate([96, 0])
.center([-0.6, 38.7]);
}
// The projections must have mutually exclusive clip regions on the sphere,
// as this will avoid emitting interleaving lines and polygons.
function multiplex(streams) {
var n = streams.length;
return {
point: function(x, y) { var i = -1; while (++i < n) streams[i].point(x, y); },
sphere: function() { var i = -1; while (++i < n) streams[i].sphere(); },
lineStart: function() { var i = -1; while (++i < n) streams[i].lineStart(); },
lineEnd: function() { var i = -1; while (++i < n) streams[i].lineEnd(); },
polygonStart: function() { var i = -1; while (++i < n) streams[i].polygonStart(); },
polygonEnd: function() { var i = -1; while (++i < n) streams[i].polygonEnd(); }
};
}
// A composite projection for the United States, configured by default for
// 960×500. The projection also works quite well at 960×600 if you change the
// scale to 1285 and adjust the translate accordingly. The set of standard
// parallels for each region comes from USGS, which is published here:
// http://egsc.usgs.gov/isb/pubs/MapProjections/projections.html#albers
function albersUsa() {
var cache,
cacheStream,
lower48 = albers(), lower48Point,
alaska = conicEqualArea().rotate([154, 0]).center([-2, 58.5]).parallels([55, 65]), alaskaPoint, // EPSG:3338
hawaii = conicEqualArea().rotate([157, 0]).center([-3, 19.9]).parallels([8, 18]), hawaiiPoint, // ESRI:102007
point, pointStream = {point: function(x, y) { point = [x, y]; }};
function albersUsa(coordinates) {
var x = coordinates[0], y = coordinates[1];
return point = null,
(lower48Point.point(x, y), point)
|| (alaskaPoint.point(x, y), point)
|| (hawaiiPoint.point(x, y), point);
}
albersUsa.invert = function(coordinates) {
var k = lower48.scale(),
t = lower48.translate(),
x = (coordinates[0] - t[0]) / k,
y = (coordinates[1] - t[1]) / k;
return (y >= 0.120 && y < 0.234 && x >= -0.425 && x < -0.214 ? alaska
: y >= 0.166 && y < 0.234 && x >= -0.214 && x < -0.115 ? hawaii
: lower48).invert(coordinates);
};
albersUsa.stream = function(stream) {
return cache && cacheStream === stream ? cache : cache = multiplex([lower48.stream(cacheStream = stream), alaska.stream(stream), hawaii.stream(stream)]);
};
albersUsa.precision = function(_) {
if (!arguments.length) return lower48.precision();
lower48.precision(_), alaska.precision(_), hawaii.precision(_);
return albersUsa;
};
albersUsa.scale = function(_) {
if (!arguments.length) return lower48.scale();
lower48.scale(_), alaska.scale(_ * 0.35), hawaii.scale(_);
return albersUsa.translate(lower48.translate());
};
albersUsa.translate = function(_) {
if (!arguments.length) return lower48.translate();
var k = lower48.scale(), x = +_[0], y = +_[1];
lower48Point = lower48
.translate(_)
.clipExtent([[x - 0.455 * k, y - 0.238 * k], [x + 0.455 * k, y + 0.238 * k]])
.stream(pointStream);
alaskaPoint = alaska
.translate([x - 0.307 * k, y + 0.201 * k])
.clipExtent([[x - 0.425 * k + epsilon$4, y + 0.120 * k + epsilon$4], [x - 0.214 * k - epsilon$4, y + 0.234 * k - epsilon$4]])
.stream(pointStream);
hawaiiPoint = hawaii
.translate([x - 0.205 * k, y + 0.212 * k])
.clipExtent([[x - 0.214 * k + epsilon$4, y + 0.166 * k + epsilon$4], [x - 0.115 * k - epsilon$4, y + 0.234 * k - epsilon$4]])
.stream(pointStream);
return albersUsa;
};
albersUsa.fitExtent = fitExtent(albersUsa);
albersUsa.fitSize = fitSize(albersUsa);
return albersUsa.scale(1070);
}
function azimuthalRaw(scale) {
return function(x, y) {
var cx = cos(x),
cy = cos(y),
k = scale(cx * cy);
return [
k * cy * sin(x),
k * sin(y)
];
}
}
function azimuthalInvert(angle) {
return function(x, y) {
var z = sqrt$1(x * x + y * y),
c = angle(z),
sc = sin(c),
cc = cos(c);
return [
atan2(x * sc, z * cc),
asin$1(z && y * sc / z)
];
}
}
var azimuthalEqualAreaRaw = azimuthalRaw(function(cxcy) {
return sqrt$1(2 / (1 + cxcy));
});
azimuthalEqualAreaRaw.invert = azimuthalInvert(function(z) {
return 2 * asin$1(z / 2);
});
function azimuthalEqualArea() {
return projection(azimuthalEqualAreaRaw)
.scale(124.75)
.clipAngle(180 - 1e-3);
}
var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
return (c = acos(c)) && c / sin(c);
});
azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
return z;
});
function azimuthalEquidistant() {
return projection(azimuthalEquidistantRaw)
.scale(79.4188)
.clipAngle(180 - 1e-3);
}
function mercatorRaw(lambda, phi) {
return [lambda, log$1(tan((halfPi$2 + phi) / 2))];
}
mercatorRaw.invert = function(x, y) {
return [x, 2 * atan(exp(y)) - halfPi$2];
};
function mercator() {
return mercatorProjection(mercatorRaw)
.scale(961 / tau$3);
}
function mercatorProjection(project) {
var m = projection(project),
scale = m.scale,
translate = m.translate,
clipExtent = m.clipExtent,
clipAuto;
m.scale = function(_) {
return arguments.length ? (scale(_), clipAuto && m.clipExtent(null), m) : scale();
};
m.translate = function(_) {
return arguments.length ? (translate(_), clipAuto && m.clipExtent(null), m) : translate();
};
m.clipExtent = function(_) {
if (!arguments.length) return clipAuto ? null : clipExtent();
if (clipAuto = _ == null) {
var k = pi$3 * scale(),
t = translate();
_ = [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]];
}
clipExtent(_);
return m;
};
return m.clipExtent(null);
}
function tany(y) {
return tan((halfPi$2 + y) / 2);
}
function conicConformalRaw(y0, y1) {
var cy0 = cos(y0),
n = y0 === y1 ? sin(y0) : log$1(cy0 / cos(y1)) / log$1(tany(y1) / tany(y0)),
f = cy0 * pow$1(tany(y0), n) / n;
if (!n) return mercatorRaw;
function project(x, y) {
if (f > 0) { if (y < -halfPi$2 + epsilon$4) y = -halfPi$2 + epsilon$4; }
else { if (y > halfPi$2 - epsilon$4) y = halfPi$2 - epsilon$4; }
var r = f / pow$1(tany(y), n);
return [r * sin(n * x), f - r * cos(n * x)];
}
project.invert = function(x, y) {
var fy = f - y, r = sign$1(n) * sqrt$1(x * x + fy * fy);
return [atan2(x, fy) / n, 2 * atan(pow$1(f / r, 1 / n)) - halfPi$2];
};
return project;
}
function conicConformal() {
return conicProjection(conicConformalRaw)
.scale(109.5)
.parallels([30, 30]);
}
function equirectangularRaw(lambda, phi) {
return [lambda, phi];
}
equirectangularRaw.invert = equirectangularRaw;
function equirectangular() {
return projection(equirectangularRaw)
.scale(152.63);
}
function conicEquidistantRaw(y0, y1) {
var cy0 = cos(y0),
n = y0 === y1 ? sin(y0) : (cy0 - cos(y1)) / (y1 - y0),
g = cy0 / n + y0;
if (abs(n) < epsilon$4) return equirectangularRaw;
function project(x, y) {
var gy = g - y, nx = n * x;
return [gy * sin(nx), g - gy * cos(nx)];
}
project.invert = function(x, y) {
var gy = g - y;
return [atan2(x, gy) / n, g - sign$1(n) * sqrt$1(x * x + gy * gy)];
};
return project;
}
function conicEquidistant() {
return conicProjection(conicEquidistantRaw)
.scale(131.154)
.center([0, 13.9389]);
}
function gnomonicRaw(x, y) {
var cy = cos(y), k = cos(x) * cy;
return [cy * sin(x) / k, sin(y) / k];
}
gnomonicRaw.invert = azimuthalInvert(atan);
function gnomonic() {
return projection(gnomonicRaw)
.scale(144.049)
.clipAngle(60);
}
function orthographicRaw(x, y) {
return [cos(y) * sin(x), sin(y)];
}
orthographicRaw.invert = azimuthalInvert(asin$1);
function orthographic() {
return projection(orthographicRaw)
.scale(249.5)
.clipAngle(90 + epsilon$4);
}
function stereographicRaw(x, y) {
var cy = cos(y), k = 1 + cos(x) * cy;
return [cy * sin(x) / k, sin(y) / k];
}
stereographicRaw.invert = azimuthalInvert(function(z) {
return 2 * atan(z);
});
function stereographic() {
return projection(stereographicRaw)
.scale(250)
.clipAngle(142);
}
function transverseMercatorRaw(lambda, phi) {
return [log$1(tan((halfPi$2 + phi) / 2)), -lambda];
}
transverseMercatorRaw.invert = function(x, y) {
return [-y, 2 * atan(exp(x)) - halfPi$2];
};
function transverseMercator() {
var m = mercatorProjection(transverseMercatorRaw),
center = m.center,
rotate = m.rotate;
m.center = function(_) {
return arguments.length ? center([-_[1], _[0]]) : (_ = center(), [_[1], -_[0]]);
};
m.rotate = function(_) {
return arguments.length ? rotate([_[0], _[1], _.length > 2 ? _[2] + 90 : 90]) : (_ = rotate(), [_[0], _[1], _[2] - 90]);
};
return rotate([0, 0, 90])
.scale(159.155);
}
function attrsFunction(selection, map) {
return selection.each(function() {
var x = map.apply(this, arguments), s = select(this);
for (var name in x) s.attr(name, x[name]);
});
}
function attrsObject(selection, map) {
for (var name in map) selection.attr(name, map[name]);
return selection;
}
function selection_attrs(map) {
return (typeof map === "function" ? attrsFunction : attrsObject)(this, map);
}
function stylesFunction(selection, map, priority) {
return selection.each(function() {
var x = map.apply(this, arguments), s = select(this);
for (var name in x) s.style(name, x[name], priority);
});
}
function stylesObject(selection, map, priority) {
for (var name in map) selection.style(name, map[name], priority);
return selection;
}
function selection_styles(map, priority) {
return (typeof map === "function" ? stylesFunction : stylesObject)(this, map, priority == null ? "" : priority);
}
function propertiesFunction(selection, map) {
return selection.each(function() {
var x = map.apply(this, arguments), s = select(this);
for (var name in x) s.property(name, x[name]);
});
}
function propertiesObject(selection, map) {
for (var name in map) selection.property(name, map[name]);
return selection;
}
function selection_properties(map) {
return (typeof map === "function" ? propertiesFunction : propertiesObject)(this, map);
}
function attrsFunction$1(transition, map) {
return transition.each(function() {
var x = map.apply(this, arguments), t = select(this).transition(transition);
for (var name in x) t.attr(name, x[name]);
});
}
function attrsObject$1(transition, map) {
for (var name in map) transition.attr(name, map[name]);
return transition;
}
function transition_attrs(map) {
return (typeof map === "function" ? attrsFunction$1 : attrsObject$1)(this, map);
}
function stylesFunction$1(transition, map, priority) {
return transition.each(function() {
var x = map.apply(this, arguments), t = select(this).transition(transition);
for (var name in x) t.style(name, x[name], priority);
});
}
function stylesObject$1(transition, map, priority) {
for (var name in map) transition.style(name, map[name], priority);
return transition;
}
function transition_styles(map, priority) {
return (typeof map === "function" ? stylesFunction$1 : stylesObject$1)(this, map, priority == null ? "" : priority);
}
selection.prototype.attrs = selection_attrs;
selection.prototype.styles = selection_styles;
selection.prototype.properties = selection_properties;
transition.prototype.attrs = transition_attrs;
transition.prototype.styles = transition_styles;
function translateSelection(xy) {
return this.attr('transform', function(d,i) {
return 'translate('+[typeof xy == 'function' ? xy.call(this, d,i) : xy]+')';
});
};
function parseAttributes(name) {
if (typeof name === "string") {
var attr = {},
parts = name.split(/([\.#])/g), p;
name = parts.shift();
while ((p = parts.shift())) {
if (p == '.') attr['class'] = attr['class'] ? attr['class'] + ' ' + parts.shift() : parts.shift();
else if (p == '#') attr.id = parts.shift();
}
return {tag: name, attr: attr};
}
return name;
}
function append(name) {
var n = parseAttributes(name), s;
name = creator(n.tag);
s = this.select(function() {
return this.appendChild(name.apply(this, arguments));
});
//attrs not provided by default in v4
for (var key in n.attr) { s.attr(key, n.attr[key]) }
return s;
};
function selectAppend(name) {
var select = selector(name),
n = parseAttributes(name), s;
name = creator(n.tag);
s = this.select(function() {
return select.apply(this, arguments)
|| this.appendChild(name.apply(this, arguments));
});
//attrs not provided by default in v4
for (var key in n.attr) { s.attr(key, n.attr[key]) }
return s;
};
function tspans(lines, lh) {
return this.selectAll('tspan')
.data(lines).enter()
.append('tspan')
.text(function(d) { return d; })
.attr('x', 0)
.attr('dy', function(d, i) { return i ? lh || 15 : 0; });
};
function appendMany(data, name){
return this.selectAll(null).data(data).enter().append(name);
};
function at(name, value) {
if (typeof(name) == 'object'){
for (var key in name){
this.attr(key.replace(/([a-z\d])([A-Z])/g, '$1-$2').toLowerCase(), name[key])
}
return this
} else{
return arguments.length == 1 ? this.attr(name) : this.attr(name, value)
}
};
function f(){
var functions = arguments
//convert all string arguments into field accessors
var i = 0, l = functions.length
while (i < l) {
if (typeof(functions[i]) === 'string' || typeof(functions[i]) === 'number'){
functions[i] = (function(str){ return function(d){ return d[str] } })(functions[i])
}
i++
}
//return composition of functions
return function(d) {
var i=0, l = functions.length
while (i++ < l) d = functions[i-1].call(this, d)
return d
}
}
f.not = function(d){ return !d }
f.run = function(d){ return d() }
f.objToFn = function(obj, defaultVal){
if (arguments.length == 1) defaultVal = undefined
return function(str){
return typeof(obj[str]) !== undefined ? obj[str] : defaultVal }
}
function st(name, value) {
if (typeof(name) == 'object'){
for (var key in name){
addStyle(this, key, name[key])
}
return this
} else{
return arguments.length == 1 ? this.style(name) : addStyle(this, name, value)
}
function addStyle(sel, style, value){
var style = style.replace(/([a-z\d])([A-Z])/g, '$1-$2').toLowerCase()
var pxStyles = 'top left bottom right padding-top padding-left padding-bottom padding-right border-top b-width border-left-width border-botto-width m border-right-width margin-top margin-left margin-bottom margin-right font-size width height stroke-width line-height margin padding border max-width min-width'
if (~pxStyles.indexOf(style) ){
sel.style(style, typeof value == 'function' ? f(value, addPx) : addPx(value))
} else{
sel.style(style, value)
}
return sel
}
function addPx(d){ return d.match ? d : d + 'px' }
};
function wordwrap(line, maxCharactersPerLine) {
var w = line.split(' '),
lines = [],
words = [],
maxChars = maxCharactersPerLine || 40,
l = 0;
w.forEach(function(d) {
if (l+d.length > maxChars) {
lines.push(words.join(' '));
words.length = 0;
l = 0;
}
l += d.length;
words.push(d);
});
if (words.length) {
lines.push(words.join(' '));
}
return lines.filter(function(d){ return d != '' });
};
function ascendingKey(key) {
return typeof key == 'function' ? function (a, b) {
return key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : key(a) >= key(b) ? 0 : NaN;
} : function (a, b) {
return a[key] < b[key] ? -1 : a[key] > b[key] ? 1 : a[key] >= b[key] ? 0 : NaN;
};
};
function descendingKey(key) {
return typeof key == 'function' ? function (a, b) {
return key(b) < key(a) ? -1 : key(b) > key(a) ? 1 : key(b) >= key(a) ? 0 : NaN;
} : function (a, b) {
return b[key] < a[key] ? -1 : b[key] > a[key] ? 1 : b[key] >= a[key] ? 0 : NaN;
};
};
function conventions(c){
c = c || {}
c.margin = c.margin || {top: 20, right: 20, bottom: 20, left: 20}
;['top', 'right', 'bottom', 'left'].forEach(function(d){
if (!c.margin[d] && c.margin[d] != 0) c.margin[d] = 20
})
c.width = c.width || c.totalWidth - c.margin.left - c.margin.right || 900
c.height = c.height || c.totalHeight - c.margin.top - c.margin.bottom || 460
c.totalWidth = c.width + c.margin.left + c.margin.right
c.totalHeight = c.height + c.margin.top + c.margin.bottom
c.parentSel = c.parentSel || select('body')
c.rootsvg = c.parentSel.append('svg')
c.svg = c.rootsvg
.attr('width', c.totalWidth)
.attr('height', c.totalHeight)
.append('g')
.attr('transform', 'translate(' + c.margin.left + ',' + c.margin.top + ')')
c.x = c.x || linear$2().range([0, c.width])
c.y = c.y || linear$2().range([c.height, 0])
c.xAxis = c.xAxis || axisBottom().scale(c.x)
c.yAxis = c.yAxis || axisLeft().scale(c.y)
c.drawAxis = function(){
c.svg.append('g')
.attr('class', 'x axis')
.attr('transform', 'translate(0,' + c.height + ')')
.call(c.xAxis);
c.svg.append('g')
.attr('class', 'y axis')
.call(c.yAxis);
}
return c
}
function attachTooltip(sel, tooltipSel, fieldFns){
if (!sel.size()) return
tooltipSel = tooltipSel || select('.tooltip')
sel
.on('mouseover.attachTooltip', ttDisplay)
.on('mousemove.attachTooltip', ttMove)
.on('mouseout.attachTooltip', ttHide)
.on('click.attachTooltip', function(d){ console.log(d) })
var d = sel.datum()
fieldFns = fieldFns || d3keys(d)
.filter(function(str){
return (typeof d[str] != 'object') && (d[str] != 'array')
})
.map(function(str){
return function(d){ return str + ': <b>' + d[str] + '</b>'} })
function ttDisplay(d){
tooltipSel
.classed('tooltip-hidden', false)
.html('')
.appendMany(fieldFns, 'div')
.html(function(fn){ return fn(d) })
select(this).classed('tooltipped', true)
}
function ttMove(d){
var tt = tooltipSel
if (!tt.size()) return
var e = exports.event,
x = e.clientX,
y = e.clientY,
n = tt.node(),
nBB = n.getBoundingClientRect(),
doctop = (window.scrollY)? window.scrollY : (document.documentElement && document.documentElement.scrollTop)? document.documentElement.scrollTop : document.body.scrollTop,
topPos = y+doctop-nBB.height-18;
tt.style('top', (topPos < 0 ? 18 + y : topPos)+'px');
tt.style('left', Math.min(Math.max(20, (x-nBB.width/2)), window.innerWidth - nBB.width - 20)+'px');
}
function ttHide(d){
tooltipSel.classed('tooltip-hidden', true);
selectAll('.tooltipped').classed('tooltipped', false)
}
}
function loadData(files, cb){
var q = queue()
files.forEach(function(d){
var type = d.split('.').reverse()[0]
var loadFn = {csv: csv$1, tsv: tsv$1, json: json}[type]
if (!loadFn) return cb(new Error('Invalid type', d))
q.defer(loadFn, d)
})
q.awaitAll(cb)
}
function nestBy(array, key){
return nest().key(key).entries(array).map(function(d){
d.values.key = d.key
return d.values
})
}
function round(n, p) {
return p ? Math.round(n * (p = Math.pow(10, p))) / p : Math.round(n);
};
selection.prototype.translate = translateSelection
selection.prototype.append = append
selection.prototype.selectAppend = selectAppend
selection.prototype.tspans = tspans
selection.prototype.appendMany = appendMany
selection.prototype.at = at
selection.prototype.st = st
selection.prototype.prop = selection.prototype.property
exports.bisect = bisectRight;
exports.bisectRight = bisectRight;
exports.bisectLeft = bisectLeft;
exports.ascending = ascending;
exports.bisector = bisector;
exports.descending = descending;
exports.deviation = deviation;
exports.extent = extent;
exports.histogram = histogram;
exports.thresholdFreedmanDiaconis = freedmanDiaconis;
exports.thresholdScott = scott;
exports.thresholdSturges = sturges;
exports.max = max;
exports.mean = mean;
exports.median = median;
exports.merge = merge;
exports.min = min;
exports.pairs = pairs;
exports.permute = permute;
exports.quantile = threshold;
exports.range = range;
exports.scan = scan;
exports.shuffle = shuffle;
exports.sum = sum;
exports.ticks = ticks;
exports.tickStep = tickStep;
exports.transpose = transpose;
exports.variance = variance;
exports.zip = zip;
exports.entries = entries;
exports.keys = d3keys;
exports.values = values;
exports.map = map$1;
exports.set = set;
exports.nest = nest;
exports.randomUniform = uniform;
exports.randomNormal = normal;
exports.randomLogNormal = logNormal;
exports.randomBates = bates;
exports.randomIrwinHall = irwinHall;
exports.randomExponential = exponential;
exports.easeLinear = linear;
exports.easeQuad = quadInOut;
exports.easeQuadIn = quadIn;
exports.easeQuadOut = quadOut;
exports.easeQuadInOut = quadInOut;
exports.easeCubic = easeCubicInOut;
exports.easeCubicIn = cubicIn;
exports.easeCubicOut = cubicOut;
exports.easeCubicInOut = easeCubicInOut;
exports.easePoly = polyInOut;
exports.easePolyIn = polyIn;
exports.easePolyOut = polyOut;
exports.easePolyInOut = polyInOut;
exports.easeSin = sinInOut;
exports.easeSinIn = sinIn;
exports.easeSinOut = sinOut;
exports.easeSinInOut = sinInOut;
exports.easeExp = expInOut;
exports.easeExpIn = expIn;
exports.easeExpOut = expOut;
exports.easeExpInOut = expInOut;
exports.easeCircle = circleInOut;
exports.easeCircleIn = circleIn;
exports.easeCircleOut = circleOut;
exports.easeCircleInOut = circleInOut;
exports.easeBounce = bounceOut;
exports.easeBounceIn = bounceIn;
exports.easeBounceOut = bounceOut;
exports.easeBounceInOut = bounceInOut;
exports.easeBack = backInOut;
exports.easeBackIn = backIn;
exports.easeBackOut = backOut;
exports.easeBackInOut = backInOut;
exports.easeElastic = elasticOut;
exports.easeElasticIn = elasticIn;
exports.easeElasticOut = elasticOut;
exports.easeElasticInOut = elasticInOut;
exports.polygonArea = area;
exports.polygonCentroid = centroid;
exports.polygonHull = hull;
exports.polygonContains = contains;
exports.polygonLength = length$1;
exports.path = path;
exports.quadtree = quadtree;
exports.queue = queue;
exports.arc = arc;
exports.area = area$1;
exports.line = line;
exports.pie = pie;
exports.radialArea = radialArea;
exports.radialLine = radialLine$1;
exports.symbol = symbol;
exports.symbols = symbols;
exports.symbolCircle = circle;
exports.symbolCross = cross$1;
exports.symbolDiamond = diamond;
exports.symbolSquare = square;
exports.symbolStar = star;
exports.symbolTriangle = triangle;
exports.symbolWye = wye;
exports.curveBasisClosed = basisClosed;
exports.curveBasisOpen = basisOpen;
exports.curveBasis = basis;
exports.curveBundle = bundle;
exports.curveCardinalClosed = cardinalClosed;
exports.curveCardinalOpen = cardinalOpen;
exports.curveCardinal = cardinal;
exports.curveCatmullRomClosed = catmullRomClosed;
exports.curveCatmullRomOpen = catmullRomOpen;
exports.curveCatmullRom = catmullRom;
exports.curveLinearClosed = linearClosed;
exports.curveLinear = curveLinear;
exports.curveMonotoneX = monotoneX;
exports.curveMonotoneY = monotoneY;
exports.curveNatural = natural;
exports.curveStep = step;
exports.curveStepAfter = stepAfter;
exports.curveStepBefore = stepBefore;
exports.stack = stack;
exports.stackOffsetExpand = expand;
exports.stackOffsetNone = none;
exports.stackOffsetSilhouette = silhouette;
exports.stackOffsetWiggle = wiggle;
exports.stackOrderAscending = ascending$1;
exports.stackOrderDescending = descending$2;
exports.stackOrderInsideOut = insideOut;
exports.stackOrderNone = none$1;
exports.stackOrderReverse = reverse;
exports.color = color;
exports.rgb = colorRgb;
exports.hsl = colorHsl;
exports.lab = lab;
exports.hcl = colorHcl;
exports.cubehelix = cubehelix;
exports.interpolate = interpolate;
exports.interpolateArray = array$1;
exports.interpolateNumber = interpolateNumber;
exports.interpolateObject = object;
exports.interpolateRound = interpolateRound;
exports.interpolateString = interpolateString;
exports.interpolateTransformCss = interpolateTransform$1;
exports.interpolateTransformSvg = interpolateTransform$2;
exports.interpolateZoom = interpolateZoom;
exports.interpolateRgb = interpolateRgb;
exports.interpolateRgbBasis = rgbBasis;
exports.interpolateRgbBasisClosed = rgbBasisClosed;
exports.interpolateHsl = hsl$1;
exports.interpolateHslLong = hslLong;
exports.interpolateLab = lab$1;
exports.interpolateHcl = hcl$1;
exports.interpolateHclLong = hclLong;
exports.interpolateCubehelix = cubehelix$2;
exports.interpolateCubehelixLong = interpolateCubehelixLong;
exports.interpolateBasis = basis$2;
exports.interpolateBasisClosed = basisClosed$1;
exports.quantize = quantize;
exports.dispatch = dispatch;
exports.dsvFormat = dsv;
exports.csvParse = csvParse;
exports.csvParseRows = csvParseRows;
exports.csvFormat = csvFormat;
exports.csvFormatRows = csvFormatRows;
exports.tsvParse = tsvParse;
exports.tsvParseRows = tsvParseRows;
exports.tsvFormat = tsvFormat;
exports.tsvFormatRows = tsvFormatRows;
exports.request = request;
exports.html = html;
exports.json = json;
exports.text = text;
exports.xml = xml;
exports.csv = csv$1;
exports.tsv = tsv$1;
exports.now = now;
exports.timer = timer;
exports.timerFlush = timerFlush;
exports.timeout = timeout$1;
exports.interval = interval$1;
exports.timeInterval = newInterval;
exports.timeMillisecond = millisecond;
exports.timeMilliseconds = milliseconds;
exports.timeSecond = second;
exports.timeSeconds = seconds;
exports.timeMinute = minute;
exports.timeMinutes = minutes;
exports.timeHour = hour;
exports.timeHours = hours;
exports.timeDay = day;
exports.timeDays = days;
exports.timeWeek = timeWeek;
exports.timeWeeks = sundays;
exports.timeSunday = timeWeek;
exports.timeSundays = sundays;
exports.timeMonday = timeMonday;
exports.timeMondays = mondays;
exports.timeTuesday = tuesday;
exports.timeTuesdays = tuesdays;
exports.timeWednesday = wednesday;
exports.timeWednesdays = wednesdays;
exports.timeThursday = thursday;
exports.timeThursdays = thursdays;
exports.timeFriday = friday;
exports.timeFridays = fridays;
exports.timeSaturday = saturday;
exports.timeSaturdays = saturdays;
exports.timeMonth = month;
exports.timeMonths = months;
exports.timeYear = year;
exports.timeYears = years;
exports.utcMillisecond = millisecond;
exports.utcMilliseconds = milliseconds;
exports.utcSecond = second;
exports.utcSeconds = seconds;
exports.utcMinute = utcMinute;
exports.utcMinutes = utcMinutes;
exports.utcHour = utcHour;
exports.utcHours = utcHours;
exports.utcDay = utcDay;
exports.utcDays = utcDays;
exports.utcWeek = utcWeek;
exports.utcWeeks = utcSundays;
exports.utcSunday = utcWeek;
exports.utcSundays = utcSundays;
exports.utcMonday = utcMonday;
exports.utcMondays = utcMondays;
exports.utcTuesday = utcTuesday;
exports.utcTuesdays = utcTuesdays;
exports.utcWednesday = utcWednesday;
exports.utcWednesdays = utcWednesdays;
exports.utcThursday = utcThursday;
exports.utcThursdays = utcThursdays;
exports.utcFriday = utcFriday;
exports.utcFridays = utcFridays;
exports.utcSaturday = utcSaturday;
exports.utcSaturdays = utcSaturdays;
exports.utcMonth = utcMonth;
exports.utcMonths = utcMonths;
exports.utcYear = utcYear;
exports.utcYears = utcYears;
exports.formatLocale = formatLocale;
exports.formatDefaultLocale = defaultLocale;
exports.formatSpecifier = formatSpecifier;
exports.precisionFixed = precisionFixed;
exports.precisionPrefix = precisionPrefix;
exports.precisionRound = precisionRound;
exports.isoFormat = formatIso;
exports.isoParse = parseIso;
exports.timeFormatLocale = formatLocale$1;
exports.timeFormatDefaultLocale = defaultLocale$1;
exports.scaleBand = band;
exports.scalePoint = point$4;
exports.scaleIdentity = identity$4;
exports.scaleLinear = linear$2;
exports.scaleLog = log;
exports.scaleOrdinal = ordinal;
exports.scaleImplicit = implicit;
exports.scalePow = pow;
exports.scaleSqrt = sqrt;
exports.scaleQuantile = quantile;
exports.scaleQuantize = quantize$1;
exports.scaleThreshold = threshold$1;
exports.scaleTime = time;
exports.scaleUtc = utcTime;
exports.schemeCategory10 = category10;
exports.schemeCategory20b = category20b;
exports.schemeCategory20c = category20c;
exports.schemeCategory20 = category20;
exports.scaleSequential = sequential;
exports.interpolateCubehelixDefault = cubehelix$3;
exports.interpolateRainbow = rainbow$1;
exports.interpolateWarm = warm;
exports.interpolateCool = cool;
exports.interpolateViridis = viridis;
exports.interpolateMagma = magma;
exports.interpolateInferno = inferno;
exports.interpolatePlasma = plasma;
exports.creator = creator;
exports.customEvent = customEvent;
exports.local = local;
exports.matcher = matcher$1;
exports.mouse = mouse;
exports.namespace = namespace;
exports.namespaces = namespaces;
exports.select = select;
exports.selectAll = selectAll;
exports.selection = selection;
exports.selector = selector;
exports.selectorAll = selectorAll;
exports.touch = touch;
exports.touches = touches;
exports.window = window$1;
exports.active = active;
exports.interrupt = interrupt;
exports.transition = transition;
exports.axisTop = axisTop;
exports.axisRight = axisRight;
exports.axisBottom = axisBottom;
exports.axisLeft = axisLeft;
exports.cluster = cluster;
exports.hierarchy = hierarchy;
exports.pack = index;
exports.packSiblings = siblings;
exports.packEnclose = enclose;
exports.partition = partition;
exports.stratify = stratify;
exports.tree = tree;
exports.treemap = index$1;
exports.treemapBinary = binary;
exports.treemapDice = treemapDice;
exports.treemapSlice = treemapSlice;
exports.treemapSliceDice = sliceDice;
exports.treemapSquarify = squarify;
exports.treemapResquarify = resquarify;
exports.forceCenter = center$1;
exports.forceCollide = collide;
exports.forceLink = link;
exports.forceManyBody = manyBody;
exports.forceSimulation = simulation;
exports.forceX = x$3;
exports.forceY = y$3;
exports.drag = drag;
exports.dragDisable = dragDisable;
exports.dragEnable = dragEnable;
exports.voronoi = voronoi;
exports.zoom = zoom;
exports.zoomIdentity = identity$6;
exports.zoomTransform = transform;
exports.brush = brush;
exports.brushX = brushX;
exports.brushY = brushY;
exports.brushSelection = brushSelection;
exports.geoArea = area$2;
exports.geoBounds = bounds;
exports.geoCentroid = centroid$1;
exports.geoCircle = circle$1;
exports.geoClipExtent = extent$1;
exports.geoDistance = distance;
exports.geoGraticule = graticule;
exports.geoInterpolate = interpolate$2;
exports.geoLength = length$2;
exports.geoPath = index$3;
exports.geoAlbers = albers;
exports.geoAlbersUsa = albersUsa;
exports.geoAzimuthalEqualArea = azimuthalEqualArea;
exports.geoAzimuthalEquidistant = azimuthalEquidistant;
exports.geoConicConformal = conicConformal;
exports.geoConicEqualArea = conicEqualArea;
exports.geoConicEquidistant = conicEquidistant;
exports.geoEquirectangular = equirectangular;
exports.geoGnomonic = gnomonic;
exports.geoProjection = projection;
exports.geoProjectionMutator = projectionMutator;
exports.geoMercator = mercator;
exports.geoOrthographic = orthographic;
exports.geoStereographic = stereographic;
exports.geoTransverseMercator = transverseMercator;
exports.geoRotation = rotation;
exports.geoStream = geoStream;
exports.geoTransform = transform$1;
exports.wordwrap = wordwrap;
exports.parseAttributes = parseAttributes;
exports.f = f;
exports.ascendingKey = ascendingKey;
exports.descendingKey = descendingKey;
exports.conventions = conventions;
exports.attachTooltip = attachTooltip;
exports.loadData = loadData;
exports.nestBy = nestBy;
exports.round = round;
Object.defineProperty(exports, '__esModule', { value: true });
}));
[{"author":"Mike Bostock","name":"d3-scale","description":"Encodings that map abstract data to visual representation.","githubStars":716,"githubIssues":81,"githubContributers":11,"downloads":76767,"dependentsCount":88,"npmStars":5,"repoSize":311483,"link":"https://github.com/d3/d3-scale"},{"author":"Mike Bostock","name":"d3-queue","description":"Evaluate asynchronous tasks with configurable concurrency.","githubStars":1245,"githubIssues":62,"githubContributers":5,"downloads":123103,"dependentsCount":33,"npmStars":2,"repoSize":36121,"link":"https://github.com/d3/d3-queue"},{"author":"Mike Bostock","name":"d3-shape","description":"Graphical primitives for visualization, such as lines and areas.","githubStars":1277,"githubIssues":81,"githubContributers":5,"downloads":72605,"dependentsCount":48,"npmStars":1,"repoSize":961309,"link":"https://github.com/d3/d3-shape"},{"author":"Mike Bostock","name":"d3-selection","description":"Data-driven DOM manipulation: select elements and join them to data.","githubStars":115,"githubIssues":103,"githubContributers":7,"downloads":51812,"dependentsCount":79,"npmStars":2,"repoSize":200786,"link":"https://github.com/d3/d3-selection"},{"author":"Mike Bostock","name":"d3-format","description":"Format numbers for human consumption.","githubStars":128,"githubIssues":31,"githubContributers":6,"downloads":77191,"dependentsCount":24,"npmStars":2,"repoSize":73878,"link":"https://github.com/d3/d3-format"},{"author":"Mike Bostock","name":"d3-interpolate","description":"Interpolate numbers, colors, strings, arrays, objects, whatever!","githubStars":60,"githubIssues":30,"githubContributers":4,"downloads":84492,"dependentsCount":31,"npmStars":0,"repoSize":140178,"link":"https://github.com/d3/d3-interpolate"},{"author":"Mike Bostock","name":"d3-array","description":"Array manipulation, ordering, searching, summarizing, etc.","githubStars":55,"githubIssues":44,"githubContributers":4,"downloads":71890,"dependentsCount":81,"npmStars":1,"repoSize":140097,"link":"https://github.com/d3/d3-array"},{"author":"Mike Bostock","name":"d3-time","description":"A calculator for humanity’s peculiar conventions of time.","githubStars":90,"githubIssues":15,"githubContributers":3,"downloads":82499,"dependentsCount":15,"npmStars":1,"repoSize":215467,"link":"https://github.com/d3/d3-time"},{"author":"Mike Bostock","name":"d3-dsv","description":"A parser and formatter for delimiter-separated values, such as CSV and TSV","githubStars":92,"githubIssues":20,"githubContributers":4,"downloads":49519,"dependentsCount":27,"npmStars":1,"repoSize":59218,"link":"https://github.com/d3/d3-dsv"},{"author":"Mike Bostock","name":"d3-color","description":"Color spaces! RGB, HSL, Cubehelix, Lab and HCL (Lch).","githubStars":104,"githubIssues":30,"githubContributers":7,"downloads":80612,"dependentsCount":31,"npmStars":2,"repoSize":77995,"link":"https://github.com/d3/d3-color"},{"author":"Mike Bostock","name":"d3-geo-projection","description":"Extended geographic projections for d3-geo.","githubStars":387,"githubIssues":71,"githubContributers":6,"downloads":27403,"dependentsCount":9,"npmStars":0,"repoSize":7788548,"link":"https://github.com/d3/d3-geo-projection"},{"author":"Mike Bostock","name":"d3-transition","description":"Animated transitions for D3 selections.","githubStars":44,"githubIssues":59,"githubContributers":2,"downloads":48290,"dependentsCount":33,"npmStars":0,"repoSize":158685,"link":"https://github.com/d3/d3-transition"},{"author":"Mike Bostock","name":"d3-ease","description":"Easing functions for smooth animation.","githubStars":196,"githubIssues":15,"githubContributers":2,"downloads":53668,"dependentsCount":15,"npmStars":0,"repoSize":513985,"link":"https://github.com/d3/d3-ease"},{"author":"Mike Bostock","name":"d3-geo","description":"Shapes and calculators for spherical coordinates.","githubStars":90,"githubIssues":65,"githubContributers":9,"downloads":48862,"dependentsCount":12,"npmStars":0,"repoSize":3170224,"link":"https://github.com/d3/d3-geo"},{"author":"Mike Bostock","name":"d3-time-format","description":"A JavaScript time formatter and parser inspired by strftime and strptime.","githubStars":60,"githubIssues":25,"githubContributers":4,"downloads":72404,"dependentsCount":18,"npmStars":1,"repoSize":84491,"link":"https://github.com/d3/d3-time-format"},{"author":"Mike Bostock","name":"d3-voronoi","description":"Compute the Voronoi diagram of a set of two-dimensional points.","githubStars":57,"githubIssues":19,"githubContributers":4,"downloads":46083,"dependentsCount":11,"npmStars":0,"repoSize":52644,"link":"https://github.com/d3/d3-voronoi"},{"author":"Mike Bostock","name":"d3-axis","description":"Displays automatic reference lines for scales.","githubStars":22,"githubIssues":18,"githubContributers":2,"downloads":45370,"dependentsCount":23,"npmStars":0,"repoSize":24127,"link":"https://github.com/d3/d3-axis"},{"author":"Mike Bostock","name":"d3-dispatch","description":"Register named callbacks and call them with arguments.","githubStars":21,"githubIssues":13,"githubContributers":2,"downloads":56509,"dependentsCount":22,"npmStars":1,"repoSize":25212,"link":"https://github.com/d3/d3-dispatch"},{"author":"Mike Bostock","name":"d3-collection","description":"Handy data structures for elements keyed by string.","githubStars":28,"githubIssues":9,"githubContributers":2,"downloads":75052,"dependentsCount":24,"npmStars":1,"repoSize":56078,"link":"https://github.com/d3/d3-collection"},{"author":"Mike Bostock","name":"d3-hierarchy","description":"Layout algorithms for visualizing hierarchical data.","githubStars":79,"githubIssues":59,"githubContributers":4,"downloads":40149,"dependentsCount":12,"npmStars":0,"repoSize":555434,"link":"https://github.com/d3/d3-hierarchy"},{"author":"Mike Bostock","name":"d3-path","description":"Serialize Canvas path commands to SVG.","githubStars":57,"githubIssues":8,"githubContributers":2,"downloads":71142,"dependentsCount":12,"npmStars":1,"repoSize":25154,"link":"https://github.com/d3/d3-path"},{"author":"Mike Bostock","name":"d3-quadtree","description":"Two-dimensional recursive spatial subdivision.","githubStars":34,"githubIssues":17,"githubContributers":2,"downloads":39684,"dependentsCount":6,"npmStars":0,"repoSize":53639,"link":"https://github.com/d3/d3-quadtree"},{"author":"Mike Bostock","name":"d3-zoom","description":"Pan and zoom SVG, HTML or Canvas using mouse or touch input.","githubStars":31,"githubIssues":65,"githubContributers":4,"downloads":38805,"dependentsCount":9,"npmStars":0,"repoSize":235253,"link":"https://github.com/d3/d3-zoom"},{"author":"Mike Bostock","name":"d3-request","description":"A convenient alternative to XMLHttpRequest.","githubStars":42,"githubIssues":17,"githubContributers":2,"downloads":40410,"dependentsCount":6,"npmStars":1,"repoSize":38625,"link":"https://github.com/d3/d3-request"},{"author":"Mike Bostock","name":"d3-random","description":"Generate random numbers from various distributions.","githubStars":17,"githubIssues":16,"githubContributers":3,"downloads":38658,"dependentsCount":6,"npmStars":0,"repoSize":20782,"link":"https://github.com/d3/d3-random"},{"author":"Mike Bostock","name":"d3-timer","description":"An efficient queue capable of managing thousands of concurrent animations.","githubStars":35,"githubIssues":16,"githubContributers":2,"downloads":55870,"dependentsCount":14,"npmStars":0,"repoSize":33319,"link":"https://github.com/d3/d3-timer"},{"author":"Mike Bostock","name":"d3-chord","description":"Visualize relationships or network flow with an aesthetically-pleasing circular layout.","githubStars":14,"githubIssues":6,"githubContributers":2,"downloads":37964,"dependentsCount":4,"npmStars":0,"repoSize":149324,"link":"https://github.com/d3/d3-chord"},{"author":"Mike Bostock","name":"d3-polygon","description":"Operations for two-dimensional polygons.","githubStars":15,"githubIssues":8,"githubContributers":2,"downloads":38467,"dependentsCount":3,"npmStars":0,"repoSize":29875,"link":"https://github.com/d3/d3-polygon"},{"author":"Susie Lu","name":"d3-svg-legend","description":"A legend component for d3. Given a d3.scale it can create either a color legend, size legend, or symbol legend.","githubStars":431,"githubIssues":46,"githubContributers":12,"downloads":1597,"dependentsCount":1,"npmStars":2,"repoSize":1044789,"link":"https://github.com/susielu/d3-legend"},{"author":"Mike Bostock","name":"d3-selection-multi","description":"Multi-value map syntax for D3 selections.","githubStars":18,"githubIssues":8,"githubContributers":1,"downloads":994,"dependentsCount":8,"npmStars":0,"repoSize":17431,"link":"https://github.com/d3/d3-selection-multi"},{"author":"Mike Bostock","name":"d3-drag","description":"Drag and drop SVG, HTML or Canvas using mouse or touch input.","githubStars":37,"githubIssues":29,"githubContributers":3,"downloads":39592,"dependentsCount":12,"npmStars":0,"repoSize":201232,"link":"https://github.com/d3/d3-drag"},{"author":"Mike Bostock","name":"d3-brush","description":"Select a one- or two-dimensional region using the mouse or touch.","githubStars":18,"githubIssues":21,"githubContributers":2,"downloads":40566,"dependentsCount":7,"npmStars":0,"repoSize":159598,"link":"https://github.com/d3/d3-brush"},{"author":"Mike Bostock","name":"d3-force","description":"Force-directed graph layout using velocity Verlet integration.","githubStars":100,"githubIssues":67,"githubContributers":5,"downloads":43136,"dependentsCount":7,"npmStars":0,"repoSize":374267,"link":"https://github.com/d3/d3-force"},{"author":"Peter Beshai","name":"d3-interpolate-path","description":"Interpolates path `d` attribute smoothly when A and B have different number of points.","githubStars":39,"githubIssues":5,"githubContributers":1,"downloads":163,"dependentsCount":2,"npmStars":0,"repoSize":32006,"link":"https://github.com/pbeshai/d3-interpolate-path"},{"author":"John Walley","name":"d3-bumps-chart","description":"Draw bumps charts.","githubStars":1,"githubIssues":1,"githubContributers":1,"downloads":227,"dependentsCount":1,"npmStars":0,"repoSize":373015,"link":"https://github.com/johnwalley/d3-bumps-chart"},{"author":"Mike Bostock","name":"d3-tile","description":"Compute the quadtree tiles to display in a rectangular viewport.","githubStars":20,"githubIssues":23,"githubContributers":2,"downloads":69,"dependentsCount":0,"npmStars":0,"repoSize":10171,"link":"https://github.com/d3/d3-tile"},{"author":"none","name":"d3-textwrap","description":"wrap long lines of text using foreignObject tags or tspans as appropriate, depending on browser support","githubStars":49,"githubIssues":13,"githubContributers":1,"downloads":26,"dependentsCount":0,"npmStars":0,"repoSize":15060,"link":"https://github.com/vijithassar/d3-textwrap"},{"author":"Peter Beshai","name":"d3-line-chunked","description":"A d3 plugin that renders a line with potential gaps in the data by styling the gaps differently from the defined areas. Single points are rendered as circles. Transitions are supported.","githubStars":57,"githubIssues":14,"githubContributers":1,"downloads":184,"dependentsCount":0,"npmStars":0,"repoSize":87369,"link":"https://github.com/pbeshai/d3-line-chunked"},{"author":"none","name":"d3-rect","description":"draw rectangles with paths","githubStars":1,"githubIssues":0,"githubContributers":1,"downloads":18,"dependentsCount":0,"npmStars":0,"repoSize":8731,"link":"https://github.com/vijithassar/d3-rect"},{"author":"John Walley","name":"d3-tube-map","description":"Draw tube map.","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":58,"dependentsCount":0,"npmStars":0,"repoSize":72051,"link":"https://github.com/johnwalley/d3-tube-map"},{"author":"none","name":"d3-history","description":"control the HTML5 History API using JavaScript events and d3-dispatch","githubStars":34,"githubIssues":1,"githubContributers":1,"downloads":17,"dependentsCount":0,"npmStars":0,"repoSize":15869,"link":"https://github.com/vijithassar/d3-history"},{"author":"Adam Pearce","name":"d3-jetpack-module","description":"handy shortcuts for d3","githubStars":10,"githubIssues":15,"githubContributers":3,"downloads":266,"dependentsCount":0,"npmStars":0,"repoSize":520078,"link":"https://github.com/1wheel/d3-jetpack-module"},{"author":"Mike Bostock","name":"d3-scale-chromatic","description":"Sequential, diverging and categorical color schemes from ColorBrewer.","githubStars":77,"githubIssues":3,"githubContributers":1,"downloads":732,"dependentsCount":5,"npmStars":0,"repoSize":38524,"link":"https://github.com/d3/d3-scale-chromatic"},{"author":"none","name":"d3-gridding","description":"grid partitions and overlays for d3 charts","githubStars":12,"githubIssues":0,"githubContributers":1,"downloads":82,"dependentsCount":0,"npmStars":0,"repoSize":16352,"link":"https://github.com/romsson/d3-gridding"},{"author":"Alexey S","name":"d3-hcg","description":"The HCG (Hue, Chroma, Grayness) color space.","githubStars":7,"githubIssues":0,"githubContributers":2,"downloads":57,"dependentsCount":0,"npmStars":0,"repoSize":17813,"link":"https://github.com/d3/d3-hcg"},{"author":"none","name":"d3-x3dom-shape","description":"Graphical primitives for x3dom based visualization, such as lines and surfaces.","githubStars":4,"githubIssues":0,"githubContributers":1,"downloads":14,"dependentsCount":0,"npmStars":0,"repoSize":21062,"link":"https://github.com/fabid/d3-x3dom-shape"},{"author":"Peter Beshai","name":"d3-scale-interactive","description":"An interactive UI for editing d3 v4 scales in your browser","githubStars":20,"githubIssues":35,"githubContributers":2,"downloads":177,"dependentsCount":0,"npmStars":0,"repoSize":90022,"link":"https://github.com/pbeshai/d3-scale-interactive"},{"author":"Eric Socolofsky","name":"d3-force-cluster","description":"Clustering force for d3.forceSimulation.","githubStars":1,"githubIssues":0,"githubContributers":1,"downloads":5,"dependentsCount":0,"npmStars":0,"repoSize":11294,"link":"https://github.com/ericsoco/d3-force-cluster"},{"author":"Charles Hornbaker","name":"d3-multichord","description":"Circular layout for visualizing relationships or network flows. Modification of d3-chord to enable display of multiple categories of chords in the same chart.","githubStars":1,"githubIssues":0,"githubContributers":1,"downloads":22,"dependentsCount":0,"npmStars":0,"repoSize":26836,"link":"https://github.com/chornbaker/d3-multichord"},{"author":"Sylvain","name":"d3-beeswarm","description":"D3 plugin which computes a 'beeswarm' arrangement","githubStars":4,"githubIssues":13,"githubContributers":2,"downloads":12,"dependentsCount":0,"npmStars":0,"repoSize":49138,"link":"https://github.com/Kcnarf/d3-beeswarm"},{"author":"Elijah Meeks","name":"d3-bboxCollide","description":"A bounding box collision detection constraint for d3 forceSimulation.","githubStars":27,"githubIssues":1,"githubContributers":2,"downloads":0,"dependentsCount":0,"npmStars":0,"repoSize":79575,"link":"https://github.com/emeeks/d3-bboxCollide"},{"author":"none","name":"d3-icon","description":"offering common icons","githubStars":2,"githubIssues":0,"githubContributers":1,"downloads":13,"dependentsCount":0,"npmStars":0,"repoSize":6265,"link":"https://github.com/comsysto/d3-icon"},{"author":"Eric Socolofsky","name":"d3-force-attract","description":"Attraction force for d3.forceSimulation.","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":4,"dependentsCount":0,"npmStars":0,"repoSize":6895,"link":"https://github.com/ericsoco/d3-force-attract"},{"author":"none","name":"d3-symbol-extra","description":"Additional D3 symbol types.","githubStars":2,"githubIssues":1,"githubContributers":1,"downloads":33,"dependentsCount":0,"npmStars":0,"repoSize":35350,"link":"https://github.com/YellowTugboat/d3-symbol-extra"},{"author":"Kiril Mandov","name":"d3-horizon-chart","description":"D3 Plugin that draws horizon charts using canvas.","githubStars":2,"githubIssues":3,"githubContributers":1,"downloads":131,"dependentsCount":0,"npmStars":0,"repoSize":14064,"link":"https://github.com/kmandov/d3-horizon-chart"},{"author":"none","name":"d3-geo-warp","description":"Raster reprojection for d3","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":20,"dependentsCount":0,"npmStars":0,"repoSize":365725,"link":"https://github.com/rasmuse/d3-geo-warp"},{"author":"Andrew Walter","name":"d3-table","description":"A simple d3 plugin for creating HTML tables.","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":21,"dependentsCount":0,"npmStars":0,"repoSize":18840,"link":"https://github.com/mister-walter/d3-table"},{"author":"Chris Polis","name":"d3-annotate","description":"Interactively and programmatically add, edit, move and save SVG chart annotations","githubStars":5,"githubIssues":7,"githubContributers":1,"downloads":43,"dependentsCount":0,"npmStars":0,"repoSize":17692,"link":"https://github.com/cmpolis/d3-annotate"},{"author":"Mike Bostock","name":"d3-fetch","description":"Convenient parsing for Fetch.","githubStars":21,"githubIssues":0,"githubContributers":1,"downloads":7,"dependentsCount":0,"npmStars":0,"repoSize":8550,"link":"https://github.com/d3/d3-fetch"},{"author":"Philippe Riviere","name":"d3-geo-voronoi","description":"Spherical Voronoi Diagram and Delaunay Triangulation","githubStars":25,"githubIssues":1,"githubContributers":1,"downloads":20,"dependentsCount":0,"npmStars":0,"repoSize":606630,"link":"https://github.com/Fil/d3-geo-voronoi"},{"author":"Corin Lawson","name":"d3-compose","description":"Utility function that supports composition for `d3.call`s.","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":27,"dependentsCount":0,"npmStars":0,"repoSize":4713,"link":"https://github.com/au-phiware/d3-compose"},{"author":"Adam Pearce","name":"d3-swoopy-drag","description":"Artisanal label placement for d3 graphics.","githubStars":83,"githubIssues":11,"githubContributers":1,"downloads":0,"dependentsCount":0,"npmStars":0,"repoSize":501794,"link":"https://github.com/1wheel/swoopy-drag"},{"author":"Corin Lawson","name":"d3-wrap","description":"A small utility function that supports wrapping a function to d3.call.","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":11,"dependentsCount":0,"npmStars":0,"repoSize":5123,"link":"https://github.com/au-phiware/d3-wrap"},{"author":"Adam Pearce","name":"graph-scroll","description":"experiments using scrolling instead of steppers","githubStars":315,"githubIssues":13,"githubContributers":1,"downloads":15,"dependentsCount":0,"npmStars":0,"repoSize":492317,"link":"https://github.com/1wheel/graph-scroll"},{"author":"Adam Pearce","name":"d3-force-container","description":"constrain particles to an area for forceSimulation in d3v4.","githubStars":0,"githubIssues":0,"githubContributers":1,"downloads":0,"dependentsCount":0,"npmStars":0,"repoSize":6362,"link":"https://github.com/1wheel/d3-force-container"}]
var request = require('sync-request');
var fs = require('fs');
var res = request('GET', 'https://api.npms.io/v2/search?from=0&q=keywords%3Ad3-module&size=100');
var modules = JSON.parse(res.getBody().toString('utf-8')).results
modules.forEach(function(d, i){
console.log(i, d.package.name)
var res = request('GET', 'https://api.npms.io/v2/package/' + d.package.name)
d.metadata = JSON.parse(res.getBody().toString('utf-8'))
})
fs.writeFileSync('modules.json', JSON.stringify(modules))
var modules = JSON.parse(fs.readFileSync('modules.json'))
var denseModules = modules
.filter(d => d.metadata.collected.github)
.map(function(d){
var rv = {}
rv.author = d.package.author ? d.package.author.name : 'none'
rv.name = d.package.name
rv.description = d.metadata.collected.metadata.description
rv.githubStars = d.metadata.collected.github.starsCount
rv.githubIssues = d.metadata.collected.github.issues.count
rv.githubContributers = d.metadata.collected.github.contributors ? d.metadata.collected.github.contributors.length : 1
rv.downloads = Math.ceil(d.metadata.evaluation.popularity.downloadsCount)
rv.dependentsCount = d.metadata.collected.npm.dependentsCount
rv.npmStars = d.metadata.collected.npm.starsCount
rv.repoSize = d.metadata.collected.source.repositorySize
rv.link = d.package.links.repository
return rv
})
fs.writeFileSync('dense-modules.json', JSON.stringify(denseModules))
<!DOCTYPE html>
<meta charset='utf-8'>
<link rel="stylesheet" type="text/css" href="style.css">
<body></body>
<script src='d3v4.js'></script>
<script src='chernoff.js'></script>
<script src='container-force.js'></script>
<script src='swoopy-drag.js'></script>
<script src='_script.js'></script>
This file has been truncated, but you can view the full file.
[{"package":{"name":"d3-scale","version":"1.0.3","description":"Encodings that map abstract data to visual representation.","keywords":["d3","d3-module","scale","visualization"],"date":"2016-08-02T21:32:35.747Z","links":{"npm":"https://www.npmjs.com/package/d3-scale","homepage":"https://d3js.org/d3-scale/","repository":"https://github.com/d3/d3-scale","bugs":"https://github.com/d3/d3-scale/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.765036327244286,"detail":{"quality":0.9260256430415238,"popularity":0.3921859360603343,"maintenance":0.9998958763163199}},"searchScore":0.022868121,"metadata":{"analyzedAt":"2016-10-19T00:43:15.835Z","collected":{"metadata":{"name":"d3-scale","version":"1.0.3","description":"Encodings that map abstract data to visual representation.","keywords":["d3","d3-module","scale","visualization"],"date":"2016-08-02T21:32:35.747Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-scale.git"},"links":{"npm":"https://www.npmjs.com/package/d3-scale","homepage":"https://d3js.org/d3-scale/","repository":"https://github.com/d3/d3-scale","bugs":"https://github.com/d3/d3-scale/issues"},"license":"BSD-3-Clause","dependencies":{"d3-array":"1","d3-collection":"1","d3-color":"1","d3-format":"1","d3-interpolate":"1","d3-time":"1","d3-time-format":"2"},"devDependencies":{"eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":3},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":13},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":30},{"from":"2014-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":34}],"hasTestScript":true,"readme":"# d3-scale\n\nScales are a convenient abstraction for a fundamental task in visualization: mapping a dimension of abstract data to a visual representation. Although most often used for position-encoding quantitative data, such as mapping a measurement in meters to a position in pixels for dots in a scatterplot, scales can represent virtually any visual encoding, such as diverging colors, stroke widths, or symbol size. Scales can also be used with virtually any type of data, such as named categorical data or discrete data that requires sensible breaks.\n\nFor [continuous](#continuous-scales) quantitative data, you typically want a [linear scale](#linear-scales). (For time series data, a [time scale](#time-scales).) If the distribution calls for it, consider transforming data using a [power](#power-scales) or [log](#log-scales) scale. A [quantize scale](#quantize-scales) may aid differentiation by rounding continuous data to a fixed set of discrete values; similarly, a [quantile scale](#quantile-scales) computes quantiles from a sample population, and a [threshold scale](#threshold-scales) allows you to specify arbitrary breaks in continuous data. Several built-in [sequential color schemes](#sequential-scales) are also provided; see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for more.\n\nFor discrete ordinal (ordered) or categorical (unordered) data, an [ordinal scale](#ordinal-scales) specifies an explicit mapping from a set of data values to a corresponding set of visual attributes (such as colors). The related [band](#band-scales) and [point](#point-scales) scales are useful for position-encoding ordinal data, such as bars in a bar chart or dots in an categorical scatterplot. Several built-in [categorical color scales](#category-scales) are also provided.\n\nScales have no intrinsic visual representation. However, most scales can [generate](#continuous_ticks) and [format](#continuous_tickFormat) ticks for reference marks to aid in the construction of axes.\n\nFor a longer introduction, see these recommended tutorials:\n\n* [Introducing d3-scale](https://medium.com/@mbostock/introducing-d3-scale-61980c51545f) by Mike Bostock\n\n* [Chapter 7. Scales](http://chimera.labs.oreilly.com/books/1230000000345/ch07.html) of *Interactive Data Visualization for the Web* by Scott Murray\n\n* [d3: scales, and color.](http://www.jeromecukier.net/blog/2011/08/11/d3-scales-and-color/) by Jérôme Cukier\n\n## Installing\n\nIf you use NPM, `npm install d3-scale`. Otherwise, download the [latest release](https://github.com/d3/d3-scale/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-scale.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-array.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-collection.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-color.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-format.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-interpolate.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-time.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-time-format.v2.min.js\"></script>\n<script src=\"https://d3js.org/d3-scale.v1.min.js\"></script>\n<script>\n\nvar x = d3.scaleLinear();\n\n</script>\n```\n\n(You can omit d3-time and d3-time-format if you’re not use [d3.scaleTime](#scaleTime) or [d3.scaleUtc](#scaleUtc).)\n\n[Try d3-scale in your browser.](https://tonicdev.com/npm/d3-scale)\n\n## API Reference\n\n* [Continuous](#continuous-scales) ([Linear](#linear-scales), [Power](#power-scales), [Log](#log-scales), [Identity](#identity-scales), [Time](#time-scales))\n* [Sequential](#sequential-scales)\n* [Quantize](#quantize-scales)\n* [Quantile](#quantile-scales)\n* [Threshold](#threshold-scales)\n* [Ordinal](#ordinal-scales) ([Band](#band-scales), [Point](#point-scales), [Category](#category-scales))\n\n### Continuous Scales\n\nContinuous scales map a continuous, quantitative input [domain](#continuous_domain) to a continuous output [range](#continuous_range). If the range is also numeric, the mapping may be [inverted](#continuous_invert). A continuous scale is not constructed directly; instead, try a [linear](#linear-scales), [power](#power-scales), [log](#log-scales), [identity](#identity-scales), [time](#time-scales) or [sequential color](#sequential-scales) scale.\n\n<a name=\"_continuous\" href=\"#_continuous\">#</a> <i>continuous</i>(<i>value</i>)\n\nGiven a *value* from the [domain](#continuous_domain), returns the corresponding value from the [range](#continuous_range). If the given *value* is outside the domain, and [clamping](#continuous_clamp) is not enabled, the mapping may be extrapolated such that the returned value is outside the range. For example, to apply a position encoding:\n\n```js\nvar x = d3.scaleLinear()\n .domain([10, 130])\n .range([0, 960]);\n\nx(20); // 80\nx(50); // 320\n```\n\nOr to apply a color encoding:\n\n```js\nvar color = d3.scaleLinear()\n .domain([10, 100])\n .range([\"brown\", \"steelblue\"]);\n\ncolor(20); // \"#9a3439\"\ncolor(50); // \"#7b5167\"\n```\n\n<a name=\"continuous_invert\" href=\"#continuous_invert\">#</a> <i>continuous</i>.<b>invert</b>(<i>value</i>)\n\nGiven a *value* from the [range](#continuous_range), returns the corresponding value from the [domain](#continuous_domain). Inversion is useful for interaction, say to determine the data value corresponding to the position of the mouse. For example, to invert a position encoding:\n\n```js\nvar x = d3.scaleLinear()\n .domain([10, 130])\n .range([0, 960]);\n\nx.invert(80); // 20\nx.invert(320); // 50\n```\n\nIf the given *value* is outside the range, and [clamping](#continuous_clamp) is not enabled, the mapping may be extrapolated such that the returned value is outside the domain. This method is only supported if the range is numeric. If the range is not numeric, returns NaN.\n\nFor a valid value *y* in the range, <i>continuous</i>(<i>continuous</i>.invert(<i>y</i>)) approximately equals *y*; similarly, for a valid value *x* in the domain, <i>continuous</i>.invert(<i>continuous</i>(<i>x</i>)) approximately equals *x*. The scale and its inverse may not be exact due to the limitations of floating point precision.\n\n<a name=\"continuous_domain\" href=\"#continuous_domain\">#</a> <i>continuous</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the scale’s domain to the specified array of numbers. The array must contain two or more elements. If the elements in the given array are not numbers, they will be coerced to numbers. If *domain* is not specified, returns a copy of the scale’s current domain.\n\nAlthough continuous scales typically have two values each in their domain and range, specifying more than two values produces a piecewise scale. For example, to create a diverging color scale that interpolates between white and red for negative values, and white and green for positive values, say:\n\n```js\nvar color = d3.scaleLinear()\n .domain([-1, 0, 1])\n .range([\"red\", \"white\", \"green\"]);\n\ncolor(-0.5); // \"rgb(255, 128, 128)\"\ncolor(+0.5); // \"rgb(128, 192, 128)\"\n```\n\nInternally, a piecewise scale performs a [binary search](https://github.com/d3/d3-array#bisect) for the range interpolator corresponding to the given domain value. Thus, the domain must be in ascending or descending order. If the domain and range have different lengths *N* and *M*, only the first *min(N,M)* elements in each are observed.\n\n<a name=\"continuous_range\" href=\"#continuous_range\">#</a> <i>continuous</i>.<b>range</b>([<i>range</i>])\n\nIf *range* is specified, sets the scale’s range to the specified array of values. The array must contain two or more elements. Unlike the [domain](#continuous_domain), elements in the given array need not be numbers; any value that is supported by the underlying [interpolator](#continuous_interpolate) will work, though note that numeric ranges are required for [invert](#continuous_invert). If *range* is not specified, returns a copy of the scale’s current range. See [*continuous*.interpolate](#continuous_interpolate) for more examples.\n\n<a name=\"continuous_rangeRound\" href=\"#continuous_rangeRound\">#</a> <i>continuous</i>.<b>rangeRound</b>([<i>range</i>])\n\nSets the scale’s [*range*](#continuous_range) to the specified array of values while also setting the scale’s [interpolator](#continuous_interpolate) to [interpolateRound](https://github.com/d3/d3-interpolate#interpolateRound). This is a convenience method equivalent to:\n\n```js\ncontinuous\n .range(range)\n .interpolate(d3.interpolateRound);\n```\n\nThe rounding interpolator is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles. Note that this interpolator can only be used with numeric ranges.\n\n<a name=\"continuous_clamp\" href=\"#continuous_clamp\">#</a> <i>continuous</i>.<b>clamp</b>(<i>clamp</i>)\n\nIf *clamp* is specified, enables or disables clamping accordingly. If clamping is disabled and the scale is passed a value outside the [domain](#continuous_domain), the scale may return a value outside the [range](#continuous_range) through extrapolation. If clamping is enabled, the return value of the scale is always within the scale’s range. Clamping similarly applies to [*continuous*.invert](#continuous_invert). For example:\n\n```js\nvar x = d3.scaleLinear()\n .domain([10, 130])\n .range([0, 960]);\n\nx(-10); // -160, outside range\nx.invert(-160); // -10, outside domain\n\nx.clamp(true);\nx(-10); // 0, clamped to range\nx.invert(-160); // 10, clamped to domain\n```\n\nIf *clamp* is not specified, returns whether or not the scale currently clamps values to within the range.\n\n<a name=\"continuous_interpolate\" href=\"#continuous_interpolate\">#</a> <i>continuous</i>.<b>interpolate</b>(<i>interpolate</i>)\n\nIf *interpolate* is specified, sets the scale’s [range](#continuous_range) interpolator factory. This interpolator factory is used to create interpolators for each adjacent pair of values from the range; these interpolators then map a normalized domain parameter *t* in [0, 1] to the corresponding value in the range. If *factory* is not specified, returns the scale’s current interpolator factory, which defaults to [interpolate](https://github.com/d3/d3-interpolate#interpolate). See [d3-interpolate](https://github.com/d3/d3-interpolate) for more interpolators.\n\nFor example, consider a diverging color scale with three colors in the range:\n\n```js\nvar color = d3.scaleLinear()\n .domain([-100, 0, +100])\n .range([\"red\", \"white\", \"green\"]);\n```\n\nTwo interpolators are created internally by the scale, equivalent to:\n\n```js\nvar i0 = d3.interpolate(\"red\", \"white\"),\n i1 = d3.interpolate(\"white\", \"green\");\n```\n\nA common reason to specify a custom interpolator is to change the color space of interpolation. For example, to use [HCL](https://github.com/d3/d3-interpolate#interpolateHcl):\n\n```js\nvar color = d3.scaleLinear()\n .domain([10, 100])\n .range([\"brown\", \"steelblue\"])\n .interpolate(d3.interpolateHcl);\n```\n\nOr for [Cubehelix](https://github.com/d3/d3-interpolate#interpolateCubehelix) with a custom gamma:\n\n```js\nvar color = d3.scaleLinear()\n .domain([10, 100])\n .range([\"brown\", \"steelblue\"])\n .interpolate(d3.interpolateCubehelix.gamma(3));\n```\n\nNote: the [default interpolator](https://github.com/d3/d3-interpolate#interpolate) **may reuse return values**. For example, if the range values are objects, then the value interpolator always returns the same object, modifying it in-place. If the scale is used to set an attribute or style, this is typically acceptable (and desirable for performance); however, if you need to store the scale’s return value, you must specify your own interpolator or make a copy as appropriate.\n\n<a name=\"continuous_ticks\" href=\"#continuous_ticks\">#</a> <i>continuous</i>.<b>ticks</b>([<i>count</i>])\n\nReturns approximately *count* representative values from the scale’s [domain](#continuous_domain). If *count* is not specified, it defaults to 10. The returned tick values are uniformly spaced, have human-readable values (such as multiples of powers of 10), and are guaranteed to be within the extent of the domain. Ticks are often used to display reference lines, or tick marks, in conjunction with the visualized data. The specified *count* is only a hint; the scale may return more or fewer values depending on the domain. See also d3-array’s [ticks](https://github.com/d3/d3-array#ticks).\n\n<a name=\"continuous_tickFormat\" href=\"#continuous_tickFormat\">#</a> <i>continuous</i>.<b>tickFormat</b>([<i>count</i>[, <i>specifier</i>]])\n\nReturns a [number format](https://github.com/d3/d3-format) function suitable for displaying a tick value, automatically computing the appropriate precision based on the fixed interval between tick values. The specified *count* should have the same value as the count that is used to generate the [tick values](#continuous_ticks).\n\nAn optional *specifier* allows a [custom format](https://github.com/d3/d3-format#locale_format) where the precision of the format is automatically set by the scale as appropriate for the tick interval. For example, to format percentage change, you might say:\n\n```js\nvar x = d3.scaleLinear()\n .domain([-1, 1])\n .range([0, 960]);\n\nvar ticks = x.ticks(5),\n tickFormat = x.tickFormat(5, \"+%\");\n\nticks.map(tickFormat); // [\"-100%\", \"-50%\", \"+0%\", \"+50%\", \"+100%\"]\n```\n\nIf *specifier* uses the format type `s`, the scale will return a [SI-prefix format](https://github.com/d3/d3-format#locale_formatPrefix) based on the largest value in the domain. If the *specifier* already specifies a precision, this method is equivalent to [*locale*.format](https://github.com/d3/d3-format#locale_format).\n\n<a name=\"continuous_nice\" href=\"#continuous_nice\">#</a> <i>continuous</i>.<b>nice</b>([<i>count</i>])\n\nExtends the [domain](#continuous_domain) so that it starts and ends on nice round values. This method typically modifies the scale’s domain, and may only extend the bounds to the nearest round value. An optional tick *count* argument allows greater control over the step size used to extend the bounds, guaranteeing that the returned [ticks](#continuous_ticks) will exactly cover the domain. Nicing is useful if the domain is computed from data, say using [extent](https://github.com/d3/d3-array#extent), and may be irregular. For example, for a domain of [0.201479…, 0.996679…], a nice domain might be [0.2, 1.0]. If the domain has more than two values, nicing the domain only affects the first and last value. See also d3-array’s [tickStep](https://github.com/d3/d3-array#tickStep).\n\n<a name=\"continuous_copy\" href=\"#continuous_copy\">#</a> <i>continuous</i>.<b>copy</b>()\n\nReturns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n#### Linear Scales\n\n<a name=\"scaleLinear\" href=\"#scaleLinear\">#</a> d3.<b>scaleLinear</b>()\n\nConstructs a new [continuous scale](#continuous-scales) with the unit [domain](#continuous_domain) [0, 1], the unit [range](#continuous_range) [0, 1], the [default](https://github.com/d3/d3-interpolate#interpolate) [interpolator](#continuous_interpolate) and [clamping](#continuous_clamp) disabled. Linear scales are a good default choice for continuous quantitative data because they preserve proportional differences. Each range value *y* can be expressed as a function of the domain value *x*: *y* = *mx* + *b*.\n\n#### Power Scales\n\nPower scales are similar to [linear scales](#linear-scales), except an exponential transform is applied to the input domain value before the output range value is computed. Each range value *y* can be expressed as a function of the domain value *x*: *y* = *mx^k* + *b*, where *k* is the [exponent](#pow_exponent) value. Power scales also support negative domain values, in which case the input value and the resulting output value are multiplied by -1.\n\n<a name=\"scalePow\" href=\"#scalePow\">#</a> d3.<b>scalePow</b>()\n\nConstructs a new [continuous scale](#continuous-scales) with the unit [domain](#continuous_domain) [0, 1], the unit [range](#continuous_range) [0, 1], the [exponent](#pow_exponent) 1, the [default](https://github.com/d3/d3-interpolate#interpolate) [interpolator](#continuous_interpolate) and [clamping](#continuous_clamp) disabled. (Note that this is effectively a [linear](#linear-scales) scale until you set a different exponent.)\n\n<a name=\"pow\" href=\"#_pow\">#</a> <i>pow</i>(<i>value</i>)\n\nSee [*continuous*](#_continuous).\n\n<a name=\"pow_invert\" href=\"#pow_invert\">#</a> <i>pow</i>.<b>invert</b>(<i>value</i>)\n\nSee [*continuous*.invert](#continuous_invert).\n\n<a name=\"pow_exponent\" href=\"#pow_exponent\">#</a> <i>pow</i>.<b>exponent</b>([<i>exponent</i>])\n\nIf *exponent* is specified, sets the current exponent to the given numeric value. If *exponent* is not specified, returns the current exponent, which defaults to 1. (Note that this is effectively a [linear](#linear-scales) scale until you set a different exponent.)\n\n<a name=\"pow_domain\" href=\"#pow_domain\">#</a> <i>pow</i>.<b>domain</b>([<i>domain</i>])\n\nSee [*continuous*.domain](#continuous_domain).\n\n<a name=\"pow_range\" href=\"#pow_range\">#</a> <i>pow</i>.<b>range</b>([<i>range</i>])\n\nSee [*continuous*.range](#continuous_range).\n\n<a name=\"pow_rangeRound\" href=\"#pow_rangeRound\">#</a> <i>pow</i>.<b>rangeRound</b>([<i>range</i>])\n\nSee [*continuous*.rangeRound](#continuous_rangeRound).\n\n<a name=\"pow_clamp\" href=\"#pow_clamp\">#</a> <i>pow</i>.<b>clamp</b>(<i>clamp</i>)\n\nSee [*continuous*.clamp](#continuous_clamp).\n\n<a name=\"pow_interpolate\" href=\"#pow_interpolate\">#</a> <i>pow</i>.<b>interpolate</b>(<i>interpolate</i>)\n\nSee [*continuous*.interpolate](#continuous_interpolate).\n\n<a name=\"pow_ticks\" href=\"#pow_ticks\">#</a> <i>pow</i>.<b>ticks</b>([<i>count</i>])\n\nSee [*continuous*.ticks](#continuous_ticks).\n\n<a name=\"pow_tickFormat\" href=\"#pow_tickFormat\">#</a> <i>pow</i>.<b>tickFormat</b>([<i>count</i>[, <i>specifier</i>]])\n\nSee [*continuous*.tickFormat](#continuous_tickFormat).\n\n<a name=\"pow_nice\" href=\"#pow_nice\">#</a> <i>pow</i>.<b>nice</b>([<i>count</i>])\n\nSee [*continuous*.nice](#continuous_nice).\n\n<a name=\"pow_copy\" href=\"#pow_copy\">#</a> <i>pow</i>.<b>copy</b>()\n\nSee [*continuous*.copy](#continuous_copy).\n\n<a name=\"scaleSqrt\" href=\"#scaleSqrt\">#</a> d3.<b>scaleSqrt</b>()\n\nConstructs a new [continuous](#continuous-scales) [power scale](#power-scales) with the unit [domain](#continuous_domain) [0, 1], the unit [range](#continuous_range) [0, 1], the [exponent](#pow_exponent) 0.5, the [default](https://github.com/d3/d3-interpolate#interpolate) [interpolator](#continuous_interpolate) and [clamping](#continuous_clamp) disabled. This is a convenience method equivalent to `d3.scalePow().exponent(0.5)`.\n\n#### Log Scales\n\nLog scales are similar to [linear scales](#linear-scales), except a logarithmic transform is applied to the input domain value before the output range value is computed. The mapping to the range value *y* can be expressed as a function of the domain value *x*: *y* = *m* log(<i>x</i>) + *b*.\n\nAs log(0) = -∞, a log scale domain must be **strictly-positive or strictly-negative**; the domain must not include or cross zero. A log scale with a positive domain has a well-defined behavior for positive values, and a log scale with a negative domain has a well-defined behavior for negative values. (For a negative domain, input and output values are implicitly multiplied by -1.) The behavior of the scale is undefined if you pass a negative value to a log scale with a positive domain or vice versa.\n\n<a name=\"scaleLog\" href=\"#scaleLog\">#</a> d3.<b>scaleLog</b>()\n\nConstructs a new [continuous scale](#continuous-scales) with the [domain](#log_domain) [1, 10], the unit [range](#log_range) [0, 1], the [base](#log_base) 10, the [default](https://github.com/d3/d3-interpolate#interpolate) [interpolator](#log_interpolate) and [clamping](#log_clamp) disabled.\n\n<a name=\"log\" href=\"#_log\">#</a> <i>log</i>(<i>value</i>)\n\nSee [*continuous*](#_continuous).\n\n<a name=\"log_invert\" href=\"#log_invert\">#</a> <i>log</i>.<b>invert</b>(<i>value</i>)\n\nSee [*continuous*.invert](#continuous_invert).\n\n<a name=\"log_base\" href=\"#log_base\">#</a> <i>log</i>.<b>base</b>([<i>base</i>])\n\nIf *base* is specified, sets the base for this logarithmic scale to the specified value. If *base* is not specified, returns the current base, which defaults to 10.\n\n<a name=\"log_domain\" href=\"#log_domain\">#</a> <i>log</i>.<b>domain</b>([<i>domain</i>])\n\nSee [*continuous*.domain](#continuous_domain).\n\n<a name=\"log_range\" href=\"#log_range\">#</a> <i>log</i>.<b>range</b>([<i>range</i>])\n\nSee [*continuous*.range](#continuous_range).\n\n<a name=\"log_rangeRound\" href=\"#log_rangeRound\">#</a> <i>log</i>.<b>rangeRound</b>([<i>range</i>])\n\nSee [*continuous*.rangeRound](#continuous_rangeRound).\n\n<a name=\"log_clamp\" href=\"#log_clamp\">#</a> <i>log</i>.<b>clamp</b>(<i>clamp</i>)\n\nSee [*continuous*.clamp](#continuous_clamp).\n\n<a name=\"log_interpolate\" href=\"#log_interpolate\">#</a> <i>log</i>.<b>interpolate</b>(<i>interpolate</i>)\n\nSee [*continuous*.interpolate](#continuous_interpolate).\n\n<a name=\"log_ticks\" href=\"#log_ticks\">#</a> <i>log</i>.<b>ticks</b>([<i>count</i>])\n\nLike [*continuous*.ticks](#continuous_ticks), but customized for a log scale. If the [base](#log_base) is an integer, the returned ticks are uniformly spaced within each integer power of base; otherwise, one tick per power of base is returned. The returned ticks are guaranteed to be within the extent of the domain. If the orders of magnitude in the [domain](#log_domain) is greater than *count*, then at most one tick per power is returned. Otherwise, the tick values are unfiltered, but note that you can use [*log*.tickFormat](#log_tickFormat) to filter the display of tick labels. If *count* is not specified, it defaults to 10.\n\n<a name=\"log_tickFormat\" href=\"#log_tickFormat\">#</a> <i>log</i>.<b>tickFormat</b>([<i>count</i>[, <i>specifier</i>]])\n\nLike [*continuous*.tickFormat](#continuous_tickFormat), but customized for a log scale. The specified *count* typically has the same value as the count that is used to generate the [tick values](#continuous_ticks). If there are too many ticks, the formatter may return the empty string for some of the tick labels; however, note that the ticks are still shown. To disable filtering, specify a *count* of Infinity. When specifying a count, you may also provide a format *specifier* or format function. For example, to get a tick formatter that will display 20 ticks of a currency, say `log.tickFormat(20, \"$,f\")`. If the specifier does not have a defined precision, the precision will be set automatically by the scale, returning the appropriate format. This provides a convenient way of specifying a format whose precision will be automatically set by the scale.\n\n<a name=\"log_nice\" href=\"#log_nice\">#</a> <i>log</i>.<b>nice</b>()\n\nLike [*continuous*.nice](#continuous_nice), except extends the domain to integer powers of [base](#log_base). For example, for a domain of [0.201479…, 0.996679…], and base 10, the nice domain is [0.1, 1]. If the domain has more than two values, nicing the domain only affects the first and last value.\n\n<a name=\"log_copy\" href=\"#log_copy\">#</a> <i>log</i>.<b>copy</b>()\n\nSee [*continuous*.copy](#continuous_copy).\n\n#### Identity Scales\n\nIdentity scales are a special case of [linear scales](#linear-scales) where the domain and range are identical; the scale and its invert method are thus the identity function. These scales are occasionally useful when working with pixel coordinates, say in conjunction with an axis or brush. Identity scales do not support [rangeRound](#continuous_rangeRound), [clamp](#continuous_clamp) or [interpolate](#continuous_interpolate).\n\n<a name=\"scaleIdentity\" href=\"#scaleIdentity\">#</a> d3.<b>scaleIdentity</b>()\n\nConstructs a new identity scale with the unit [domain](#continuous_domain) [0, 1] and the unit [range](#continuous_range) [0, 1].\n\n#### Time Scales\n\nTime scales are a variant of [linear scales](#linear-scales) that have a temporal domain: domain values are coerced to [dates](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Date) rather than numbers, and [invert](#continuous_invert) likewise returns a date. Time scales implement [ticks](#time_ticks) based on [calendar intervals](https://github.com/d3/d3-time), taking the pain out of generating axes for temporal domains.\n\nFor example, to create a position encoding:\n\n```js\nvar x = d3.scaleTime()\n .domain([new Date(2000, 0, 1), new Date(2000, 0, 2)])\n .range([0, 960]);\n\nx(new Date(2000, 0, 1, 5)); // 200\nx(new Date(2000, 0, 1, 16)); // 640\nx.invert(200); // Sat Jan 01 2000 05:00:00 GMT-0800 (PST)\nx.invert(640); // Sat Jan 01 2000 16:00:00 GMT-0800 (PST)\n```\n\nFor a valid value *y* in the range, <i>time</i>(<i>time</i>.invert(<i>y</i>)) equals *y*; similarly, for a valid value *x* in the domain, <i>time</i>.invert(<i>time</i>(<i>x</i>)) equals *x*. The invert method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.\n\n<a name=\"scaleTime\" href=\"#scaleTime\">#</a> d3.<b>scaleTime</b>()\n\nConstructs a new time scale with the [domain](#time_domain) [2000-01-01, 2000-01-02], the unit [range](#time_range) [0, 1], the [default](https://github.com/d3/d3-interpolate#interpolate) [interpolator](#time_interpolate) and [clamping](#time_clamp) disabled.\n\n<a name=\"time\" href=\"#_time\">#</a> <i>time</i>(<i>value</i>)\n\nSee [*continuous*](#_continuous).\n\n<a name=\"time_invert\" href=\"#time_invert\">#</a> <i>time</i>.<b>invert</b>(<i>value</i>)\n\nSee [*continuous*.invert](#continuous_invert).\n\n<a name=\"time_domain\" href=\"#time_domain\">#</a> <i>time</i>.<b>domain</b>([<i>domain</i>])\n\nSee [*continuous*.domain](#continuous_domain).\n\n<a name=\"time_range\" href=\"#time_range\">#</a> <i>time</i>.<b>range</b>([<i>range</i>])\n\nSee [*continuous*.range](#continuous_range).\n\n<a name=\"time_rangeRound\" href=\"#time_rangeRound\">#</a> <i>time</i>.<b>rangeRound</b>([<i>range</i>])\n\nSee [*continuous*.rangeRound](#continuous_rangeRound).\n\n<a name=\"time_clamp\" href=\"#time_clamp\">#</a> <i>time</i>.<b>clamp</b>(<i>clamp</i>)\n\nSee [*continuous*.clamp](#continuous_clamp).\n\n<a name=\"time_interpolate\" href=\"#time_interpolate\">#</a> <i>time</i>.<b>interpolate</b>(<i>interpolate</i>)\n\nSee [*continuous*.interpolate](#continuous_interpolate).\n\n<a name=\"time_ticks\" href=\"#time_ticks\">#</a> <i>time</i>.<b>ticks</b>([<i>count</i>])\n<br><a name=\"time_ticks\" href=\"#time_ticks\">#</a> <i>time</i>.<b>ticks</b>([<i>interval</i>])\n\nReturns representative dates from the scale’s [domain](#time_domain). The returned tick values are uniformly-spaced (mostly), have sensible values (such as every day at midnight), and are guaranteed to be within the extent of the domain. Ticks are often used to display reference lines, or tick marks, in conjunction with the visualized data.\n\nAn optional *count* may be specified to affect how many ticks are generated. If *count* is not specified, it defaults to 10. The specified *count* is only a hint; the scale may return more or fewer values depending on the domain. For example, to create ten default ticks, say:\n\n```js\nvar x = d3.scaleTime();\n\nx.ticks(10);\n// [Sat Jan 01 2000 00:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 03:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 06:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 09:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 12:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 15:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 18:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 21:00:00 GMT-0800 (PST),\n// Sun Jan 02 2000 00:00:00 GMT-0800 (PST)]\n```\n\nThe following time intervals are considered for automatic ticks:\n\n* 1-, 5-, 15- and 30-second.\n* 1-, 5-, 15- and 30-minute.\n* 1-, 3-, 6- and 12-hour.\n* 1- and 2-day.\n* 1-week.\n* 1- and 3-month.\n* 1-year.\n\nIn lieu of a *count*, a [time *interval*](https://github.com/d3/d3-time#intervals) may be explicitly specified. To prune the generated ticks for a given time *interval*, use [*interval*.every](https://github.com/d3/d3-time#interval_every). For example, to generate ticks at 15-[minute](https://github.com/d3/d3-time#minute) intervals:\n\n```js\nvar x = d3.scaleTime()\n .domain([new Date(2000, 0, 1, 0), new Date(2000, 0, 1, 2)]);\n\nx.ticks(d3.timeMinute.every(15));\n// [Sat Jan 01 2000 00:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 00:15:00 GMT-0800 (PST),\n// Sat Jan 01 2000 00:30:00 GMT-0800 (PST),\n// Sat Jan 01 2000 00:45:00 GMT-0800 (PST),\n// Sat Jan 01 2000 01:00:00 GMT-0800 (PST),\n// Sat Jan 01 2000 01:15:00 GMT-0800 (PST),\n// Sat Jan 01 2000 01:30:00 GMT-0800 (PST),\n// Sat Jan 01 2000 01:45:00 GMT-0800 (PST),\n// Sat Jan 01 2000 02:00:00 GMT-0800 (PST)]\n```\n\nAlternatively, pass a test function to [*interval*.filter](https://github.com/d3/d3-time#interval_filter):\n\n```js\nx.ticks(d3.timeMinute.filter(function(d) {\n return d.getMinutes() % 15 === 0;\n}));\n```\n\nNote: in some cases, such as with day ticks, specifying a *step* can result in irregular spacing of ticks because time intervals have varying length.\n\n<a name=\"time_tickFormat\" href=\"#time_tickFormat\">#</a> <i>time</i>.<b>tickFormat</b>([<i>count</i>[, <i>specifier</i>]])\n<br><a href=\"#time_tickFormat\">#</a> <i>time</i>.<b>tickFormat</b>([<i>interval</i>[, <i>specifier</i>]])\n\nReturns a time format function suitable for displaying [tick](#time_ticks) values. The specified *count* or *interval* is currently ignored, but is accepted for consistency with other scales such as [*continuous*.tickFormat](#continuous_tickFormat). If a format *specifier* is specified, this method is equivalent to [format](https://github.com/d3/d3-time-format#format). If *specifier* is not specified, the default time format is returned. The default multi-scale time format chooses a human-readable representation based on the specified date as follows:\n\n* `%Y` - for year boundaries, such as `2011`.\n* `%B` - for month boundaries, such as `February`.\n* `%b %d` - for week boundaries, such as `Feb 06`.\n* `%a %d` - for day boundaries, such as `Mon 07`.\n* `%I %p` - for hour boundaries, such as `01 AM`.\n* `%I:%M` - for minute boundaries, such as `01:23`.\n* `:%S` - for second boundaries, such as `:45`.\n* `.%L` - milliseconds for all other times, such as `.012`.\n\nAlthough somewhat unusual, this default behavior has the benefit of providing both local and global context: for example, formatting a sequence of ticks as [11 PM, Mon 07, 01 AM] reveals information about hours, dates, and day simultaneously, rather than just the hours [11 PM, 12 AM, 01 AM]. See [d3-time-format](https://github.com/d3/d3-time-format) if you’d like to roll your own conditional time format.\n\n<a name=\"time_nice\" href=\"#time_nice\">#</a> <i>time</i>.<b>nice</b>([<i>count</i>])\n<br><a name=\"time_nice\" href=\"#time_nice\">#</a> <i>time</i>.<b>nice</b>([<i>interval</i>[, <i>step</i>]])\n\nExtends the [domain](#time_domain) so that it starts and ends on nice round values. This method typically modifies the scale’s domain, and may only extend the bounds to the nearest round value.\n\nAn optional tick *count* argument allows greater control over the step size used to extend the bounds, guaranteeing that the returned [ticks](#time_ticks) will exactly cover the domain. Alternatively, a [time *interval*](https://github.com/d3/d3-time#intervals) may be specified to explicitly set the ticks. If an *interval* is specified, an optional *step* may also be specified to skip some ticks. For example, `time.nice(d3.timeSecond, 10)` will extend the domain to an even ten seconds (0, 10, 20, <i>etc.</i>). See [*time*.ticks](#time_ticks) and [*interval*.every](https://github.com/d3/d3-time#interval_every) for further detail.\n\nNicing is useful if the domain is computed from data, say using [extent](https://github.com/d3/d3-array#extent), and may be irregular. For example, for a domain of [2009-07-13T00:02, 2009-07-13T23:48], the nice domain is [2009-07-13, 2009-07-14]. If the domain has more than two values, nicing the domain only affects the first and last value.\n\n<a name=\"scaleUtc\" href=\"#scaleUtc\">#</a> d3.<b>scaleUtc</b>()\n\nEquivalent to [time](#time), but the returned time scale operates in [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) rather than local time.\n\n### Sequential Scales\n\nSequential scales are similar to [continuous scales](#continuous-scales) in that they map a continuous, numeric input domain to a continuous output range. However, unlike continuous scales, the output range of a sequential scale is fixed by its interpolator and not configurable. These scales do not expose [invert](#continuous_invert), [range](#continuous_range), [rangeRound](#continuous_rangeRound) and [interpolate](#continuous_interpolate) methods.\n\n<a name=\"scaleSequential\" href=\"#scaleSequential\">#</a> d3.<b>scaleSequential</b>(<i>interpolator</i>)\n\nConstructs a new sequential scale with the given [*interpolator*](#sequential_interpolator) function. When the scale is [applied](#_sequential), the interpolator will be invoked with a value typically in the range [0, 1], where 0 represents the start of the domain, and 1 represents the end of the domain. For example, to implement the ill-advised [HSL](https://github.com/d3/d3-color#hsl) rainbow scale:\n\n```js\nvar rainbow = d3.scaleSequential(function(t) {\n return d3.hsl(t * 360, 1, 0.5) + \"\";\n});\n```\n\nA more aesthetically-pleasing and perceptually-effective cyclical hue encoding is to use [d3.interpolateRainbow](#interpolateRainbow):\n\n```js\nvar rainbow = d3.scaleSequential(d3.interpolateRainbow);\n```\n\nFor even more sequential color schemes, see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic).\n\n<a name=\"_sequential\" href=\"#_sequential\">#</a> <i>sequential</i>(<i>value</i>)\n\nSee [*continuous*](#_continuous).\n\n<a name=\"sequential_domain\" href=\"#sequential_domain\">#</a> <i>sequential</i>.<b>domain</b>([<i>domain</i>])\n\nSee [*continuous*.domain](#continuous_domain). Note that a sequential scale’s domain must be numeric and must contain exactly two values.\n\n<a name=\"sequential_clamp\" href=\"#sequential_clamp\">#</a> <i>sequential</i>.<b>clamp</b>([<i>clamp</i>])\n\nSee [*continuous*.clamp](#continuous_clamp).\n\n<a name=\"sequential_interpolator\" href=\"#sequential_interpolator\">#</a> <i>sequential</i>.<b>interpolator</b>([<i>interpolator</i>])\n\nIf *interpolator* is specified, sets the scale’s interpolator to the specified function. If *interpolator* is not specified, returns the scale’s current interpolator.\n\n<a name=\"sequential_copy\" href=\"#sequential_copy\">#</a> <i>sequential</i>.<b>copy</b>()\n\nSee [*continuous*.copy](#continuous_copy).\n\n<a name=\"interpolateViridis\" href=\"#interpolateViridis\">#</a> d3.<b>interpolateViridis</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/viridis.png\" width=\"100%\" height=\"40\" alt=\"viridis\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from the “viridis” perceptually-uniform color scheme designed by [van der Walt, Smith and Firing](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.\n\n<a name=\"interpolateInferno\" href=\"#interpolateInferno\">#</a> d3.<b>interpolateInferno</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/inferno.png\" width=\"100%\" height=\"40\" alt=\"inferno\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from the “inferno” perceptually-uniform color scheme designed by [van der Walt and Smith](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.\n\n<a name=\"interpolateMagma\" href=\"#interpolateMagma\">#</a> d3.<b>interpolateMagma</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/magma.png\" width=\"100%\" height=\"40\" alt=\"magma\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from the “magma” perceptually-uniform color scheme designed by [van der Walt and Smith](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.\n\n<a name=\"interpolatePlasma\" href=\"#interpolatePlasma\">#</a> d3.<b>interpolatePlasma</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/plasma.png\" width=\"100%\" height=\"40\" alt=\"plasma\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from the “plasma” perceptually-uniform color scheme designed by [van der Walt and Smith](https://bids.github.io/colormap/) for matplotlib, represented as an RGB string.\n\n<a name=\"interpolateWarm\" href=\"#interpolateWarm\">#</a> d3.<b>interpolateWarm</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/warm.png\" width=\"100%\" height=\"40\" alt=\"warm\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from a 180° rotation of [Niccoli’s perceptual rainbow](https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/), represented as an RGB string.\n\n<a name=\"interpolateCool\" href=\"#interpolateCool\">#</a> d3.<b>interpolateCool</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/cool.png\" width=\"100%\" height=\"40\" alt=\"cool\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from [Niccoli’s perceptual rainbow](https://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/), represented as an RGB string.\n\n<a name=\"interpolateRainbow\" href=\"#interpolateRainbow\">#</a> d3.<b>interpolateRainbow</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/rainbow.png\" width=\"100%\" height=\"40\" alt=\"rainbow\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from [d3.interpolateWarm](#interpolateWarm) scale from [0.0, 0.5] followed by the [d3.interpolateCool](#interpolateCool) scale from [0.5, 1.0], thus implementing the cyclical [less-angry rainbow](http://bl.ocks.org/mbostock/310c99e53880faec2434) color scheme.\n\n<a name=\"interpolateCubehelixDefault\" href=\"#interpolateCubehelixDefault\">#</a> d3.<b>interpolateCubehelixDefault</b>(<i>t</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/cubehelix.png\" width=\"100%\" height=\"40\" alt=\"cubehelix\">\n\nGiven a number *t* in the range [0,1], returns the corresponding color from [Green’s default Cubehelix](https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/) represented as an RGB string.\n\n### Quantize Scales\n\nQuantize scales are similar to [linear scales](#linear-scales), except they use a discrete rather than continuous range. The continuous input domain is divided into uniform segments based on the number of values in (*i.e.*, the cardinality of) the output range. Each range value *y* can be expressed as a quantized linear function of the domain value *x*: *y* = *m round(x)* + *b*. See [bl.ocks.org/4060606](http://bl.ocks.org/mbostock/4060606) for an example.\n\n<a name=\"scaleQuantize\" href=\"#scaleQuantize\">#</a> d3.<b>scaleQuantize</b>()\n\nConstructs a new quantize scale with the unit [domain](#quantize_domain) [0, 1] and the unit [range](#quantize_range) [0, 1]. Thus, the default quantize scale is equivalent to the [Math.round](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/round) function.\n\n<a name=\"_quantize\" href=\"#_quantize\">#</a> <i>quantize</i>(<i>value</i>)\n\nGiven a *value* in the input [domain](#quantize_domain), returns the corresponding value in the output [range](#quantize_range). For example, to apply a color encoding:\n\n```js\nvar color = d3.scaleQuantize()\n .domain([0, 1])\n .range([\"brown\", \"steelblue\"]);\n\ncolor(0.49); // \"brown\"\ncolor(0.51); // \"steelblue\"\n```\n\nOr dividing the domain into three equally-sized parts with different range values to compute an appropriate stroke width:\n\n```js\nvar width = d3.scaleQuantize()\n .domain([10, 100])\n .range([1, 2, 4]);\n\nwidth(20); // 1\nwidth(50); // 2\nwidth(80); // 4\n```\n\n<a name=\"quantize_invertExtent\" href=\"#quantize_invertExtent\">#</a> <i>quantize</i>.<b>invertExtent</b>(<i>value</i>)\n\nReturns the extent of values in the [domain](#quantize_domain) [<i>x0</i>, <i>x1</i>] for the corresponding *value* in the [range](#quantize_range): the inverse of [*quantize*](#_quantize). This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.\n\n```js\nvar width = d3.scaleQuantize()\n .domain([10, 100])\n .range([1, 2, 4]);\n\nwidth.invertExtent(2); // [40, 70]\n```\n\n<a name=\"quantize_domain\" href=\"#quantize_domain\">#</a> <i>quantize</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the scale’s domain to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *domain* is not specified, returns the scale’s current domain.\n\n<a name=\"quantize_range\" href=\"#quantize_range\">#</a> <i>quantize</i>.<b>range</b>([<i>range</i>])\n\nIf *range* is specified, sets the scale’s range to the specified array of values. The array may contain any number of discrete values. The elements in the given array need not be numbers; any value or type will work. If *range* is not specified, returns the scale’s current range.\n\n<a name=\"quantize_ticks\" href=\"#quantize_ticks\">#</a> <i>quantize</i>.<b>ticks</b>([<i>count</i>])\n\nEquivalent to [*continuous*.ticks](#continuous_ticks).\n\n<a name=\"quantize_tickFormat\" href=\"#quantize_tickFormat\">#</a> <i>quantize</i>.<b>tickFormat</b>([<i>count</i>[, <i>specifier</i>]])\n\nEquivalent to [*continuous*.tickFormat](#continuous_tickFormat).\n\n<a name=\"quantize_nice\" href=\"#quantize_nice\">#</a> <i>quantize</i>.<b>nice</b>()\n\nEquivalent to [*continuous*.nice](#continuous_nice).\n\n<a name=\"quantize_copy\" href=\"#quantize_copy\">#</a> <i>quantize</i>.<b>copy</b>()\n\nReturns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n### Quantile Scales\n\nQuantile scales map a sampled input domain to a discrete range. The domain is considered continuous and thus the scale will accept any reasonable input value; however, the domain is specified as a discrete set of sample values. The number of values in (the cardinality of) the output range determines the number of quantiles that will be computed from the domain. To compute the quantiles, the domain is sorted, and treated as a [population of discrete values](https://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population); see d3-array’s [quantile](https://github.com/d3/d3-array#quantile). See [bl.ocks.org/8ca036b3505121279daf](http://bl.ocks.org/mbostock/8ca036b3505121279daf) for an example.\n\n<a name=\"scaleQuantile\" href=\"#scaleQuantile\">#</a> d3.<b>scaleQuantile</b>()\n\nConstructs a new quantile scale with an empty [domain](#quantile_domain) and an empty [range](#quantile_range). The quantile scale is invalid until both a domain and range are specified.\n\n<a name=\"_quantile\" href=\"#_quantile\">#</a> <i>quantile</i>(<i>value</i>)\n\nGiven a *value* in the input [domain](#quantile_domain), returns the corresponding value in the output [range](#quantile_range).\n\n<a name=\"quantile_invertExtent\" href=\"#quantile_invertExtent\">#</a> <i>quantile</i>.<b>invertExtent</b>(<i>value</i>)\n\nReturns the extent of values in the [domain](#quantile_domain) [<i>x0</i>, <i>x1</i>] for the corresponding *value* in the [range](#quantile_range): the inverse of [*quantile*](#_quantile). This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse.\n\n<a name=\"quantile_domain\" href=\"#quantile_domain\">#</a> <i>quantile</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the domain of the quantile scale to the specified set of discrete numeric values. The array must not be empty, and must contain at least one numeric value; NaN, null and undefined values are ignored and not considered part of the sample population. If the elements in the given array are not numbers, they will be coerced to numbers. A copy of the input array is sorted and stored internally. If *domain* is not specified, returns the scale’s current domain.\n\n<a name=\"quantile_range\" href=\"#quantile_range\">#</a> <i>quantile</i>.<b>range</b>([<i>range</i>])\n\nIf *range* is specified, sets the discrete values in the range. The array must not be empty, and may contain any type of value. The number of values in (the cardinality, or length, of) the *range* array determines the number of quantiles that are computed. For example, to compute quartiles, *range* must be an array of four elements such as [0, 1, 2, 3]. If *range* is not specified, returns the current range.\n\n<a name=\"quantile_quantiles\" href=\"#quantile_quantiles\">#</a> <i>quantile</i>.<b>quantiles</b>()\n\nReturns the quantile thresholds. If the [range](#quantile_range) contains *n* discrete values, the returned array will contain *n* - 1 thresholds. Values less than the first threshold are considered in the first quantile; values greater than or equal to the first threshold but less than the second threshold are in the second quantile, and so on. Internally, the thresholds array is used with [bisect](https://github.com/d3/d3-array#bisect) to find the output quantile associated with the given input value.\n\n<a name=\"quantile_copy\" href=\"#quantile_copy\">#</a> <i>quantile</i>.<b>copy</b>()\n\nReturns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n### Threshold Scales\n\nThreshold scales are similar to [quantize scales](#quantize-scales), except they allow you to map arbitrary subsets of the domain to discrete values in the range. The input domain is still continuous, and divided into slices based on a set of threshold values. See [bl.ocks.org/3306362](http://bl.ocks.org/mbostock/3306362) for an example.\n\n<a name=\"scaleThreshold\" href=\"#scaleThreshold\">#</a> d3.<b>scaleThreshold</b>()\n\nConstructs a new threshold scale with the default [domain](#threshold_domain) [0.5] and the default [range](#threshold_range) [0, 1]. Thus, the default threshold scale is equivalent to the [Math.round](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/round) function for numbers; for example threshold(0.49) returns 0, and threshold(0.51) returns 1.\n\n<a name=\"_threshold\" href=\"#_threshold\">#</a> <i>threshold</i>(<i>value</i>)\n\nGiven a *value* in the input [domain](#threshold_domain), returns the corresponding value in the output [range](#threshold_range). For example:\n\n```js\nvar color = d3.scaleThreshold()\n .domain([0, 1])\n .range([\"red\", \"white\", \"green\"]);\n\ncolor(-1); // \"red\"\ncolor(0); // \"white\"\ncolor(0.5); // \"white\"\ncolor(1); // \"green\"\ncolor(1000); // \"green\"\n```\n\n<a name=\"threshold_invertExtent\" href=\"#threshold_invertExtent\">#</a> <i>threshold</i>.<b>invertExtent</b>(<i>value</i>)\n\nReturns the extent of values in the [domain](#threshold_domain) [<i>x0</i>, <i>x1</i>] for the corresponding *value* in the [range](#threshold_range), representing the inverse mapping from range to domain. This method is useful for interaction, say to determine the value in the domain that corresponds to the pixel location under the mouse. For example:\n\n```js\nvar color = d3.scaleThreshold()\n .domain([0, 1])\n .range([\"red\", \"white\", \"green\"]);\n\ncolor.invertExtent(\"red\"); // [undefined, 0]\ncolor.invertExtent(\"white\"); // [0, 1]\ncolor.invertExtent(\"green\"); // [1, undefined]\n```\n\n<a name=\"threshold_domain\" href=\"#threshold_domain\">#</a> <i>threshold</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the scale’s domain to the specified array of values. The values must be in sorted ascending order, or the behavior of the scale is undefined. The values are typically numbers, but any naturally ordered values (such as strings) will work; a threshold scale can be used to encode any type that is ordered. If the number of values in the scale’s range is N+1, the number of values in the scale’s domain must be N. If there are fewer than N elements in the domain, the additional values in the range are ignored. If there are more than N elements in the domain, the scale may return undefined for some inputs. If *domain* is not specified, returns the scale’s current domain.\n\n<a name=\"threshold_range\" href=\"#threshold_range\">#</a> <i>threshold</i>.<b>range</b>([<i>range</i>])\n\nIf *range* is specified, sets the scale’s range to the specified array of values. If the number of values in the scale’s domain is N, the number of values in the scale’s range must be N+1. If there are fewer than N+1 elements in the range, the scale may return undefined for some inputs. If there are more than N+1 elements in the range, the additional values are ignored. The elements in the given array need not be numbers; any value or type will work. If *range* is not specified, returns the scale’s current range.\n\n<a name=\"threshold_copy\" href=\"#threshold_copy\">#</a> <i>threshold</i>.<b>copy</b>()\n\nReturns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n### Ordinal Scales\n\nUnlike [continuous scales](#continuous-scales), ordinal scales have a discrete domain and range. For example, an ordinal scale might map a set of named categories to a set of colors, or determine the horizontal positions of columns in a column chart.\n\n<a name=\"scaleOrdinal\" href=\"#scaleOrdinal\">#</a> d3.<b>scaleOrdinal</b>([<i>range</i>])\n\nConstructs a new ordinal scale with an empty [domain](#ordinal_domain) and the specified [*range*](#ordinal_range). If a *range* is not specified, it defaults to the empty array; an ordinal scale always returns undefined until a non-empty range is defined.\n\n<a name=\"_ordinal\" href=\"#_ordinal\">#</a> <i>ordinal</i>(<i>value</i>)\n\nGiven a *value* in the input [domain](#ordinal_domain), returns the corresponding value in the output [range](#ordinal_range). If the given *value* is not in the scale’s [domain](#ordinal_domain), returns the [unknown](#ordinal_value); or, if the unknown value is [implicit](#implicit) (the default), then the *value* is implicitly added to the domain and the next-available value in the range is assigned to *value*, such that this and subsequent invocations of the scale given the same input *value* return the same output value.\n\n<a name=\"ordinal_domain\" href=\"#ordinal_domain\">#</a> <i>ordinal</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first element in the range, the second domain value to the second range value, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to retrieve a value from the range. Thus, an ordinal scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding range value. If *domain* is not specified, this method returns the current domain.\n\nSetting the domain on an ordinal scale is optional if the [unknown value](#ordinal_unknown) is [implicit](#implicit) (the default). In this case, the domain will be inferred implicitly from usage by assigning each unique value passed to the scale a new value from the range. Note that an explicit domain is recommended to ensure deterministic behavior, as inferring the domain from usage will be dependent on ordering.\n\n<a name=\"ordinal_range\" href=\"#ordinal_range\">#</a> <i>ordinal</i>.<b>range</b>([<i>range</i>])\n\nIf *range* is specified, sets the range of the ordinal scale to the specified array of values. The first element in the domain will be mapped to the first element in *range*, the second domain value to the second range value, and so on. If there are fewer elements in the range than in the domain, the scale will reuse values from the start of the range. If *range* is not specified, this method returns the current range.\n\n<a name=\"ordinal_unknown\" href=\"#ordinal_unknown\">#</a> <i>ordinal</i>.<b>unknown</b>([<i>value</i>])\n\nIf *value* is specified, sets the output value of the scale for unknown input values and returns this scale. If *value* is not specified, returns the current unknown value, which defaults to [implicit](#implicit). The implicit value enables implicit domain construction; see [*ordinal*.domain](#ordinal_domain).\n\n<a name=\"ordinal_copy\" href=\"#ordinal_copy\">#</a> <i>ordinal</i>.<b>copy</b>()\n\nReturns an exact copy of this ordinal scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n<a name=\"scaleImplicit\" href=\"#scaleImplicit\">#</a> d3.<b>scaleImplicit</b>\n\nA special value for [*ordinal*.unknown](#ordinal_unknown) that enables implicit domain construction: unknown values are implicitly added to the domain.\n\n#### Band Scales\n\nBand scales are like [ordinal scales](#ordinal-scales) except the output range is continuous and numeric. Discrete output values are automatically computed by the scale by dividing the continuous range into uniform bands. Band scales are typically used for bar charts with an ordinal or categorical dimension. The [unknown value](#ordinal_unknown) of a band scale is effectively undefined: they do not allow implicit domain construction.\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/band.png\" width=\"751\" height=\"238\" alt=\"band\">\n\n<a name=\"scaleBand\" href=\"#scaleBand\">#</a> d3.<b>scaleBand</b>()\n\nConstructs a new band scale with the empty [domain](#band_domain), the unit [range](#band_range) [0, 1], no [padding](#band_padding), no [rounding](#band_round) and center [alignment](#band_align).\n\n<a name=\"_band\" href=\"#_band\">#</a> <i>band</i>(*value*)\n\nGiven a *value* in the input [domain](#band_domain), returns the start of the corresponding band derived from the output [range](#band_range). If the given *value* is not in the scale’s domain, returns undefined.\n\n<a name=\"band_domain\" href=\"#band_domain\">#</a> <i>band</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first band, the second domain value to the second band, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to determine the band. Thus, a band scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding band. If *domain* is not specified, this method returns the current domain.\n\n<a name=\"band_range\" href=\"#band_range\">#</a> <i>band</i>.<b>range</b>([<i>range</i>])\n\nIf *range* is specified, sets the scale’s range to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *range* is not specified, returns the scale’s current range, which defaults to [0, 1].\n\n<a name=\"band_rangeRound\" href=\"#band_rangeRound\">#</a> <i>band</i>.<b>rangeRound</b>([<i>range</i>])\n\nSets the scale’s [*range*](#band_range) to the specified two-element array of numbers while also enabling [rounding](#band_round). This is a convenience method equivalent to:\n\n```js\nband\n .range(range)\n .round(true);\n```\n\nRounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles.\n\n<a name=\"band_round\" href=\"#band_round\">#</a> <i>band</i>.<b>round</b>([<i>round</i>])\n\nIf *round* is specified, enables or disables rounding accordingly. If rounding is enabled, the start and stop of each band will be integers. Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles. Note that if the width of the domain is not a multiple of the cardinality of the range, there may be leftover unused space, even without padding! Use [*band*.align](#band_align) to specify how the leftover space is distributed.\n\n<a name=\"band_paddingInner\" href=\"#band_paddingInner\">#</a> <i>band</i>.<b>paddingInner</b>([<i>padding</i>])\n\nIf *padding* is specified, sets the inner padding to the specified value which must be in the range [0, 1]. If *padding* is not specified, returns the current inner padding which defaults to 0. The inner padding determines the ratio of the range that is reserved for blank space between bands.\n\n<a name=\"band_paddingOuter\" href=\"#band_paddingOuter\">#</a> <i>band</i>.<b>paddingOuter</b>([<i>padding</i>])\n\nIf *padding* is specified, sets the outer padding to the specified value which must be in the range [0, 1]. If *padding* is not specified, returns the current outer padding which defaults to 0. The outer padding determines the ratio of the range that is reserved for blank space before the first band and after the last band.\n\n<a name=\"band_padding\" href=\"#band_padding\">#</a> <i>band</i>.<b>padding</b>([<i>padding</i>])\n\nA convenience method for setting the [inner](#band_paddingInner) and [outer](#band_paddingOuter) padding to the same *padding* value. If *padding* is not specified, returns the inner padding.\n\n<a name=\"band_align\" href=\"#band_align\">#</a> <i>band</i>.<b>align</b>([<i>align</i>])\n\nIf *align* is specified, sets the alignment to the specified value which must be in the range [0, 1]. If *align* is not specified, returns the current alignment which defaults to 0.5. The alignment determines how any leftover unused space in the range is distributed. A value of 0.5 indicates that the leftover space should be equally distributed before the first band and after the last band; *i.e.*, the bands should be centered within the range. A value of 0 or 1 may be used to shift the bands to one side, say to position them adjacent to an axis.\n\n<a name=\"band_bandwidth\" href=\"#band_bandwidth\">#</a> <i>band</i>.<b>bandwidth</b>()\n\nReturns the width of each band.\n\n<a name=\"band_step\" href=\"#band_step\">#</a> <i>band</i>.<b>step</b>()\n\nReturns the distance between the starts of adjacent bands.\n\n<a name=\"band_copy\" href=\"#band_copy\">#</a> <i>band</i>.<b>copy</b>()\n\nReturns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n#### Point Scales\n\nPoint scales are a variant of [band scales](#band-scales) with the bandwidth fixed to zero. Point scales are typically used for scatterplots with an ordinal or categorical dimension. The [unknown value](#ordinal_unknown) of a point scale is always undefined: they do not allow implicit domain construction.\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/point.png\" width=\"648\" height=\"155\" alt=\"point\">\n\n<a name=\"scalePoint\" href=\"#scalePoint\">#</a> d3.<b>scalePoint</b>()\n\nConstructs a new point scale with the empty [domain](#point_domain), the unit [range](#point_range) [0, 1], no [padding](#point_padding), no [rounding](#point_round) and center [alignment](#point_align).\n\n<a name=\"_point\" href=\"#_point\">#</a> <i>point</i>(*value*)\n\nGiven a *value* in the input [domain](#point_domain), returns the corresponding point derived from the output [range](#point_range). If the given *value* is not in the scale’s domain, returns undefined.\n\n<a name=\"point_domain\" href=\"#point_domain\">#</a> <i>point</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the domain to the specified array of values. The first element in *domain* will be mapped to the first point, the second domain value to the second point, and so on. Domain values are stored internally in a map from stringified value to index; the resulting index is then used to determine the point. Thus, a point scale’s values must be coercible to a string, and the stringified version of the domain value uniquely identifies the corresponding point. If *domain* is not specified, this method returns the current domain.\n\n<a name=\"point_range\" href=\"#point_range\">#</a> <i>point</i>.<b>range</b>([<i>range</i>])\n\nIf *domain* is specified, sets the scale’s domain to the specified two-element array of numbers. If the elements in the given array are not numbers, they will be coerced to numbers. If *range* is not specified, returns the scale’s current range, which defaults to [0, 1].\n\n<a name=\"point_rangeRound\" href=\"#point_rangeRound\">#</a> <i>point</i>.<b>rangeRound</b>([<i>range</i>])\n\nSets the scale’s [*range*](#point_range) to the specified two-element array of numbers while also enabling [rounding](#point_round). This is a convenience method equivalent to:\n\n```js\npoint\n .range(range)\n .round(true);\n```\n\nRounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles.\n\n<a name=\"point_round\" href=\"#point_round\">#</a> <i>point</i>.<b>round</b>([<i>round</i>])\n\nIf *round* is specified, enables or disables rounding accordingly. If rounding is enabled, the position of each point will be integers. Rounding is sometimes useful for avoiding antialiasing artifacts, though also consider the [shape-rendering](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/shape-rendering) “crispEdges” styles. Note that if the width of the domain is not a multiple of the cardinality of the range, there may be leftover unused space, even without padding! Use [*point*.align](#point_align) to specify how the leftover space is distributed.\n\n<a name=\"point_padding\" href=\"#point_padding\">#</a> <i>point</i>.<b>padding</b>([<i>padding</i>])\n\nIf *padding* is specified, sets the outer padding to the specified value which must be in the range [0, 1]. If *padding* is not specified, returns the current outer padding which defaults to 0. The outer padding determines the ratio of the range that is reserved for blank space before the first point and after the last point. Equivalent to [*band*.paddingOuter](#band_paddingOuter).\n\n<a name=\"point_align\" href=\"#point_align\">#</a> <i>point</i>.<b>align</b>([<i>align</i>])\n\nIf *align* is specified, sets the alignment to the specified value which must be in the range [0, 1]. If *align* is not specified, returns the current alignment which defaults to 0.5. The alignment determines how any leftover unused space in the range is distributed. A value of 0.5 indicates that the leftover space should be equally distributed before the first point and after the last point; *i.e.*, the points should be centered within the range. A value of 0 or 1 may be used to shift the points to one side, say to position them adjacent to an axis.\n\n<a name=\"point_bandwidth\" href=\"#point_bandwidth\">#</a> <i>point</i>.<b>bandwidth</b>()\n\nReturns zero.\n\n<a name=\"point_step\" href=\"#point_step\">#</a> <i>point</i>.<b>step</b>()\n\nReturns the distance between the starts of adjacent points.\n\n<a name=\"point_copy\" href=\"#point_copy\">#</a> <i>point</i>.<b>copy</b>()\n\nReturns an exact copy of this scale. Changes to this scale will not affect the returned scale, and vice versa.\n\n#### Category Scales\n\nThese color schemes are designed to work with [d3.scaleOrdinal](#scaleOrdinal). For example:\n\n```js\nvar color = d3.scaleOrdinal(d3.schemeCategory10);\n```\n\nFor even more category scales, see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic).\n\n<a name=\"schemeCategory10\" href=\"#schemeCategory10\">#</a> d3.<b>schemeCategory10</b>\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/category10.png\" width=\"100%\" height=\"40\" alt=\"category10\">\n\nAn array of ten categorical colors represented as RGB hexadecimal strings.\n\n<a name=\"schemeCategory20\" href=\"#schemeCategory20\">#</a> d3.<b>schemeCategory20</b>\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/category20.png\" width=\"100%\" height=\"40\" alt=\"category20\">\n\nAn array of twenty categorical colors represented as RGB hexadecimal strings.\n\n<a name=\"schemeCategory20b\" href=\"#schemeCategory20b\">#</a> d3.<b>schemeCategory20b</b>\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/category20b.png\" width=\"100%\" height=\"40\" alt=\"category20b\">\n\nAn array of twenty categorical colors represented as RGB hexadecimal strings.\n\n<a name=\"schemeCategory20c\" href=\"#schemeCategory20c\">#</a> d3.<b>schemeCategory20c</b>\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-scale/master/img/category20c.png\" width=\"100%\" height=\"40\" alt=\"category20c\">\n\nAn array of twenty categorical colors represented as RGB hexadecimal strings. This color scale includes color specifications and designs developed by Cynthia Brewer ([colorbrewer2.org](http://colorbrewer2.org/))."},"npm":{"downloads":[{"from":"2016-10-18T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":22037},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":101548},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":230301},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":300895},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":334144}],"dependentsCount":88,"starsCount":5},"github":{"starsCount":716,"forksCount":52,"subscribersCount":34,"issues":{"count":81,"openCount":10,"distribution":{"3600":18,"10800":7,"32400":12,"97200":12,"291600":6,"874800":7,"2624400":2,"7873200":8,"23619600":5,"70858800":4,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":367},{"username":"curran","commitsCount":8},{"username":"billyjanitsch","commitsCount":2},{"username":"existentialism","commitsCount":2},{"username":"jasondavies","commitsCount":1},{"username":"lsbardel","commitsCount":1},{"username":"danielgavrilov","commitsCount":1},{"username":"JeroenBe","commitsCount":1},{"username":"Devinsuit","commitsCount":1},{"username":"rausnitz","commitsCount":1},{"username":"devgru","commitsCount":1}],"commits":[{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":10},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":56},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":218}]},"source":{"files":{"readmeSize":64959,"testsSize":140504,"hasNpmIgnore":true},"repositorySize":311483,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":818,"downloadsCount":76767,"downloadsAcceleration":806.4115487062405,"dependentsCount":88},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9626712328767123,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.765036327244286,"detail":{"quality":0.9260256430415238,"popularity":0.3921859360603343,"maintenance":0.9998958763163199}}}},{"package":{"name":"d3-queue","version":"3.0.3","description":"Evaluate asynchronous tasks with configurable concurrency.","keywords":["d3","d3-module","asynchronous","async","queue"],"date":"2016-08-22T16:58:03.257Z","links":{"npm":"https://www.npmjs.com/package/d3-queue","homepage":"https://d3js.org/d3-queue/","repository":"https://github.com/d3/d3-queue","bugs":"https://github.com/d3/d3-queue/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7694681928984323,"detail":{"quality":0.9260256430415238,"popularity":0.40486571616804184,"maintenance":0.9998785695061729}},"searchScore":0.022644628,"metadata":{"analyzedAt":"2016-10-16T22:38:07.626Z","collected":{"metadata":{"name":"d3-queue","version":"3.0.3","description":"Evaluate asynchronous tasks with configurable concurrency.","keywords":["d3","d3-module","asynchronous","async","queue"],"date":"2016-08-22T16:58:03.257Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-queue.git"},"links":{"npm":"https://www.npmjs.com/package/d3-queue","homepage":"https://d3js.org/d3-queue/","repository":"https://github.com/d3/d3-queue","bugs":"https://github.com/d3/d3-queue/issues"},"license":"BSD-3-Clause","devDependencies":{"eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":3},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":5},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":14},{"from":"2014-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":14}],"hasTestScript":true,"readme":"# d3-queue\n\nA **queue** evaluates zero or more *deferred* asynchronous tasks with configurable concurrency: you control how many tasks run at the same time. When all the tasks complete, or an error occurs, the queue passes the results to your *await* callback. This library is similar to [Async.js](https://github.com/caolan/async)’s [parallel](https://github.com/caolan/async#paralleltasks-callback) (when *concurrency* is infinite), [series](https://github.com/caolan/async#seriestasks-callback) (when *concurrency* is 1), and [queue](https://github.com/caolan/async#queue), but features a much smaller footprint: as of release 2, d3-queue is about 700 bytes gzipped, compared to 4,300 for Async.\n\nEach task is defined as a function that takes a callback as its last argument. For example, here’s a task that says hello after a short delay:\n\n```js\nfunction delayedHello(callback) {\n setTimeout(function() {\n console.log(\"Hello!\");\n callback(null);\n }, 250);\n}\n```\n\nWhen a task completes, it must call the provided callback. The first argument to the callback should be null if the task is successfull, or the error if the task failed. The optional second argument to the callback is the return value of the task. (To return multiple values from a single callback, wrap the results in an object or array.)\n\nTo run multiple tasks simultaneously, create a queue, *defer* your tasks, and then register an *await* callback to be called when all of the tasks complete (or an error occurs):\n\n```js\nvar q = d3.queue();\nq.defer(delayedHello);\nq.defer(delayedHello);\nq.await(function(error) {\n if (error) throw error;\n console.log(\"Goodbye!\");\n});\n```\n\nOf course, you can also use a `for` loop to defer many tasks:\n\n```js\nvar q = d3.queue();\n\nfor (var i = 0; i < 1000; ++i) {\n q.defer(delayedHello);\n}\n\nq.awaitAll(function(error) {\n if (error) throw error;\n console.log(\"Goodbye!\");\n});\n```\n\nTasks can take optional arguments. For example, here’s how to configure the delay before hello and provide a name:\n\n```js\nfunction delayedHello(name, delay, callback) {\n setTimeout(function() {\n console.log(\"Hello, \" + name + \"!\");\n callback(null);\n }, delay);\n}\n```\n\nAny additional arguments provided to [*queue*.defer](#queue_defer) are automatically passed along to the task function before the callback argument. You can also use method chaining for conciseness, avoiding the need for a local variable:\n\n```js\nd3.queue()\n .defer(delayedHello, \"Alice\", 250)\n .defer(delayedHello, \"Bob\", 500)\n .defer(delayedHello, \"Carol\", 750)\n .await(function(error) {\n if (error) throw error;\n console.log(\"Goodbye!\");\n });\n```\n\nThe [asynchronous callback pattern](https://github.com/maxogden/art-of-node#callbacks) is very common in Node.js, so Queue works directly with many Node APIs. For example, to [stat two files](https://nodejs.org/dist/latest/docs/api/fs.html#fs_fs_stat_path_callback) concurrently:\n\n```js\nd3.queue()\n .defer(fs.stat, __dirname + \"/../Makefile\")\n .defer(fs.stat, __dirname + \"/../package.json\")\n .await(function(error, file1, file2) {\n if (error) throw error;\n console.log(file1, file2);\n });\n```\n\nYou can also make abortable tasks: these tasks return an object with an *abort* method which terminates the task. So, if a task calls [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setTimeout) on start, it can call [clearTimeout](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearTimeout) on abort. For example:\n\n```js\nfunction delayedHello(name, delay, callback) {\n var id = setTimeout(function() {\n console.log(\"Hello, \" + name + \"!\");\n callback(null);\n }, delay);\n return {\n abort: function() {\n clearTimeout(id);\n }\n };\n}\n```\n\nWhen you call [*queue*.abort](#queue_abort), any in-progress tasks will be immediately aborted; in addition, any pending (not-yet-started) tasks not be started. Note that you can also use *queue*.abort *without* abortable tasks, in which case pending tasks will be cancelled, though active tasks will continue to run. Conveniently, the [d3-request](https://github.com/d3/d3-request) library implements abort atop XMLHttpRequest. For example:\n\n```js\nvar q = d3.queue()\n .defer(d3.request, \"http://www.google.com:81\")\n .defer(d3.request, \"http://www.google.com:81\")\n .defer(d3.request, \"http://www.google.com:81\")\n .awaitAll(function(error, results) {\n if (error) throw error;\n console.log(results);\n });\n```\n\nTo abort these requests, call `q.abort()`.\n\n## Installing\n\nIf you use NPM, `npm install d3-queue`. If you use Bower, `bower install d3-queue`. Otherwise, download the [latest release](https://github.com/d3/d3-queue/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-queue.v3.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-queue.v3.min.js\"></script>\n<script>\n\nvar q = d3.queue();\n\n</script>\n```\n\n[Try d3-queue in your browser.](https://tonicdev.com/npm/d3-queue)\n\n## API Reference\n\n<a href=\"#queue\" name=\"queue\">#</a> d3.<b>queue</b>([<i>concurrency</i>]) [<>](https://github.com/d3/d3-queue/blob/master/src/queue.js \"Source\")\n\nConstructs a new queue with the specified *concurrency*. If *concurrency* is not specified, the queue has infinite concurrency. Otherwise, *concurrency* is a positive integer. For example, if *concurrency* is 1, then all tasks will be run in series. If *concurrency* is 3, then at most three tasks will be allowed to proceed concurrently; this is useful, for example, when loading resources in a web browser.\n\n<a href=\"#queue_defer\" name=\"queue_defer\">#</a> <i>queue</i>.<b>defer</b>(<i>task</i>[, <i>arguments</i>…]) [<>](https://github.com/d3/d3-queue/blob/master/src/queue.js#L20 \"Source\")\n\nAdds the specified asynchronous *task* callback to the queue, with any optional *arguments*. The *task* is a function that will be called when the task should start. It is passed the specified optional *arguments* and an additional *callback* as the last argument; the callback must be invoked by the task when it finishes. The task must invoke the callback with two arguments: the *error*, if any, and the *result* of the task. To return multiple results from a single callback, wrap the results in an object or array.\n\nFor example, here’s a task which computes the answer to the ultimate question of life, the universe, and everything after a short delay:\n\n```js\nfunction simpleTask(callback) {\n setTimeout(function() {\n callback(null, {answer: 42});\n }, 250);\n}\n```\n\nIf the task calls back with an error, any tasks that were scheduled *but not yet started* will not run. For a serial queue (of *concurrency* 1), this means that a task will only run if all previous tasks succeed. For a queue with higher concurrency, only the first error that occurs is reported to the await callback, and tasks that were started before the error occurred will continue to run; note, however, that their results will not be reported to the await callback.\n\nTasks can only be deferred before [*queue*.await](#queue_await) or [*queue*.awaitAll](#queue_awaitAll) is called. If a task is deferred after then, an error is thrown. If the *task* is not a function, an error is thrown.\n\n<a href=\"#queue_abort\" name=\"queue_abort\">#</a> <i>queue</i>.<b>abort</b>() [<>](https://github.com/d3/d3-queue/blob/master/src/queue.js#L29 \"Source\")\n\nAborts any active tasks, invoking each active task’s *task*.abort function, if any. Also prevents any new tasks from starting, and immediately invokes the [*queue*.await](#queue_await) or [*queue*.awaitAll](#queue_awaitAll) callback with an error indicating that the queue was aborted. See the [introduction](#d3-queue) for an example implementation of an abortable task. Note that if your tasks are not abortable, any running tasks will continue to run, even after the await callback has been invoked with the abort error. The await callback is invoked exactly once on abort, and so is not called when any running tasks subsequently succeed or fail.\n\n<a href=\"#queue_await\" name=\"queue_await\">#</a> <i>queue</i>.<b>await</b>(<i>callback</i>) [<>](https://github.com/d3/d3-queue/blob/master/src/queue.js#L33 \"Source\")\n\nSets the *callback* to be invoked when all deferred tasks have finished. The first argument to the *callback* is the first error that occurred, or null if no error occurred. If an error occurred, there are no additional arguments to the callback. Otherwise, the *callback* is passed each result as an additional argument. For example:\n\n```js\nd3.queue()\n .defer(fs.stat, __dirname + \"/../Makefile\")\n .defer(fs.stat, __dirname + \"/../package.json\")\n .await(function(error, file1, file2) { console.log(file1, file2); });\n```\n\nIf all [deferred](#queue_defer) tasks have already completed, the callback will be invoked immediately. This method may only be called once, after any tasks have been deferred. If this method is called multiple times, or if it is called after [*queue*.awaitAll](#queue_awaitAll), an error is thrown. If the *callback* is not a function, an error is thrown.\n\n<a href=\"#queue_awaitAll\" name=\"queue_awaitAll\">#</a> <i>queue</i>.<b>awaitAll</b>(<i>callback</i>) [<>](https://github.com/d3/d3-queue/blob/master/src/queue.js#L39 \"Source\")\n\nSets the *callback* to be invoked when all deferred tasks have finished. The first argument to the *callback* is the first error that occurred, or null if no error occurred. If an error occurred, there are no additional arguments to the callback. Otherwise, the *callback* is also passed an array of results as the second argument. For example:\n\n```js\nd3.queue()\n .defer(fs.stat, __dirname + \"/../Makefile\")\n .defer(fs.stat, __dirname + \"/../package.json\")\n .awaitAll(function(error, files) { console.log(files); });\n```\n\nIf all [deferred](#queue_defer) tasks have already completed, the callback will be invoked immediately. This method may only be called once, after any tasks have been deferred. If this method is called multiple times, or if it is called after [*queue*.await](#queue_await), an error is thrown. If the *callback* is not a function, an error is thrown."},"npm":{"downloads":[{"from":"2016-10-15T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":2410},{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":37241},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":152605},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":369307},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":527570},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":632044}],"dependentsCount":33,"starsCount":2},"github":{"homepage":"http://bl.ocks.org/mbostock/1696080","starsCount":1245,"forksCount":120,"subscribersCount":59,"issues":{"count":62,"openCount":0,"distribution":{"3600":13,"10800":4,"32400":7,"97200":11,"291600":5,"874800":0,"2624400":3,"7873200":6,"23619600":5,"70858800":7,"212576400":1},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":147},{"username":"thejamespinto","commitsCount":1},{"username":"mking","commitsCount":1},{"username":"Devinsuit","commitsCount":1},{"username":"jasondavies","commitsCount":1}],"commits":[{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":6},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":13},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":115}]},"source":{"files":{"readmeSize":10346,"testsSize":18411,"hasNpmIgnore":true},"repositorySize":36121,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":1431,"downloadsCount":123102.33333333333,"downloadsAcceleration":1138.6307458143074,"dependentsCount":33},"maintenance":{"releasesFrequency":0.9970034246575343,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.7694681928984323,"detail":{"quality":0.9260256430415238,"popularity":0.40486571616804184,"maintenance":0.9998785695061729}}}},{"package":{"name":"d3-shape","version":"1.0.3","description":"Graphical primitives for visualization, such as lines and areas.","keywords":["d3","d3-module","graphics","visualization","canvas","svg"],"date":"2016-08-20T16:05:22.506Z","links":{"npm":"https://www.npmjs.com/package/d3-shape","homepage":"https://d3js.org/d3-shape/","repository":"https://github.com/d3/d3-shape","bugs":"https://github.com/d3/d3-shape/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7651178828825577,"detail":{"quality":0.9260256430415238,"popularity":0.39241957749659395,"maintenance":0.9998952509894077}},"searchScore":0.017190356,"metadata":{"analyzedAt":"2016-10-19T00:42:07.154Z","collected":{"metadata":{"name":"d3-shape","version":"1.0.3","description":"Graphical primitives for visualization, such as lines and areas.","keywords":["d3","d3-module","graphics","visualization","canvas","svg"],"date":"2016-08-20T16:05:22.506Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-shape.git"},"links":{"npm":"https://www.npmjs.com/package/d3-shape","homepage":"https://d3js.org/d3-shape/","repository":"https://github.com/d3/d3-shape","bugs":"https://github.com/d3/d3-shape/issues"},"license":"BSD-3-Clause","dependencies":{"d3-path":"1"},"devDependencies":{"d3-polygon":"1","eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":4},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":8},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":21},{"from":"2014-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":21}],"hasTestScript":true,"readme":"# d3-shape\n\nVisualizations typically consist of discrete graphical marks, such as [symbols](#symbols), [arcs](#arcs), [lines](#lines) and [areas](#areas). While the rectangles of a bar chart may be easy enough to generate directly using [SVG](http://www.w3.org/TR/SVG/paths.html#PathData) or [Canvas](http://www.w3.org/TR/2dcontext/#canvaspathmethods), other shapes are complex, such as rounded annular sectors and centripetal Catmull–Rom splines. This module provides a variety of shape generators for your convenience.\n\nAs with other aspects of D3, these shapes are driven by data: each shape generator exposes accessors that control how the input data are mapped to a visual representation. For example, you might define a line generator for a time series by [scaling](https://github.com/d3/d3-scale) fields of your data to fit the chart:\n\n```js\nvar line = d3.line()\n .x(function(d) { return x(d.date); })\n .y(function(d) { return y(d.value); });\n```\n\nThis line generator can then be used to compute the `d` attribute of an SVG path element:\n\n```js\npath.datum(data).attr(\"d\", line);\n```\n\nOr you can use it to render to a Canvas 2D context:\n\n```js\nline.context(context)(data);\n```\n\nFor more, read [Introducing d3-shape](https://medium.com/@mbostock/introducing-d3-shape-73f8367e6d12).\n\n## Installing\n\nIf you use NPM, `npm install d3-shape`. Otherwise, download the [latest release](https://github.com/d3/d3-shape/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-shape.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-path.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-shape.v1.min.js\"></script>\n<script>\n\nvar line = d3.line();\n\n</script>\n```\n\n[Try d3-shape in your browser.](https://tonicdev.com/npm/d3-shape)\n\n## API Reference\n\n* [Arcs](#arcs)\n* [Pies](#pies)\n* [Lines](#lines)\n* [Areas](#areas)\n* [Curves](#curves)\n* [Custom Curves](#custom-curves)\n* [Symbols](#symbols)\n* [Custom Symbol Types](#custom-symbol-types)\n* [Stacks](#stacks)\n\n### Arcs\n\n[<img alt=\"Pie Chart\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/pie.png\" width=\"295\" height=\"295\">](http://bl.ocks.org/mbostock/8878e7fd82034f1d63cf)[<img alt=\"Donut Chart\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/donut.png\" width=\"295\" height=\"295\">](http://bl.ocks.org/mbostock/2394b23da1994fc202e1)\n\nThe arc generator produces a [circular](https://en.wikipedia.org/wiki/Circular_sector) or [annular](https://en.wikipedia.org/wiki/Annulus_\\(mathematics\\)) sector, as in a pie or donut chart. If the difference between the [start](#arc_startAngle) and [end](#arc_endAngle) angles (the *angular span*) is greater than [τ](https://en.wikipedia.org/wiki/Turn_\\(geometry\\)#Tau_proposal), the arc generator will produce a complete circle or annulus. If it is less than τ, arcs may have [rounded corners](#arc_cornerRadius) and [angular padding](#arc_padAngle). Arcs are always centered at ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to move the arc to a different position.\n\nSee also the [pie generator](#pies), which computes the necessary angles to represent an array of data as a pie or donut chart; these angles can then be passed to an arc generator.\n\n<a name=\"arc\" href=\"#arc\">#</a> d3.<b>arc</b>()\n\nConstructs a new arc generator with the default settings.\n\n<a name=\"_arc\" href=\"#_arc\">#</a> <i>arc</i>(<i>arguments…</i>)\n\nGenerates an arc for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the arc generator’s accessor functions along with the `this` object. For example, with the default settings, an object with radii and angles is expected:\n\n```js\nvar arc = d3.arc();\n\narc({\n innerRadius: 0,\n outerRadius: 100,\n startAngle: 0,\n endAngle: Math.PI / 2\n}); // \"M0,-100A100,100,0,0,1,100,0L0,0Z\"\n```\n\nIf the radii and angles are instead defined as constants, you can generate an arc without any arguments:\n\n```js\nvar arc = d3.arc()\n .innerRadius(0)\n .outerRadius(100)\n .startAngle(0)\n .endAngle(Math.PI / 2);\n\narc(); // \"M0,-100A100,100,0,0,1,100,0L0,0Z\"\n```\n\nIf the arc generator has a [context](#arc_context), then the arc is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.\n\n<a name=\"arc_centroid\" href=\"#arc_centroid\">#</a> <i>arc</i>.<b>centroid</b>(<i>arguments…</i>)\n\nComputes the midpoint [*x*, *y*] of the center line of the arc that would be [generated](#_arc) by the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the arc generator’s accessor functions along with the `this` object. To be consistent with the generated arc, the accessors must be deterministic, *i.e.*, return the same value given the same arguments. The midpoint is defined as ([startAngle](#arc_startAngle) + [endAngle](#arc_endAngle)) / 2 and ([innerRadius](#arc_innerRadius) + [outerRadius](#arc_outerRadius)) / 2. For example:\n\n[<img alt=\"Circular Sector Centroids\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/centroid-circular-sector.png\" width=\"250\" height=\"250\">](http://bl.ocks.org/mbostock/9b5a2fd1ce1a146f27e4)[<img alt=\"Annular Sector Centroids\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/centroid-annular-sector.png\" width=\"250\" height=\"250\">](http://bl.ocks.org/mbostock/c274877f647361f3df7d)\n\nNote that this is **not the geometric center** of the arc, which may be outside the arc; this method is merely a convenience for positioning labels.\n\n<a name=\"arc_innerRadius\" href=\"#arc_innerRadius\">#</a> <i>arc</i>.<b>innerRadius</b>([<i>radius</i>])\n\nIf *radius* is specified, sets the inner radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current inner radius accessor, which defaults to:\n\n```js\nfunction innerRadius(d) {\n return d.innerRadius;\n}\n```\n\nSpecifying the inner radius as a function is useful for constructing a stacked polar bar chart, often in conjunction with a [sqrt scale](https://github.com/d3/d3-scale#sqrt). More commonly, a constant inner radius is used for a donut or pie chart. If the outer radius is smaller than the inner radius, the inner and outer radii are swapped. A negative value is treated as zero.\n\n<a name=\"arc_outerRadius\" href=\"#arc_outerRadius\">#</a> <i>arc</i>.<b>outerRadius</b>([<i>radius</i>])\n\nIf *radius* is specified, sets the outer radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current outer radius accessor, which defaults to:\n\n```js\nfunction outerRadius(d) {\n return d.outerRadius;\n}\n```\n\nSpecifying the outer radius as a function is useful for constructing a coxcomb or polar bar chart, often in conjunction with a [sqrt scale](https://github.com/d3/d3-scale#sqrt). More commonly, a constant outer radius is used for a pie or donut chart. If the outer radius is smaller than the inner radius, the inner and outer radii are swapped. A negative value is treated as zero.\n\n<a name=\"arc_cornerRadius\" href=\"#arc_cornerRadius\">#</a> <i>arc</i>.<b>cornerRadius</b>([<i>radius</i>])\n\nIf *radius* is specified, sets the corner radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current corner radius accessor, which defaults to:\n\n```js\nfunction cornerRadius() {\n return 0;\n}\n```\n\nIf the corner radius is greater than zero, the corners of the arc are rounded using circles of the given radius. For a circular sector, the two outer corners are rounded; for an annular sector, all four corners are rounded. The corner circles are shown in this diagram:\n\n[<img alt=\"Rounded Circular Sectors\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/rounded-circular-sector.png\" width=\"250\" height=\"250\">](http://bl.ocks.org/mbostock/e5e3680f3079cf5c3437)[<img alt=\"Rounded Annular Sectors\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/rounded-annular-sector.png\" width=\"250\" height=\"250\">](http://bl.ocks.org/mbostock/f41f50e06a6c04828b6e)\n\nThe corner radius may not be larger than ([outerRadius](#arc_outerRadius) - [innerRadius](#arc_innerRadius)) / 2. In addition, for arcs whose angular span is less than π, the corner radius may be reduced as two adjacent rounded corners intersect. This is occurs more often with the inner corners. See the [arc corners animation](http://bl.ocks.org/mbostock/b7671cb38efdfa5da3af) for illustration.\n\n<a name=\"arc_startAngle\" href=\"#arc_startAngle\">#</a> <i>arc</i>.<b>startAngle</b>([<i>angle</i>])\n\nIf *angle* is specified, sets the start angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:\n\n```js\nfunction startAngle(d) {\n return d.startAngle;\n}\n```\n\nThe *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise. If |endAngle - startAngle| ≥ τ, a complete circle or annulus is generated rather than a sector.\n\n<a name=\"arc_endAngle\" href=\"#arc_endAngle\">#</a> <i>arc</i>.<b>endAngle</b>([<i>angle</i>])\n\nIf *angle* is specified, sets the end angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:\n\n```js\nfunction endAngle(d) {\n return d.endAngle;\n}\n```\n\nThe *angle* is specified in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise. If |endAngle - startAngle| ≥ τ, a complete circle or annulus is generated rather than a sector.\n\n<a name=\"arc_padAngle\" href=\"#arc_padAngle\">#</a> <i>arc</i>.<b>padAngle</b>([<i>angle</i>])\n\nIf *angle* is specified, sets the pad angle to the specified function or number and returns this arc generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:\n\n```js\nfunction padAngle() {\n return d && d.padAngle;\n}\n```\n\nThe pad angle is converted to a fixed linear distance separating adjacent arcs, defined as [padRadius](#arc_padRadius) * padAngle. This distance is subtracted equally from the [start](#arc_startAngle) and [end](#arc_endAngle) of the arc. If the arc forms a complete circle or annulus, as when |endAngle - startAngle| ≥ τ, the pad angle is ignored.\n\nIf the [inner radius](#arc_innerRadius) or angular span is small relative to the pad angle, it may not be possible to maintain parallel edges between adjacent arcs. In this case, the inner edge of the arc may collapse to a point, similar to a circular sector. For this reason, padding is typically only applied to annular sectors (*i.e.*, when innerRadius is positive), as shown in this diagram:\n\n[<img alt=\"Padded Circular Sectors\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/padded-circular-sector.png\" width=\"250\" height=\"250\">](http://bl.ocks.org/mbostock/f37b07b92633781a46f7)[<img alt=\"Padded Annular Sectors\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/padded-annular-sector.png\" width=\"250\" height=\"250\">](http://bl.ocks.org/mbostock/99f0a6533f7c949cf8b8)\n\nThe recommended minimum inner radius when using padding is outerRadius \\* padAngle / sin(θ), where θ is the angular span of the smallest arc before padding. For example, if the outer radius is 200 pixels and the pad angle is 0.02 radians, a reasonable θ is 0.04 radians, and a reasonable inner radius is 100 pixels. See the [arc padding animation](http://bl.ocks.org/mbostock/053fcc2295a445afab07) for illustration.\n\nOften, the pad angle is not set directly on the arc generator, but is instead computed by the [pie generator](#pies) so as to ensure that the area of padded arcs is proportional to their value; see [*pie*.padAngle](#pie_padAngle). See the [pie padding animation](http://bl.ocks.org/mbostock/3e961b4c97a1b543fff2) for illustration. If you apply a constant pad angle to the arc generator directly, it tends to subtract disproportionately from smaller arcs, introducing distortion.\n\n<a name=\"arc_padRadius\" href=\"#arc_padRadius\">#</a> <i>arc</i>.<b>padRadius</b>([<i>radius</i>])\n\nIf *radius* is specified, sets the pad radius to the specified function or number and returns this arc generator. If *radius* is not specified, returns the current pad radius accessor, which defaults to null, indicating that the pad radius should be automatically computed as sqrt([innerRadius](#arc_innerRadius) * innerRadius + [outerRadius](#arc_outerRadius) * outerRadius). The pad radius determines the fixed linear distance separating adjacent arcs, defined as padRadius * [padAngle](#arc_padAngle).\n\n<a name=\"arc_context\" href=\"#arc_context\">#</a> <i>arc</i>.<b>context</b>([<i>context</i>])\n\nIf *context* is specified, sets the context and returns this arc generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated arc](#_arc) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated arc is returned.\n\n### Pies\n\nThe pie generator does not produce a shape directly, but instead computes the necessary angles to represent a tabular dataset as a pie or donut chart; these angles can then be passed to an [arc generator](#arcs).\n\n<a name=\"pie\" href=\"#pie\">#</a> d3.<b>pie</b>()\n\nConstructs a new pie generator with the default settings.\n\n<a name=\"_pie\" href=\"#_pie\">#</a> <i>pie</i>(<i>data</i>[, <i>arguments…</i>])\n\nGenerates a pie for the given array of *data*, returning an array of objects representing each datum’s arc angles. Any additional *arguments* are arbitrary; they are simply propagated to the pie generator’s accessor functions along with the `this` object. The length of the returned array is the same as *data*, and each element *i* in the returned array corresponds to the element *i* in the input data. Each object in the returned array has the following properties:\n\n* `data` - the input datum; the corresponding element in the input data array.\n* `value` - the numeric [value](#pie_value) of the arc.\n* `index` - the zero-based [sorted index](#pie_sort) of the arc.\n* `startAngle` - the [start angle](#pie_startAngle) of the arc.\n* `endAngle` - the [end angle](#pie_endAngle) of the arc.\n* `padAngle` - the [pad angle](#pie_padAngle) of the arc.\n\nThis representation is designed to work with the arc generator’s default [startAngle](#arc_startAngle), [endAngle](#arc_endAngle) and [padAngle](#arc_padAngle) accessors. The angular units are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify angles in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.\n\nGiven a small dataset of numbers, here is how to compute the arc angles to render this data as a pie chart:\n\n```js\nvar data = [1, 1, 2, 3, 5, 8, 13, 21];\nvar arcs = d3.pie()(data);\n```\n\nThe first pair of parens, `pie()`, [constructs](#pie) a default pie generator. The second, `pie()(data)`, [invokes](#_pie) this generator on the dataset, returning an array of objects:\n\n```json\n[\n {\"data\": 1, \"value\": 1, \"startAngle\": 6.050474740247008, \"endAngle\": 6.166830023713296, \"padAngle\": 0},\n {\"data\": 1, \"value\": 1, \"startAngle\": 6.166830023713296, \"endAngle\": 6.283185307179584, \"padAngle\": 0},\n {\"data\": 2, \"value\": 2, \"startAngle\": 5.817764173314431, \"endAngle\": 6.050474740247008, \"padAngle\": 0},\n {\"data\": 3, \"value\": 3, \"startAngle\": 5.468698322915565, \"endAngle\": 5.817764173314431, \"padAngle\": 0},\n {\"data\": 5, \"value\": 5, \"startAngle\": 4.886921905584122, \"endAngle\": 5.468698322915565, \"padAngle\": 0},\n {\"data\": 8, \"value\": 8, \"startAngle\": 3.956079637853813, \"endAngle\": 4.886921905584122, \"padAngle\": 0},\n {\"data\": 13, \"value\": 13, \"startAngle\": 2.443460952792061, \"endAngle\": 3.956079637853813, \"padAngle\": 0},\n {\"data\": 21, \"value\": 21, \"startAngle\": 0.000000000000000, \"endAngle\": 2.443460952792061, \"padAngle\": 0}\n]\n```\n\nNote that the returned array is in the same order as the data, even though this pie chart is [sorted](#pie_sortValues) by descending value, starting with the arc for the last datum (value 21) at 12 o’clock.\n\n<a name=\"pie_value\" href=\"#pie_value\">#</a> <i>pie</i>.<b>value</b>([<i>value</i>])\n\nIf *value* is specified, sets the value accessor to the specified function or number and returns this pie generator. If *value* is not specified, returns the current value accessor, which defaults to:\n\n```js\nfunction value(d) {\n return d;\n}\n```\n\nWhen a pie is [generated](#_pie), the value accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default value accessor assumes that the input data are numbers, or that they are coercible to numbers using [valueOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf). If your data are not simply numbers, then you should specify an accessor that returns the corresponding numeric value for a given datum. For example:\n\n```js\nvar data = [\n {\"number\": 4, \"name\": Locke},\n {\"number\": 8, \"name\": Reyes},\n {\"number\": 15, \"name\": Ford},\n {\"number\": 16, \"name\": Jarrah},\n {\"number\": 23, \"name\": Shephard},\n {\"number\": 42, \"name\": Kwon}\n];\n\nvar arcs = d3.pie()\n .value(function(d) { return d.number; })\n (data);\n```\n\nThis is similar to [mapping](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) your data to values before invoking the pie generator:\n\n```js\nvar arcs = d3.pie()(data.map(function(d) { return d.number; }));\n```\n\nThe benefit of an accessor is that the input data remains associated with the returned objects, thereby making it easier to access other fields of the data, for example to set the color or to add text labels.\n\n<a name=\"pie_sort\" href=\"#pie_sort\">#</a> <i>pie</i>.<b>sort</b>([<i>compare</i>])\n\nIf *compare* is specified, sets the data comparator to the specified function and returns this pie generator. If *compare* is not specified, returns the current data comparator, which defaults to null. If both the data comparator and the value comparator are null, then arcs are positioned in the original input order. Otherwise, the data is sorted according to the data comparator, and the resulting order is used. Setting the data comparator implicitly sets the [value comparator](#pie_sortValues) to null.\n\nThe *compare* function takes two arguments *a* and *b*, each elements from the input data array. If the arc for *a* should be before the arc for *b*, then the comparator must return a number less than zero; if the arc for *a* should be after the arc for *b*, then the comparator must return a number greater than zero; returning zero means that the relative order of *a* and *b* is unspecified. For example, to sort arcs by their associated name:\n\n```js\npie.sort(function(a, b) { return a.name.localeCompare(b.name); });\n```\n\nSorting does not affect the order of the [generated arc array](#_pie) which is always in the same order as the input data array; it merely affects the computed angles of each arc. The first arc starts at the [start angle](#pie_startAngle) and the last arc ends at the [end angle](#pie_endAngle).\n\n<a name=\"pie_sortValues\" href=\"#pie_sortValues\">#</a> <i>pie</i>.<b>sortValues</b>([<i>compare</i>])\n\nIf *compare* is specified, sets the value comparator to the specified function and returns this pie generator. If *compare* is not specified, returns the current value comparator, which defaults to descending value. The default value comparator is implemented as:\n\n```js\nfunction compare(a, b) {\n return b - a;\n}\n```\n\nIf both the data comparator and the value comparator are null, then arcs are positioned in the original input order. Otherwise, the data is sorted according to the data comparator, and the resulting order is used. Setting the value comparator implicitly sets the [data comparator](#pie_sort) to null.\n\nThe value comparator is similar to the [data comparator](#pie_sort), except the two arguments *a* and *b* are values derived from the input data array using the [value accessor](#pie_value), not the data elements. If the arc for *a* should be before the arc for *b*, then the comparator must return a number less than zero; if the arc for *a* should be after the arc for *b*, then the comparator must return a number greater than zero; returning zero means that the relative order of *a* and *b* is unspecified. For example, to sort arcs by ascending value:\n\n```js\npie.sortValues(function(a, b) { return a - b; });\n```\n\nSorting does not affect the order of the [generated arc array](#_pie) which is always in the same order as the input data array; it merely affects the computed angles of each arc. The first arc starts at the [start angle](#pie_startAngle) and the last arc ends at the [end angle](#pie_endAngle).\n\n<a name=\"pie_startAngle\" href=\"#pie_startAngle\">#</a> <i>pie</i>.<b>startAngle</b>([<i>angle</i>])\n\nIf *angle* is specified, sets the overall start angle of the pie to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current start angle accessor, which defaults to:\n\n```js\nfunction startAngle() {\n return 0;\n}\n```\n\nThe start angle here means the *overall* start angle of the pie, *i.e.*, the start angle of the first arc. The start angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.\n\n<a name=\"pie_endAngle\" href=\"#pie_endAngle\">#</a> <i>pie</i>.<b>endAngle</b>([<i>angle</i>])\n\nIf *angle* is specified, sets the overall end angle of the pie to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current end angle accessor, which defaults to:\n\n```js\nfunction endAngle() {\n return 2 * Math.PI;\n}\n```\n\nThe end angle here means the *overall* end angle of the pie, *i.e.*, the end angle of the last arc. The end angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians, with 0 at -*y* (12 o’clock) and positive angles proceeding clockwise.\n\nThe value of the end angle is constrained to [startAngle](#pie_startAngle) ± τ, such that |endAngle - startAngle| ≤ τ.\n\n<a name=\"pie_padAngle\" href=\"#pie_padAngle\">#</a> <i>pie</i>.<b>padAngle</b>([<i>angle</i>])\n\nIf *angle* is specified, sets the pad angle to the specified function or number and returns this pie generator. If *angle* is not specified, returns the current pad angle accessor, which defaults to:\n\n```js\nfunction padAngle() {\n return 0;\n}\n```\n\nThe pad angle here means the angular separation between each adjacent arc. The total amount of padding reserved is the specified *angle* times the number of elements in the input data array, and at most |endAngle - startAngle|; the remaining space is then divided proportionally by [value](#pie_value) such that the relative area of each arc is preserved. See the [pie padding animation](http://bl.ocks.org/mbostock/3e961b4c97a1b543fff2) for illustration. The pad angle accessor is invoked once, being passed the same arguments and `this` context as the [pie generator](#_pie). The units of *angle* are arbitrary, but if you plan to use the pie generator in conjunction with an [arc generator](#arcs), you should specify an angle in radians.\n\n### Lines\n\n[<img width=\"295\" height=\"154\" alt=\"Line Chart\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/line.png\">](http://bl.ocks.org/mbostock/1550e57e12e73b86ad9e)\n\nThe line generator produces a [spline](https://en.wikipedia.org/wiki/Spline_\\(mathematics\\)) or [polyline](https://en.wikipedia.org/wiki/Polygonal_chain), as in a line chart. Lines also appear in many other visualization types, such as the links in [hierarchical edge bundling](http://bl.ocks.org/mbostock/7607999).\n\n<a name=\"line\" href=\"#line\">#</a> d3.<b>line</b>()\n\nConstructs a new line generator with the default settings.\n\n<a name=\"_line\" href=\"#_line\">#</a> <i>line</i>(<i>data</i>)\n\nGenerates a line for the given array of *data*. Depending on this line generator’s associated [curve](#line_curve), the given input *data* may need to be sorted by *x*-value before being passed to the line generator. If the line generator has a [context](#line_context), then the line is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.\n\n<a name=\"line_x\" href=\"#line_x\">#</a> <i>line</i>.<b>x</b>([<i>x</i>])\n\nIf *x* is specified, sets the x accessor to the specified function or number and returns this line generator. If *x* is not specified, returns the current x accessor, which defaults to:\n\n```js\nfunction x(d) {\n return d[0];\n}\n```\n\nWhen a line is [generated](#_line), the x accessor will be invoked for each [defined](#line_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default x accessor assumes that the input data are two-element arrays of numbers. If your data are in a different format, or if you wish to transform the data before rendering, then you should specify a custom accessor. For example, if `x` is a [time scale](https://github.com/d3/d3-scale#time-scales) and `y` is a [linear scale](https://github.com/d3/d3-scale#linear-scales):\n\n```js\nvar data = [\n {date: new Date(2007, 3, 24), value: 93.24},\n {date: new Date(2007, 3, 25), value: 95.35},\n {date: new Date(2007, 3, 26), value: 98.84},\n {date: new Date(2007, 3, 27), value: 99.92},\n {date: new Date(2007, 3, 30), value: 99.80},\n {date: new Date(2007, 4, 1), value: 99.47},\n …\n];\n\nvar line = d3.line()\n .x(function(d) { return x(d.date); })\n .y(function(d) { return y(d.value); });\n```\n\n<a name=\"line_y\" href=\"#line_y\">#</a> <i>line</i>.<b>y</b>([<i>y</i>])\n\nIf *y* is specified, sets the y accessor to the specified function or number and returns this line generator. If *y* is not specified, returns the current y accessor, which defaults to:\n\n```js\nfunction y(d) {\n return d[1];\n}\n```\n\nWhen a line is [generated](#_line), the y accessor will be invoked for each [defined](#line_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default y accessor assumes that the input data are two-element arrays of numbers. See [*line*.x](#line_x) for more information.\n\n<a name=\"line_defined\" href=\"#line_defined\">#</a> <i>line</i>.<b>defined</b>([<i>defined</i>])\n\nIf *defined* is specified, sets the defined accessor to the specified function or boolean and returns this line generator. If *defined* is not specified, returns the current defined accessor, which defaults to:\n\n```js\nfunction defined() {\n return true;\n}\n```\n\nThe default accessor thus assumes that the input data is always defined. When a line is [generated](#_line), the defined accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. If the given element is defined (*i.e.*, if the defined accessor returns a truthy value for this element), the [x](#line_x) and [y](#line_y) accessors will subsequently be evaluated and the point will be added to the current line segment. Otherwise, the element will be skipped, the current line segment will be ended, and a new line segment will be generated for the next defined point. As a result, the generated line may have several discrete segments. For example:\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/line-defined.png\" width=\"480\" height=\"250\" alt=\"Line with Missing Data\">](http://bl.ocks.org/mbostock/0533f44f2cfabecc5e3a)\n\nNote that if a line segment consists of only a single point, it may appear invisible unless rendered with rounded or square [line caps](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap). In addition, some curves such as [curveCardinalOpen](#curveCardinalOpen) only render a visible segment if it contains multiple points.\n\n<a name=\"line_curve\" href=\"#line_curve\">#</a> <i>line</i>.<b>curve</b>([<i>curve</i>])\n\nIf *curve* is specified, sets the [curve factory](#curves) and returns this line generator. If *curve* is not specified, returns the current curve factory, which defaults to [curveLinear](#curveLinear).\n\n<a name=\"line_context\" href=\"#line_context\">#</a> <i>line</i>.<b>context</b>([<i>context</i>])\n\nIf *context* is specified, sets the context and returns this line generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated line](#_line) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated line is returned.\n\n<a name=\"radialLine\" href=\"#radialLine\">#</a> d3.<b>radialLine</b>()\n\n<img alt=\"Radial Line\" width=\"250\" height=\"250\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/line-radial.png\">\n\nConstructs a new radial line generator with the default settings. A radial line generator is equivalent to the standard Cartesian [line generator](#line), except the [x](#line_x) and [y](#line_y) accessors are replaced with [angle](#radialLine_angle) and [radius](#radialLine_radius) accessors. Radial lines are always positioned relative to ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to change the origin.\n\n<a name=\"_radialLine\" href=\"#_radialLine\">#</a> <i>radialLine</i>(<i>data</i>)\n\nEquivalent to [*line*](#_line).\n\n<a name=\"radialLine_angle\" href=\"#radialLine_angle\">#</a> <i>radialLine</i>.<b>angle</b>([<i>angle</i>])\n\nEquivalent to [*line*.x](#line_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).\n\n<a name=\"radialLine_radius\" href=\"#radialLine_radius\">#</a> <i>radialLine</i>.<b>radius</b>([<i>radius</i>])\n\nEquivalent to [*line*.y](#line_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.\n\n<a name=\"radialLine_defined\" href=\"#radialLine_defined\">#</a> <i>radialLine</i>.<b>defined</b>([<i>defined</i>])\n\nEquivalent to [*line*.defined](#line_defined).\n\n<a name=\"radialLine_curve\" href=\"#radialLine_curve\">#</a> <i>radialLine</i>.<b>curve</b>([<i>curve</i>])\n\nEquivalent to [*line*.curve](#line_curve). Note that [curveMonotoneX](#curveMonotoneX) or [curveMonotoneY](#curveMonotoneY) are not recommended for radial lines because they assume that the data is monotonic in *x* or *y*, which is typically untrue of radial lines.\n\n<a name=\"radialLine_context\" href=\"#radialLine_context\">#</a> <i>radialLine</i>.<b>context</b>([<i>context</i>])\n\nEquivalent to [*line*.context](#line_context).\n\n### Areas\n\n[<img alt=\"Area Chart\" width=\"295\" height=\"154\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/area.png\">](http://bl.ocks.org/mbostock/3883195)[<img alt=\"Stacked Area Chart\" width=\"295\" height=\"154\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/area-stacked.png\">](http://bl.ocks.org/mbostock/3885211)[<img alt=\"Difference Chart\" width=\"295\" height=\"154\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/area-difference.png\">](http://bl.ocks.org/mbostock/3894205)\n\nThe area generator produces an area, as in an area chart. An area is defined by two bounding [lines](#lines), either splines or polylines. Typically, the two lines share the same [*x*-values](#area_x) ([x0](#area_x0) = [x1](#area_x1)), differing only in *y*-value ([y0](#area_y0) and [y1](#area_y1)); most commonly, y0 is defined as a constant representing [zero](http://www.vox.com/2015/11/19/9758062/y-axis-zero-chart). The first line (the <i>topline</i>) is defined by x1 and y1 and is rendered first; the second line (the <i>baseline</i>) is defined by x0 and y0 and is rendered second, with the points in reverse order. With a [curveLinear](#curveLinear) [curve](#area_curve), this produces a clockwise polygon.\n\n<a name=\"area\" href=\"#area\">#</a> d3.<b>area</b>()\n\nConstructs a new area generator with the default settings.\n\n<a name=\"_area\" href=\"#_area\">#</a> <i>area</i>(<i>data</i>)\n\nGenerates an area for the given array of *data*. Depending on this area generator’s associated [curve](#area_curve), the given input *data* may need to be sorted by *x*-value before being passed to the area generator. If the area generator has a [context](#line_context), then the area is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.\n\n<a name=\"area_x\" href=\"#area_x\">#</a> <i>area</i>.<b>x</b>([<i>x</i>])\n\nIf *x* is specified, sets [x0](#area_x0) to *x* and [x1](#area_x1) to null and returns this area generator. If *x* is not specified, returns the current x0 accessor.\n\n<a name=\"area_x0\" href=\"#area_x0\">#</a> <i>area</i>.<b>x0</b>([<i>x</i>])\n\nIf *x* is specified, sets the x0 accessor to the specified function or number and returns this area generator. If *x* is not specified, returns the current x0 accessor, which defaults to:\n\n```js\nfunction x(d) {\n return d[0];\n}\n```\n\nWhen an area is [generated](#_area), the x0 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default x0 accessor assumes that the input data are two-element arrays of numbers. If your data are in a different format, or if you wish to transform the data before rendering, then you should specify a custom accessor. For example, if `x` is a [time scale](https://github.com/d3/d3-scale#time-scales) and `y` is a [linear scale](https://github.com/d3/d3-scale#linear-scales):\n\n```js\nvar data = [\n {date: new Date(2007, 3, 24), value: 93.24},\n {date: new Date(2007, 3, 25), value: 95.35},\n {date: new Date(2007, 3, 26), value: 98.84},\n {date: new Date(2007, 3, 27), value: 99.92},\n {date: new Date(2007, 3, 30), value: 99.80},\n {date: new Date(2007, 4, 1), value: 99.47},\n …\n];\n\nvar area = d3.area()\n .x(function(d) { return x(d.date); })\n .y1(function(d) { return y(d.value); })\n .y0(y(0));\n```\n\n<a name=\"area_x1\" href=\"#area_x1\">#</a> <i>area</i>.<b>x1</b>([<i>x</i>])\n\nIf *x* is specified, sets the x1 accessor to the specified function or number and returns this area generator. If *x* is not specified, returns the current x1 accessor, which defaults to null, indicating that the previously-computed [x0](#area_x0) value should be reused for the x1 value.\n\nWhen an area is [generated](#_area), the x1 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.\n\n<a name=\"area_y\" href=\"#area_y\">#</a> <i>area</i>.<b>y</b>([<i>y</i>])\n\nIf *y* is specified, sets [y0](#area_y0) to *y* and [y1](#area_y1) to null and returns this area generator. If *y* is not specified, returns the current y0 accessor.\n\n<a name=\"area_y0\" href=\"#area_y0\">#</a> <i>area</i>.<b>y0</b>([<i>y</i>])\n\nIf *y* is specified, sets the y0 accessor to the specified function or number and returns this area generator. If *y* is not specified, returns the current y0 accessor, which defaults to:\n\n```js\nfunction y() {\n return 0;\n}\n```\n\nWhen an area is [generated](#_area), the y0 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.\n\n<a name=\"area_y1\" href=\"#area_y1\">#</a> <i>area</i>.<b>y1</b>([<i>y</i>])\n\nIf *y* is specified, sets the y1 accessor to the specified function or number and returns this area generator. If *y* is not specified, returns the current y1 accessor, which defaults to:\n\n```js\nfunction y(d) {\n return d[1];\n}\n```\n\nA null accessor is also allowed, indicating that the previously-computed [y0](#area_y0) value should be reused for the y1 value. When an area is [generated](#_area), the y1 accessor will be invoked for each [defined](#area_defined) element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. See [*area*.x0](#area_x0) for more information.\n\n<a name=\"area_defined\" href=\"#area_defined\">#</a> <i>area</i>.<b>defined</b>([<i>defined</i>])\n\nIf *defined* is specified, sets the defined accessor to the specified function or boolean and returns this area generator. If *defined* is not specified, returns the current defined accessor, which defaults to:\n\n```js\nfunction defined() {\n return true;\n}\n```\n\nThe default accessor thus assumes that the input data is always defined. When an area is [generated](#_area), the defined accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. If the given element is defined (*i.e.*, if the defined accessor returns a truthy value for this element), the [x0](#area_x0), [x1](#area_x1), [y0](#area_y0) and [y1](#area_y1) accessors will subsequently be evaluated and the point will be added to the current area segment. Otherwise, the element will be skipped, the current area segment will be ended, and a new area segment will be generated for the next defined point. As a result, the generated area may have several discrete segments. For example:\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/area-defined.png\" width=\"480\" height=\"250\" alt=\"Area with Missing Data\">](http://bl.ocks.org/mbostock/3035090)\n\nNote that if an area segment consists of only a single point, it may appear invisible unless rendered with rounded or square [line caps](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap). In addition, some curves such as [curveCardinalOpen](#curveCardinalOpen) only render a visible segment if it contains multiple points.\n\n<a name=\"area_curve\" href=\"#area_curve\">#</a> <i>area</i>.<b>curve</b>([<i>curve</i>])\n\nIf *curve* is specified, sets the [curve factory](#curves) and returns this area generator. If *curve* is not specified, returns the current curve factory, which defaults to [curveLinear](#curveLinear).\n\n<a name=\"area_context\" href=\"#area_context\">#</a> <i>area</i>.<b>context</b>([<i>context</i>])\n\nIf *context* is specified, sets the context and returns this area generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated area](#_area) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated area is returned.\n\n<a name=\"area_lineX0\" href=\"#area_lineX0\">#</a> <i>area</i>.<b>lineX0</b>()\n<br><a name=\"area_lineY0\" href=\"#area_lineY0\">#</a> <i>area</i>.<b>lineY0</b>()\n\nReturns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x0*-accessor](#area_x0), and the line’s [*y*-accessor](#line_y) is this area’s [*y0*-accessor](#area_y0).\n\n<a name=\"area_lineX1\" href=\"#area_lineX1\">#</a> <i>area</i>.<b>lineX1</b>()\n\nReturns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x1*-accessor](#area_x1), and the line’s [*y*-accessor](#line_y) is this area’s [*y0*-accessor](#area_y0).\n\n<a name=\"area_lineY1\" href=\"#area_lineY1\">#</a> <i>area</i>.<b>lineY1</b>()\n\nReturns a new [line generator](#lines) that has this area generator’s current [defined accessor](#area_defined), [curve](#area_curve) and [context](#area_context). The line’s [*x*-accessor](#line_x) is this area’s [*x0*-accessor](#area_x0), and the line’s [*y*-accessor](#line_y) is this area’s [*y1*-accessor](#area_y1).\n\n<a name=\"radialArea\" href=\"#radialArea\">#</a> d3.<b>radialArea</b>()\n\n<img alt=\"Radial Area\" width=\"250\" height=\"250\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/area-radial.png\">\n\nConstructs a new radial area generator with the default settings. A radial area generator is equivalent to the standard Cartesian [area generator](#area), except the [x](#area_x) and [y](#area_y) accessors are replaced with [angle](#radialArea_angle) and [radius](#radialArea_radius) accessors. Radial areas are always positioned relative to ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to change the origin.\n\n<a name=\"_radialArea\" href=\"#_radialArea\">#</a> <i>radialArea</i>(<i>data</i>)\n\nEquivalent to [*area*](#_area).\n\n<a name=\"radialArea_angle\" href=\"#radialArea_angle\">#</a> <i>radialArea</i>.<b>angle</b>([<i>angle</i>])\n\nEquivalent to [*area*.x](#area_x), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock).\n\n<a name=\"radialArea_startAngle\" href=\"#radialArea_startAngle\">#</a> <i>radialArea</i>.<b>startAngle</b>([<i>angle</i>])\n\nEquivalent to [*area*.x0](#area_x0), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock). Note: typically [angle](#radialArea_angle) is used instead of setting separate start and end angles.\n\n<a name=\"radialArea_endAngle\" href=\"#radialArea_endAngle\">#</a> <i>radialArea</i>.<b>endAngle</b>([<i>angle</i>])\n\nEquivalent to [*area*.x1](#area_x1), except the accessor returns the angle in radians, with 0 at -*y* (12 o’clock). Note: typically [angle](#radialArea_angle) is used instead of setting separate start and end angles.\n\n<a name=\"radialArea_radius\" href=\"#radialArea_radius\">#</a> <i>radialArea</i>.<b>radius</b>([<i>radius</i>])\n\nEquivalent to [*area*.y](#area_y), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.\n\n<a name=\"radialArea_innerRadius\" href=\"#radialArea_innerRadius\">#</a> <i>radialArea</i>.<b>innerRadius</b>([<i>radius</i>])\n\nEquivalent to [*area*.y0](#area_y0), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.\n\n<a name=\"radialArea_outerRadius\" href=\"#radialArea_outerRadius\">#</a> <i>radialArea</i>.<b>outerRadius</b>([<i>radius</i>])\n\nEquivalent to [*area*.y1](#area_y1), except the accessor returns the radius: the distance from the origin ⟨0,0⟩.\n\n<a name=\"radialArea_defined\" href=\"#radialArea_defined\">#</a> <i>radialArea</i>.<b>defined</b>([<i>defined</i>])\n\nEquivalent to [*area*.defined](#area_defined).\n\n<a name=\"radialArea_curve\" href=\"#radialArea_curve\">#</a> <i>radialArea</i>.<b>curve</b>([<i>curve</i>])\n\nEquivalent to [*area*.curve](#area_curve). Note that [curveMonotoneX](#curveMonotoneX) or [curveMonotoneY](#curveMonotoneY) are not recommended for radial areas because they assume that the data is monotonic in *x* or *y*, which is typically untrue of radial areas.\n\n<a name=\"radialArea_context\" href=\"#radialArea_context\">#</a> <i>radialArea</i>.<b>context</b>([<i>context</i>])\n\nEquivalent to [*line*.context](#line_context).\n\n<a name=\"radialArea_lineStartAngle\" href=\"#radialArea_lineStartAngle\">#</a> <i>radialArea</i>.<b>lineStartAngle</b>()\n<br><a name=\"radialArea_lineInnerRadius\" href=\"#radialArea_lineInnerRadius\">#</a> <i>radialArea</i>.<b>lineInnerRadius</b>()\n\nReturns a new [radial line generator](#radialLine) that has this radial area generator’s current [defined accessor](#radialArea_defined), [curve](#radialArea_curve) and [context](#radialArea_context). The line’s [angle accessor](#radialLine_angle) is this area’s [start angle accessor](#radialArea_startAngle), and the line’s [radius accessor](#radialLine_radius) is this area’s [inner radius accessor](#radialArea_innerRadius).\n\n<a name=\"radialArea_lineEndAngle\" href=\"#radialArea_lineEndAngle\">#</a> <i>radialArea</i>.<b>lineEndAngle</b>()\n\nReturns a new [radial line generator](#radialLine) that has this radial area generator’s current [defined accessor](#radialArea_defined), [curve](#radialArea_curve) and [context](#radialArea_context). The line’s [angle accessor](#radialLine_angle) is this area’s [end angle accessor](#radialArea_endAngle), and the line’s [radius accessor](#radialLine_radius) is this area’s [inner radius accessor](#radialArea_innerRadius).\n\n<a name=\"radialArea_lineOuterRadius\" href=\"#radialArea_lineOuterRadius\">#</a> <i>radialArea</i>.<b>lineOuterRadius</b>()\n\nReturns a new [radial line generator](#radialLine) that has this radial area generator’s current [defined accessor](#radialArea_defined), [curve](#radialArea_curve) and [context](#radialArea_context). The line’s [angle accessor](#radialLine_angle) is this area’s [start angle accessor](#radialArea_startAngle), and the line’s [radius accessor](#radialLine_radius) is this area’s [outer radius accessor](#radialArea_outerRadius).\n\n### Curves\n\nWhile [lines](#lines) are defined as a sequence of two-dimensional [*x*, *y*] points, and [areas](#areas) are similarly defined by a topline and a baseline, there remains the task of transforming this discrete representation into a continuous shape: *i.e.*, how to interpolate between the points. A variety of curves are provided for this purpose.\n\nCurves are typically not constructed or used directly, instead being passed to [*line*.curve](#line_curve) and [*area*.curve](#area_curve). For example:\n\n```js\nvar line = d3.line()\n .x(function(d) { return x(d.date); })\n .y(function(d) { return y(d.value); })\n .curve(d3.curveCatmullRom.alpha(0.5));\n```\n\n<a name=\"curveBasis\" href=\"#curveBasis\">#</a> d3.<b>curveBasis</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/basis.png\" width=\"888\" height=\"240\" alt=\"basis\">\n\nProduces a cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. The first and last points are triplicated such that the spline starts at the first point and ends at the last point, and is tangent to the line between the first and second points, and to the line between the penultimate and last points.\n\n<a name=\"curveBasisClosed\" href=\"#curveBasisClosed\">#</a> d3.<b>curveBasisClosed</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/basisClosed.png\" width=\"888\" height=\"240\" alt=\"basisClosed\">\n\nProduces a closed cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. When a line segment ends, the first three control points are repeated, producing a closed loop with C2 continuity.\n\n<a name=\"curveBasisOpen\" href=\"#curveBasisOpen\">#</a> d3.<b>curveBasisOpen</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/basisOpen.png\" width=\"888\" height=\"240\" alt=\"basisOpen\">\n\nProduces a cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points. Unlike [basis](#basis), the first and last points are not repeated, and thus the curve typically does not intersect these points.\n\n<a name=\"curveBundle\" href=\"#curveBundle\">#</a> d3.<b>curveBundle</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/bundle.png\" width=\"888\" height=\"240\" alt=\"bundle\">\n\nProduces a straightened cubic [basis spline](https://en.wikipedia.org/wiki/B-spline) using the specified control points, with the spline straightened according to the curve’s [*beta*](#curveBundle_beta), which defaults to 0.85. This curve is typically used in [hierarchical edge bundling](http://bl.ocks.org/mbostock/7607999) to disambiguate connections, as proposed by [Danny Holten](https://www.win.tue.nl/vis1/home/dholten/) in [Hierarchical Edge Bundles: Visualization of Adjacency Relations in Hierarchical Data](https://www.win.tue.nl/vis1/home/dholten/papers/bundles_infovis.pdf). This curve does not implement [*curve*.areaStart](#curve_areaStart) and [*curve*.areaEnd](#curve_areaEnd); it is intended to work with [d3.line](#lines), not [d3.area](#areas).\n\n<a name=\"curveBundle_beta\" href=\"#curveBundle_beta\">#</a> <i>bundle</i>.<b>beta</b>(<i>beta</i>)\n\nReturns a bundle curve with the specified *beta* in the range [0, 1], representing the bundle strength. If *beta* equals zero, a straight line between the first and last point is produced; if *beta* equals one, a standard [basis](#basis) spline is produced. For example:\n\n```js\nvar line = d3.line().curve(d3.curveBundle.beta(0.5));\n```\n\n<a name=\"curveCardinal\" href=\"#curveCardinal\">#</a> d3.<b>curveCardinal</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/cardinal.png\" width=\"888\" height=\"240\" alt=\"cardinal\">\n\nProduces a cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points, with one-sided differences used for the first and last piece. The default [tension](#curveCardinal_tension) is 0.\n\n<a name=\"curveCardinalClosed\" href=\"#curveCardinalClosed\">#</a> d3.<b>curveCardinalClosed</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/cardinalClosed.png\" width=\"888\" height=\"240\" alt=\"cardinalClosed\">\n\nProduces a closed cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points. When a line segment ends, the first three control points are repeated, producing a closed loop. The default [tension](#curveCardinal_tension) is 0.\n\n<a name=\"curveCardinalOpen\" href=\"#curveCardinalOpen\">#</a> d3.<b>curveCardinalOpen</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/cardinalOpen.png\" width=\"888\" height=\"240\" alt=\"cardinalOpen\">\n\nProduces a cubic [cardinal spline](https://en.wikipedia.org/wiki/Cubic_Hermite_spline#Cardinal_spline) using the specified control points. Unlike [curveCardinal](#curveCardinal), one-sided differences are not used for the first and last piece, and thus the curve starts at the second point and ends at the penultimate point. The default [tension](#curveCardinal_tension) is 0.\n\n<a name=\"curveCardinal_tension\" href=\"#curveCardinal_tension\">#</a> <i>cardinal</i>.<b>tension</b>(<i>tension</i>)\n\nReturns a cardinal curve with the specified *tension* in the range [0, 1]. The *tension* determines the length of the tangents: a *tension* of one yields all zero tangents, equivalent to [curveLinear](#curveLinear); a *tension* of zero produces a uniform [Catmull–Rom](#curveCatmullRom) spline. For example:\n\n```js\nvar line = d3.line().curve(d3.curveCardinal.tension(0.5));\n```\n\n<a name=\"curveCatmullRom\" href=\"#curveCatmullRom\">#</a> d3.<b>curveCatmullRom</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/catmullRom.png\" width=\"888\" height=\"240\" alt=\"catmullRom\">\n\nProduces a cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#catmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. in [On the Parameterization of Catmull–Rom Curves](http://www.cemyuksel.com/research/catmullrom_param/), with one-sided differences used for the first and last piece.\n\n<a name=\"curveCatmullRomClosed\" href=\"#curveCatmullRomClosed\">#</a> d3.<b>curveCatmullRomClosed</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/catmullRomClosed.png\" width=\"888\" height=\"330\" alt=\"catmullRomClosed\">\n\nProduces a closed cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#catmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. When a line segment ends, the first three control points are repeated, producing a closed loop.\n\n<a name=\"curveCatmullRomOpen\" href=\"#curveCatmullRomOpen\">#</a> d3.<b>curveCatmullRomOpen</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/catmullRomOpen.png\" width=\"888\" height=\"240\" alt=\"catmullRomOpen\">\n\nProduces a cubic Catmull–Rom spline using the specified control points and the parameter [*alpha*](#catmullRom_alpha), which defaults to 0.5, as proposed by Yuksel et al. Unlike [curveCatmullRom](#curveCatmullRom), one-sided differences are not used for the first and last piece, and thus the curve starts at the second point and ends at the penultimate point.\n\n<a name=\"curveCatmullRom_alpha\" href=\"#curveCatmullRom_alpha\">#</a> <i>catmullRom</i>.<b>alpha</b>(<i>alpha</i>)\n\nReturns a cubic Catmull–Rom curve with the specified *alpha* in the range [0, 1]. If *alpha* is zero, produces a uniform spline, equivalent to [curveCardinal](#curveCardinal) with a tension of zero; if *alpha* is one, produces a chordal spline; if *alpha* is 0.5, produces a [centripetal spline](https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline). Centripetal splines are recommended to avoid self-intersections and overshoot. For example:\n\n```js\nvar line = d3.line().curve(d3.curveCatmullRom.alpha(0.5));\n```\n\n<a name=\"curveLinear\" href=\"#curveLinear\">#</a> d3.<b>curveLinear</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/linear.png\" width=\"888\" height=\"240\" alt=\"linear\">\n\nProduces a polyline through the specified points.\n\n<a name=\"curveLinearClosed\" href=\"#curveLinearClosed\">#</a> d3.<b>curveLinearClosed</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/linearClosed.png\" width=\"888\" height=\"240\" alt=\"linearClosed\">\n\nProduces a closed polyline through the specified points by repeating the first point when the line segment ends.\n\n<a name=\"curveMonotoneX\" href=\"#curveMonotoneX\">#</a> d3.<b>curveMonotoneX</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/monotoneX.png\" width=\"888\" height=\"240\" alt=\"monotoneX\">\n\nProduces a cubic spline that [preserves monotonicity](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation) in *y*, assuming monotonicity in *x*, as proposed by Steffen in [A simple method for monotonic interpolation in one dimension](http://adsabs.harvard.edu/full/1990A%26A...239..443S): “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.”\n\n<a name=\"curveMonotoneY\" href=\"#curveMonotoneY\">#</a> d3.<b>curveMonotoneY</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/monotoneY.png\" width=\"888\" height=\"240\" alt=\"monotoneY\">\n\nProduces a cubic spline that [preserves monotonicity](https://en.wikipedia.org/wiki/Monotone_cubic_interpolation) in *x*, assuming monotonicity in *y*, as proposed by Steffen in [A simple method for monotonic interpolation in one dimension](http://adsabs.harvard.edu/full/1990A%26A...239..443S): “a smooth curve with continuous first-order derivatives that passes through any given set of data points without spurious oscillations. Local extrema can occur only at grid points where they are given by the data, but not in between two adjacent grid points.”\n\n<a name=\"curveNatural\" href=\"#curveNatural\">#</a> d3.<b>curveNatural</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/natural.png\" width=\"888\" height=\"240\" alt=\"natural\">\n\nProduces a [natural](https://en.wikipedia.org/wiki/Spline_interpolation) [cubic spline](http://mathworld.wolfram.com/CubicSpline.html) with the second derivative of the spline set to zero at the endpoints.\n\n<a name=\"curveStep\" href=\"#curveStep\">#</a> d3.<b>curveStep</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/step.png\" width=\"888\" height=\"240\" alt=\"step\">\n\nProduces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes at the midpoint of each pair of adjacent *x*-values.\n\n<a name=\"curveStepAfter\" href=\"#curveStepAfter\">#</a> d3.<b>curveStepAfter</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/stepAfter.png\" width=\"888\" height=\"240\" alt=\"stepAfter\">\n\nProduces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes after the *x*-value.\n\n<a name=\"curveStepBefore\" href=\"#curveStepBefore\">#</a> d3.<b>curveStepBefore</b>(<i>context</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/stepBefore.png\" width=\"888\" height=\"240\" alt=\"stepBefore\">\n\nProduces a piecewise constant function (a [step function](https://en.wikipedia.org/wiki/Step_function)) consisting of alternating horizontal and vertical lines. The *y*-value changes before the *x*-value.\n\n### Custom Curves\n\nCurves are typically not used directly, instead being passed to [*line*.curve](#line_curve) and [*area*.curve](#area_curve). However, you can define your own curve implementation should none of the built-in curves satisfy your needs using the following interface. You can also use this low-level interface with a built-in curve type as an alternative to the line and area generators.\n\n<a name=\"curve_areaStart\" href=\"#curve_areaStart\">#</a> <i>curve</i>.<b>areaStart</b>()\n\nIndicates the start of a new area segment. Each area segment consists of exactly two [line segments](#curve_lineStart): the topline, followed by the baseline, with the baseline points in reverse order.\n\n<a name=\"curve_areaEnd\" href=\"#curve_areaEnd\">#</a> <i>curve</i>.<b>areaEnd</b>()\n\nIndicates the end of the current area segment.\n\n<a name=\"curve_lineStart\" href=\"#curve_lineStart\">#</a> <i>curve</i>.<b>lineStart</b>()\n\nIndicates the start of a new line segment. Zero or more [points](#curve_point) will follow.\n\n<a name=\"curve_lineEnd\" href=\"#curve_lineEnd\">#</a> <i>curve</i>.<b>lineEnd</b>()\n\nIndicates the end of the current line segment.\n\n<a name=\"curve_point\" href=\"#curve_point\">#</a> <i>curve</i>.<b>point</b>(<i>x</i>, <i>y</i>)\n\nIndicates a new point in the current line segment with the given *x*- and *y*-values.\n\n### Symbols\n\n<a href=\"#symbolCircle\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/circle.png\" width=\"100\" height=\"100\"></a><a href=\"#symbolCross\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/cross.png\" width=\"100\" height=\"100\"></a><a href=\"#symbolDiamond\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/diamond.png\" width=\"100\" height=\"100\"></a><a href=\"#symbolSquare\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/square.png\" width=\"100\" height=\"100\"></a><a href=\"#symbolStar\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/star.png\" width=\"100\" height=\"100\"></a><a href=\"#symbolTriangle\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/triangle.png\" width=\"100\" height=\"100\"><a href=\"#symbolWye\"><img src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/wye.png\" width=\"100\" height=\"100\"></a>\n\nSymbols provide a categorical shape encoding as is commonly used in scatterplots. Symbols are always centered at ⟨0,0⟩; use a transform (see: [SVG](http://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](http://www.w3.org/TR/2dcontext/#transformations)) to move the arc to a different position.\n\n<a name=\"symbol\" href=\"#symbol\">#</a> d3.<b>symbol</b>()\n\nConstructs a new symbol generator with the default settings.\n\n<a name=\"_symbol\" href=\"#_symbol\">#</a> <i>symbol</i>(<i>arguments</i>…)\n\nGenerates a symbol for the given *arguments*. The *arguments* are arbitrary; they are simply propagated to the symbol generator’s accessor functions along with the `this` object. For example, with the default settings, no arguments are needed to produce a circle with area 64 square pixels. If the symbol generator has a [context](#symbol_context), then the symbol is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls and this function returns void. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string is returned.\n\n<a name=\"symbol_type\" href=\"#symbol_type\">#</a> <i>symbol</i>.<b>type</b>([<i>type</i>])\n\nIf *type* is specified, sets the symbol type to the specified function or symbol type and returns this line generator. If *type* is not specified, returns the current symbol type accessor, which defaults to:\n\n```js\nfunction type() {\n return circle;\n}\n```\n\nSee [symbols](#symbols) for the set of built-in symbol types. To implement a custom symbol type, pass an object that implements [*symbolType*.draw](#symbolType_draw).\n\n<a name=\"symbol_size\" href=\"#symbol_size\">#</a> <i>symbol</i>.<b>size</b>([<i>size</i>])\n\nIf *size* is specified, sets the size to the specified function or number and returns this symbol generator. If *size* is not specified, returns the current size accessor, which defaults to:\n\n```js\nfunction size() {\n return 64;\n}\n```\n\nSpecifying the size as a function is useful for constructing a scatterplot with a size encoding. If you wish to scale the symbol to fit a given bounding box, rather than by area, try [SVG’s getBBox](http://bl.ocks.org/mbostock/3dd515e692504c92ab65).\n\n<a name=\"symbol_context\" href=\"#symbol_context\">#</a> <i>symbol</i>.<b>context</b>([<i>context</i>])\n\nIf *context* is specified, sets the context and returns this symbol generator. If *context* is not specified, returns the current context, which defaults to null. If the context is not null, then the [generated symbol](#_symbol) is rendered to this context as a sequence of [path method](http://www.w3.org/TR/2dcontext/#canvaspathmethods) calls. Otherwise, a [path data](http://www.w3.org/TR/SVG/paths.html#PathData) string representing the generated symbol is returned.\n\n<a name=\"symbols\" href=\"#symbols\">#</a> d3.<b>symbols</b>\n\nAn array containing the set of all built-in symbol types: [circle](#symbolCircle), [cross](#symbolCross), [diamond](#symbolDiamond), [square](#symbolSquare), [star](#symbolStar), [triangle](#symbolTriangle), and [wye](#symbolWye). Useful for constructing the range of an [ordinal scale](https://github.com/d3/d3-scale#ordinal-scales) should you wish to use a shape encoding for categorical data.\n\n<a name=\"symbolCircle\" href=\"#symbolCircle\">#</a> d3.<b>symbolCircle</b>\n\nThe circle symbol type.\n\n<a name=\"symbolCross\" href=\"#symbolCross\">#</a> d3.<b>symbolCross</b>\n\nThe Greek cross symbol type, with arms of equal length.\n\n<a name=\"symbolDiamond\" href=\"#symbolDiamond\">#</a> d3.<b>symbolDiamond</b>\n\nThe rhombus symbol type.\n\n<a name=\"symbolSquare\" href=\"#symbolSquare\">#</a> d3.<b>symbolSquare</b>\n\nThe square symbol type.\n\n<a name=\"symbolStar\" href=\"#symbolStar\">#</a> d3.<b>symbolStar</b>\n\nThe pentagonal star (pentagram) symbol type.\n\n<a name=\"symbolTriangle\" href=\"#symbolTriangle\">#</a> d3.<b>symbolTriangle</b>\n\nThe up-pointing triangle symbol type.\n\n<a name=\"symbolWye\" href=\"#symbolWye\">#</a> d3.<b>symbolWye</b>\n\nThe Y-shape symbol type.\n\n### Custom Symbol Types\n\nSymbol types are typically not used directly, instead being passed to [*symbol*.type](#symbol_type). However, you can define your own sumbol type implementation should none of the built-in types satisfy your needs using the following interface. You can also use this low-level interface with a built-in symbol type as an alternative to the symbol generator.\n\n<a name=\"symbolType_draw\" href=\"#symbolType_draw\">#</a> <i>symbolType</i>.<b>draw</b>(<i>context</i>, <i>size</i>)\n\nRenders this symbol type to the specified *context* with the specified *size* in square pixels. The *context* implements the [CanvasPathMethods](http://www.w3.org/TR/2dcontext/#canvaspathmethods) interface. (Note that this is a subset of the CanvasRenderingContext2D interface!)\n\n### Stacks\n\n[<img alt=\"Stacked Bar Chart\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/stacked-bar.png\" width=\"295\" height=\"154\">](http://bl.ocks.org/mbostock/3886208)[<img alt=\"Streamgraph\" src=\"https://raw.githubusercontent.com/d3/d3-shape/master/img/stacked-stream.png\" width=\"295\" height=\"154\">](http://bl.ocks.org/mbostock/4060954)\n\nSome shape ty"},"npm":{"downloads":[{"from":"2016-10-18T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":21357},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":98757},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":217814},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":271030},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":291910}],"dependentsCount":48,"starsCount":1},"github":{"starsCount":1277,"forksCount":64,"subscribersCount":43,"issues":{"count":81,"openCount":8,"distribution":{"3600":10,"10800":9,"32400":9,"97200":11,"291600":8,"874800":4,"2624400":12,"7873200":10,"23619600":5,"70858800":3,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":359},{"username":"jviide","commitsCount":3},{"username":"ColinEberhardt","commitsCount":1},{"username":"ivanvanderbyl","commitsCount":1},{"username":"Devinsuit","commitsCount":1}],"commits":[{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":9},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":26},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":354}]},"source":{"files":{"readmeSize":75107,"testsSize":113779,"hasNpmIgnore":true},"repositorySize":961309,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":1390,"downloadsCount":72604.66666666667,"downloadsAcceleration":799.5288432267885,"dependentsCount":48},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9553835616438356,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.7651178828825577,"detail":{"quality":0.9260256430415238,"popularity":0.39241957749659395,"maintenance":0.9998952509894077}}}},{"package":{"name":"d3-selection","version":"1.0.2","description":"Data-driven DOM manipulation: select elements and join them to data.","keywords":["d3","d3-module","dom","selection","data-join"],"date":"2016-08-02T21:31:48.183Z","links":{"npm":"https://www.npmjs.com/package/d3-selection","homepage":"https://d3js.org/d3-selection/","repository":"https://github.com/d3/d3-selection","bugs":"https://github.com/d3/d3-selection/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7432667815514267,"detail":{"quality":0.9260256430415238,"popularity":0.32988340520718074,"maintenance":0.9999997051898752}},"searchScore":0.01073497,"metadata":{"analyzedAt":"2016-10-19T00:41:52.326Z","collected":{"metadata":{"name":"d3-selection","version":"1.0.2","description":"Data-driven DOM manipulation: select elements and join them to data.","keywords":["d3","d3-module","dom","selection","data-join"],"date":"2016-08-02T21:31:48.183Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-selection.git"},"links":{"npm":"https://www.npmjs.com/package/d3-selection","homepage":"https://d3js.org/d3-selection/","repository":"https://github.com/d3/d3-selection","bugs":"https://github.com/d3/d3-selection/issues"},"license":"BSD-3-Clause","devDependencies":{"eslint":"2","jsdom":"9","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":3},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":9},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":29},{"from":"2014-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":42}],"hasTestScript":true,"readme":"# d3-selection\n\nSelections allow powerful data-driven transformation of the document object model (DOM): set [attributes](#selection_attr), [styles](#selection_style), [properties](#selection_property), [HTML](#selection_html) or [text](#selection_text) content, and more. Using the [data join](#joining-data)’s [enter](#selection_enter) and [exit](#selection_enter) selections, you can also [add](#selection_append) or [remove](#selection_remove) elements to correspond to data.\n\nSelection methods typically return the current selection, or a new selection, allowing the concise application of multiple operations on a given selection via method chaining. For example, to set the class and color style of all paragraph elements in the current document:\n\n```js\nd3.selectAll(\"p\")\n .attr(\"class\", \"graf\")\n .style(\"color\", \"red\");\n```\n\nThis is equivalent to:\n\n```js\nvar p = d3.selectAll(\"p\");\np.attr(\"class\", \"graf\");\np.style(\"color\", \"red\");\n```\n\nBy convention, selection methods that return the current selection use *four* spaces of indent, while methods that return a new selection use only *two*. This helps reveal changes of context by making them stick out of the chain:\n\n```js\nd3.select(\"body\")\n .append(\"svg\")\n .attr(\"width\", 960)\n .attr(\"height\", 500)\n .append(\"g\")\n .attr(\"transform\", \"translate(20,20)\")\n .append(\"rect\")\n .attr(\"width\", 920)\n .attr(\"height\", 460);\n```\n\nSelections are immutable. All selection methods that affect which elements are selected (or their order) return a new selection rather than modifying the current selection. However, note that elements are necessarily mutable, as selections drive transformations of the document!\n\n## Installing\n\nIf you use NPM, `npm install d3-selection`. Otherwise, download the [latest release](https://github.com/d3/d3-selection/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-selection.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-selection.v1.min.js\"></script>\n<script>\n\nvar div = d3.selectAll(\"div\");\n\n</script>\n```\n\n[Try d3-selection in your browser.](https://tonicdev.com/npm/d3-selection)\n\n## API Reference\n\n* [Selecting Elements](#selecting-elements)\n* [Modifying Elements](#modifying-elements)\n* [Joining Data](#joining-data)\n* [Handling Events](#handling-events)\n* [Control Flow](#control-flow)\n* [Local Variables](#local-variables)\n* [Namespaces](#namespaces)\n\n### Selecting Elements\n\nSelection methods accept [W3C selector strings](http://www.w3.org/TR/selectors-api/) such as `.fancy` to select elements with the class *fancy*, or `div` to select DIV elements. Selection methods come in two forms: select and selectAll: the former selects only the first matching element, while the latter selects all matching elements in document order. The top-level selection methods, [d3.select](#select) and [d3.selectAll](#selectAll), query the entire document; the subselection methods, [*selection*.select](#selection_select) and [*selection*.selectAll](#selection_selectAll), restrict selection to descendants of the selected elements.\n\n<a name=\"selection\" href=\"#selection\">#</a> d3.<b>selection</b>()\n\n[Selects](#select) the root element, `document.documentElement`. This function can also be used to test for selections (`instanceof d3.selection`) or to extend the selection prototype. For example, to add a method to check checkboxes:\n\n```js\nd3.selection.prototype.checked = function(value) {\n return arguments.length < 1\n ? this.property(\"checked\")\n : this.property(\"checked\", !!value);\n};\n```\n\nAnd then to use:\n\n```js\nd3.selectAll(\"input[type=checkbox]\").checked(true);\n```\n\n<a name=\"select\" href=\"#select\">#</a> d3.<b>select</b>(<i>selector</i>)\n\nSelects the first element that matches the specified *selector* string. If no elements match the *selector*, returns an empty selection. If multiple elements match the *selector*, only the first matching element (in document order) will be selected. For example, to select the first anchor element:\n\n```js\nvar anchor = d3.select(\"a\");\n```\n\nIf the *selector* is not a string, instead selects the specified node; this is useful if you already have a reference to a node, such as `this` within an event listener or a global such as `document.body`. For example, to make a clicked paragraph red:\n\n```js\nd3.selectAll(\"p\").on(\"click\", function() {\n d3.select(this).style(\"color\", \"red\");\n});\n```\n\n<a name=\"selectAll\" href=\"#selectAll\">#</a> d3.<b>selectAll</b>(<i>selector</i>)\n\nSelects all elements that match the specified *selector* string. The elements will be selected in document order (top-to-bottom). If no elements in the document match the *selector*, or if the *selector* is null or undefined, returns an empty selection. For example, to select all paragraphs:\n\n```js\nvar paragraph = d3.selectAll(\"p\");\n```\n\nIf the *selector* is not a string, instead selects the specified array of nodes; this is useful if you already have a reference to nodes, such as `this.childNodes` within an event listener or a global such as `document.links`. The nodes may instead be a pseudo-array such as a `NodeList` or `arguments`. For example, to color all links red:\n\n```js\nd3.selectAll(document.links).style(\"color\", \"red\");\n```\n\n<a name=\"selection_select\" href=\"#selection_select\">#</a> <i>selection</i>.<b>select</b>(<i>selector</i>)\n\nFor each selected element, selects the first descendant element that matches the specified *selector* string. If no element matches the specified selector for the current element, the element at the current index will be null in the returned selection. (If the *selector* is null, every element in the returned selection will be null, resulting in an empty selection.) If the current element has associated data, this data is propagated to the corresponding selected element. If multiple elements match the selector, only the first matching element in document order is selected. For example, to select the first bold element in every paragraph:\n\n```js\nvar b = d3.selectAll(\"p\").select(\"b\");\n```\n\nIf the *selector* is a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. It must return an element, or null if there is no matching element. For example, to select the previous sibling of each paragraph:\n\n```js\nvar previous = d3.selectAll(\"p\").select(function() {\n return this.previousElementSibling;\n});\n```\n\nUnlike [*selection*.selectAll](#selection_selectAll), *selection*.select does not affect grouping: it preserves the existing group structure and indexes, and propagates data (if any) to selected children. Grouping plays an important role in the [data join](#joining-data). See [Nested Selections](http://bost.ocks.org/mike/nest/) and [How Selections Work](http://bost.ocks.org/mike/selection/) for more on this topic.\n\n<a name=\"selection_selectAll\" href=\"#selection_selectAll\">#</a> <i>selection</i>.<b>selectAll</b>(<i>selector</i>)\n\nFor each selected element, selects the descendant elements that match the specified *selector* string. The elements in the returned selection are grouped by their corresponding parent node in this selection. If no element matches the specified selector for the current element, or if the *selector* is null, the group at the current index will be empty. The selected elements do not inherit data from this selection; use [*selection*.data](#selection_data) to propagate data to children. For example, to select the bold elements in every paragraph:\n\n```js\nvar b = d3.selectAll(\"p\").selectAll(\"b\");\n```\n\nIf the *selector* is a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. It must return an array of elements (or a pseudo-array, such as a NodeList), or the empty array if there are no matching elements. For example, to select the previous and next siblings of each paragraph:\n\n```js\nvar sibling = d3.selectAll(\"p\").selectAll(function() {\n return [\n this.previousElementSibling,\n this.nextElementSibling\n ];\n});\n```\n\nUnlike [*selection*.select](#selection_select), *selection*.selectAll does affect grouping: each selected descendant is grouped by the parent element in the originating selection. Grouping plays an important role in the [data join](#joining-data). See [Nested Selections](http://bost.ocks.org/mike/nest/) and [How Selections Work](http://bost.ocks.org/mike/selection/) for more on this topic.\n\n<a name=\"selection_filter\" href=\"#selection_filter\">#</a> <i>selection</i>.<b>filter</b>(<i>filter</i>)\n\nFilters the selection, returning a new selection that contains only the elements for which the specified *filter* is true. The *filter* may be specified either as a selector string or a function. If a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element.\n\nFor example, to filter a selection of table rows to contain only even rows:\n\n```js\nvar even = d3.selectAll(\"tr\").filter(\":nth-child(even)\");\n```\n\nThis is approximately equivalent to using [d3.selectAll](#selectAll) directly, although the indexes may be different:\n\n```js\nvar even = d3.selectAll(\"tr:nth-child(even)\");\n```\n\nSimilarly, using a function:\n\n```js\nvar even = d3.selectAll(\"tr\").filter(function(d, i) { return i & 1; });\n```\n\nOr using [*selection*.select](#selection_select):\n\n```js\nvar even = d3.selectAll(\"tr\").select(function(d, i) { return i & 1 ? this : null; });\n```\n\nNote that the `:nth-child` pseudo-class is a one-based index rather than a zero-based index. Also, the above filter functions do not have precisely the same meaning as `:nth-child`; they rely on the selection index rather than the number of preceeding sibling elements in the DOM.\n\nThe returned filtered selection preserves the parents of this selection, but like [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), it does not preserve indexes as some elements may be removed; use [*selection*.select](#selection_select) to preserve the index, if needed.\n\n<a name=\"selection_merge\" href=\"#selection_merge\">#</a> <i>selection</i>.<b>merge</b>(<i>other</i>)\n\nReturns a new selection merging this selection with the specified *other* selection. The returned selection has the same number of groups and the same parents as this selection. Any missing (null) elements in this selection are filled with the corresponding element, if present (not null), from the specified *selection*. (If the *other* selection has additional groups or parents, they are ignored.)\n\nThis method is commonly used to merge the [enter](#selection_enter) and [update](#selection_data) selections after a [data-join](#joining-data). After modifying the entering and updating elements separately, you can merge the two selections and perform operations on both without duplicate code. For example:\n\n```js\nvar circle = svg.selectAll(\"circle\").data(data) // UPDATE\n .style(\"fill\", \"blue\");\n\ncircle.exit().remove(); // EXIT\n\ncircle.enter().append(\"circle\") // ENTER\n .style(\"fill\", \"green\")\n .merge(circle) // ENTER + UPDATE\n .style(\"stroke\", \"black\");\n```\n\nSee [*selection*.data](#selection_data) for a more complete explanation of this code, which is known as the general update pattern.\n\nThis method is not intended for concatenating arbitrary selections, however: if both this selection and the specified *other* selection have (non-null) elements at the same index, this selection’s element is returned in the merge and the *other* selection’s element is ignored.\n\n<a name=\"matcher\" href=\"#matcher\">#</a> d3.<b>matcher</b>(<i>selector</i>)\n\nGiven the specified *selector*, returns a function which returns true if `this` element [matches](https://developer.mozilla.org/en-US/docs/Web/API/Element/matches) the specified selector. This method is used internally by [*selection*.filter](#selection_filter). For example, this:\n\n```js\nvar div = selection.filter(\"div\");\n```\n\nIs equivalent to:\n\n```js\nvar div = selection.filter(d3.matcher(\"div\"));\n```\n\n(Although D3 is not a compatibility layer, this implementation does support vendor-prefixed implementations due to the recent standardization of *element*.matches.)\n\n<a name=\"selector\" href=\"#selector\">#</a> d3.<b>selector</b>(<i>selector</i>)\n\nGiven the specified *selector*, returns a function which returns the first descendant of `this` element that matches the specified selector. This method is used internally by [*selection*.select](#selection_select). For example, this:\n\n```js\nvar div = selection.select(\"div\");\n```\n\nIs equivalent to:\n\n```js\nvar div = selection.select(d3.selector(\"div\"));\n```\n\n<a name=\"selectorAll\" href=\"#selectorAll\">#</a> d3.<b>selectorAll</b>(<i>selector</i>)\n\nGiven the specified *selector*, returns a function which returns all descendants of `this` element that match the specified selector. This method is used internally by [*selection*.selectAll](#selection_selectAll). For example, this:\n\n```js\nvar div = selection.selectAll(\"div\");\n```\n\nIs equivalent to:\n\n```js\nvar div = selection.selectAll(d3.selectorAll(\"div\"));\n```\n\n<a name=\"window\" href=\"#window\">#</a> d3.<b>window</b>(<i>node</i>)\n\nReturns the owner window for the specified *node*. If *node* is a node, returns the owner document’s default view; if *node* is a document, returns its default view; otherwise returns the *node*.\n\n### Modifying Elements\n\nAfter selecting elements, use the selection’s transformation methods to affect document content. For example, to set the name attribute and color style of an anchor element:\n\n```js\nd3.select(\"a\")\n .attr(\"name\", \"fred\")\n .style(\"color\", \"red\");\n```\n\nTo experiment with selections, visit [d3js.org](https://d3js.org) and open your browser’s developer console! (In Chrome, open the console with ⌥⌘J.) Select elements and then inspect the returned selection to see which elements are selected and how they are grouped. Call selection methods and see how the page content changes.\n\n<a name=\"selection_attr\" href=\"#selection_attr\">#</a> <i>selection</i>.<b>attr</b>(<i>name</i>[, <i>value</i>])\n\nIf a *value* is specified, sets the attribute with the specified *name* to the specified value on the selected elements and returns this selection. If the *value* is a constant, all elements are given the same attribute value; otherwise, if the *value* is a function, the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function’s return value is then used to set each element’s attribute. A null value will remove the specified attribute.\n\nIf a *value* is not specified, returns the current value of the specified attribute for the first (non-null) element in the selection. This is generally useful only if you know that the selection contains exactly one element.\n\nThe specified *name* may have a namespace prefix, such as `xlink:href` to specify the `href` attribute in the XLink namespace. See [namespaces](#namespaces) for the map of supported namespaces; additional namespaces can be registered by adding to the map.\n\n<a name=\"selection_classed\" href=\"#selection_classed\">#</a> <i>selection</i>.<b>classed</b>(<i>names</i>[, <i>value</i>])\n\nIf a *value* is specified, assigns or unassigns the specified CSS class *names* on the selected elements by setting the `class` attribute or modifying the `classList` property and returns this selection. The specified *names* is a string of space-separated class names. For example, to assign the classes `foo` and `bar` to the selected elements:\n\n```js\nselection.classed(\"foo bar\", true);\n```\n\nIf the *value* is truthy, then all elements are assigned the specified classes; otherwise, the classes are unassigned. If the *value* is a function, then the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function’s return value is then used to assign or unassign classes on each element. For example, to randomly associate the class *foo* with on average half the selected elements:\n\n```js\nselection.classed(\"foo\", function() { return Math.random(); });\n```\n\nIf a *value* is not specified, returns true if and only if the first (non-null) selected element has the specified *classes*. This is generally useful only if you know the selection contains exactly one element.\n\n<a name=\"selection_style\" href=\"#selection_style\">#</a> <i>selection</i>.<b>style</b>(<i>name</i>[, <i>value</i>[, <i>priority</i>]])\n\nIf a *value* is specified, sets the style property with the specified *name* to the specified value on the selected elements and returns this selection. If the *value* is a constant, then all elements are given the same style property value; otherwise, if the *value* is a function, then the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function’s return value is then used to set each element’s style property. A null value will remove the style property. An optional *priority* may also be specified, either as null or the string `important` (without the exclamation point).\n\nIf a *value* is not specified, returns the current computed value of the specified style property for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element. The computed value **may be different than the previously-set value**, particularly if it was set using a shorthand property (such as the `font` style, which is shorthand for `font-size`, `font-face`, etc.).\n\nCaution: unlike many SVG attributes, CSS styles typically have associated units. For example, `3px` is a valid stroke-width property value, while `3` is not. Some browsers implicitly assign the `px` (pixel) unit to numeric values, but not all browsers do: IE, for example, throws an “invalid arguments” error!\n\n<a name=\"selection_property\" href=\"#selection_property\">#</a> <i>selection</i>.<b>property</b>(<i>name</i>[, <i>value</i>])\n\nSome HTML elements have special properties that are not addressable using attributes or styles, such as a form field’s text `value` and a checkbox’s `checked` boolean. Use this method to get or set these properties.\n\nIf a *value* is specified, sets the property with the specified *name* to the specified value on selected elements. If the *value* is a constant, then all elements are given the same property value; otherwise, if the *value* is a function, then the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function’s return value is then used to set each element’s property. A null value will delete the specified property.\n\nIf a *value* is not specified, returns the value of the specified property for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element.\n\n<a name=\"selection_text\" href=\"#selection_text\">#</a> <i>selection</i>.<b>text</b>([<i>value</i>])\n\nIf a *value* is specified, sets the [text content](http://www.w3.org/TR/DOM-Level-3-Core/core.html#Node3-textContent) to the specified value on all selected elements, replacing any existing child elements. If the *value* is a constant, then all elements are given the same text content; otherwise, if the *value* is a function, then the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function’s return value is then used to set each element’s text content. A null value will clear the content.\n\nIf a *value* is not specified, returns the text content for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element.\n\n<a name=\"selection_html\" href=\"#selection_html\">#</a> <i>selection</i>.<b>html</b>([<i>value</i>])\n\nIf a *value* is specified, sets the [inner HTML](http://dev.w3.org/html5/spec-LC/apis-in-html-documents.html#innerhtml) to the specified value on all selected elements, replacing any existing child elements. If the *value* is a constant, then all elements are given the same inner HTML; otherwise, if the *value* is a function, then the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function’s return value is then used to set each element’s inner HTML. A null value will clear the content.\n\nIf a *value* is not specified, returns the inner HTML for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element.\n\nUse [*selection*.append](#selection_append) or [*selection*.insert](#selection_insert) instead to create data-driven content; this method is intended for when you want a little bit of HTML, say for rich formatting. Also, *selection*.html is only supported on HTML elements. SVG elements and other non-HTML elements do not support the innerHTML property, and thus are incompatible with *selection*.html. Consider using [XMLSerializer](https://developer.mozilla.org/en-US/docs/XMLSerializer) to convert a DOM subtree to text. See also the [innersvg polyfill](https://code.google.com/p/innersvg/), which provides a shim to support the innerHTML property on SVG elements.\n\n<a name=\"selection_append\" href=\"#selection_append\">#</a> <i>selection</i>.<b>append</b>(<i>type</i>)\n\nIf the specified *type* is a string, appends a new element of this type (tag name) as the last child of each selected element, or the next following sibling in the update selection if this is an [enter selection](#selection_enter). (The enter behavior allows you to insert elements into the DOM in an order consistent with bound data; however, the slower [*selection*.order](#selection_order) may still be required if updating elements change order.) Otherwise, the *type* may be a function which is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. This function should return an element to be appended. (The function typically creates a new element, but it may instead return an existing element.) For example, to append a DIV element to each paragraph:\n\n```js\nd3.selectAll(\"p\").append(\"div\");\n```\n\nThis is equivalent to:\n\n```js\nd3.selectAll(\"p\").append(function() {\n return document.createElement(\"div\");\n});\n```\n\nWhich is equivalent to:\n\n```js\nd3.selectAll(\"p\").select(function() {\n return this.appendChild(document.createElement(\"div\"));\n});\n```\n\nIn both cases, this method returns a new selection containing the appended elements. Each new element inherits the data of the current elements, if any, in the same manner as [*selection*.select](#selection_select).\n\nThe specified *name* may have a namespace prefix, such as `svg:text` to specify a `text` attribute in the SVG namespace. See [namespaces](#namespaces) for the map of supported namespaces; additional namespaces can be registered by adding to the map. If no namespace is specified, the namespace will be inherited from the parent element; or, if the name is one of the known prefixes, the corresponding namespace will be used (for example, `svg` implies `svg:svg`).\n\n<a name=\"selection_insert\" href=\"#selection_insert\">#</a> <i>selection</i>.<b>insert</b>(<i>type</i>, <i>before</i>)\n\nIf the specified *type* is a string, inserts a new element of this type (tag name) before the element matching the specified *before* selector for each selected element. For example, a *before* selector `:first-child` will prepend nodes before the first child. Both *type* and *before* may instead be specified as functions which are evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The *type* function should return an element to be inserted; the *before* function should return the child element before which the element should be inserted. For example, to insert a DIV element to each paragraph:\n\n```js\nd3.selectAll(\"p\").insert(\"div\");\n```\n\nThis is equivalent to:\n\n```js\nd3.selectAll(\"p\").insert(function() {\n return document.createElement(\"div\");\n});\n```\n\nWhich is equivalent to:\n\n```js\nd3.selectAll(\"p\").select(function() {\n return this.insertBefore(document.createElement(\"div\"), null);\n});\n```\n\nIn both cases, this method returns a new selection containing the appended elements. Each new element inherits the data of the current elements, if any, in the same manner as [*selection*.select](#selection_select).\n\nThe specified *name* may have a namespace prefix, such as `svg:text` to specify a `text` attribute in the SVG namespace. See [namespaces](#namespaces) for the map of supported namespaces; additional namespaces can be registered by adding to the map. If no namespace is specified, the namespace will be inherited from the parent element; or, if the name is one of the known prefixes, the corresponding namespace will be used (for example, `svg` implies `svg:svg`).\n\n<a name=\"selection_remove\" href=\"#selection_remove\">#</a> <i>selection</i>.<b>remove</b>()\n\nRemoves the selected elements from the document. Returns this selection (the removed elements) which are now detached from the DOM. There is not currently a dedicated API to add removed elements back to the document; however, you can pass a function to [*selection*.append](#selection_append) or [*selection*.insert](#selection_insert) to re-add elements.\n\n<a name=\"selection_sort\" href=\"#selection_sort\">#</a> <i>selection</i>.<b>sort</b>(<i>compare</i>)\n\nReturns a new selection that contains a copy of each group in this selection sorted according to the *compare* function. After sorting, re-inserts elements to match the resulting order (per [*selection*.order](#selection_order)).\n\nThe compare function, which defaults to [ascending](https://github.com/d3/d3-array#ascending), is passed two elements’ data *a* and *b* to compare. It should return either a negative, positive, or zero value. If negative, then *a* should be before *b*; if positive, then *a* should be after *b*; otherwise, *a* and *b* are considered equal and the order is arbitrary.\n\nNote that sorting is not guaranteed to be stable; however, it is guaranteed to have the same behavior as your browser’s built-in [sort](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort) method on arrays.\n\n<a name=\"selection_order\" href=\"#selection_order\">#</a> <i>selection</i>.<b>order</b>()\n\nRe-inserts elements into the document such that the document order of each group matches the selection order. This is equivalent to calling [*selection*.sort](#selection_sort) if the data is already sorted, but much faster.\n\n<a name=\"selection_raise\" href=\"#selection_raise\">#</a> <i>selection</i>.<b>raise</b>()\n\nRe-inserts each selected element, in order, as the last child of its parent. Equivalent to:\n\n```js\nselection.each(function() {\n this.parentNode.appendChild(this);\n});\n```\n\n<a name=\"selection_lower\" href=\"#selection_lower\">#</a> <i>selection</i>.<b>lower</b>()\n\nRe-inserts each selected element, in order, as the first child of its parent. Equivalent to:\n\n```js\nselection.each(function() {\n this.parentNode.insertBefore(this, this.parentNode.firstChild);\n});\n```\n\n<a name=\"creator\" href=\"#creator\">#</a> d3.<b>creator</b>(<i>name</i>)\n\nGiven the specified element *name*, returns a function which creates an element of the given name, assuming that `this` is the parent element. This method is used internally by [*selection*.append](#selection_append) and [*selection*.insert](#selection_insert) to create new elements. For example, this:\n\n```js\nselection.append(\"div\");\n```\n\nIs equivalent to:\n\n```js\nselection.append(d3.creator(\"div\"));\n```\n\nSee [namespace](#namespace) for details on supported namespace prefixes, such as for SVG elements.\n\n### Joining Data\n\nFor an introduction to D3’s data joins, see [Thinking With Joins](http://bost.ocks.org/mike/join/). Also see the [General Update Pattern](http://bl.ocks.org/mbostock/3808218) examples.\n\n<a name=\"selection_data\" href=\"#selection_data\">#</a> <i>selection</i>.<b>data</b>([<i>data</i>[, <i>key</i>]])\n\nJoins the specified array of *data* with the selected elements, returning a new selection that it represents the *update* selection: the elements successfully bound to data. Also defines the [enter](#selection_enter) and [exit](#selection_exit) selections on the returned selection, which can be used to add or remove elements to correspond to the new data. The specified *data* is an array of arbitrary values (*e.g.*, numbers or objects), or a function that returns an array of values for each group. When data is assigned to an element, it is stored in the property `__data__`, thus making the data “sticky” and available on re-selection.\n\nThe *data* is specified **for each group** in the selection. If the selection has multiple groups (such as [d3.selectAll](#selectAll) followed by [*selection*.selectAll](#selection_selectAll)), then *data* should typically be specified as a function. This function will be evaluated for each group in order, being passed the group’s parent datum (*d*, which may be undefined), the group index (*i*), and the selection’s parent nodes (*nodes*), with *this* as the group’s parent element. For example, to create an HTML table from a matrix of numbers:\n\n```js\nvar matrix = [\n [11975, 5871, 8916, 2868],\n [ 1951, 10048, 2060, 6171],\n [ 8010, 16145, 8090, 8045],\n [ 1013, 990, 940, 6907]\n];\n\nvar tr = d3.select(\"body\")\n .append(\"table\")\n .selectAll(\"tr\")\n .data(matrix)\n .enter().append(\"tr\");\n\nvar td = tr.selectAll(\"td\")\n .data(function(d) { return d; })\n .enter().append(\"td\")\n .text(function(d) { return d; });\n```\n\nIn this example the *data* function is the identity function: for each table row, it returns the corresponding row from the data matrix.\n\nIf a *key* function is not specified, then the first datum in *data* is assigned to the first selected element, the second datum to the second selected element, and so on. A *key* function may be specified to control which datum is assigned to which element, replacing the default join-by-index. This key function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The key function is then also evaluated for each new datum in *data*, being passed the current datum (*d*), the current index (*i*), and the group’s new *data*, with *this* as the group’s parent DOM element. The datum for a given key is assigned to the element with the matching key. If multiple elements have the same key, the duplicate elements are put into the exit selection; if multiple data have the same key, the duplicate data are put into the enter selection.\n\nFor example, given this document:\n\n```html\n<div id=\"Ford\"></div>\n<div id=\"Jarrah\"></div>\n<div id=\"Kwon\"></div>\n<div id=\"Locke\"></div>\n<div id=\"Reyes\"></div>\n<div id=\"Shephard\"></div>\n```\n\nYou could join data by key as follows:\n\n\n```js\nvar data = [\n {name: \"Locke\", number: 4},\n {name: \"Reyes\", number: 8},\n {name: \"Ford\", number: 15},\n {name: \"Jarrah\", number: 16},\n {name: \"Shephard\", number: 31},\n {name: \"Kwon\", number: 34}\n];\n\nd3.selectAll(\"div\")\n .data(data, function(d) { return d ? d.name : this.id; })\n .text(function(d) { return d.number; });\n```\n\nThis example key function uses the datum *d* if present, and otherwise falls back to the element’s id property. Since these elements were not previously bound to data, the datum *d* is null when the key function is evaluated on selected elements, and non-null when the key function is evaluated on the new data.\n\nThe *update* and *enter* selections are returned in data order, while the *exit* selection preserves the selection order prior to the join. If a key function is specified, the order of elements in the selection may not match their order in the document; use [*selection*.order](#order) or [*selection*.sort](#sort) as needed. For more on how the key function affects the join, see [A Bar Chart, Part 2](http://bost.ocks.org/mike/bar/2/) and [Object Constancy](http://bost.ocks.org/mike/constancy/).\n\nAlthough the data-join can be used simply to create (to *enter*) a set of elements corresponding to data, more generally the data-join is designed to let you create, destroy or update elements as needed so that the resulting DOM corresponds to the new data. The data-join lets you do this efficiently by executing only the minimum necessary operations on each state of element (entering, updating, or exiting), and allows you to declare concise animated transitions between states as well. Here is a simple example of the [General Update Pattern](http://bl.ocks.org/mbostock/3808218):\n\n```js\nvar circle = svg.selectAll(\"circle\") // 1\n .data(data) // 2\n .style(\"fill\", \"blue\"); // 3\n\ncircle.exit().remove(); // 4\n\ncircle.enter().append(\"circle\") // 5\n .style(\"fill\", \"green\") // 6\n .merge(circle) // 7\n .style(\"stroke\", \"black\"); // 8\n```\n\nBreaking this down into discrete steps:\n\n1. Any existing circles (that are descendants of the `svg` selection) are [selected](#selection_selectAll).\n2. These circles are [joined to new `data`](#selection_data), returning the matching circles: the *update* selection.\n3. These updating circles are given a blue fill.\n4. Any existing circles that do *not* match new data—the *exit* selection—are removed.\n5. New circles are [appended](#selection_append) for any new data that do *not* match any existing circle: the *enter* selection.\n6. These entering circles are given a green fill.\n7. A new selection representing the [union](#selection_merge) of entering and updating circles is created.\n8. These entering and updating circles are given a black stroke.\n\nAs described in the preceding paragraphs, the “matching” logic is determined by the key function passed to *selection*.data; since no key function is used in the above code sample, the elements and data are joined by index.\n\nIf *data* is not specified, this method returns the array of data for the selected elements.\n\nThis method cannot be used to clear bound data; use [*selection*.datum](#selection_datum) instead.\n\n<a name=\"selection_enter\" href=\"#selection_enter\">#</a> <i>selection</i>.<b>enter</b>()\n\nReturns the enter selection: placeholder nodes for each datum that had no corresponding DOM element in the selection. The enter selection is determined by [*selection*.data](#selection_data), and is empty on a selection that is not joined to data.\n\nThe enter selection is typically used to create “missing” elements corresponding to new data. For example, to create DIV elements from an array of numbers:\n\n```js\nvar div = d3.select(\"body\")\n .selectAll(\"div\")\n .data([4, 8, 15, 16, 23, 42])\n .enter().append(\"div\")\n .text(function(d) { return d; });\n```\n\nIf the body is initially empty, the above code will create six new DIV elements, append them to the body in-order, and assign their text content as the associated (string-coerced) number:\n\n```html\n<div>4</div>\n<div>8</div>\n<div>15</div>\n<div>16</div>\n<div>23</div>\n<div>42</div>\n```\n\nConceptually, the enter selection’s placeholders are pointers to the parent element (in this example, the document body). The enter selection is typically only used transiently to append elements, and is often [merged](#selection_merge) with the update selection after appending, such that modifications can be applied to both entering and updating elements.\n\n<a name=\"selection_exit\" href=\"#selection_exit\">#</a> <i>selection</i>.<b>exit</b>()\n\nReturns the exit selection: existing DOM elements in the selection for which no new datum was found. The exit selection is determined by the previous [*selection*.data](#selection_data), and is thus empty until the selection is joined to data. If the exit selection is retrieved more than once after a data join, subsequent calls return the empty selection.\n\nThe exit selection is typically used to remove “superfluous” elements corresponding to old data. For example, to update the DIV elements created previously with a new array of numbers:\n\n```js\ndiv = div.data([1, 2, 4, 8, 16, 32], function(d) { return d; });\n```\n\nSince a key function was specified (as the identity function), and the new data contains the numbers [4, 8, 16] which match existing elements in the document, the update selection contains three DIV elements. Leaving those elements as-is, we can append new elements for [1, 2, 32] using the enter selection:\n\n```js\ndiv.enter().append(\"div\").text(function(d) { return d; });\n```\n\nLikewise, to remove the exiting elements [15, 23, 42]:\n\n```js\ndiv.exit().remove();\n```\n\nNow the document body looks like this:\n\n```html\n<div>1</div>\n<div>2</div>\n<div>4</div>\n<div>8</div>\n<div>16</div>\n<div>32</div>\n```\n\nThe order of the DOM elements matches the order of the data because the old data’s order and the new data’s order were consistent. If the new data’s order is different, use [*selection*.order](#selection_order) to reorder the elements in the DOM. See the [General Update Pattern](http://bl.ocks.org/mbostock/3808218) example thread for more on data joins.\n\n<a name=\"selection_datum\" href=\"#selection_datum\">#</a> <i>selection</i>.<b>datum</b>([<i>value</i>])\n\nGets or sets the bound data for each selected element. Unlike [*selection*.data](#selection_data), this method does not compute a join and does not affect indexes or the enter and exit selections.\n\nIf a *value* is specified, sets the element’s bound data to the specified value on all selected elements. If the *value* is a constant, all elements are given the same datum; otherwise, if the *value* is a function, then the function is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. The function is then used to set each element’s new data. A null value will delete the bound data.\n\nIf a *value* is not specified, returns the bound datum for the first (non-null) element in the selection. This is generally useful only if you know the selection contains exactly one element.\n\nThis method is useful for accessing HTML5 [custom data attributes](http://www.w3.org/TR/html5/dom.html#custom-data-attribute). For example, given the following elements:\n\n```html\n<ul id=\"list\">\n <li data-username=\"shawnbot\">Shawn Allen</li>\n <li data-username=\"mbostock\">Mike Bostock</li>\n</ul>\n```\n\nYou can expose the custom data attributes by setting each element’s data as the built-in [dataset](http://www.w3.org/TR/html5/dom.html#dom-dataset) property:\n\n```js\nselection.datum(function() { return this.dataset; })\n```\n\n### Handling Events\n\nFor interaction, selections allow listening for and dispatching of events.\n\n<a name=\"selection_on\" href=\"#selection_on\">#</a> <i>selection</i>.<b>on</b>(<i>typenames</i>[, <i>listener</i>[, <i>capture</i>]])\n\nAdds or removes a *listener* to each selected element for the specified event *typenames*. The *typenames* is a string event type, such as `click`, `mouseover`, or `submit`; any [DOM event type](https://developer.mozilla.org/en-US/docs/Web/Events#Standard_events) supported by your browser may be used. The type may be optionally followed by a period (`.`) and a name; the optional name allows multiple callbacks to be registered to receive events of the same type, such as `click.foo` and `click.bar`. To specify multiple typenames, separate typenames with spaces, such as `input change` or `click.foo click.bar`.\n\nWhen a specified event is dispatched on a selected node, the specified *listener* will be evaluated for each selected element, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. Listeners always see the latest datum for their element, but the index is a property of the selection and is fixed when the listener is assigned; to update the index, re-assign the listener. To access the current event within a listener, use [d3.event](#event).\n\nIf an event listener was previously registered for the same *typename* on a selected element, the old listener is removed before the new listener is added. To remove a listener, pass null as the *listener*. To remove all listeners for a given name, pass null as the *listener* and `.foo` as the *typename*, where `foo` is the name; to remove all listeners with no name, specify `.` as the *typename*.\n\nAn optional *capture* flag may be specified which corresponds to the W3C [useCapture flag](http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration): “After initiating capture, all events of the specified type will be dispatched to the registered EventListener before being dispatched to any EventTargets beneath them in the tree. Events which are bubbling upward through the tree will not trigger an EventListener designated to use capture.”\n\nIf a *listener* is not specified, returns the currently-assigned listener for the specified event *typename* on the first (non-null) selected element, if any. If multiple typenames are specified, the first matching listener is returned.\n\n<a name=\"selection_dispatch\" href=\"#selection_dispatch\">#</a> <i>selection</i>.<b>dispatch</b>(<i>type</i>[, <i>parameters</i>])\n\nDispatches a [custom event](http://www.w3.org/TR/dom/#interface-customevent) of the specified *type* to each selected element, in order. An optional *parameters* map may be specified to set additional properties of the event. It may contain the following fields:\n\n* [`bubbles`](https://www.w3.org/TR/dom/#dom-event-bubbles) - if true, the event is dispatched to ancestors in reverse tree order.\n* [`cancelable`](https://www.w3.org/TR/dom/#dom-event-cancelable) - if true, *event*.preventDefault is allowed.\n* [`detail`](https://www.w3.org/TR/dom/#dom-customevent-detail) - any custom data associated with the event.\n\nIf *parameters* is a function, it is evaluated for each selected element, in order, being passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* as the current DOM element. It must return the parameters map for the current element.\n\n<a name=\"event\" href=\"#event\">#</a> d3.<b>event</b>\n\nThe current [event](https://developer.mozilla.org/en-US/docs/DOM/event), if any. This is set during the invocation of an event listener, and is reset after the listener terminates. Use this to access standard event fields such as [*event*.timeStamp](https://www.w3.org/TR/dom/#dom-event-timestamp) and methods such as [*event*.preventDefault](https://www.w3.org/TR/dom/#dom-event-preventdefault). While you can use the native [*event*.pageX](https://developer.mozilla.org/en/DOM/event.pageX) and [*event*.pageY](https://developer.mozilla.org/en/DOM/event.pageY), it is often more convenient to transform the event position to the local coordinate system of the container that received the event using [d3.mouse](#mouse), [d3.touch](#touch) or [d3.touches](#touches).\n\nIf you use Babel, Webpack, or another ES6-to-ES5 bundler, be aware that the value of d3.event changes during an event! An import of d3.event must be a [live binding](http://www.2ality.com/2015/07/es6-module-exports.html), so you may need to configure the bundler to import from D3’s ES6 modules rather than from the generated UMD bundle; not all bundlers observe [jsnext:main](https://github.com/rollup/rollup/wiki/jsnext:main). Also beware of conflicts with the [*window*.event](https://developer.mozilla.org/en-US/docs/Web/API/Window/event) global.\n\n<a name=\"customEvent\" href=\"#customEvent\">#</a> d3.<b>customEvent</b>(<i>event</i>, <i>listener</i>[, <i>that</i>[, <i>arguments</i>]])\n\nInvokes the specified *listener*, using the specified *that* `this` context and passing the specified *arguments*, if any. During the invocation, [d3.event](#event) is set to the specified *event*; after the listener returns (or throws an error), d3.event is restored to its previous value. In addition, sets *event*.sourceEvent to the prior value of d3.event, allowing custom events to retain a reference to the originating native event. Returns the value returned by the *listener*.\n\n<a name=\"mouse\" href=\"#mouse\">#</a> d3.<b>mouse</b>(<i>container</i>)\n\nReturns the *x* and *y* coordinates of the [current event](#event) relative to the specified *container*. The container may be an HTML or SVG container element, such as a [G element](http://www.w3.org/TR/SVG/struct.html#Groups) or an [SVG element](http://www.w3.org/TR/SVG/struct.html#SVGElement). The coordinates are returned as a two-element array of numbers [*x*, *y*].\n\n<a name=\"touch\" href=\"#touch\">#</a> d3.<b>touch</b>(<i>container</i>[, <i>touches</i>], <i>identifier</i>)\n\nReturns the *x* and *y* coordinates of the touch with the specified *identifier* associated with the [current event](#event) relative to the specified *container*. The container may be an HTML or SVG container element, such as a [G element](http://www.w3.org/TR/SVG/struct.html#Groups) or an [SVG element](http://www.w3.org/TR/SVG/struct.html#SVGElement). The coordinates are returned as an array of two-element arrays of numbers \\[\\[*x1*, *y1*], [*x2*, *y2*], …\\]. If there is no touch with the specified identifier in *touches*, returns null; this can be useful for ignoring touchmove events where the only some touches have moved. If *touches* is not specified, it defaults to the current event’s [changedTouches](http://developer.apple.com/library/safari/documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html#//apple_ref/javascript/instp/TouchEvent/changedTouches) property.\n\n<a name=\"touches\" href=\"#touches\">#</a> d3.<b>touches</b>(<i>container</i>[, <i>touches</i>])\n\nReturns the *x* and *y* coordinates of the touches associated with the [current event](#event) relative to the specified *container*. The container may be an HTML or SVG container element, such as a [G element](http://www.w3.org/TR/SVG/struct.html#Groups) or an [SVG element](http://www.w3.org/TR/SVG/struct.html#SVGElement). The coordinates are returned as an array of two-element arrays of numbers \\[\\[*x1*, *y1*], [*x2*, *y2*], …\\]. If *touches* is not specified, it defaults to the current event’s [touches](http://developer.apple.com/library/safari/documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html#//apple_ref/javascript/instp/TouchEvent/touches) property.\n\n### Control Flow\n\nFor advanced usage, selections provide methods for custom control flow.\n\n<a name=\"selection_each\" href=\"#selection_each\">#</a> <i>selection</i>.<b>each</b>(<i>function</i>)\n\nInvokes the specified *function* for each selected element, passing in passed the current datum (*d*), the current index (*i*), and the current group (*nodes*), with *this* of the current DOM element. This method can be used to invoke arbitrary code for each selected element, and is useful for creating a context to access parent and child data simultaneously, such as:\n\n```js\nparent.each(function(p, j) {\n d3.select(this)\n .selectAll(\".child\")\n .text(function(d, i) { return \"child \" + d.name + \" of \" + p.name; });\n});\n```\n\nSee [Sized Donut Multiples](http://bl.ocks.org/mbostock/4c5fad723c87d2fd8273) for an example.\n\n<a name=\"selection_call\" href=\"#selection_call\">#</a> <i>selection</i>.<b>call</b>(<i>function</i>[, <i>arguments…</i>])\n\nInvokes the specified *function* exactly once, passing in this selection along with any optional *arguments*. Returns this selection. This is equivalent to invoking the function by hand but facilitates method chaining. For example, to set several styles in a reusable function:\n\n```js\nfunction name(selection, first, last) {\n selection\n .attr(\"first-name\", first)\n .attr(\"last-name\", last);\n}\n```\n\nNow say:\n\n```js\nd3.selectAll(\"div\").call(name, \"John\", \"Snow\");\n```\n\nThis is roughly equivalent to:\n\n```js\nname(d3.selectAll(\"div\"), \"John\", \"Snow\");\n```\n\nThe only difference is that *selection*.call always returns the *selection* and not the return value of the called *function*, `name`.\n\n<a name=\"selection_empty\" href=\"#selection_empty\">#</a> <i>selection</i>.<b>empty</b>()\n\nReturns true if this selection contains no (non-null) elements.\n\n<a name=\"selection_nodes\" href=\"#selection_nodes\">#</a> <i>selection</i>.<b>nodes</b>()\n\nReturns an array of all (non-null) elements in this selection.\n\n<a name=\"selection_node\" href=\"#selection_node\">#</a> <i>selection</i>.<b>node</b>()\n\nReturns the first (non-null) element in this selection. If the selection is empty, returns null.\n\n<a name=\"selection_size\" href=\"#selection_size\">#</a> <i>selection</i>.<b>size</b>()\n\nReturns the total number of elements in this selection.\n\n### Local Variables\n\nD3 locals allow you to define local state independent of data. For instance, when rendering [small multiples](http://bl.ocks.org/mbostock/e1192fe405703d8321a5187350910e08) of time-series data, you might want the same *x*-scale for all charts but distinct *y*-scales to compare the relative performance of each metric. D3 locals are scoped by DOM elements: on set, the value is stored on the given element; on get, the value is retrieved from given element or the nearest ancestor that defines it.\n\n<a name=\"local\" href=\"#local\">#</a> d3.<b>local</b>()\n\nDeclares a new local variable. For example:\n\n```js\nvar foo = d3.local();\n```\n\nLike `var`, each local is a distinct symbolic reference; unlike `var`, the value of each local is also scoped by the DOM.\n\n<a name=\"local_set\" href=\"#local_set\">#</a> <i>local</i>.<b>set</b>(<i>node</i>, <i>value</i>)\n\nSets the value of this local on the specified *node* to the *value*, and returns the specified *value*. This is often performed using [*selection*.each](#selection_each):\n\n```js\nselection.each(function(d) { foo.set(this, d.value); });\n```\n\nIf you are just setting a single variable, consider using [*selection*.property](#selection_property):\n\n```js\nselection.property(foo, function(d) { return d.value; });\n```\n\n<a name=\"local_get\" href=\"#local_get\">#</a> <i>local</i>.<b>get</b>(<i>node</i>)\n\nReturns the value of this local on the specified *node*. If the *node* does not define this local, returns the value from the nearest ancestor that defines it. Returns undefined if no ancestor defines this local.\n\n<a name=\"local_remove\" href=\"#local_remove\">#</a> <i>local</i>.<b>remove</b>(<i>node</i>)\n\nDeletes this local’s value from the specified *node* and returns its previous value. Returns true if the *node* defined this local prior to removal, and false otherwise. If ancestors also define this local, those definitions are unaffected, and thus [*local*.get](#local_get) will still return the inherited value.\n\n<a name=\"local_toString\" href=\"#local_toString\">#</a> <i>local</i>.<b>toString</b>()\n\nReturns the automatically-generated identifier for this local. This is the name of the property that is used to store the local’s value on elements, and thus you can also set or get the local’s value using *element*[*local*] or by using [*selection*.property](#selection_property).\n\n### Namespaces\n\nXML namespaces are fun! Right? Fortunately you can mostly ignore them.\n\n<a name=\"namespace\" href=\"#namespace\">#</a> d3.<b>namespace</b>(<i>name</i>)\n\nQualifies the specified *name*, which may or may not have a namespace prefix. If the name contains a colon (`:`), the substring before the colon is interpreted as the namespace prefix, which must be registered in [d3.namespaces](#namespaces). Returns an object `space` and `local` attributes describing the full namespace URL and the local name. For example:\n\n```js\nd3.namespace(\"svg:text\"); // {space: \"http://www.w3.org/2000/svg\", local: \"text\"}\n```\n\nIf the name does not contain a colon, this function merely returns the input name.\n\n<a name=\"namespaces\" href=\"#namespaces\">#</a> d3.<b>namespaces</b>\n\nThe map of registered namespace prefixes. The initial value is:\n\n```js\n{\n svg: \"http://www.w3.org/2000/svg\",\n xhtml: \"http://www.w3.org/1999/xhtml\",\n xlink: \"http://www.w3.org/1999/xlink\",\n xml: \"http://www.w3.org/XML/1998/namespace\",\n xmlns: \"http://www.w3.org/2000/xmlns/\"\n}\n```\n\nAdditional prefixes may be assigned as needed to create elements or attributes in other namespaces."},"npm":{"downloads":[{"from":"2016-10-18T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":14438},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":64890},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":155436},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":190633},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":200461}],"dependentsCount":79,"starsCount":2},"github":{"starsCount":115,"forksCount":52,"subscribersCount":23,"issues":{"count":103,"openCount":6,"distribution":{"3600":21,"10800":11,"32400":14,"97200":14,"291600":13,"874800":12,"2624400":7,"7873200":7,"23619600":4,"70858800":0,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":426},{"username":"tonysherbondy","commitsCount":2},{"username":"lyrachord","commitsCount":2},{"username":"Devinsuit","commitsCount":1},{"username":"wrgoldstein","commitsCount":1},{"username":"jimkang","commitsCount":1},{"username":"tomwanzek","commitsCount":1}],"commits":[{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":14},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":52},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":270}]},"source":{"files":{"readmeSize":53443,"testsSize":115035,"hasNpmIgnore":true},"repositorySize":200786,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":199,"downloadsCount":51812,"downloadsAcceleration":530.9139459665145,"dependentsCount":79},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9737671232876712,"openIssues":1,"issuesDistribution":0.9986493624700542}},"score":{"final":0.7432667815514267,"detail":{"quality":0.9260256430415238,"popularity":0.32988340520718074,"maintenance":0.9999997051898752}}}},{"package":{"name":"d3-format","version":"1.0.2","description":"Format numbers for human consumption.","keywords":["d3","d3-module","format","localization"],"date":"2016-08-02T21:46:36.257Z","links":{"npm":"https://www.npmjs.com/package/d3-format","homepage":"https://d3js.org/d3-format/","repository":"https://github.com/d3/d3-format","bugs":"https://github.com/d3/d3-format/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7366281878255867,"detail":{"quality":0.9260256430415238,"popularity":0.3109564021937783,"maintenance":0.9999592975580205}},"searchScore":0.010097338,"metadata":{"analyzedAt":"2016-10-19T00:43:13.578Z","collected":{"metadata":{"name":"d3-format","version":"1.0.2","description":"Format numbers for human consumption.","keywords":["d3","d3-module","format","localization"],"date":"2016-08-02T21:46:36.257Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-format.git"},"links":{"npm":"https://www.npmjs.com/package/d3-format","homepage":"https://d3js.org/d3-format/","repository":"https://github.com/d3/d3-format","bugs":"https://github.com/d3/d3-format/issues"},"license":"BSD-3-Clause","devDependencies":{"d3-queue":"3","eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":3},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":5},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":13},{"from":"2014-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":23}],"hasTestScript":true,"readme":"# d3-format\n\nEver noticed how sometimes JavaScript doesn’t display numbers the way you expect? Like, you tried to print tenths with a simple loop:\n\n```js\nfor (var i = 0; i < 10; i++) {\n console.log(0.1 * i);\n}\n```\n\nAnd you got this:\n\n```js\n0\n0.1\n0.2\n0.30000000000000004\n0.4\n0.5\n0.6000000000000001\n0.7000000000000001\n0.8\n0.9\n```\n\nWelcome to [binary floating point](https://en.wikipedia.org/wiki/Double-precision_floating-point_format)! ಠ_ಠ\n\nYet rounding error is not the only reason to customize number formatting. A table of numbers should be formatted consistently for comparison; above, 0.0 would be better than 0. Large numbers should have grouped digits (e.g., 42,000) or be in scientific or metric notation (4.2e+4, 42k). Currencies should have fixed precision ($3.50). Reported numerical results should be rounded to significant digits (4021 becomes 4000). Number formats should appropriate to the reader’s locale (42.000,00 or 42,000.00). The list goes on.\n\nFormatting numbers for human consumption is the purpose of d3-format, which is modeled after Python 3’s [format specification mini-language](https://docs.python.org/3/library/string.html#format-specification-mini-language) ([PEP 3101](https://www.python.org/dev/peps/pep-3101/)). Revisiting the example above:\n\n```js\nvar f = d3.format(\".1f\");\nfor (var i = 0; i < 10; i++) {\n console.log(f(0.1 * i));\n}\n```\n\nNow you get this:\n\n```js\n0.0\n0.1\n0.2\n0.3\n0.4\n0.5\n0.6\n0.7\n0.8\n0.9\n```\n\nBut d3-format is much more than an alias for [number.toFixed](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed)! A few more examples:\n\n```js\nd3.format(\".0%\")(0.123); // rounded percentage, \"12%\"\nd3.format(\"($.2f\")(-3.5); // localized fixed-point currency, \"(£3.50)\"\nd3.format(\"+20\")(42); // space-filled and signed, \" +42\"\nd3.format(\".^20\")(42); // dot-filled and centered, \".........42.........\"\nd3.format(\".2s\")(42e6); // SI-prefix with two significant digits, \"42M\"\nd3.format(\"#x\")(48879); // prefixed lowercase hexadecimal, \"0xbeef\"\nd3.format(\",.2r\")(4223); // grouped thousands with two significant digits, \"4,200\"\n```\n\nSee [*locale*.format](#locale_format) for a detailed specification, and try running [d3.formatSpecifier](#formatSpecifier) on the above formats to decode their meaning.\n\n## Installing\n\nIf you use NPM, `npm install d3-format`. Otherwise, download the [latest release](https://github.com/d3/d3-format/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-format.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-format.v1.min.js\"></script>\n<script>\n\nvar format = d3.format(\".2s\");\n\n</script>\n```\n\n[Try d3-format in your browser.](https://tonicdev.com/npm/d3-format)\n\n## API Reference\n\n<a name=\"format\" href=\"#format\">#</a> d3.<b>format</b>(<i>specifier</i>)\n\nAn alias for [*locale*.format](#locale_format) on the [default locale](#formatDefaultLocale).\n\n<a name=\"formatPrefix\" href=\"#formatPrefix\">#</a> d3.<b>formatPrefix</b>(<i>specifier</i>, <i>value</i>)\n\nAn alias for [*locale*.formatPrefix](#locale_formatPrefix) on the [default locale](#formatDefaultLocale).\n\n<a name=\"locale_format\" href=\"#locale_format\">#</a> <i>locale</i>.<b>format</b>(<i>specifier</i>)\n\nReturns a new format function for the given string *specifier*. The returned function takes a number as the only argument, and returns a string representing the formatted number. The general form of a specifier is:\n\n```\n[​[fill]align][sign][symbol][0][width][,][.precision][type]\n```\n\nThe *fill* can be any character. The presence of a fill character is signaled by the *align* character following it, which must be one of the following:\n\n* `>` - Forces the field to be right-aligned within the available space. (Default behavior).\n* `<` - Forces the field to be left-aligned within the available space.\n* `^` - Forces the field to be centered within the available space.\n* `=` - like `>`, but with any sign and symbol to the left of any padding.\n\nThe *sign* can be:\n\n* `-` - nothing for positive and a minus sign for negative. (Default behavior.)\n* `+` - a plus sign for positive and a minus sign for negative.\n* `(` - nothing for positive and parentheses for negative.\n* ` ` (space) - a space for positive and a minus sign for negative.\n\nThe *symbol* can be:\n\n* `$` - apply currency symbols per the locale definition.\n* `#` - for binary, octal, or hexadecimal notation, prefix by `0b`, `0o`, or `0x`, respectively.\n\nThe *zero* (`0`) option enables zero-padding; this implicitly sets *fill* to `0` and *align* to `=`. The *width* defines the minimum field width; if not specified, then the width will be determined by the content. The *comma* (`,`) option enables the use of a group separator, such as a comma for thousands.\n\nDepending on the *type*, the *precision* either indicates the number of digits that follow the decimal point (types `f` and `%`), or the number of significant digits (types `​`, `e`, `g`, `r`, `s` and `p`). If the precision is not specified, it defaults to 6 for all types except `​` (none), which defaults to 12. Precision is ignored for integer formats (types `b`, `o`, `d`, `x`, `X` and `c`). See [precisionFixed](#precisionFixed) and [precisionRound](#precisionRound) for help picking an appropriate precision.\n\nThe available *type* values are:\n\n* `e` - exponent notation.\n* `f` - fixed point notation.\n* `g` - either decimal or exponent notation, rounded to significant digits.\n* `r` - decimal notation, rounded to significant digits.\n* `s` - decimal notation with an [SI prefix](#locale_formatPrefix), rounded to significant digits.\n* `%` - multiply by 100, and then decimal notation with a percent sign.\n* `p` - multiply by 100, round to significant digits, and then decimal notation with a percent sign.\n* `b` - binary notation, rounded to integer.\n* `o` - octal notation, rounded to integer.\n* `d` - decimal notation, rounded to integer.\n* `x` - hexadecimal notation, using lower-case letters, rounded to integer.\n* `X` - hexadecimal notation, using upper-case letters, rounded to integer.\n* `c` - converts the integer to the corresponding unicode character before printing.\n* `​` (none) - like `g`, but trim insignificant trailing zeros.\n\nThe type `n` is also supported as shorthand for `,g`. For the `g`, `n` and `​` (none) types, decimal notation is used if the resulting string would have *precision* or fewer digits; otherwise, exponent notation is used. For example:\n\n```js\nd3.format(\".2\")(42); // \"42\"\nd3.format(\".2\")(4.2); // \"4.2\"\nd3.format(\".1\")(42); // \"4e+1\"\nd3.format(\".1\")(4.2); // \"4\"\n```\n\n<a name=\"locale_formatPrefix\" href=\"#locale_formatPrefix\">#</a> <i>locale</i>.<b>formatPrefix</b>(<i>specifier</i>, <i>value</i>)\n\nEquivalent to [*locale*.format](#locale_format), except the returned function will convert values to the units of the appropriate [SI prefix](https://en.wikipedia.org/wiki/Metric_prefix#List_of_SI_prefixes) for the specified numeric reference *value* before formatting in fixed point notation. The following prefixes are supported:\n\n* `y` - yocto, 10⁻²⁴\n* `z` - zepto, 10⁻²¹\n* `a` - atto, 10⁻¹⁸\n* `f` - femto, 10⁻¹⁵\n* `p` - pico, 10⁻¹²\n* `n` - nano, 10⁻⁹\n* `µ` - micro, 10⁻⁶\n* `m` - milli, 10⁻³\n* `​` (none) - 10⁰\n* `k` - kilo, 10³\n* `M` - mega, 10⁶\n* `G` - giga, 10⁹\n* `T` - tera, 10¹²\n* `P` - peta, 10¹⁵\n* `E` - exa, 10¹⁸\n* `Z` - zetta, 10²¹\n* `Y` - yotta, 10²⁴\n\nUnlike [*locale*.format](#locale_format) with the `s` format type, this method returns a formatter with a consistent SI prefix, rather than computing the prefix dynamically for each number. In addition, the *precision* for the given *specifier* represents the number of digits past the decimal point (as with `f` fixed point notation), not the number of significant digits. For example:\n\n```js\nvar f = d3.formatPrefix(\",.0\", 1e-6);\nf(0.00042); // \"420µ\"\nf(0.0042); // \"4,200µ\"\n```\n\nThis method is useful when formatting multiple numbers in the same units for easy comparison. See [precisionPrefix](#precisionPrefix) for help picking an appropriate precision, and [bl.ocks.org/9764126](http://bl.ocks.org/mbostock/9764126) for an example.\n\n<a name=\"formatSpecifier\" href=\"#formatSpecifier\">#</a> d3.<b>formatSpecifier</b>(<i>specifier</i>)\n\nParses the specified *specifier*, returning an object with exposed fields that correspond to the [format specification mini-language](#locale_format) and a toString method that reconstructs the specifier. For example, `formatSpecifier(\"s\")` returns:\n\n```js\n{\n \"fill\": \" \",\n \"align\": \">\",\n \"sign\": \"-\",\n \"symbol\": \"\",\n \"zero\": false,\n \"width\": undefined,\n \"comma\": false,\n \"precision\": 6,\n \"type\": \"s\"\n}\n```\n\nThis method is useful for understanding how format specifiers are parsed and for deriving new specifiers. For example, you might compute an appropriate precision based on the numbers you want to format using [precisionFixed](#precisionFixed) and then create a new format:\n\n```js\nvar s = d3.formatSpecifier(\"f\");\ns.precision = precisionFixed(0.01);\nvar f = d3.format(s);\nf(42); // \"42.00\";\n```\n\n<a name=\"precisionFixed\" href=\"#precisionFixed\">#</a> d3.<b>precisionFixed</b>(<i>step</i>)\n\nReturns a suggested decimal precision for fixed point notation given the specified numeric *step* value. The *step* represents the minimum absolute difference between values that will be formatted. (This assumes that the values to be formatted are also multiples of *step*.) For example, given the numbers 1, 1.5, and 2, the *step* should be 0.5 and the suggested precision is 1:\n\n```js\nvar p = d3.precisionFixed(0.5),\n f = d3.format(\".\" + p + \"f\");\nf(1); // \"1.0\"\nf(1.5); // \"1.5\"\nf(2); // \"2.0\"\n```\n\nWhereas for the numbers 1, 2 and 3, the *step* should be 1 and the suggested precision is 0:\n\n```js\nvar p = d3.precisionFixed(1),\n f = d3.format(\".\" + p + \"f\");\nf(1); // \"1\"\nf(2); // \"2\"\nf(3); // \"3\"\n```\n\nNote: for the `%` format type, subtract two:\n\n```js\nvar p = Math.max(0, d3.precisionFixed(0.05) - 2),\n f = d3.format(\".\" + p + \"%\");\nf(0.45); // \"45%\"\nf(0.50); // \"50%\"\nf(0.55); // \"55%\"\n```\n\n<a name=\"precisionPrefix\" href=\"#precisionPrefix\">#</a> d3.<b>precisionPrefix</b>(<i>step</i>, <i>value</i>)\n\nReturns a suggested decimal precision for use with [*locale*.formatPrefix](#locale_formatPrefix) given the specified numeric *step* and reference *value*. The *step* represents the minimum absolute difference between values that will be formatted, and *value* determines which SI prefix will be used. (This assumes that the values to be formatted are also multiples of *step*.) For example, given the numbers 1.1e6, 1.2e6, and 1.3e6, the *step* should be 1e5, the *value* could be 1.3e6, and the suggested precision is 1:\n\n```js\nvar p = d3.precisionPrefix(1e5, 1.3e6),\n f = d3.formatPrefix(\".\" + p, 1.3e6);\nf(1.1e6); // \"1.1M\"\nf(1.2e6); // \"1.2M\"\nf(1.3e6); // \"1.3M\"\n```\n\n<a name=\"precisionRound\" href=\"#precisionRound\">#</a> d3.<b>precisionRound</b>(<i>step</i>, <i>max</i>)\n\nReturns a suggested decimal precision for format types that round to significant digits given the specified numeric *step* and *max* values. The *step* represents the minimum absolute difference between values that will be formatted, and the *max* represents the largest absolute value that will be formatted. (This assumes that the values to be formatted are also multiples of *step*.) For example, given the numbers 0.99, 1.0, and 1.01, the *step* should be 0.01, the *max* should be 1.01, and the suggested precision is 3:\n\n```js\nvar p = d3.precisionRound(0.01, 1.01),\n f = d3.format(\".\" + p + \"r\");\nf(0.99); // \"0.990\"\nf(1.0); // \"1.00\"\nf(1.01); // \"1.01\"\n```\n\nWhereas for the numbers 0.9, 1.0, and 1.1, the *step* should be 0.1, the *max* should be 1.1, and the suggested precision is 2:\n\n```js\nvar p = d3.precisionRound(0.1, 1.1),\n f = d3.format(\".\" + p + \"r\");\nf(0.9); // \"0.90\"\nf(1.0); // \"1.0\"\nf(1.1); // \"1.1\"\n```\n\nNote: for the `e` format type, subtract one:\n\n```js\nvar p = Math.max(0, d3.precisionRound(0.01, 1.01) - 1),\n f = d3.format(\".\" + p + \"e\");\nf(0.01); // \"1.00e-2\"\nf(1.01); // \"1.01e+0\"\n```\n\n### Locales\n\n<a name=\"formatLocale\" href=\"#formatLocale\">#</a> d3.<b>formatLocale</b>(<i>definition</i>)\n\nReturns a *locale* object for the specified *definition* with [*locale*.format](#locale_format) and [*locale*.formatPrefix](#locale_formatPrefix) methods. The *definition* must include the following properties:\n\n* `decimal` - the decimal point (e.g., `\".\"`).\n* `thousands` - the group separator (e.g., `\",\"`).\n* `grouping` - the array of group sizes (e.g., `[3]`), cycled as needed.\n* `currency` - the currency prefix and suffix (e.g., `[\"$\", \"\"]`).\n\nNote that the *thousands* property is a misnomer, as the grouping definition allows groups other than thousands.\n\n<a name=\"formatDefaultLocale\" href=\"#formatDefaultLocale\">#</a> d3.<b>formatDefaultLocale</b>(<i>definition</i>)\n\nEquivalent to [d3.formatLocale](#formatLocale), except it also redefines [d3.format](#format) and [d3.formatPrefix](#formatPrefix) to the new locale’s [*locale*.format](#locale_format) and [*locale*.formatPrefix](#locale_formatPrefix). If you do not set a default locale, it defaults to [U.S. English](https://github.com/d3/d3-format/blob/master/locale/en-US.json)."},"npm":{"downloads":[{"from":"2016-10-18T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":22343},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":102326},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":231571},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":299295},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":345121}],"dependentsCount":24,"starsCount":2},"github":{"starsCount":128,"forksCount":14,"subscribersCount":10,"issues":{"count":31,"openCount":3,"distribution":{"3600":4,"10800":4,"32400":4,"97200":5,"291600":5,"874800":4,"2624400":1,"7873200":1,"23619600":3,"70858800":0,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":249},{"username":"n1n9-jp","commitsCount":3},{"username":"zakjan","commitsCount":1},{"username":"rahulpowar","commitsCount":1},{"username":"hernaneche","commitsCount":1},{"username":"Devinsuit","commitsCount":1}],"commits":[{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":5},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":21},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":51}]},"source":{"files":{"readmeSize":13477,"testsSize":42290,"hasNpmIgnore":true},"repositorySize":73878,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":160,"downloadsCount":77190.33333333333,"downloadsAcceleration":795.6356735159818,"dependentsCount":24},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9381793242040217}},"score":{"final":0.7366281878255867,"detail":{"quality":0.9260256430415238,"popularity":0.3109564021937783,"maintenance":0.9999592975580205}}}},{"package":{"name":"d3-interpolate","version":"1.1.1","description":"Interpolate numbers, colors, strings, arrays, objects, whatever!","keywords":["d3","d3-module","interpolate","interpolation","color"],"date":"2016-08-02T21:43:50.200Z","links":{"npm":"https://www.npmjs.com/package/d3-interpolate","homepage":"https://d3js.org/d3-interpolate/","repository":"https://github.com/d3/d3-interpolate","bugs":"https://github.com/d3/d3-interpolate/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7355466186983105,"detail":{"quality":0.9260256430415238,"popularity":0.3078515896330757,"maintenance":0.9999739126122198}},"searchScore":0.008556484,"metadata":{"analyzedAt":"2016-10-16T22:38:07.130Z","collected":{"metadata":{"name":"d3-interpolate","version":"1.1.1","description":"Interpolate numbers, colors, strings, arrays, objects, whatever!","keywords":["d3","d3-module","interpolate","interpolation","color"],"date":"2016-08-02T21:43:50.200Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-interpolate.git"},"links":{"npm":"https://www.npmjs.com/package/d3-interpolate","homepage":"https://d3js.org/d3-interpolate/","repository":"https://github.com/d3/d3-interpolate","bugs":"https://github.com/d3/d3-interpolate/issues"},"license":"BSD-3-Clause","dependencies":{"d3-color":"1"},"devDependencies":{"eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":2},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":10},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":23},{"from":"2014-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":26}],"hasTestScript":true,"readme":"# d3-interpolate\n\nThis module provides a variety of interpolation methods for blending between two values. Values may be numbers, colors, strings, arrays, or even deeply-nested objects. For example:\n\n```js\nvar i = d3.interpolateNumber(10, 20);\ni(0.0); // 10\ni(0.2); // 12\ni(0.5); // 15\ni(1.0); // 20\n```\n\nThe returned function `i` is called an *interpolator*. Given a starting value *a* and an ending value *b*, it takes a parameter *t* in the domain [0, 1] and returns the corresponding interpolated value between *a* and *b*. An interpolator typically returns a value equivalent to *a* at *t* = 0 and a value equivalent to *b* at *t* = 1.\n\nYou can interpolate more than just numbers. To find the perceptual midpoint between steelblue and brown:\n\n```js\nd3.interpolateLab(\"steelblue\", \"brown\")(0.5); // \"rgb(142, 92, 109)\"\n```\n\nHere’s a more elaborate example demonstrating type inference used by [interpolate](#interpolate):\n\n```js\nvar i = d3.interpolate({colors: [\"red\", \"blue\"]}, {colors: [\"white\", \"black\"]});\ni(0.0); // {colors: [\"rgb(255, 0, 0)\", \"rgb(0, 0, 255)\"]}\ni(0.5); // {colors: [\"rgb(255, 128, 128)\", \"rgb(0, 0, 128)\"]}\ni(1.0); // {colors: [\"rgb(255, 255, 255)\", \"rgb(0, 0, 0)\"]}\n```\n\nNote that the generic value interpolator detects not only nested objects and arrays, but also color strings and numbers embedded in strings!\n\n## Installing\n\nIf you use NPM, `npm install d3-interpolate`. Otherwise, download the [latest release](https://github.com/d3/d3-interpolate/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-interpolate.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-color.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-interpolate.v1.min.js\"></script>\n<script>\n\nvar interpolate = d3.interpolateRgb(\"steelblue\", \"brown\");\n\n</script>\n```\n\n[Try d3-interpolate in your browser.](https://tonicdev.com/npm/d3-interpolate)\n\n## API Reference\n\n<a name=\"interpolate\" href=\"#interpolate\">#</a> d3.<b>interpolate</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two arbitrary values *a* and *b*. The interpolator implementation is based on the type of the end value *b*, using the following algorithm:\n\n1. If *b* is null, undefined or a boolean, use the constant *b*.\n2. If *b* is a number, use [interpolateNumber](#interpolateNumber).\n3. If *b* is a [color](https://github.com/d3/d3-color#color) or a string coercible to a color, use [interpolateRgb](#interpolateRgb).\n4. If *b* is a [date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), use [interpolateDate](#interpolateDate).\n5. If *b* is a string, use [interpolateString](#interpolateString).\n6. If *b* is an [array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray), use [interpolateArray](#interpolateArray).\n7. If *b* is coercible to a number, use [interpolateNumber](#interpolateNumber).\n8. Use [interpolateObject](#interpolateObject).\n\nBased on the chosen interpolator, *a* is coerced to the suitable corresponding type.\n\n<a name=\"interpolateNumber\" href=\"#interpolateNumber\">#</a> d3.<b>interpolateNumber</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two numbers *a* and *b*. The returned interpolator is equivalent to:\n\n```js\nfunction interpolator(t) {\n return a * (1 - t) + b * t;\n}\n```\n\nCaution: avoid interpolating to or from the number zero when the interpolator is used to generate a string. When very small values are stringified, they may be converted to scientific notation, which is an invalid attribute or style property value in older browsers. For example, the number `0.0000001` is converted to the string `\"1e-7\"`. This is particularly noticeable with interpolating opacity. To avoid scientific notation, start or end the transition at 1e-6: the smallest value that is not stringified in scientific notation.\n\n<a name=\"interpolateRound\" href=\"#interpolateRound\">#</a> d3.<b>interpolateRound</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two numbers *a* and *b*; the interpolator is similar to [interpolateNumber](#interpolateNumber), except it will round the resulting value to the nearest integer.\n\n<a name=\"interpolateString\" href=\"#interpolateString\">#</a> d3.<b>interpolateString</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two strings *a* and *b*. The string interpolator finds numbers embedded in *a* and *b*, where each number is of the form understood by JavaScript. A few examples of numbers that will be detected within a string: `-1`, `42`, `3.14159`, and `6.0221413e+23`.\n\nFor each number embedded in *b*, the interpolator will attempt to find a corresponding number in *a*. If a corresponding number is found, a numeric interpolator is created using [interpolateNumber](#interpolateNumber). The remaining parts of the string *b* are used as a template: the static parts of the string *b* remain constant for the interpolation, with the interpolated numeric values embedded in the template.\n\nFor example, if *a* is `\"300 12px sans-serif\"`, and *b* is `\"500 36px Comic-Sans\"`, two embedded numbers are found. The remaining static parts of the string are a space between the two numbers (`\" \"`), and the suffix (`\"px Comic-Sans\"`). The result of the interpolator at *t* = 0.5 is `\"400 24px Comic-Sans\"`.\n\n<a name=\"interpolateDate\" href=\"#interpolateDate\">#</a> d3.<b>interpolateDate</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two [dates](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) *a* and *b*.\n\nNote: **no defensive copy** of the returned date is created; the same Date instance is returned for every evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition).\n\n<a name=\"interpolateArray\" href=\"#interpolateArray\">#</a> d3.<b>interpolateArray</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two arrays *a* and *b*. Internally, an array template is created that is the same length in *b*. For each element in *b*, if there exists a corresponding element in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such element, the static value from *b* is used in the template. Then, for the given parameter *t*, the template’s embedded interpolators are evaluated. The updated array template is then returned.\n\nFor example, if *a* is the array `[0, 1]` and *b* is the array `[1, 10, 100]`, then the result of the interpolator for *t* = 0.5 is the array `[0.5, 5.5, 100]`.\n\nNote: **no defensive copy** of the template array is created; modifications of the returned array may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition).\n\n<a name=\"interpolateObject\" href=\"#interpolateObject\">#</a> d3.<b>interpolateObject</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two objects *a* and *b*. Internally, an object template is created that has the same properties as *b*. For each property in *b*, if there exists a corresponding property in *a*, a generic interpolator is created for the two elements using [interpolate](#interpolate). If there is no such property, the static value from *b* is used in the template. Then, for the given parameter *t*, the template's embedded interpolators are evaluated and the updated object template is then returned.\n\nFor example, if *a* is the object `{x: 0, y: 1}` and *b* is the object `{x: 1, y: 10, z: 100}`, the result of the interpolator for *t* = 0.5 is the object `{x: 0.5, y: 5.5, z: 100}`.\n\nObject interpolation is particularly useful for *dataspace interpolation*, where data is interpolated rather than attribute values. For example, you can interpolate an object which describes an arc in a pie chart, and then use d3.svg.arc to compute the new SVG path data.\n\nNote: **no defensive copy** of the template object is created; modifications of the returned object may adversely affect subsequent evaluation of the interpolator. No copy is made for performance reasons; interpolators are often part of the inner loop of [animated transitions](https://github.com/d3/d3-transition).\n\n<a name=\"interpolateTransformCss\" href=\"#interpolateTransformCss\">#</a> d3.<b>interpolateTransformCss</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two 2D CSS transforms represented by *a* and *b*. Each transform is decomposed to a standard representation of translate, rotate, *x*-skew and scale; these component transformations are then interpolated. This behavior is standardized by CSS: see [matrix decomposition for animation](http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition).\n\n<a name=\"interpolateTransformSvg\" href=\"#interpolateTransformSvg\">#</a> d3.<b>interpolateTransformSvg</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two 2D SVG transforms represented by *a* and *b*. Each transform is decomposed to a standard representation of translate, rotate, *x*-skew and scale; these component transformations are then interpolated. This behavior is standardized by CSS: see [matrix decomposition for animation](http://www.w3.org/TR/css3-2d-transforms/#matrix-decomposition).\n\n<a name=\"interpolateZoom\" href=\"#interpolateZoom\">#</a> d3.<b>interpolateZoom</b>(<i>a</i>, <i>b</i>)\n\nReturns an interpolator between the two views *a* and *b* of a two-dimensional plane, based on [“Smooth and efficient zooming and panning”](http://www.win.tue.nl/~vanwijk/zoompan.pdf) by Jarke J. van Wijk and Wim A.A. Nuij. Each view is defined as an array of three numbers: *cx*, *cy* and *width*. The first two coordinates *cx*, *cy* represent the center of the viewport; the last coordinate *width* represents the size of the viewport.\n\nThe returned interpolator exposes a *duration* property which encodes the recommended transition duration in milliseconds. This duration is based on the path length of the curved trajectory through *x,y* space. If you want to a slower or faster transition, multiply this by an arbitrary scale factor (<i>V</i> as described in the original paper).\n\n### Sampling\n\n<a name=\"quantize\" href=\"#quantize\">#</a> d3.<b>quantize</b>(<i>interpolator</i>, <i>n</i>)\n\nReturns *n* uniformly-spaced samples from the specified *interpolator*, where *n* is an integer greater than one. The first sample is always at *t* = 0, and the last sample is always at *t* = 1. This can be useful in generating a fixed number of samples from a given interpolator, such as to derive the range of a [quantize scale](https://github.com/d3/d3-scale#quantize-scales) from a [continuous interpolator](https://github.com/d3/d3-scale#interpolateWarm).\n\nCaution: this method will not work with interpolators that do not return defensive copies of their output, such as [d3.interpolateArray](#interpolateArray), [d3.interpolateDate](#interpolateDate) and [d3.interpolateObject](#interpolateObject). For those interpolators, you must wrap the interpolator and create a copy for each returned value.\n\n### Color Spaces\n\n<a name=\"interpolateRgb\" href=\"#interpolateRgb\">#</a> d3.<b>interpolateRgb</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/rgb.png\" width=\"100%\" height=\"40\" alt=\"rgb\">\n\nOr, with a corrected [gamma](#interpolate_gamma) of 2.2:\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/rgbGamma.png\" width=\"100%\" height=\"40\" alt=\"rgbGamma\">\n\nReturns an RGB color space interpolator between the two colors *a* and *b* with a configurable [gamma](#interpolate_gamma). If the gamma is not specified, it defaults to 1.0. The colors *a* and *b* need not be in RGB; they will be converted to RGB using [d3.rgb](https://github.com/d3/d3-color#rgb). The return value of the interpolator is an RGB string.\n\n<a href=\"#interpolateRgbBasis\" name=\"interpolateRgbBasis\">#</a> d3.<b>interpolateRgbBasis</b>(<i>colors</i>)\n\nReturns a uniform nonrational B-spline interpolator through the specified array of *colors*, which are converted to [RGB color space](https://github.com/d3/d3-color#rgb). Implicit control points are generated such that the interpolator returns *colors*[0] at *t* = 0 and *colors*[*colors*.length - 1] at *t* = 1. Opacity interpolation is not currently supported. See also [d3.interpolateBasis](#interpolateBasis), and see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for examples.\n\n<a href=\"#interpolateRgbBasisClosed\" name=\"interpolateRgbBasisClosed\">#</a> d3.<b>interpolateRgbBasisClosed</b>(<i>colors</i>)\n\nReturns a uniform nonrational B-spline interpolator through the specified array of *colors*, which are converted to [RGB color space](https://github.com/d3/d3-color#rgb). The control points are implicitly repeated such that the resulting spline has cyclical C² continuity when repeated around *t* in [0,1]; this is useful, for example, to create cyclical color scales. Opacity interpolation is not currently supported. See also [d3.interpolateBasisClosed](#interpolateBasisClosed), and see [d3-scale-chromatic](https://github.com/d3/d3-scale-chromatic) for examples.\n\n<a name=\"interpolateHsl\" href=\"#interpolateHsl\">#</a> d3.<b>interpolateHsl</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/hsl.png\" width=\"100%\" height=\"40\" alt=\"hsl\">\n\nReturns an HSL color space interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in HSL; they will be converted to HSL using [d3.hsl](https://github.com/d3/d3-color#hsl). If either color’s hue or saturation is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.\n\n<a name=\"interpolateHslLong\" href=\"#interpolateHslLong\">#</a> d3.<b>interpolateHslLong</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/hslLong.png\" width=\"100%\" height=\"40\" alt=\"hslLong\">\n\nLike [interpolateHsl](#interpolateHsl), but does not use the shortest path between hues.\n\n<a name=\"interpolateLab\" href=\"#interpolateLab\">#</a> d3.<b>interpolateLab</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/lab.png\" width=\"100%\" height=\"40\" alt=\"lab\">\n\nReturns a Lab color space interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in Lab; they will be converted to Lab using [d3.lab](https://github.com/d3/d3-color#lab). The return value of the interpolator is an RGB string.\n\n<a name=\"interpolateHcl\" href=\"#interpolateHcl\">#</a> d3.<b>interpolateHcl</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/hcl.png\" width=\"100%\" height=\"40\" alt=\"hcl\">\n\nReturns an HCL color space interpolator between the two colors *a* and *b*. The colors *a* and *b* need not be in HCL; they will be converted to HCL using [d3.hcl](https://github.com/d3/d3-color#hcl). If either color’s hue or chroma is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.\n\n<a name=\"interpolateHclLong\" href=\"#interpolateHclLong\">#</a> d3.<b>interpolateHclLong</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/hclLong.png\" width=\"100%\" height=\"40\" alt=\"hclLong\">\n\nLike [interpolateHcl](#interpolateHcl), but does not use the shortest path between hues.\n\n<a name=\"interpolateCubehelix\" href=\"#interpolateCubehelix\">#</a> d3.<b>interpolateCubehelix</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/cubehelix.png\" width=\"100%\" height=\"40\" alt=\"cubehelix\">\n\nOr, with a [gamma](#interpolate_gamma) of 3.0 to emphasize high-intensity values:\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/cubehelixGamma.png\" width=\"100%\" height=\"40\" alt=\"cubehelixGamma\">\n\nReturns a Cubehelix color space interpolator between the two colors *a* and *b* using a configurable [gamma](#interpolate_gamma). If the gamma is not specified, it defaults to 1.0. The colors *a* and *b* need not be in Cubehelix; they will be converted to Cubehelix using [d3.cubehelix](https://github.com/d3/d3-color#cubehelix). If either color’s hue or saturation is NaN, the opposing color’s channel value is used. The shortest path between hues is used. The return value of the interpolator is an RGB string.\n\n<a name=\"interpolateCubehelixLong\" href=\"#interpolateCubehelixLong\">#</a> d3.<b>interpolateCubehelixLong</b>(<i>a</i>, <i>b</i>)\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/cubehelixLong.png\" width=\"100%\" height=\"40\" alt=\"cubehelixLong\">\n\nOr, with a [gamma](#interpolate_gamma) of 3.0 to emphasize high-intensity values:\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-interpolate/master/img/cubehelixGammaLong.png\" width=\"100%\" height=\"40\" alt=\"cubehelixGammaLong\">\n\nLike [interpolateCubehelix](#interpolateCubehelix), but does not use the shortest path between hues.\n\n<a name=\"interpolate_gamma\" href=\"#interpolate_gamma\">#</a> <i>interpolate</i>.<b>gamma</b>(<i>gamma</i>)\n\nGiven that *interpolate* is one of [interpolateRgb](#interpolateRgb), [interpolateCubehelix](#interpolateCubehelix) or [interpolateCubehelixLong](#interpolateCubehelixLong), returns a new interpolator factory of the same type using the specified *gamma*. For example, to interpolate from purple to orange with a gamma of 2.2 in RGB space:\n\n```js\nvar interpolator = d3.interpolateRgb.gamma(2.2)(\"purple\", \"orange\");\n```\n\nSee Eric Brasseur’s article, [Gamma error in picture scaling](https://web.archive.org/web/20160112115812/http://www.4p8.com/eric.brasseur/gamma.html), for more on gamma correction.\n\n### Splines\n\nWhereas standard interpolators blend from a starting value *a* at *t* = 0 to an ending value *b* at *t* = 1, spline interpolators smoothly blend multiple input values for *t* in [0,1] using piecewise polynomial functions. Only cubic uniform nonrational [B-splines](https://en.wikipedia.org/wiki/B-spline) are currently supported, also known as basis splines.\n\n<a href=\"#interpolateBasis\" name=\"interpolateBasis\">#</a> d3.<b>interpolateBasis</b>(<i>values</i>)\n\nReturns a uniform nonrational B-spline interpolator through the specified array of *values*, which must be numbers. Implicit control points are generated such that the interpolator returns *values*[0] at *t* = 0 and *values*[*values*.length - 1] at *t* = 1. See also [d3.curveBasis](https://github.com/d3/d3-shape#curveBasis).\n\n<a href=\"#interpolateBasisClosed\" name=\"interpolateBasisClosed\">#</a> d3.<b>interpolateBasisClosed</b>(<i>values</i>)\n\nReturns a uniform nonrational B-spline interpolator through the specified array of *values*, which must be numbers. The control points are implicitly repeated such that the resulting one-dimensional spline has cyclical C² continuity when repeated around *t* in [0,1]. See also [d3.curveBasisClosed](https://github.com/d3/d3-shape#curveBasisClosed)."},"npm":{"downloads":[{"from":"2016-10-15T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":1566},{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":26450},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":110474},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":253475},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":329949},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":364346}],"dependentsCount":31,"starsCount":0},"github":{"starsCount":60,"forksCount":13,"subscribersCount":12,"issues":{"count":30,"openCount":3,"distribution":{"3600":5,"10800":4,"32400":1,"97200":2,"291600":8,"874800":3,"2624400":1,"7873200":4,"23619600":2,"70858800":0,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":122},{"username":"krukon","commitsCount":4},{"username":"stefanullinger","commitsCount":1},{"username":"Devinsuit","commitsCount":1}],"commits":[{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":3},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":38},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":101}]},"source":{"files":{"readmeSize":19376,"testsSize":40355,"hasNpmIgnore":true},"repositorySize":140178,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":89,"downloadsCount":84491.66666666667,"downloadsAcceleration":879.7750570776255,"dependentsCount":31},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9558520089285714}},"score":{"final":0.7355466186983105,"detail":{"quality":0.9260256430415238,"popularity":0.3078515896330757,"maintenance":0.9999739126122198}}}},{"package":{"name":"d3-array","version":"1.0.1","description":"Array manipulation, ordering, searching, summarizing, etc.","keywords":["d3","d3-module","histogram","bisect","shuffle","statistics","search","sort","array"],"date":"2016-08-02T21:57:09.831Z","links":{"npm":"https://www.npmjs.com/package/d3-array","homepage":"https://d3js.org/d3-array/","repository":"https://github.com/d3/d3-array","bugs":"https://github.com/d3/d3-array/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7432495383147883,"detail":{"quality":0.9260256430415238,"popularity":0.32995527266926,"maintenance":0.9998785713374008}},"searchScore":0.007667571,"metadata":{"analyzedAt":"2016-10-19T00:42:54.237Z","collected":{"metadata":{"name":"d3-array","version":"1.0.1","description":"Array manipulation, ordering, searching, summarizing, etc.","keywords":["d3","d3-module","histogram","bisect","shuffle","statistics","search","sort","array"],"date":"2016-08-02T21:57:09.831Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-array.git"},"links":{"npm":"https://www.npmjs.com/package/d3-array","homepage":"https://d3js.org/d3-array/","repository":"https://github.com/d3/d3-array","bugs":"https://github.com/d3/d3-array/issues"},"license":"BSD-3-Clause","devDependencies":{"eslint":"2","package-preamble":"0.0","rollup":"0.34","seedrandom":"2","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":1},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":2},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":5},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":14},{"from":"2014-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":14}],"hasTestScript":true,"readme":"# d3-array\n\nData in JavaScript is often represented by an array, and so one tends to manipulate arrays when visualizing or analyzing data. Some common forms of manipulation include taking a contiguous slice (subset) of an array, filtering an array using a predicate function, and mapping an array to a parallel set of values using a transform function. Before looking at the set of utilities that this module provides, familiarize yourself with the powerful [array methods built-in to JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/prototype).\n\nJavaScript includes **mutation methods** that modify the array:\n\n* [*array*.pop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) - Remove the last element from the array.\n* [*array*.push](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) - Add one or more elements to the end of the array.\n* [*array*.reverse](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reverse) - Reverse the order of the elements of the array.\n* [*array*.shift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/shift) - Remove the first element from the array.\n* [*array*.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) - Sort the elements of the array.\n* [*array*.splice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) - Add or remove elements from the array.\n* [*array*.unshift](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) - Add one or more elements to the front of the array.\n\nThere are also **access methods** that return some representation of the array:\n\n* [*array*.concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) - Join the array with other array(s) or value(s).\n* [*array*.join](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) - Join all elements of the array into a string.\n* [*array*.slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) - Extract a section of the array.\n* [*array*.indexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) - Find the first occurrence of a value within the array.\n* [*array*.lastIndexOf](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/lastIndexOf) - Find the last occurrence of a value within the array.\n\nAnd finally **iteration methods** that apply functions to elements in the array:\n\n* [*array*.filter](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) - Create a new array with only the elements for which a predicate is true.\n* [*array*.forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) - Call a function for each element in the array.\n* [*array*.every](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every) - See if every element in the array satisfies a predicate.\n* [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) - Create a new array with the result of calling a function on every element in the array.\n* [*array*.some](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some) - See if at least one element in the array satisfies a predicate.\n* [*array*.reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) - Apply a function to reduce the array to a single value (from left-to-right).\n* [*array*.reduceRight](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduceRight) - Apply a function to reduce the array to a single value (from right-to-left).\n\n## Installing\n\nIf you use NPM, `npm install d3-array`. Otherwise, download the [latest release](https://github.com/d3/d3-array/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-array.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-array.v1.min.js\"></script>\n<script>\n\nvar min = d3.min(array);\n\n</script>\n```\n\n[Try d3-array in your browser.](https://tonicdev.com/npm/d3-array)\n\n## API Reference\n\n* [Statistics](#statistics)\n* [Search](#search)\n* [Transformations](#transformations)\n* [Histograms](#histograms)\n* [Histogram Thresholds](#histogram-thresholds)\n\n### Statistics\n\nMethods for computing basic summary statistics.\n\n<a name=\"min\" href=\"#min\">#</a> d3.<b>min</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the minimum value in the given *array* using natural order. If the array is empty, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the minimum value.\n\nUnlike the built-in [Math.min](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/min), this method ignores undefined, null and NaN values; this is useful for ignoring missing data. In addition, elements are compared using *natural* order rather than *numeric* order. For example, the minimum of [\"20\", \"3\"] is \"20\", while the minimum of [20, 3] is 3.\n\nSee also [scan](#scan) and [extent](#extent).\n\n<a name=\"max\" href=\"#max\">#</a> d3.<b>max</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the maximum value in the given *array* using natural order. If the array is empty, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the maximum value.\n\nUnlike the built-in [Math.max](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Math/max), this method ignores undefined values; this is useful for ignoring missing data. In addition, elements are compared using *natural* order rather than *numeric* order. For example, the maximum of [\"20\", \"3\"] is \"3\", while the maximum of [20, 3] is 20.\n\nSee also [scan](#scan) and [extent](#extent).\n\n<a name=\"extent\" href=\"#extent\">#</a> d3.<b>extent</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the [minimum](#min) and [maximum](#max) value in the given *array* using natural order. If the array is empty, returns [undefined, undefined]. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the extent.\n\n<a name=\"sum\" href=\"#sum\">#</a> d3.<b>sum</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the sum of the given *array* of numbers. If the array is empty, returns 0. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the sum. This method ignores undefined and NaN values; this is useful for ignoring missing data.\n\n<a name=\"mean\" href=\"#mean\">#</a> d3.<b>mean</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the mean of the given *array* of numbers. If the array is empty, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the mean. This method ignores undefined and NaN values; this is useful for ignoring missing data.\n\n<a name=\"median\" href=\"#median\">#</a> d3.<b>median</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the median of the given *array* of numbers using the [R-7 method](https://en.wikipedia.org/wiki/Quantile#Estimating_quantiles_from_a_sample). If the array is empty, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the median. This method ignores undefined and NaN values; this is useful for ignoring missing data.\n\n<a name=\"quantile\" href=\"#quantile\">#</a> d3.<b>quantile</b>(<i>array</i>, <i>p</i>[, <i>accessor</i>])\n\nReturns the *p*-quantile of the given sorted *array* of numbers, where *p* is a number in the range [0, 1]. For example, the median can be computed using *p* = 0.5, the first quartile at *p* = 0.25, and the third quartile at *p* = 0.75. This particular implementation uses the [R-7 method](http://en.wikipedia.org/wiki/Quantile#Quantiles_of_a_population), which is the default for the R programming language and Excel. For example:\n\n```js\nvar a = [0, 10, 30];\nd3.quantile(a, 0); // 0\nd3.quantile(a, 0.5); // 10\nd3.quantile(a, 1); // 30\nd3.quantile(a, 0.25); // 5\nd3.quantile(a, 0.75); // 20\nd3.quantile(a, 0.1); // 2\n```\n\nAn optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the quantile.\n\n<a name=\"variance\" href=\"#variance\">#</a> d3.<b>variance</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns an [unbiased estimator of the population variance](http://mathworld.wolfram.com/SampleVariance.html) of the given *array* of numbers. If the array has fewer than two values, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the variance. This method ignores undefined and NaN values; this is useful for ignoring missing data.\n\n<a name=\"deviation\" href=\"#deviation\">#</a> d3.<b>deviation</b>(<i>array</i>[, <i>accessor</i>])\n\nReturns the standard deviation, defined as the square root of the [bias-corrected variance](#variance), of the given *array* of numbers. If the array has fewer than two values, returns undefined. An optional *accessor* function may be specified, which is equivalent to calling *array.map(accessor)* before computing the standard deviation. This method ignores undefined and NaN values; this is useful for ignoring missing data.\n\n### Search\n\nMethods for searching arrays for a specific element.\n\n<a name=\"scan\" href=\"#scan\">#</a> d3.<b>scan</b>(<i>array</i>[, <i>comparator</i>])\n\nPerforms a linear scan of the specified *array*, returning the index of the least element according to the specified *comparator*. If the given *array* contains no comparable elements (*i.e.*, the comparator returns NaN when comparing each element to itself), returns undefined. If *comparator* is not specified, it defaults to [ascending](#ascending). For example:\n\n```js\nvar array = [{foo: 42}, {foo: 91}];\nd3.scan(array, function(a, b) { return a.foo - b.foo; }); // 0\nd3.scan(array, function(a, b) { return b.foo - a.foo; }); // 1\n```\n\nThis function is similar to [min](#min), except it allows the use of a comparator rather than an accessor and it returns the index instead of the accessed value. See also [bisect](#bisect).\n\n<a name=\"bisectLeft\" href=\"#bisectLeft\">#</a> d3.<b>bisectLeft</b>(<i>array</i>, <i>x</i>[, <i>lo</i>[, <i>hi</i>]])\n\nReturns the insertion point for *x* in *array* to maintain sorted order. The arguments *lo* and *hi* may be used to specify a subset of the array which should be considered; by default the entire array is used. If *x* is already present in *array*, the insertion point will be before (to the left of) any existing entries. The return value is suitable for use as the first argument to [splice](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice) assuming that *array* is already sorted. The returned insertion point *i* partitions the *array* into two halves so that all *v* < *x* for *v* in *array*.slice(*lo*, *i*) for the left side and all *v* >= *x* for *v* in *array*.slice(*i*, *hi*) for the right side.\n\n<a name=\"bisect\" href=\"#bisect\">#</a> d3.<b>bisect</b>(<i>array</i>, <i>x</i>[, <i>lo</i>[, <i>hi</i>]])<br>\n<a name=\"bisectRight\" href=\"#bisectRight\">#</a> d3.<b>bisectRight</b>(<i>array</i>, <i>x</i>[, <i>lo</i>[, <i>hi</i>]])\n\nSimilar to [bisectLeft](#bisectLeft), but returns an insertion point which comes after (to the right of) any existing entries of *x* in *array*. The returned insertion point *i* partitions the *array* into two halves so that all *v* <= *x* for *v* in *array*.slice(*lo*, *i*) for the left side and all *v* > *x* for *v* in *array*.slice(*i*, *hi*) for the right side.\n\n<a name=\"bisector\" href=\"#bisector\">#</a> d3.<b>bisector</b>(<i>accessor</i>)\n<br><a name=\"bisector\" href=\"#bisector\">#</a> d3.<b>bisector</b>(<i>comparator</i>)\n\nReturns a new bisector using the specified *accessor* or *comparator* function. This method can be used to bisect arrays of objects instead of being limited to simple arrays of primitives. For example, given the following array of objects:\n\n```js\nvar data = [\n {date: new Date(2011, 1, 1), value: 0.5},\n {date: new Date(2011, 2, 1), value: 0.6},\n {date: new Date(2011, 3, 1), value: 0.7},\n {date: new Date(2011, 4, 1), value: 0.8}\n];\n```\n\nA suitable bisect function could be constructed as:\n\n```js\nvar bisectDate = d3.bisector(function(d) { return d.date; }).right;\n```\n\nThis is equivalent to specifying a comparator:\n\n```js\nvar bisectDate = d3.bisector(function(d, x) { return d.date - x; }).right;\n```\n\nAnd then applied as `bisect(data, new Date(2011, 1, 2))`, returning an index. Note that the comparator is always passed the search value *x* as the second argument. Use a comparator rather than an accessor if you want values to be sorted in an order different than natural order, such as in descending rather than ascending order.\n\n<a name=\"bisector_left\" href=\"#bisector_left\">#</a> <i>bisector</i>.<b>left</b>(<i>array</i>, <i>x</i>[, <i>lo</i>[, <i>hi</i>]])\n\nEquivalent to [bisectLeft](#bisectLeft), but uses this bisector’s associated comparator.\n\n<a name=\"bisector_right\" href=\"#bisector_right\">#</a> <i>bisector</i>.<b>right</b>(<i>array</i>, <i>x</i>[, <i>lo</i>[, <i>hi</i>]])\n\nEquivalent to [bisectRight](#bisectRight), but uses this bisector’s associated comparator.\n\n<a name=\"ascending\" href=\"#ascending\">#</a> d3.<b>ascending</b>(<i>a</i>, <i>b</i>)\n\nReturns -1 if *a* is less than *b*, or 1 if *a* is greater than *b*, or 0. This is the comparator function for natural order, and can be used in conjunction with the built-in [*array*.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) method to arrange elements in ascending order. It is implemented as:\n\n```js\nfunction ascending(a, b) {\n return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;\n}\n```\n\nNote that if no comparator function is specified to the built-in sort method, the default order is lexicographic (alphabetical), not natural! This can lead to surprising behavior when sorting an array of numbers.\n\n<a name=\"descending\" href=\"#descending\">#</a> d3.<b>descending</b>(<i>a</i>, <i>b</i>)\n\nReturns -1 if *a* is greater than *b*, or 1 if *a* is less than *b*, or 0. This is the comparator function for reverse natural order, and can be used in conjunction with the built-in array sort method to arrange elements in descending order. It is implemented as:\n\n```js\nfunction descending(a, b) {\n return b < a ? -1 : b > a ? 1 : b >= a ? 0 : NaN;\n}\n```\n\nNote that if no comparator function is specified to the built-in sort method, the default order is lexicographic (alphabetical), not natural! This can lead to surprising behavior when sorting an array of numbers.\n\n### Transformations\n\nMethods for transforming arrays and for generating new arrays.\n\n<a name=\"merge\" href=\"#merge\">#</a> d3.<b>merge</b>(<i>arrays</i>)\n\nMerges the specified *arrays* into a single array. This method is similar to the built-in array concat method; the only difference is that it is more convenient when you have an array of arrays.\n\n```js\nd3.merge([[1], [2, 3]]); // returns [1, 2, 3]\n```\n\n<a name=\"pairs\" href=\"#pairs\">#</a> d3.<b>pairs</b>(<i>array</i>)\n\nFor each adjacent pair of elements in the specified *array*, returns a new array of tuples of element *i* and element *i* - 1. For example:\n\n```js\nd3.pairs([1, 2, 3, 4]); // returns [[1, 2], [2, 3], [3, 4]]\n```\n\nIf the specified array has fewer than two elements, returns the empty array.\n\n<a name=\"permute\" href=\"#permute\">#</a> d3.<b>permute</b>(<i>array</i>, <i>indexes</i>)\n\nReturns a permutation of the specified *array* using the specified array of *indexes*. The returned array contains the corresponding element in array for each index in indexes, in order. For example, permute([\"a\", \"b\", \"c\"], [1, 2, 0])\nreturns [\"b\", \"c\", \"a\"]. It is acceptable for the array of indexes to be a different length from the array of elements, and for indexes to be duplicated or omitted.\n\nThis method can also be used to extract the values from an object into an array with a stable order. Extracting keyed values in order can be useful for generating data arrays in nested selections. For example:\n\n```js\nvar object = {yield: 27, variety: \"Manchuria\", year: 1931, site: \"University Farm\"},\n fields = [\"site\", \"variety\", \"yield\"];\n\nd3.permute(object, fields); // returns [\"University Farm\", \"Manchuria\", 27]\n```\n\n<a name=\"shuffle\" href=\"#shuffle\">#</a> d3.<b>shuffle</b>(<i>array</i>[, <i>lo</i>[, <i>hi</i>]])\n\nRandomizes the order of the specified *array* using the [Fisher–Yates shuffle](http://bost.ocks.org/mike/shuffle/).\n\n<a name=\"ticks\" href=\"#ticks\">#</a> d3.<b>ticks</b>(<i>start</i>, <i>stop</i>, <i>count</i>)\n\nReturns an array of approximately *count* + 1 uniformly-spaced, nicely-rounded values between *start* and *stop* (inclusive). Each value is a power of ten multiplied by 1, 2 or 5. See also [tickStep](#tickStep) and [*linear*.ticks](https://github.com/d3/d3-scale#linear_ticks). Note that due to the limited precision of IEEE 754 floating point, the returned values may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption.\n\nTicks are inclusive in the sense that they may include the specified *start* and *stop* values if (and only if) they are exact, nicely-rounded values consistent with the inferred [step](#tickStep). More formally, each returned tick *t* satisfies *start* ≤ *t* and *t* ≤ *stop*.\n\n<a name=\"tickStep\" href=\"#tickStep\">#</a> d3.<b>tickStep</b>(<i>start</i>, <i>stop</i>, <i>count</i>)\n\nReturns the difference between adjacent tick values if the same arguments were passed to [ticks](#ticks): a nicely-rounded value that is a power of ten multiplied by 1, 2 or 5. Note that due to the limited precision of IEEE 754 floating point, the returned value may not be exact decimals; use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption.\n\n<a name=\"range\" href=\"#range\">#</a> d3.<b>range</b>([<i>start</i>, ]<i>stop</i>[, <i>step</i>])\n\nReturns an array containing an arithmetic progression, similar to the Python built-in [range](http://docs.python.org/library/functions.html#range). This method is often used to iterate over a sequence of uniformly-spaced numeric values, such as the indexes of an array or the ticks of a linear scale. (See also [ticks](#ticks) for nicely-rounded values.)\n\nIf *step* is omitted, it defaults to 1. If *start* is omitted, it defaults to 0. The *stop* value is exclusive; it is not included in the result. If *step* is positive, the last element is the largest *start* + *i* \\* *step* less than *stop*; if *step* is negative, the last element is the smallest *start* + *i* \\* *step* greater than *stop*. If the returned array would contain an infinite number of values, an empty range is returned.\n\nThe arguments are not required to be integers; however, the results are more predictable if they are. The values in the returned array are defined as *start* + *i* \\* *step*, where *i* is an integer from zero to one minus the total number of elements in the returned array. For example:\n\n```js\nd3.range(0, 1, 0.2) // [0, 0.2, 0.4, 0.6000000000000001, 0.8]\n```\n\nThis unexpected behavior is due to IEEE 754 double-precision floating point, which defines 0.2 * 3 = 0.6000000000000001. Use [d3-format](https://github.com/d3/d3-format) to format numbers for human consumption with appropriate rounding; see also [linear.tickFormat](https://github.com/d3/d3-scale#linear_tickFormat) in [d3-scale](https://github.com/d3/d3-scale).\n\nLikewise, if the returned array should have a specific length, consider using [array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) on an integer range. For example:\n\n```js\nd3.range(0, 1, 1 / 49); // BAD: returns 50 elements!\nd3.range(49).map(function(d) { return d / 49; }); // GOOD: returns 49 elements.\n```\n\n<a name=\"transpose\" href=\"#transpose\">#</a> d3.<b>transpose</b>(<i>matrix</i>)\n\nUses the [zip](#zip) operator as a two-dimensional [matrix transpose](http://en.wikipedia.org/wiki/Transpose).\n\n<a name=\"zip\" href=\"#zip\">#</a> d3.<b>zip</b>(<i>arrays…</i>)\n\nReturns an array of arrays, where the *i*th array contains the *i*th element from each of the argument *arrays*. The returned array is truncated in length to the shortest array in *arrays*. If *arrays* contains only a single array, the returned array contains one-element arrays. With no arguments, the returned array is empty.\n\n```js\nd3.zip([1, 2], [3, 4]); // returns [[1, 3], [2, 4]]\n```\n\n### Histograms\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-array/master/img/histogram.png\" width=\"480\" height=\"250\" alt=\"Histogram\">](http://bl.ocks.org/mbostock/3048450)\n\nHistograms bin many discrete samples into a smaller number of consecutive, non-overlapping intervals. They are often used to visualize the distribution of numerical data.\n\n<a name=\"histogram\" href=\"#histogram\">#</a> d3.<b>histogram</b>()\n\nConstructs a new histogram generator with the default settings.\n\n<a name=\"_histogram\" href=\"#_histogram\">#</a> <i>histogram</i>(<i>data</i>)\n\nComputes the histogram for the given array of *data* samples. Returns an array of bins, where each bin is an array containing the associated elements from the input *data*. Thus, the `length` of the bin is the number of elements in that bin. Each bin has two additional attributes:\n\n* `x0` - the lower bound of the bin (inclusive).\n* `x1` - the upper bound of the bin (exclusive, except for the last bin).\n\n<a name=\"histogram_value\" href=\"#histogram_value\">#</a> <i>histogram</i>.<b>value</b>([<i>value</i>])\n\nIf *value* is specified, sets the value accessor to the specified function or constant and returns this histogram generator. If *value* is not specified, returns the current value accessor, which defaults to the identity function.\n\nWhen a histogram is [generated](#_histogram), the value accessor will be invoked for each element in the input data array, being passed the element `d`, the index `i`, and the array `data` as three arguments. The default value accessor assumes that the input data are orderable (comparable), such as numbers or dates. If your data are not, then you should specify an accessor that returns the corresponding orderable value for a given datum.\n\nThis is similar to mapping your data to values before invoking the histogram generator, but has the benefit that the input data remains associated with the returned bins, thereby making it easier to access other fields of the data.\n\n<a name=\"histogram_domain\" href=\"#histogram_domain\">#</a> <i>histogram</i>.<b>domain</b>([<i>domain</i>])\n\nIf *domain* is specified, sets the domain accessor to the specified function or array and returns this histogram generator. If *domain* is not specified, returns the current domain accessor, which defaults to [extent](#extent). The histogram domain is defined as an array [*min*, *max*], where *min* is the minimum observable value and *max* is the maximum observable value; both values are inclusive. Any value outside of this domain will be ignored when the histogram is [generated](#_histogram).\n\nFor example, if you are using the the histogram in conjunction with a [linear scale](https://github.com/d3/d3-scale#linear-scales) `x`, you might say:\n\n```js\nvar histogram = d3.histogram()\n .domain(x.domain())\n .thresholds(x.ticks(20));\n```\n\nYou can then compute the bins from an array of numbers like so:\n\n```js\nvar bins = histogram(numbers);\n```\n\nNote that the domain accessor is invoked on the materialized array of [values](#histogram_value), not on the input data array.\n\n<a name=\"histogram_thresholds\" href=\"#histogram_thresholds\">#</a> <i>histogram</i>.<b>thresholds</b>([<i>count</i>])\n<br><a name=\"histogram_thresholds\" href=\"#histogram_thresholds\">#</a> <i>histogram</i>.<b>thresholds</b>([<i>thresholds</i>])\n\nIf *thresholds* is specified, sets the [threshold generator](#histogram-thresholds) to the specified function or array and returns this histogram generator. If *thresholds* is not specified, returns the current threshold generator, which by default implements [Sturges’ formula](#thresholdSturges). (Thus by default, the histogram values must be numbers!) Thresholds are defined as an array of values [*x0*, *x1*, …]. Any value less than *x0* will be placed in the first bin; any value greater than or equal to *x0* but less than *x1* will be placed in the second bin; and so on. Thus, the [generated histogram](#_histogram) will have *thresholds*.length + 1 bins. See [histogram thresholds](#histogram-thresholds) for more information.\n\nIf a *count* is specified instead of an array of *thresholds*, then the [domain](#histogram_domain) will be uniformly divided into approximately *count* bins; see [ticks](#ticks).\n\n### Histogram Thresholds\n\nThese functions are typically not used directly; instead, pass them to [*histogram*.thresholds](#histogram_thresholds). You may also implement your own threshold generator taking three arguments: the array of input [*values*](#histogram_value) derived from the data, and the [observable domain](#histogram_domain) represented as *min* and *max*. The generator may then return either the array of numeric thresholds or the *count* of bins; in the latter case the domain is divided uniformly into approximately *count* bins; see [ticks](#ticks).\n\n<a name=\"thresholdFreedmanDiaconis\" href=\"#thresholdFreedmanDiaconis\">#</a> d3.<b>thresholdFreedmanDiaconis</b>(<i>values</i>, <i>min</i>, <i>max</i>)\n\nReturns the number of bins according to the [Freedman–Diaconis rule](https://en.wikipedia.org/wiki/Histogram#Mathematical_definition); the input *values* must be numbers.\n\n<a name=\"thresholdScott\" href=\"#thresholdScott\">#</a> d3.<b>thresholdScott</b>(<i>values</i>, <i>min</i>, <i>max</i>)\n\nReturns the number of bins according to [Scott’s normal reference rule](https://en.wikipedia.org/wiki/Histogram#Mathematical_definition); the input *values* must be numbers.\n\n<a name=\"thresholdSturges\" href=\"#thresholdSturges\">#</a> d3.<b>thresholdSturges</b>(<i>values</i>)\n\nReturns the number of bins according to [Sturges’ formula](https://en.wikipedia.org/wiki/Histogram#Mathematical_definition); the input *values* must be numbers."},"npm":{"downloads":[{"from":"2016-10-18T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":21163},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":96813},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":215668},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":275243},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":293769}],"dependentsCount":81,"starsCount":1},"github":{"starsCount":55,"forksCount":24,"subscribersCount":15,"issues":{"count":44,"openCount":5,"distribution":{"3600":6,"10800":4,"32400":9,"97200":4,"291600":0,"874800":6,"2624400":3,"7873200":3,"23619600":6,"70858800":3,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":180},{"username":"Devinsuit","commitsCount":1},{"username":"aubergene","commitsCount":1},{"username":"andreasplesch","commitsCount":1}],"commits":[{"from":"2016-10-12T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-09-19T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":0},{"from":"2016-07-21T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":6},{"from":"2016-04-22T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":16},{"from":"2015-10-20T00:00:00.000Z","to":"2016-10-19T00:00:00.000Z","count":124}]},"source":{"files":{"readmeSize":26915,"testsSize":87038,"hasNpmIgnore":true},"repositorySize":140097,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":99,"downloadsCount":71889.33333333333,"downloadsAcceleration":786.6336567732116,"dependentsCount":81},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.7432495383147883,"detail":{"quality":0.9260256430415238,"popularity":0.32995527266926,"maintenance":0.9998785713374008}}}},{"package":{"name":"d3-time","version":"1.0.4","description":"A calculator for humanity’s peculiar conventions of time.","keywords":["d3","d3-module","time","interval","calendar"],"date":"2016-09-22T16:41:38.115Z","links":{"npm":"https://www.npmjs.com/package/d3-time","homepage":"https://d3js.org/d3-time/","repository":"https://github.com/d3/d3-time","bugs":"https://github.com/d3/d3-time/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.731451405151934,"detail":{"quality":0.9260256430415238,"popularity":0.2962463207753904,"maintenance":0.9998785713374008}},"searchScore":0.0075785117,"metadata":{"analyzedAt":"2016-10-22T17:33:41.738Z","collected":{"metadata":{"name":"d3-time","version":"1.0.4","description":"A calculator for humanity’s peculiar conventions of time.","keywords":["d3","d3-module","time","interval","calendar"],"date":"2016-09-22T16:41:38.115Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-time.git"},"links":{"npm":"https://www.npmjs.com/package/d3-time","homepage":"https://d3js.org/d3-time/","repository":"https://github.com/d3/d3-time","bugs":"https://github.com/d3/d3-time/issues"},"license":"BSD-3-Clause","devDependencies":{"eslint":"3","package-preamble":"0.0","rollup":"0.36","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-22T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":2},{"from":"2016-07-24T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":5},{"from":"2016-04-25T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":10},{"from":"2015-10-23T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":20},{"from":"2014-10-23T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":24}],"hasTestScript":true,"readme":"# d3-time\n\nWhen visualizing time series data, analyzing temporal patterns, or working with time in general, the irregularities of conventional time units quickly become apparent. In the [Gregorian calendar](https://en.wikipedia.org/wiki/Gregorian_calendar), for example, most months have 31 days but some have 28, 29 or 30; most years have 365 days but [leap years](https://en.wikipedia.org/wiki/Leap_year) have 366; and with [daylight saving](https://en.wikipedia.org/wiki/Daylight_saving_time), most days have 24 hours but some have 23 or 25. Adding to complexity, daylight saving conventions vary around the world.\n\nAs a result of these temporal peculiarities, it can be difficult to perform seemingly-trivial tasks. For example, if you want to compute the number of days that have passed between two dates, you can’t simply subtract and divide by 24 hours (86,400,000 ms):\n\n```js\nvar start = new Date(2015, 02, 01), // Sun Mar 01 2015 00:00:00 GMT-0800 (PST)\n end = new Date(2015, 03, 01); // Wed Apr 01 2015 00:00:00 GMT-0700 (PDT)\n(end - start) / 864e5; // 30.958333333333332, oops!\n```\n\nYou can, however, use [timeDay](#timeDay).[count](#interval_count):\n\n```js\nd3.timeDay.count(start, end); // 31\n```\n\nThe [day](#day) [interval](#api-reference) is one of several provided by d3-time. Each interval represents a conventional unit of time—[hours](#timeHour), [weeks](#timeWeek), [months](#timeMonth), *etc.*—and has methods to calculate boundary dates. For example, [timeDay](#timeDay) computes midnight (typically 12:00 AM local time) of the corresponding day. In addition to [rounding](#interval_round) and [counting](#interval_count), intervals can also be used to generate arrays of boundary dates. For example, to compute each Sunday in the current month:\n\n```js\nvar now = new Date;\nd3.timeWeek.range(d3.timeMonth.floor(now), d3.timeMonth.ceil(now));\n// [Sun Jun 07 2015 00:00:00 GMT-0700 (PDT),\n// Sun Jun 14 2015 00:00:00 GMT-0700 (PDT),\n// Sun Jun 21 2015 00:00:00 GMT-0700 (PDT),\n// Sun Jun 28 2015 00:00:00 GMT-0700 (PDT)]\n```\n\nThe d3-time module does not implement its own calendaring system; it merely implements a convenient API for calendar math on top of ECMAScript [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date). Thus, it ignores leap seconds and can only work with the local time zone and [Coordinated Universal Time](https://en.wikipedia.org/wiki/Coordinated_Universal_Time) (UTC).\n\nThis module is used by D3’s time scales to generate sensible ticks, by D3’s time format, and can also be used directly to do things like [calendar layouts](http://bl.ocks.org/mbostock/4063318).\n\n## Installing\n\nIf you use NPM, `npm install d3-time`. Otherwise, download the [latest release](https://github.com/d3/d3-time/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-time.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-time.v1.min.js\"></script>\n<script>\n\nvar day = d3.timeDay(new Date);\n\n</script>\n```\n\n[Try d3-time in your browser.](https://tonicdev.com/npm/d3-time)\n\n## API Reference\n\n<a name=\"_interval\" href=\"#_interval\">#</a> <i>interval</i>(<i>date</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L6 \"Source\")\n\nAlias for [*interval*.floor](#interval_floor). For example, [timeYear](#timeYear)(*date*) and timeYear.floor(*date*) are equivalent.\n\n<a name=\"interval_floor\" href=\"#interval_floor\">#</a> <i>interval</i>.<b>floor</b>(<i>date</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L10 \"Source\")\n\nReturns a new date representing the latest interval boundary date before or equal to *date*. For example, [timeDay](#timeDay).floor(*date*) typically returns 12:00 AM local time on the given *date*.\n\nThis method is idempotent: if the specified *date* is already floored to the current interval, a new date with an identical time is returned. Furthermore, the returned date is the minimum expressible value of the associated interval, such that *interval*.floor(*interval*.floor(*date*) - 1) returns the preceeding interval boundary date.\n\nNote that the `==` and `===` operators do not compare by value with [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects, and thus you cannot use them to tell whether the specified *date* has already been floored. Instead, coerce to a number and then compare:\n\n```js\n// Returns true if the specified date is a day boundary.\nfunction isDay(date) {\n return +d3.timeDay.floor(date) === +date;\n}\n```\n\nThis is more reliable than testing whether the time is 12:00 AM, as in some time zones midnight may not exist due to daylight saving.\n\n<a name=\"interval_round\" href=\"#interval_round\">#</a> <i>interval</i>.<b>round</b>(<i>date</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L16 \"Source\")\n\nReturns a new date representing the closest interval boundary date to *date*. For example, [timeDay](#timeDay).round(*date*) typically returns 12:00 AM local time on the given *date* if it is on or before noon, and 12:00 AM of the following day if it is after noon.\n\nThis method is idempotent: if the specified *date* is already rounded to the current interval, a new date with an identical time is returned.\n\n<a name=\"interval_ceil\" href=\"#interval_ceil\">#</a> <i>interval</i>.<b>ceil</b>(<i>date</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L12 \"Source\")\n\nReturns a new date representing the earliest interval boundary date after or equal to *date*. For example, [timeDay](#timeDay).ceil(*date*) typically returns 12:00 AM local time on the date following the given *date*.\n\nThis method is idempotent: if the specified *date* is already ceilinged to the current interval, a new date with an identical time is returned. Furthermore, the returned date is the maximum expressible value of the associated interval, such that *interval*.ceil(*interval*.ceil(*date*) + 1) returns the following interval boundary date.\n\n<a name=\"interval_offset\" href=\"#interval_offset\">#</a> <i>interval</i>.<b>offset</b>(<i>date</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L22 \"Source\")\n\nReturns a new date equal to *date* plus *step* intervals. If *step* is not specified it defaults to 1. If *step* is negative, then the returned date will be before the specified *date*; if *step* is zero, then a copy of the specified *date* is returned; if *step* is not an integer, it is [floored](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor). This method does not round the specified *date* to the interval. For example, if *date* is today at 5:34 PM, then [timeDay](#timeDay).offset(*date*, 1) returns 5:34 PM tomorrow (even if daylight saving changes!).\n\n<a name=\"interval_range\" href=\"#interval_range\">#</a> <i>interval</i>.<b>range</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L26 \"Source\")\n\nReturns every an array of dates representing every interval boundary after or equal to *start* (inclusive) and before *stop* (exclusive). If *step* is specified, then every *step*th boundary will be returned; for example, for the [timeDay](#timeDay) interval a *step* of 2 will return every other day. If *step* is not an integer, it is [floored](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor).\n\nThe first date in the returned array is the earliest boundary after or equal to *start*; subsequent dates are [offset](#interval_offset) by *step* intervals and [floored](#interval_floor). Thus, two overlapping ranges may be consistent. For example, this range contains odd days:\n\n```js\nd3.timeDay.range(new Date(2015, 0, 1), new Date(2015, 0, 7), 2);\n// [Thu Jan 01 2015 00:00:00 GMT-0800 (PST),\n// Sat Jan 03 2015 00:00:00 GMT-0800 (PST),\n// Mon Jan 05 2015 00:00:00 GMT-0800 (PST)]\n```\n\nWhile this contains even days:\n\n```js\nd3.timeDay.range(new Date(2015, 0, 2), new Date(2015, 0, 8), 2);\n// [Fri Jan 02 2015 00:00:00 GMT-0800 (PST),\n// Sun Jan 04 2015 00:00:00 GMT-0800 (PST),\n// Tue Jan 06 2015 00:00:00 GMT-0800 (PST)]\n```\n\nTo make ranges consistent when a *step* is specified, use [*interval*.every](#interval_every) instead.\n\n<a name=\"interval_filter\" href=\"#interval_filter\">#</a> <i>interval</i>.<b>filter</b>(<i>test</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L35 \"Source\")\n\nReturns a new interval that is a filtered subset of this interval using the specified *test* function. The *test* function is passed a date and should return true if and only if the specified date should be considered part of the interval. For example, to create an interval that returns the 1st, 11th, 21th and 31th (if it exists) of each month:\n\n```js\nvar i = d3.timeDay.filter(function(d) { return (d.getDate() - 1) % 10 === 0; });\n```\n\nThe returned filtered interval does not support [count](#interval_count). See also [*interval*.every](#interval_every).\n\n<a name=\"interval_every\" href=\"#interval_every\">#</a> <i>interval</i>.<b>every</b>(<i>step</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L50 \"Source\")\n\nReturns a [filtered](#interval_filter) view of this interval representing every *step*th date. The meaning of *step* is dependent on this interval’s parent interval as defined by the field function. For example, [timeMinute](#timeMinute).every(15) returns an interval representing every fifteen minutes, starting on the hour: :00, :15, :30, :45, <i>etc.</i> Note that for some intervals, the resulting dates may not be uniformly-spaced; [timeDay](#timeDay)’s parent interval is [timeMonth](#timeMonth), and thus the interval number resets at the start of each month. If *step* is not valid, returns null. If *step* is one, returns this interval.\n\nThis method can be used in conjunction with [*interval*.range](#interval_range) to ensure that two overlapping ranges are consistent. For example, this range contains odd days:\n\n```js\nd3.timeDay.every(2).range(new Date(2015, 0, 1), new Date(2015, 0, 7));\n// [Thu Jan 01 2015 00:00:00 GMT-0800 (PST),\n// Sat Jan 03 2015 00:00:00 GMT-0800 (PST),\n// Mon Jan 05 2015 00:00:00 GMT-0800 (PST)]\n```\n\nAs does this one:\n\n```js\nd3.timeDay.every(2).range(new Date(2015, 0, 2), new Date(2015, 0, 8));\n// [Sat Jan 03 2015 00:00:00 GMT-0800 (PST),\n// Mon Jan 05 2015 00:00:00 GMT-0800 (PST),\n// Wed Jan 07 2015 00:00:00 GMT-0800 (PST)]\n```\n\nSee also [*interval*.filter](#interval_filter).\n\n<a name=\"interval_count\" href=\"#interval_count\">#</a> <i>interval</i>.<b>count</b>(<i>start</i>, <i>end</i>) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L44 \"Source\")\n\nReturns the number of interval boundaries after *start* (exclusive) and before or equal to *end* (inclusive). Note that this behavior is slightly different than [*interval*.range](#interval_range) because its purpose is to return the zero-based number of the specified *end* date relative to the specified *start* date. For example, to compute the current zero-based day-of-year number:\n\n```js\nvar now = new Date;\nd3.timeDay.count(d3.timeYear(now), now); // 177\n```\n\nLikewise, to compute the current zero-based week-of-year number for weeks that start on Sunday:\n\n```js\nd3.timeSunday.count(d3.timeYear(now), now); // 25\n```\n\n<a name=\"timeInterval\" href=\"#timeInterval\">#</a> d3.<b>timeInterval</b>(<i>floor</i>, <i>offset</i>[, <i>count</i>[, <i>field</i>]]) [<>](https://github.com/d3/d3-time/blob/master/src/interval.js#L4 \"Source\")\n\nConstructs a new custom interval given the specified *floor* and *offset* functions and an optional *count* function.\n\nThe *floor* function takes a single date as an argument and rounds it down to the nearest interval boundary.\n\nThe *offset* function takes a date and an integer step as arguments and advances the specified date by the specified number of boundaries; the step may be positive, negative or zero.\n\nThe optional *count* function takes a start date and an end date, already floored to the current interval, and returns the number of boundaries between the start (exclusive) and end (inclusive). If a *count* function is not specified, the returned interval does not expose [count](#interval_count) or [every](#interval_every) methods. Note: due to an internal optimization, the specified *count* function must not invoke *interval*.count on other time intervals.\n\nThe optional *field* function takes a date, already floored to the current interval, and returns the field value of the specified date, corresponding to the number of boundaries between this date (exclusive) and the latest previous parent boundary. For example, for the [timeDay](#timeDay) interval, this returns the number of days since the start of the month. If a *field* function is not specified, it defaults to counting the number of interval boundaries since the UNIX epoch of January 1, 1970 UTC. The *field* function defines the behavior of [*interval*.every](#interval_every).\n\n### Intervals\n\nThe following intervals are provided:\n\n<a name=\"timeMillisecond\" href=\"#timeMillisecond\">#</a> d3.<b>timeMillisecond</b> [<>](https://github.com/d3/d3-time/blob/master/src/millisecond.js \"Source\")\n<br><a href=\"#timeMillisecond\">#</a> d3.<b>utcMillisecond</b>\n\nMilliseconds; the shortest available time unit.\n\n<a name=\"timeSecond\" href=\"#timeSecond\">#</a> d3.<b>timeSecond</b> [<>](https://github.com/d3/d3-time/blob/master/src/second.js \"Source\")\n<br><a href=\"#timeSecond\">#</a> d3.<b>utcSecond</b>\n\nSeconds (e.g., 01:23:45.0000 AM); 1,000 milliseconds.\n\n<a name=\"timeMinute\" href=\"#timeMinute\">#</a> d3.<b>timeMinute</b> [<>](https://github.com/d3/d3-time/blob/master/src/minute.js \"Source\")\n<br><a href=\"#timeMinute\">#</a> d3.<b>utcMinute</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcMinute.js \"Source\")\n\nMinutes (e.g., 01:02:00 AM); 60 seconds. Note that ECMAScript [ignores leap seconds](http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.1).\n\n<a name=\"timeHour\" href=\"#timeHour\">#</a> d3.<b>timeHour</b> [<>](https://github.com/d3/d3-time/blob/master/src/hour.js \"Source\")\n<br><a href=\"#timeHour\">#</a> d3.<b>utcHour</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcHour.js \"Source\")\n\nHours (e.g., 01:00 AM); 60 minutes. Note that advancing time by one hour in local time can return the same hour or skip an hour due to daylight saving.\n\n<a name=\"timeDay\" href=\"#timeDay\">#</a> d3.<b>timeDay</b> [<>](https://github.com/d3/d3-time/blob/master/src/day.js \"Source\")\n<br><a href=\"#timeDay\">#</a> d3.<b>utcDay</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcDay.js \"Source\")\n\nDays (e.g., February 7, 2012 at 12:00 AM); typically 24 hours. Days in local time may range from 23 to 25 hours due to daylight saving.\n\n<a name=\"timeWeek\" href=\"#timeWeek\">#</a> d3.<b>timeWeek</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js \"Source\")\n<br><a href=\"#timeWeek\">#</a> d3.<b>utcWeek</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js \"Source\")\n\nAlias for [sunday](#sunday); 7 days and typically 168 hours. Weeks in local time may range from 167 to 169 hours due on daylight saving.\n\n<a name=\"timeSunday\" href=\"#timeSunday\">#</a> d3.<b>timeSunday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L15 \"Source\")\n<br><a href=\"#timeSunday\">#</a> d3.<b>utcSunday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L15 \"Source\")\n\nSunday-based weeks (e.g., February 5, 2012 at 12:00 AM).\n\n<a name=\"timeMonday\" href=\"#timeMonday\">#</a> d3.<b>timeMonday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L16 \"Source\")\n<br><a href=\"#timeMonday\">#</a> d3.<b>utcMonday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L16 \"Source\")\n\nMonday-based weeks (e.g., February 6, 2012 at 12:00 AM).\n\n<a name=\"timeTuesday\" href=\"#timeTuesday\">#</a> d3.<b>timeTuesday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L17 \"Source\")\n<br><a href=\"#timeTuesday\">#</a> d3.<b>utcTuesday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L17 \"Source\")\n\nTuesday-based weeks (e.g., February 7, 2012 at 12:00 AM).\n\n<a name=\"timeWednesday\" href=\"#timeWednesday\">#</a> d3.<b>timeWednesday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L18 \"Source\")\n<br><a href=\"#timeWednesday\">#</a> d3.<b>utcWednesday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L18 \"Source\")\n\nWednesday-based weeks (e.g., February 8, 2012 at 12:00 AM).\n\n<a name=\"timeThursday\" href=\"#timeThursday\">#</a> d3.<b>timeThursday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L19 \"Source\")\n<br><a href=\"#timeThursday\">#</a> d3.<b>utcThursday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L19 \"Source\")\n\nThursday-based weeks (e.g., February 9, 2012 at 12:00 AM).\n\n<a name=\"timeFriday\" href=\"#timeFriday\">#</a> d3.<b>timeFriday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L20 \"Source\")\n<br><a href=\"#timeFriday\">#</a> d3.<b>utcFriday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L20 \"Source\")\n\nFriday-based weeks (e.g., February 10, 2012 at 12:00 AM).\n\n<a name=\"timeSaturday\" href=\"#timeSaturday\">#</a> d3.<b>timeSaturday</b> [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L21 \"Source\")\n<br><a href=\"#timeSaturday\">#</a> d3.<b>utcSaturday</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L21 \"Source\")\n\nSaturday-based weeks (e.g., February 11, 2012 at 12:00 AM).\n\n<a name=\"timeMonth\" href=\"#timeMonth\">#</a> d3.<b>timeMonth</b> [<>](https://github.com/d3/d3-time/blob/master/src/month.js \"Source\")\n<br><a href=\"#timeMonth\">#</a> d3.<b>utcMonth</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcMonth.js \"Source\")\n\nMonths (e.g., February 1, 2012 at 12:00 AM); ranges from 28 to 31 days.\n\n<a name=\"timeYear\" href=\"#timeYear\">#</a> d3.<b>timeYear</b> [<>](https://github.com/d3/d3-time/blob/master/src/year.js \"Source\")\n<br><a href=\"#timeYear\">#</a> d3.<b>utcYear</b> [<>](https://github.com/d3/d3-time/blob/master/src/utcYear.js \"Source\")\n\nYears (e.g., January 1, 2012 at 12:00 AM); ranges from 365 to 366 days.\n\n### Ranges\n\nFor convenience, aliases for [*interval*.range](#interval_range) are also provided as plural forms of the corresponding interval.\n\n<a name=\"timeMilliseconds\" href=\"#timeMilliseconds\">#</a> d3.<b>timeMilliseconds</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/millisecond.js#L26 \"Source\")\n<br><a href=\"#timeMilliseconds\">#</a> d3.<b>utcMilliseconds</b>(<i>start</i>, <i>stop</i>[, <i>step</i>])\n\nAliases for [timeMillisecond](#timeMillisecond).[range](#interval_range) and [utcMillisecond](#timeMillisecond).[range](#interval_range).\n\n<a name=\"timeSeconds\" href=\"#timeSeconds\">#</a> d3.<b>timeSeconds</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/second.js#L15 \"Source\")\n<br><a href=\"#timeSeconds\">#</a> d3.<b>utcSeconds</b>(<i>start</i>, <i>stop</i>[, <i>step</i>])\n\nAliases for [timeSecond](#timeSecond).[range](#interval_range) and [utcSecond](#timeSecond).[range](#interval_range).\n\n<a name=\"timeMinutes\" href=\"#timeMinutes\">#</a> d3.<b>timeMinutes</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/minute.js#L15 \"Source\")\n<br><a href=\"#timeMinutes\">#</a> d3.<b>utcMinutes</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcMinute.js#L15 \"Source\")\n\nAliases for [timeMinute](#timeMinute).[range](#interval_range) and [utcMinute](#timeMinute).[range](#interval_range).\n\n<a name=\"timeHours\" href=\"#timeHours\">#</a> d3.<b>timeHours</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/hour.js#L17 \"Source\")\n<br><a href=\"#timeHours\">#</a> d3.<b>utcHours</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcHour.js#L15 \"Source\")\n\nAliases for [timeHour](#timeHour).[range](#interval_range) and [utcHour](#timeHour).[range](#interval_range).\n\n<a name=\"timeDays\" href=\"#timeDays\">#</a> d3.<b>timeDays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/day.js#L15 \"Source\")\n<br><a href=\"#timeDays\">#</a> d3.<b>utcDays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcDay.js#L15 \"Source\")\n\nAliases for [timeDay](#timeDay).[range](#interval_range) and [utcDay](#timeDay).[range](#interval_range).\n\n<a name=\"timeWeeks\" href=\"#timeWeeks\">#</a> d3.<b>timeWeeks</b>(<i>start</i>, <i>stop</i>[, <i>step</i>])\n<br><a href=\"#timeWeeks\">#</a> d3.<b>utcWeeks</b>(<i>start</i>, <i>stop</i>[, <i>step</i>])\n\nAliases for [timeWeek](#timeWeek).[range](#interval_range) and [utcWeek](#timeWeek).[range](#interval_range).\n\n<a name=\"timeSundays\" href=\"#timeSundays\">#</a> d3.<b>timeSundays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L23 \"Source\")\n<br><a href=\"#timeSundays\">#</a> d3.<b>utcSundays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L23 \"Source\")\n\nAliases for [timeSunday](#timeSunday).[range](#interval_range) and [utcSunday](#timeSunday).[range](#interval_range).\n\n<a name=\"timeMondays\" href=\"#timeMondays\">#</a> d3.<b>timeMondays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L24 \"Source\")\n<br><a href=\"#timeMondays\">#</a> d3.<b>utcMondays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L24 \"Source\")\n\nAliases for [timeMonday](#timeMonday).[range](#interval_range) and [utcMonday](#timeMonday).[range](#interval_range).\n\n<a name=\"timeTuesdays\" href=\"#timeTuesdays\">#</a> d3.<b>timeTuesdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L25 \"Source\")\n<br><a href=\"#timeTuesdays\">#</a> d3.<b>utcTuesdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L25 \"Source\")\n\nAliases for [timeTuesday](#timeTuesday).[range](#interval_range) and [utcTuesday](#timeTuesday).[range](#interval_range).\n\n<a name=\"timeWednesdays\" href=\"#timeWednesdays\">#</a> d3.<b>timeWednesdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L26 \"Source\")\n<br><a href=\"#timeWednesdays\">#</a> d3.<b>utcWednesdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L26 \"Source\")\n\nAliases for [timeWednesday](#timeWednesday).[range](#interval_range) and [utcWednesday](#timeWednesday).[range](#interval_range).\n\n<a name=\"timeThursdays\" href=\"#timeThursdays\">#</a> d3.<b>timeThursdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L27 \"Source\")\n<br><a href=\"#timeThursdays\">#</a> d3.<b>utcThursdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L27 \"Source\")\n\nAliases for [timeThursday](#timeThursday).[range](#interval_range) and [utcThursday](#timeThursday).[range](#interval_range).\n\n<a name=\"timeFridays\" href=\"#timeFridays\">#</a> d3.<b>timeFridays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L28 \"Source\")\n<br><a href=\"#timeFridays\">#</a> d3.<b>utcFridays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L28 \"Source\")\n\nAliases for [timeFriday](#timeFriday).[range](#interval_range) and [utcFriday](#timeFriday).[range](#interval_range).\n\n<a name=\"timeSaturdays\" href=\"#timeSaturdays\">#</a> d3.<b>timeSaturdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/week.js#L29 \"Source\")\n<br><a href=\"#timeSaturdays\">#</a> d3.<b>utcSaturdays</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcWeek.js#L29 \"Source\")\n\nAliases for [timeSaturday](#timeSaturday).[range](#interval_range) and [utcSaturday](#timeSaturday).[range](#interval_range).\n\n<a name=\"timeMonths\" href=\"#timeMonths\">#</a> d3.<b>timeMonths</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/month.js#L15 \"Source\")\n<br><a href=\"#timeMonths\">#</a> d3.<b>utcMonths</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcMonth.js#L15 \"Source\")\n\nAliases for [timeMonth](#timeMonth).[range](#interval_range) and [utcMonth](#timeMonth).[range](#interval_range).\n\n<a name=\"timeYears\" href=\"#timeYears\">#</a> d3.<b>timeYears</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/year.js#L26 \"Source\")\n<br><a href=\"#timeYears\">#</a> d3.<b>utcYears</b>(<i>start</i>, <i>stop</i>[, <i>step</i>]) [<>](https://github.com/d3/d3-time/blob/master/src/utcYear.js#L26 \"Source\")\n\nAliases for [timeYear](#timeYear).[range](#interval_range) and [utcYear](#timeYear).[range](#interval_range)."},"npm":{"downloads":[{"from":"2016-10-21T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":4068},{"from":"2016-10-15T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":26632},{"from":"2016-09-22T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":110519},{"from":"2016-07-24T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":247497},{"from":"2016-04-25T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":317862},{"from":"2015-10-23T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":367362}],"dependentsCount":15,"starsCount":1},"github":{"starsCount":90,"forksCount":10,"subscribersCount":10,"issues":{"count":15,"openCount":2,"distribution":{"3600":3,"10800":1,"32400":3,"97200":4,"291600":1,"874800":0,"2624400":1,"7873200":0,"23619600":0,"70858800":2,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":153},{"username":"Devinsuit","commitsCount":1},{"username":"pjaspers","commitsCount":1}],"commits":[{"from":"2016-10-15T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":0},{"from":"2016-09-22T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":0},{"from":"2016-07-24T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":10},{"from":"2016-04-25T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":26},{"from":"2015-10-23T00:00:00.000Z","to":"2016-10-22T00:00:00.000Z","count":58}]},"source":{"files":{"readmeSize":25386,"testsSize":173656,"hasNpmIgnore":true},"repositorySize":215467,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":114,"downloadsCount":82499,"downloadsAcceleration":859.2310502283106,"dependentsCount":15},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.731451405151934,"detail":{"quality":0.9260256430415238,"popularity":0.2962463207753904,"maintenance":0.9998785713374008}}}},{"package":{"name":"d3-dsv","version":"1.0.3","description":"A parser and formatter for delimiter-separated values, such as CSV and TSV","keywords":["d3","d3-module","dsv","csv","tsv"],"date":"2016-09-09T22:42:43.211Z","links":{"npm":"https://www.npmjs.com/package/d3-dsv","homepage":"https://d3js.org/d3-dsv/","repository":"https://github.com/d3/d3-dsv","bugs":"https://github.com/d3/d3-dsv/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7279744165163313,"detail":{"quality":0.9260256430415238,"popularity":0.28631206753081134,"maintenance":0.9998785713374008}},"searchScore":0.0068290345,"metadata":{"analyzedAt":"2016-10-18T22:32:48.576Z","collected":{"metadata":{"name":"d3-dsv","version":"1.0.3","description":"A parser and formatter for delimiter-separated values, such as CSV and TSV","keywords":["d3","d3-module","dsv","csv","tsv"],"date":"2016-09-09T22:42:43.211Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-dsv.git"},"links":{"npm":"https://www.npmjs.com/package/d3-dsv","homepage":"https://d3js.org/d3-dsv/","repository":"https://github.com/d3/d3-dsv","bugs":"https://github.com/d3/d3-dsv/issues"},"license":"BSD-3-Clause","dependencies":{"commander":"2","iconv-lite":"0.4","rw":"1"},"devDependencies":{"eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-18T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":0},{"from":"2016-07-20T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":4},{"from":"2016-04-21T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":6},{"from":"2015-10-19T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":19},{"from":"2014-10-19T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":26}],"hasTestScript":true,"readme":"# d3-dsv\n\nThis module provides a parser and formatter for delimiter-separated values, most commonly [comma-](https://en.wikipedia.org/wiki/Comma-separated_values) (CSV) or tab-separated values (TSV). These tabular formats are popular with spreadsheet programs such as Microsoft Excel, and are often more space-efficient than JSON. This implementation is based on [RFC 4180](http://tools.ietf.org/html/rfc4180).\n\nComma (CSV) and tab (TSV) delimiters are built-in. For example, to parse:\n\n```js\nd3.csvParse(\"foo,bar\\n1,2\"); // [{foo: \"1\", bar: \"2\"}, columns: [\"foo\", \"bar\"]]\nd3.tsvParse(\"foo\\tbar\\n1\\t2\"); // [{foo: \"1\", bar: \"2\"}, columns: [\"foo\", \"bar\"]]\n```\n\nOr to format:\n\n```js\nd3.csvFormat([{foo: \"1\", bar: \"2\"}]); // \"foo,bar\\n1,2\"\nd3.tsvFormat([{foo: \"1\", bar: \"2\"}]); // \"foo\\tbar\\n1\\t2\"\n```\n\nTo use a different delimiter, such as “|” for pipe-separated values, use [d3.dsvFormat](#dsvFormat):\n\n```js\nvar psv = d3.dsvFormat(\"|\");\n\nconsole.log(psv.parse(\"foo|bar\\n1|2\")); // [{foo: \"1\", bar: \"2\"}, columns: [\"foo\", \"bar\"]]\n```\n\nFor easy loading of DSV files in a browser, see [d3-request](https://github.com/d3/d3-request)’s [d3.csv](https://github.com/d3/d3-request#csv) and [d3.tsv](https://github.com/d3/d3-request#tsv) methods.\n\n## Installing\n\nIf you use NPM, `npm install d3-dsv`. Otherwise, download the [latest release](https://github.com/d3/d3-dsv/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-dsv.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-dsv.v1.min.js\"></script>\n<script>\n\nvar data = d3.csvParse(string);\n\n</script>\n```\n\n[Try d3-dsv in your browser.](https://tonicdev.com/npm/d3-dsv)\n\n## API Reference\n\n<a name=\"csvParse\" href=\"#csvParse\">#</a> d3.<b>csvParse</b>(<i>string</i>[, <i>row</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js#L5 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\",\").[parse](#dsv_parse).\n\n<a name=\"csvParseRows\" href=\"#csvParseRows\">#</a> d3.<b>csvParseRows</b>(<i>string</i>[, <i>row</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js#L6 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\",\").[parseRows](#dsv_parseRows).\n\n<a name=\"csvFormat\" href=\"#csvFormat\">#</a> d3.<b>csvFormat</b>(<i>rows</i>[, <i>columns</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js#L7 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\",\").[format](#dsv_format).\n\n<a name=\"csvFormatRows\" href=\"#csvFormatRows\">#</a> d3.<b>csvFormatRows</b>(<i>rows</i>) [<>](https://github.com/d3/d3-dsv/blob/master/src/csv.js#L8 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\",\").[formatRows](#dsv_formatRows).\n\n<a name=\"tsvParse\" href=\"#tsvParse\">#</a> d3.<b>tsvParse</b>(<i>string</i>[, <i>row</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js#L5 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\"\\t\").[parse](#dsv_parse).\n\n<a name=\"tsvParseRows\" href=\"#tsvParseRows\">#</a> d3.<b>tsvParseRows</b>(<i>string</i>[, <i>row</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js#L6 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\"\\t\").[parseRows](#dsv_parseRows).\n\n<a name=\"tsvFormat\" href=\"#tsvFormat\">#</a> d3.<b>tsvFormat</b>(<i>rows</i>[, <i>columns</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js#L7 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\"\\t\").[format](#dsv_format).\n\n<a name=\"tsvFormatRows\" href=\"#tsvFormatRows\">#</a> d3.<b>tsvFormatRows</b>(<i>rows</i>) [<>](https://github.com/d3/d3-dsv/blob/master/src/tsv.js#L8 \"Source\")\n\nEquivalent to [dsvFormat](#dsvFormat)(\"\\t\").[formatRows](#dsv_formatRows).\n\n<a name=\"dsvFormat\" href=\"#dsvFormat\">#</a> d3.<b>dsvFormat</b>(<i>delimiter</i>) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js#L30)\n\nConstructs a new DSV parser and formatter for the specified *delimiter*. The *delimiter* must be a single character (*i.e.*, a single 16-bit code unit); so, ASCII delimiters are fine, but emoji delimiters are not.\n\n<a name=\"dsv_parse\" href=\"#dsv_parse\">#</a> *dsv*.<b>parse</b>(<i>string</i>[, <i>row</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js#L34 \"Source\")\n\nParses the specified *string*, which must be in the delimiter-separated values format with the appropriate delimiter, returning an array of objects representing the parsed rows.\n\nUnlike [*dsv*.parseRows](#dsv_parseRows), this method requires that the first line of the DSV content contains a delimiter-separated list of column names; these column names become the attributes on the returned objects. For example, consider the following CSV file:\n\n```\nYear,Make,Model,Length\n1997,Ford,E350,2.34\n2000,Mercury,Cougar,2.38\n```\n\nThe resulting JavaScript array is:\n\n```js\n[\n {\"Year\": \"1997\", \"Make\": \"Ford\", \"Model\": \"E350\", \"Length\": \"2.34\"},\n {\"Year\": \"2000\", \"Make\": \"Mercury\", \"Model\": \"Cougar\", \"Length\": \"2.38\"}\n]\n```\n\nThe returned array also exposes a `columns` property containing the column names in input order (in contrast to Object.keys, whose iteration order is arbitrary). For example:\n\n```js\ndata.columns; // [\"Year\", \"Make\", \"Model\", \"Length\"]\n```\n\nIf a *row* conversion function is not specified, field values are strings. For safety, there is no automatic conversion to numbers, dates, or other types. In some cases, JavaScript may coerce strings to numbers for you automatically (for example, using the `+` operator), but better is to specify a *row* conversion function.\n\nIf a *row* conversion function is specified, the specified function is invoked for each row, being passed an object representing the current row (`d`), the index (`i`) starting at zero for the first non-header row, and the array of column names. If the returned value is null or undefined, the row is skipped and will be ommitted from the array returned by *dsv*.parse; otherwise, the returned value defines the corresponding row object. For example:\n\n```js\nvar data = d3.csvParse(string, function(d) {\n return {\n year: new Date(+d.Year, 0, 1), // lowercase and convert \"Year\" to Date\n make: d.Make, // lowercase\n model: d.Model, // lowercase\n length: +d.Length // lowercase and convert \"Length\" to number\n };\n});\n```\n\nNote: using `+` rather than [parseInt](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseInt) or [parseFloat](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/parseFloat) is typically faster, though more restrictive. For example, `\"30px\"` when coerced using `+` returns `NaN`, while parseInt and parseFloat return `30`.\n\n<a name=\"dsv_parseRows\" href=\"#dsv_parseRows\">#</a> <i>dsv</i>.<b>parseRows</b>(<i>string</i>[, <i>row</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js#L43 \"Source\")\n\nParses the specified *string*, which must be in the delimiter-separated values format with the appropriate delimiter, returning an array of arrays representing the parsed rows.\n\nUnlike [*dsv*.parse](#dsv_parse), this method treats the header line as a standard row, and should be used whenever DSV content does not contain a header. Each row is represented as an array rather than an object. Rows may have variable length. For example, consider the following CSV file, which notably lacks a header line:\n\n```\n1997,Ford,E350,2.34\n2000,Mercury,Cougar,2.38\n```\n\nThe resulting JavaScript array is:\n\n```js\n[\n [\"1997\", \"Ford\", \"E350\", \"2.34\"],\n [\"2000\", \"Mercury\", \"Cougar\", \"2.38\"]\n]\n```\n\nIf a *row* conversion function is not specified, field values are strings. For safety, there is no automatic conversion to numbers, dates, or other types. In some cases, JavaScript may coerce strings to numbers for you automatically (for example, using the `+` operator), but better is to specify a *row* conversion function.\n\nIf a *row* conversion function is specified, the specified function is invoked for each row, being passed an array representing the current row (`d`), the index (`i`) starting at zero for the first row, and the array of column names. If the returned value is null or undefined, the row is skipped and will be ommitted from the array returned by *dsv*.parse; otherwise, the returned value defines the corresponding row object. For example:\n\n```js\nvar data = d3.csvParseRows(string, function(d, i) {\n return {\n year: new Date(+d[0], 0, 1), // convert first colum column to Date\n make: d[1],\n model: d[2],\n length: +d[3] // convert fourth column to number\n };\n});\n```\n\nIn effect, *row* is similar to applying a [map](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/map) and [filter](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/filter) operator to the returned rows.\n\n<a name=\"dsv_format\" href=\"#dsv_format\">#</a> <i>dsv</i>.<b>format</b>(<i>rows</i>[, <i>columns</i>]) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js#L105 \"Source\")\n\nFormats the specified array of object *rows* as delimiter-separated values, returning a string. This operation is the inverse of [*dsv*.parse](#dsv_parse). Each row will be separated by a newline (`\\n`), and each column within each row will be separated by the delimiter (such as a comma, `,`). Values that contain either the delimiter, a double-quote (`\"`) or a newline will be escaped using double-quotes.\n\nIf *columns* is not specified, the list of column names that forms the header row is determined by the union of all properties on all objects in *rows*; the order of columns is nondeterministic. If *columns* is specified, it is an array of strings representing the column names. For example:\n\n```js\nvar string = d3.csvFormat(data, [\"year\", \"make\", \"model\", \"length\"]);\n```\n\nAll fields on each row object will be coerced to strings. For more control over which and how fields are formatted, first map *rows* to an array of array of string, and then use [*dsv*.formatRows](#dsv_formatRows).\n\n<a name=\"dsv_formatRows\" href=\"#dsv_formatRows\">#</a> <i>dsv</i>.<b>formatRows</b>(<i>rows</i>) [<>](https://github.com/d3/d3-dsv/blob/master/src/dsv.js#L114 \"Source\")\n\nFormats the specified array of array of string *rows* as delimiter-separated values, returning a string. This operation is the reverse of [*dsv*.parseRows](#dsv_parseRows). Each row will be separated by a newline (`\\n`), and each column within each row will be separated by the delimiter (such as a comma, `,`). Values that contain either the delimiter, a double-quote (\") or a newline will be escaped using double-quotes.\n\nTo convert an array of objects to an array of arrays while explicitly specifying the columns, use [*array*.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map). For example:\n\n```js\nvar string = d3.csvFormatRows(data.map(function(d, i) {\n return [\n d.year.getFullYear(), // Assuming d.year is a Date object.\n d.make,\n d.model,\n d.length\n ];\n}));\n```\n\nIf you like, you can also [*array*.concat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat) this result with an array of column names to generate the first row:\n\n```js\nvar string = d3.csvFormatRows([[\n \"year\",\n \"make\",\n \"model\",\n \"length\"\n ]].concat(data.map(function(d, i) {\n return [\n d.year.getFullYear(), // Assuming d.year is a Date object.\n d.make,\n d.model,\n d.length\n ];\n})));\n```\n\n### Content Security Policy\n\nIf a [content security policy](http://www.w3.org/TR/CSP/) is in place, note that [*dsv*.parse](#dsv_parse) requires `unsafe-eval` in the `script-src` directive, due to the (safe) use of dynamic code generation for fast parsing. (See [source](https://github.com/d3/d3-dsv/blob/master/src/dsv.js).) Alternatively, use [*dsv*.parseRows](#dsv_parseRows).\n\n## Command Line Reference\n\n### dsv2dsv\n\n<a name=\"dsv2dsv\" href=\"#dsv2dsv\">#</a> <b>dsv2dsv</b> [<i>options…</i>] [<i>file</i>]\n\nConverts the specified DSV input *file* to DSV (typically with a different delimiter or encoding). If *file* is not specified, defaults to reading from stdin. For example, to convert to CSV to TSV:\n\n```\ncsv2tsv < example.csv > example.tsv\n```\n\nTo convert windows-1252 CSV to utf-8 CSV:\n\n```\ndsv2dsv --input-encoding windows-1252 < latin1.csv > utf8.csv\n```\n\n<a name=\"dsv2dsv_help\" href=\"dsv2dsv_help\">#</a> dsv2dsv <b>-h</b>\n<br><a href=\"dsv2dsv_help\">#</a> dsv2dsv <b>--help</b>\n\nOutput usage information.\n\n<a name=\"dsv2dsv_version\" href=\"dsv2dsv_version\">#</a> dsv2dsv <b>-V</b>\n<br><a href=\"dsv2dsv_version\">#</a> dsv2dsv <b>--version</b>\n\nOutput the version number.\n\n<a name=\"dsv2dsv_out\" href=\"dsv2dsv_out\">#</a> dsv2dsv <b>-o</b> <i>file</i>\n<br><a href=\"dsv2dsv_out\">#</a> dsv2dsv <b>--out</b> <i>file</i>\n\nSpecify the output file name. Defaults to “-” for stdout.\n\n<a name=\"dsv2dsv_input_delimiter\" href=\"dsv2dsv_input_delimiter\">#</a> dsv2dsv <b>-r</b> <i>delimiter</i>\n<br><a href=\"dsv2dsv_input_delimiter\">#</a> dsv2dsv <b>--input-delimiter</b> <i>delimiter</i>\n\nSpecify the input delimiter character. Defaults to “,” for reading CSV. (You can enter a tab on the command line by typing ⌃V.)\n\n<a name=\"dsv2dsv_input_encoding\" href=\"dsv2dsv_input_encoding\">#</a> dsv2dsv <b>--input-encoding</b> <i>encoding</i>\n\nSpecify the input character encoding. Defaults to “utf8”.\n\n<a name=\"dsv2dsv_output_delimiter\" href=\"dsv2dsv_output_delimiter\">#</a> dsv2dsv <b>-w</b> <i>delimiter</i>\n<br><a href=\"dsv2dsv_output_delimiter\">#</a> dsv2dsv <b>--output-delimiter</b> <i>delimiter</i>\n\nSpecify the output delimiter character. Defaults to “,” for writing CSV. (You can enter a tab on the command line by typing ⌃V.)\n\n<a name=\"dsv2dsv_output_encoding\" href=\"dsv2dsv_output_encoding\">#</a> dsv2dsv <b>--output-encoding</b> <i>encoding</i>\n\nSpecify the output character encoding. Defaults to “utf8”.\n\n<a name=\"csv2tsv\" href=\"#csv2tsv\">#</a> <b>csv2tsv</b> [<i>options…</i>] [<i>file</i>]\n\nEquivalent to [dsv2dsv](#dsv2dsv), but the [output delimiter](#dsv2dsv_output_delimiter) defaults to the tab character (\\t).\n\n<a name=\"tsv2csv\" href=\"#tsv2csv\">#</a> <b>tsv2csv</b> [<i>options…</i>] [<i>file</i>]\n\nEquivalent to [dsv2dsv](#dsv2dsv), but the [input delimiter](#dsv2dsv_output_delimiter) defaults to the tab character (\\t).\n\n### dsv2json\n\n<a name=\"dsv2json\" href=\"#dsv2json\">#</a> <b>dsv2json</b> [<i>options…</i>] [<i>file</i>]\n\nConverts the specified DSV input *file* to JSON. If *file* is not specified, defaults to reading from stdin. For example, to convert to CSV to JSON:\n\n```\ncsv2json < example.csv > example.json\n```\n\nOr to convert CSV to a newline-delimited JSON stream:\n\n```\ncsv2json -n < example.csv > example.ndjson\n```\n\n<a name=\"dsv2json_help\" href=\"dsv2json_help\">#</a> dsv2json <b>-h</b>\n<br><a href=\"dsv2json_help\">#</a> dsv2json <b>--help</b>\n\nOutput usage information.\n\n<a name=\"dsv2json_version\" href=\"dsv2json_version\">#</a> dsv2json <b>-V</b>\n<br><a href=\"dsv2json_version\">#</a> dsv2json <b>--version</b>\n\nOutput the version number.\n\n<a name=\"dsv2json_out\" href=\"dsv2json_out\">#</a> dsv2json <b>-o</b> <i>file</i>\n<br><a href=\"dsv2json_out\">#</a> dsv2json <b>--out</b> <i>file</i>\n\nSpecify the output file name. Defaults to “-” for stdout.\n\n<a name=\"dsv2json_input_delimiter\" href=\"dsv2json_input_delimiter\">#</a> dsv2json <b>-r</b> <i>delimiter</i>\n<br><a href=\"dsv2json_input_delimiter\">#</a> dsv2json <b>--input-delimiter</b> <i>delimiter</i>\n\nSpecify the input delimiter character. Defaults to “,” for reading CSV. (You can enter a tab on the command line by typing ⌃V.)\n\n<a name=\"dsv2json_input_encoding\" href=\"dsv2json_input_encoding\">#</a> dsv2json <b>--input-encoding</b> <i>encoding</i>\n\nSpecify the input character encoding. Defaults to “utf8”.\n\n<a name=\"dsv2json_output_encoding\" href=\"dsv2json_output_encoding\">#</a> dsv2json <b>-r</b> <i>encoding</i>\n<br><a href=\"dsv2json_output_encoding\">#</a> dsv2json <b>--output-encoding</b> <i>encoding</i>\n\nSpecify the output character encoding. Defaults to “utf8”.\n\n<a name=\"dsv2json_newline_delimited\" href=\"dsv2json_newline_delimited\">#</a> dsv2json <b>-n</b>\n<br><a href=\"dsv2json_newline_delimited\">#</a> dsv2json <b>--newline-delimited</b>\n\nOutput [newline-delimited JSON](https://github.com/mbostock/ndjson-cli) instead of a single JSON array.\n\n<a name=\"csv2json\" href=\"#csv2json\">#</a> <b>csv2json</b> [<i>options…</i>] [<i>file</i>]\n\nEquivalent to [dsv2json](#dsv2json).\n\n<a name=\"tsv2json\" href=\"#csv2json\">#</a> <b>tsv2json</b> [<i>options…</i>] [<i>file</i>]\n\nEquivalent to [dsv2json](#dsv2json), but the [input delimiter](#dsv2json_input_delimiter) defaults to the tab character (\\t).\n\n### json2dsv\n\n<a name=\"json2dsv\" href=\"#json2dsv\">#</a> <b>json2dsv</b> [<i>options…</i>] [<i>file</i>]\n\nConverts the specified JSON input *file* to DSV. If *file* is not specified, defaults to reading from stdin. For example, to convert to JSON to CSV:\n\n```\njson2csv < example.json > example.csv\n```\n\nOr to convert a newline-delimited JSON stream to CSV:\n\n```\njson2csv -n < example.ndjson > example.csv\n```\n\n<a name=\"json2dsv_help\" href=\"json2dsv_help\">#</a> json2dsv <b>-h</b>\n<br><a href=\"json2dsv_help\">#</a> json2dsv <b>--help</b>\n\nOutput usage information.\n\n<a name=\"json2dsv_version\" href=\"json2dsv_version\">#</a> json2dsv <b>-V</b>\n<br><a href=\"json2dsv_version\">#</a> json2dsv <b>--version</b>\n\nOutput the version number.\n\n<a name=\"json2dsv_out\" href=\"json2dsv_out\">#</a> json2dsv <b>-o</b> <i>file</i>\n<br><a href=\"json2dsv_out\">#</a> json2dsv <b>--out</b> <i>file</i>\n\nSpecify the output file name. Defaults to “-” for stdout.\n\n<a name=\"json2dsv_input_encoding\" href=\"json2dsv_input_encoding\">#</a> json2dsv <b>--input-encoding</b> <i>encoding</i>\n\nSpecify the input character encoding. Defaults to “utf8”.\n\n<a name=\"json2dsv_output_delimiter\" href=\"json2dsv_output_delimiter\">#</a> json2dsv <b>-w</b> <i>delimiter</i>\n<br><a href=\"json2dsv_output_delimiter\">#</a> json2dsv <b>--output-delimiter</b> <i>delimiter</i>\n\nSpecify the output delimiter character. Defaults to “,” for writing CSV. (You can enter a tab on the command line by typing ⌃V.)\n\n<a name=\"json2dsv_output_encoding\" href=\"json2dsv_output_encoding\">#</a> json2dsv <b>--output-encoding</b> <i>encoding</i>\n\nSpecify the output character encoding. Defaults to “utf8”.\n\n<a name=\"json2dsv_newline_delimited\" href=\"json2dsv_newline_delimited\">#</a> json2dsv <b>-n</b>\n<br><a href=\"json2dsv_newline_delimited\">#</a> json2dsv <b>--newline-delimited</b>\n\nRead [newline-delimited JSON](https://github.com/mbostock/ndjson-cli) instead of a single JSON array.\n\n<a name=\"csv2json\" href=\"#csv2json\">#</a> <b>csv2json</b> [<i>options…</i>] [<i>file</i>]\n\nEquivalent to [json2dsv](#json2dsv).\n\n<a name=\"tsv2json\" href=\"#csv2json\">#</a> <b>tsv2json</b> [<i>options…</i>] [<i>file</i>]\n\nEquivalent to [json2dsv](#json2dsv), but the [output delimiter](#json2dsv_output_delimiter) defaults to the tab character (\\t)."},"npm":{"downloads":[{"from":"2016-10-17T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":3099},{"from":"2016-10-11T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":15547},{"from":"2016-09-18T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":61778},{"from":"2016-07-20T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":148557},{"from":"2016-04-21T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":179544},{"from":"2015-10-19T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":205480}],"dependentsCount":27,"starsCount":1},"github":{"starsCount":92,"forksCount":12,"subscribersCount":8,"issues":{"count":20,"openCount":2,"distribution":{"3600":4,"10800":2,"32400":4,"97200":1,"291600":1,"874800":1,"2624400":1,"7873200":3,"23619600":0,"70858800":3,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":84},{"username":"tmcw","commitsCount":1},{"username":"Devinsuit","commitsCount":1},{"username":"dandv","commitsCount":1}],"commits":[{"from":"2016-10-11T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":0},{"from":"2016-09-18T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":0},{"from":"2016-07-20T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":7},{"from":"2016-04-21T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":14},{"from":"2015-10-19T00:00:00.000Z","to":"2016-10-18T00:00:00.000Z","count":55}]},"source":{"files":{"readmeSize":18963,"testsSize":27361,"hasNpmIgnore":true},"repositorySize":59218,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":117,"downloadsCount":49519,"downloadsAcceleration":482.70388127853886,"dependentsCount":27},"maintenance":{"releasesFrequency":1,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.7279744165163313,"detail":{"quality":0.9260256430415238,"popularity":0.28631206753081134,"maintenance":0.9998785713374008}}}},{"package":{"name":"d3-color","version":"1.0.1","description":"Color spaces! RGB, HSL, Cubehelix, Lab and HCL (Lch).","keywords":["d3","d3-module","color","rgb","hsl","lab","hcl","lch","cubehelix"],"date":"2016-08-02T21:53:04.979Z","links":{"npm":"https://www.npmjs.com/package/d3-color","homepage":"https://d3js.org/d3-color/","repository":"https://github.com/d3/d3-color","bugs":"https://github.com/d3/d3-color/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}]},"score":{"final":0.7387433304113963,"detail":{"quality":0.9260256430415238,"popularity":0.3170865650295209,"maintenance":0.9998723992531626}},"searchScore":0.006719287,"metadata":{"analyzedAt":"2016-10-16T23:06:03.368Z","collected":{"metadata":{"name":"d3-color","version":"1.0.1","description":"Color spaces! RGB, HSL, Cubehelix, Lab and HCL (Lch).","keywords":["d3","d3-module","color","rgb","hsl","lab","hcl","lch","cubehelix"],"date":"2016-08-02T21:53:04.979Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mike@ocks.org"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-color.git"},"links":{"npm":"https://www.npmjs.com/package/d3-color","homepage":"https://d3js.org/d3-color/","repository":"https://github.com/d3/d3-color","bugs":"https://github.com/d3/d3-color/issues"},"license":"BSD-3-Clause","devDependencies":{"eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","uglify-js":"2"},"releases":[{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":2},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":4},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":15},{"from":"2014-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":25}],"hasTestScript":true,"readme":"# d3-color\n\nEven though your browser understands a lot about colors, it doesn’t offer much help in manipulating colors through JavaScript. The d3-color module therefore provides representations for various color spaces, allowing specification, conversion and manipulation. (Also see [d3-interpolate](https://github.com/d3/d3-interpolate) for color interpolation.)\n\nFor example, take the color named “steelblue”:\n\n```js\nvar c = d3.color(\"steelblue\"); // {r: 70, g: 130, b: 180, opacity: 1}\n```\n\nLet’s try converting it to HSL:\n\n```js\nvar c = d3.hsl(\"steelblue\"); // {h: 207.27…, s: 0.44, l: 0.4902…, opacity: 1}\n```\n\nNow rotate the hue by 90°, bump up the saturation, and format as a string for CSS:\n\n```js\nc.h += 90;\nc.s += 0.2;\nc + \"\"; // rgb(198, 45, 205)\n```\n\nTo fade the color slightly:\n\n```js\nc.opacity = 0.8;\nc + \"\"; // rgba(198, 45, 205, 0.8)\n```\n\nIn addition to the ubiquitous and machine-friendly [RGB](#rgb) and [HSL](#hsl) color space, d3-color supports two color spaces that are designed for humans:\n\n* Dave Green’s [Cubehelix](#cubehelix)\n* [Lab (CIELAB)](#lab) and [HCL (CIELCH)](#hcl)\n\nCubehelix features monotonic lightness, while Lab and HCL are perceptually uniform. Note that HCL is the cylindrical form of Lab, similar to how HSL is the cylindrical form of RGB.\n\n## Installing\n\nIf you use NPM, `npm install d3-color`. Otherwise, download the [latest release](https://github.com/d3/d3-color/releases/latest). You can also load directly from [d3js.org](https://d3js.org), either as a [standalone library](https://d3js.org/d3-color.v1.min.js) or as part of [D3 4.0](https://github.com/d3/d3). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-color.v1.min.js\"></script>\n<script>\n\nvar steelblue = d3.rgb(\"steelblue\");\n\n</script>\n```\n\n[Try d3-color in your browser.](https://tonicdev.com/npm/d3-color)\n\n## API Reference\n\n<a name=\"color\" href=\"#color\">#</a> d3.<b>color</b>(<i>specifier</i>)\n\nParses the specified [CSS Color Module Level 3](http://www.w3.org/TR/css3-color/#colorunits) *specifier* string, returning an [RGB](#rgb) or [HSL](#hsl) color. If the specifier was not valid, null is returned. Some examples:\n\n* `rgb(255, 255, 255)`\n* `rgb(10%, 20%, 30%)`\n* `rgba(255, 255, 255, 0.4)`\n* `rgba(10%, 20%, 30%, 0.4)`\n* `hsl(120, 50%, 20%)`\n* `hsla(120, 50%, 20%, 0.4)`\n* `#ffeeaa`\n* `#fea`\n* `steelblue`\n\nThe list of supported [named colors](http://www.w3.org/TR/SVG/types.html#ColorKeywords) is specified by CSS.\n\nNote: this function may also be used with `instanceof` to test if an object is a color instance. The same is true of color subclasses, allowing you to test whether a color is in a particular color space.\n\n<a name=\"color_opacity\" href=\"#color_opacity\">#</a> *color*.<b>opacity</b>\n\nThis color’s opacity, typically in the range [0, 1].\n\n<a name=\"color_rgb\" href=\"#color_rgb\">#</a> *color*.<b>rgb</b>()\n\nReturns the [RGB equivalent](#rgb) of this color. For RGB colors, that’s `this`.\n\n<a name=\"color_brighter\" href=\"#color_brighter\">#</a> *color*.<b>brighter</b>([<i>k</i>])\n\nReturns a brighter copy of this color. If *k* is specified, it controls how much brighter the returned color should be. If *k* is not specified, it defaults to 1. The behavior of this method is dependent on the implementing color space.\n\n<a name=\"color_darker\" href=\"#color_darker\">#</a> *color*.<b>darker</b>([<i>k</i>])\n\nReturns a darker copy of this color. If *k* is specified, it controls how much brighter the returned color should be. If *k* is not specified, it defaults to 1. The behavior of this method is dependent on the implementing color space.\n\n<a name=\"color_displayable\" href=\"#color_displayable\">#</a> *color*.<b>displayable</b>()\n\nReturns true if and only if the color is displayable on standard hardware. For example, this returns false for an RGB color if any channel value is less than zero or greater than 255, or if the opacity is not in the range [0, 1].\n\n<a name=\"color_toString\" href=\"#color_toString\">#</a> *color*.<b>toString</b>()\n\nReturns a string representing this color according to the [CSS Object Model specification](https://drafts.csswg.org/cssom/#serialize-a-css-component-value), such as `rgb(247, 234, 186)`. If this color is not displayable, a suitable displayable color is returned instead. For example, RGB channel values greater than 255 are clamped to 255.\n\n<a name=\"rgb\" href=\"#rgb\">#</a> d3.<b>rgb</b>(<i>r</i>, <i>g</i>, <i>b</i>[, <i>opacity</i>])<br>\n<a href=\"#rgb\">#</a> d3.<b>rgb</b>(<i>specifier</i>)<br>\n<a href=\"#rgb\">#</a> d3.<b>rgb</b>(<i>color</i>)<br>\n\nConstructs a new [RGB](https://en.wikipedia.org/wiki/RGB_color_model) color. The channel values are exposed as `r`, `g` and `b` properties on the returned instance. Use the [RGB color picker](http://bl.ocks.org/mbostock/78d64ca7ef013b4dcf8f) to explore this color space.\n\nIf *r*, *g* and *b* are specified, these represent the channel values of the returned color; an *opacity* may also be specified. If a CSS Color Module Level 3 *specifier* string is specified, it is parsed and then converted to the RGB color space. See [color](#color) for examples. If a [*color*](#color) instance is specified, it is converted to the RGB color space using [*color*.rgb](#color_rgb). Note that unlike [*color*.rgb](#color_rgb) this method *always* returns a new instance, even if *color* is already an RGB color.\n\n<a name=\"hsl\" href=\"#hsl\">#</a> d3.<b>hsl</b>(<i>h</i>, <i>s</i>, <i>l</i>[, <i>opacity</i>])<br>\n<a href=\"#hsl\">#</a> d3.<b>hsl</b>(<i>specifier</i>)<br>\n<a href=\"#hsl\">#</a> d3.<b>hsl</b>(<i>color</i>)<br>\n\nConstructs a new [HSL](https://en.wikipedia.org/wiki/HSL_and_HSV) color. The channel values are exposed as `h`, `s` and `l` properties on the returned instance. Use the [HSL color picker](http://bl.ocks.org/mbostock/debaad4fcce9bcee14cf) to explore this color space.\n\nIf *h*, *s* and *l* are specified, these represent the channel values of the returned color; an *opacity* may also be specified. If a CSS Color Module Level 3 *specifier* string is specified, it is parsed and then converted to the HSL color space. See [color](#color) for examples. If a [*color*](#color) instance is specified, it is converted to the RGB color space using [*color*.rgb](#color_rgb) and then converted to HSL. (Colors already in the HSL color space skip the conversion to RGB.)\n\n<a name=\"lab\" href=\"#lab\">#</a> d3.<b>lab</b>(<i>l</i>, <i>a</i>, <i>b</i>[, <i>opacity</i>])<br>\n<a href=\"#lab\">#</a> d3.<b>lab</b>(<i>specifier</i>)<br>\n<a href=\"#lab\">#</a> d3.<b>lab</b>(<i>color</i>)<br>\n\nConstructs a new [Lab](https://en.wikipedia.org/wiki/Lab_color_space#CIELAB) color. The channel values are exposed as `l`, `a` and `b` properties on the returned instance. Use the [Lab color picker](http://bl.ocks.org/mbostock/9f37cc207c0cb166921b) to explore this color space.\n\nIf *l*, *a* and *b* are specified, these represent the channel values of the returned color; an *opacity* may also be specified. If a CSS Color Module Level 3 *specifier* string is specified, it is parsed and then converted to the Lab color space. See [color](#color) for examples. If a [*color*](#color) instance is specified, it is converted to the RGB color space using [*color*.rgb](#color_rgb) and then converted to Lab. (Colors already in the Lab color space skip the conversion to RGB, and colors in the HCL color space are converted directly to Lab.)\n\n<a name=\"hcl\" href=\"#hcl\">#</a> d3.<b>hcl</b>(<i>h</i>, <i>c</i>, <i>l</i>[, <i>opacity</i>])<br>\n<a href=\"#hcl\">#</a> d3.<b>hcl</b>(<i>specifier</i>)<br>\n<a href=\"#hcl\">#</a> d3.<b>hcl</b>(<i>color</i>)<br>\n\nConstructs a new [HCL](https://en.wikipedia.org/wiki/Lab_color_space#CIELAB) color. The channel values are exposed as `h`, `c` and `l` properties on the returned instance. Use the [HCL color picker](http://bl.ocks.org/mbostock/3e115519a1b495e0bd95) to explore this color space.\n\nIf *h*, *c* and *l* are specified, these represent the channel values of the returned color; an *opacity* may also be specified. If a CSS Color Module Level 3 *specifier* string is specified, it is parsed and then converted to the HCL color space. See [color](#color) for examples. If a [*color*](#color) instance is specified, it is converted to the RGB color space using [*color*.rgb](#color_rgb) and then converted to HCL. (Colors already in the HCL color space skip the conversion to RGB, and colors in the Lab color space are converted directly to HCL.)\n\n<a name=\"cubehelix\" href=\"#cubehelix\">#</a> d3.<b>cubehelix</b>(<i>h</i>, <i>s</i>, <i>l</i>[, <i>opacity</i>])<br>\n<a href=\"#cubehelix\">#</a> d3.<b>cubehelix</b>(<i>specifier</i>)<br>\n<a href=\"#cubehelix\">#</a> d3.<b>cubehelix</b>(<i>color</i>)<br>\n\nConstructs a new [Cubehelix](https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/) color. The channel values are exposed as `h`, `s` and `l` properties on the returned instance. Use the [Cubehelix color picker](http://bl.ocks.org/mbostock/ba8d75e45794c27168b5) to explore this color space.\n\nIf *h*, *s* and *l* are specified, these represent the channel values of the returned color; an *opacity* may also be specified. If a CSS Color Module Level 3 *specifier* string is specified, it is parsed and then converted to the Cubehelix color space. See [color](#color) for examples. If a [*color*](#color) instance is specified, it is converted to the RGB color space using [*color*.rgb](#color_rgb) and then converted to Cubehelix. (Colors already in the Cubehelix color space skip the conversion to RGB.)"},"npm":{"downloads":[{"from":"2016-10-15T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":1480},{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":25346},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":106289},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":241834},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":310753},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":348762}],"dependentsCount":31,"starsCount":2},"github":{"starsCount":104,"forksCount":17,"subscribersCount":17,"issues":{"count":30,"openCount":2,"distribution":{"3600":5,"10800":1,"32400":5,"97200":5,"291600":3,"874800":3,"2624400":0,"7873200":4,"23619600":3,"70858800":1,"212576400":0},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":132},{"username":"Devinsuit","commitsCount":3},{"username":"tschaub","commitsCount":1},{"username":"devgru","commitsCount":1},{"username":"jasondavies","commitsCount":1},{"username":"Rich-Harris","commitsCount":1},{"username":"vijithassar","commitsCount":1}],"commits":[{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":1},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":1},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":6},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":13},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":45}]},"source":{"files":{"readmeSize":9539,"testsSize":49223,"hasNpmIgnore":true},"repositorySize":77995,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":147,"downloadsCount":80611.33333333333,"downloadsAcceleration":839.5868911719939,"dependentsCount":31},"maintenance":{"releasesFrequency":0.9561643835616439,"commitsFrequency":0.9,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.7387433304113963,"detail":{"quality":0.9260256430415238,"popularity":0.3170865650295209,"maintenance":0.9998723992531626}}}},{"package":{"name":"d3-geo-projection","version":"1.0.3","description":"Extended geographic projections for d3-geo.","keywords":["d3","d3-module","cartography","projection"],"date":"2016-08-02T21:59:52.624Z","links":{"npm":"https://www.npmjs.com/package/d3-geo-projection","homepage":"https://d3js.org/d3-geo-projection/","repository":"https://github.com/d3/d3-geo-projection","bugs":"https://github.com/d3/d3-geo-projection/issues"},"author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mbostock@gmail.com"},{"username":"jasondavies","email":"jason@jasondavies.com"}]},"score":{"final":0.7221779726913196,"detail":{"quality":0.9260256430415238,"popularity":0.26981420210661916,"maintenance":0.9998151686901307}},"searchScore":0.0065520583,"metadata":{"analyzedAt":"2016-10-16T23:06:25.679Z","collected":{"metadata":{"name":"d3-geo-projection","version":"1.0.3","description":"Extended geographic projections for d3-geo.","keywords":["d3","d3-module","cartography","projection"],"date":"2016-08-02T21:59:52.624Z","author":{"name":"Mike Bostock","url":"http://bost.ocks.org/mike"},"publisher":{"username":"mbostock","email":"mbostock@gmail.com"},"maintainers":[{"username":"mbostock","email":"mbostock@gmail.com"},{"username":"jasondavies","email":"jason@jasondavies.com"}],"contributors":[{"name":"Jason Davies","url":"http://www.jasondavies.com"}],"repository":{"type":"git","url":"git+https://github.com/d3/d3-geo-projection.git"},"links":{"npm":"https://www.npmjs.com/package/d3-geo-projection","homepage":"https://d3js.org/d3-geo-projection/","repository":"https://github.com/d3/d3-geo-projection","bugs":"https://github.com/d3/d3-geo-projection/issues"},"license":"BSD-3-Clause","dependencies":{"d3-array":"1","d3-geo":"^1.1.0"},"devDependencies":{"canvas":"1","d3-format":"1","eslint":"2","package-preamble":"0.0","rollup":"0.34","tape":"4","topojson":"1","uglify-js":"2"},"releases":[{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":2},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":5},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":6},{"from":"2014-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":11}],"hasTestScript":true,"readme":"# d3-geo-projection\n\nExtended geographic projections for [d3-geo](https://github.com/d3/d3-geo).\n\n## Installing\n\nIf you use NPM, `npm install d3-geo-projection`. Otherwise, download the [latest release](https://github.com/d3/d3-geo-projection/releases/latest). You can also load directly from [d3js.org](https://d3js.org) as a [standalone library](https://d3js.org/d3-geo-projection.v1.min.js). AMD, CommonJS, and vanilla environments are supported. In vanilla, a `d3` global is exported:\n\n```html\n<script src=\"https://d3js.org/d3-array.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-geo.v1.min.js\"></script>\n<script src=\"https://d3js.org/d3-geo-projection.v1.min.js\"></script>\n<script>\n\nvar aitoff = d3.geoAitoff();\n\n</script>\n```\n\n[Try d3-geo-projection in your browser.](https://tonicdev.com/npm/d3-geo-projection)\n\n## API Reference\n\n### Projections\n\n<a href=\"#geoAitoff\" name=\"geoAitoff\">#</a> d3.<b>geoAitoff</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/aitoff.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3682698)\n\nThe Aitoff projection.\n\n<a href=\"#geoAiry\" name=\"geoAiry\">#</a> d3.<b>geoAiry</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/airy.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5620807)\n\nAiry’s minimum-error azimuthal projection.\n\n<a href=\"airy_radius\" name=\"airy_raidus\">#</a> <i>airy</i>.<b>radius</b>([<i>radius</i>])\n\nDefaults to 90°.\n\n<a href=\"#geoAlbers\" name=\"geoAlbers\">#</a> d3.<b>geoAlbers</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/albers.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734308)\n\nAlber’s [equal-area conic projection](#geoConicEqualArea); see [d3-geo](https://github.com/d3/d3-geo#geoAlbers).\n\n<a href=\"#geoArmadillo\" name=\"geoArmadillo\">#</a> d3.<b>geoArmadillo</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/armadillo.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4463127)\n\nThe armadillo projection. The default center assumes the default [parallel](#armadillo_parallel) of 20° and should be changed if a different parallel is used. Note: requires clipping to the sphere.\n\n<a href=\"#armadillo_parallel\" name=\"armadillo_parallel\">#</a> <i>armadillo</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 20°.\n\n<a href=\"#geoAugust\" name=\"geoAugust\">#</a> d3.<b>geoAugust</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/august.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3797581)\n\nAugust’s epicycloidal conformal projection.\n\n<a href=\"#geoAzimuthalEqualArea\" name=\"geoAzimuthalEqualArea\">#</a> d3.<b>geoAzimuthalEqualArea</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/azimuthalEqualArea.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757101)\n\nThe Lambert azimuthal equal-area projection; see [d3-geo](https://github.com/d3/d3-geo#geoAzimuthalEqualArea).\n\n<a href=\"#geoAzimuthalEquidistant\" name=\"geoAzimuthalEquidistant\">#</a> d3.<b>geoAzimuthalEquidistant</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/azimuthalEquidistant.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757110)\n\nThe azimuthal equidistant projection; see [d3-geo](https://github.com/d3/d3-geo#geoAzimuthalEquidistant).\n\n<a href=\"#geoBaker\" name=\"geoBaker\">#</a> d3.<b>geoBaker</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/baker.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4476279)\n\nThe Baker Dinomic projection.\n\n<a href=\"#geoBerghaus\" name=\"geoBerghaus\">#</a> d3.<b>geoBerghaus</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/berghaus.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4463049)\n\nBerghaus’ star projection. The default center assumes the default [lobe number](#berghaus_lobes) of 5 and should be changed if a different number of lobes is used. Note: requires clipping to the sphere.\n\n<a href=\"#berghaus_lobes\" name=\"berghaus_lobes\">#</a> <i>berghaus</i>.<b>lobes</b>([<i>lobes</i>])\n\nIf *lobes* is specified, sets the number of lobes in the resulting star, and returns this projection. If *lobes* is not specified, returns the current lobe number, which defaults to 5.\n\n<a href=\"#geoBoggs\" name=\"geoBoggs\">#</a> d3.<b>geoBoggs</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/boggs.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4481220)\n\nThe Boggs eumorphic projection. More commonly used in [interrupted form](#geoInterruptedBoggs).\n\n<a href=\"#geoBonne\" name=\"geoBonne\">#</a> d3.<b>geoBonne</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/bonne.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734313)\n\nThe Bonne pseudoconical equal-area projection. The [Werner projection](http://bl.ocks.org/mbostock/a7ae83252305ed4d54d4) is a limiting form of the Bonne projection with a standard parallel at ±90°. The default center assumes the default [parallel](#bonne_parallel) of 45° and should be changed if a different parallel is used.\n\n<a href=\"#bonne_parallel\" name=\"bonne_parallel\">#</a> <i>bonne</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 45°.\n\n<a href=\"#geoBottomley\" name=\"geoBottomley\">#</a> d3.<b>geoBottomley</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/bottomley.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/ad2d520dd26dcc5af13b)\n\nThe [Bottomley projection](http://cybergeo.revues.org/3977) “draws lines of latitude as concentric circular arcs, with arc lengths equal to their lengths on the globe, and placed symmetrically and equally spaced across the vertical central meridian.”\n\n<a href=\"#bottomley_fraction\" name=\"bottomley_fraction\">#</a> <i>bottomley</i>.<b>fraction</b>([<i>fraction</i>])\n\nDefaults to 0.5, corresponding to a sin(ψ) where ψ = π/6.\n\n<a href=\"#geoBromley\" name=\"geoBromley\">#</a> d3.<b>geoBromley</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/bromley.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4487695)\n\nThe Bromley projection is a rescaled [Mollweide projection](#geoMollweide).\n\n<a href=\"#geoChamberlin\" name=\"geoChamberlin\">#</a> d3.<b>geoChamberlin</b>(<i>point0</i>, <i>point1</i>, <i>point2</i>)\n\nThe Chamberlin trimetric projection. This method does not support [*projection*.rotate](https://github.com/d3/d3-geo#projection_rotate): the three reference points implicitly determine a fixed rotation.\n\n<a href=\"#geoChamberlinAfrica\" name=\"geoChamberlinAfrica\">#</a> d3.<b>geoChamberlinAfrica</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/chamberlinAfrica.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5625053)\n\nThe Chamberlin projection for Africa using points [0°, 22°], [45°, 22°], [22.5°, -22°].\n\n<a href=\"#geoCollignon\" name=\"geoCollignon\">#</a> d3.<b>geoCollignon</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/collignon.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734316)\n\nThe Collignon equal-area pseudocylindrical projection. This projection is used in the polar areas of the [HEALPix projection](#geoHealpix).\n\n<a href=\"#geoConicConformal\" name=\"geoConicConformal\">#</a> d3.<b>geoConicConformal</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/conicConformal.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734321)\n\nThe Lambert conformal conic projection; see [d3-geo](https://github.com/d3/d3-geo#geoConicConformal).\n\n<a href=\"#geoConicEqualArea\" name=\"geoConicEqualArea\">#</a> d3.<b>geoConicEqualArea</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/conicEqualArea.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734308)\n\nAlber’s conic equal-area projection; see [d3-geo](https://github.com/d3/d3-geo#geoConicEqualArea).\n\n<a href=\"#geoConicEquidistant\" name=\"geoConicEquidistant\">#</a> d3.<b>geoConicEquidistant</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/conicEquidistant.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734317)\n\nThe conic equidistant projection; see [d3-geo](https://github.com/d3/d3-geo#geoConicEquidistant).\n\n<a href=\"#geoCraig\" name=\"geoCraig\">#</a> d3.<b>geoCraig</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/craig.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4459466)\n\nThe Craig retroazimuthal projection. Note: this projection tends to [fold over itself](http://bl.ocks.org/mbostock/4459716) if the [standard parallel](#craig_parallel) is non-zero; we have not yet implemented the necessary advanced clipping to avoid overlap.\n\n<a href=\"#craig_parallel\" name=\"craig_parallel\">#</a> <i>craig</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 0°.\n\n<a href=\"#geoCraster\" name=\"geoCraster\">#</a> d3.<b>geoCraster</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/craster.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4465118)\n\nThe Craster parabolic projection; also known as Putniņš P4.\n\n<a href=\"#geoCylindricalEqualArea\" name=\"geoCylindricalEqualArea\">#</a> d3.<b>geoCylindricalEqualArea</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/cylindricalEqualArea.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3712408)\n\nThe cylindrical equal-area projection. Depending on the chosen [parallel](#cylindricalEqualArea_parallel), this projection is also known as the Lambert cylindrical equal-area (0°), [Gall–Peters](http://bl.ocks.org/mbostock/3946824) (45°), [Hobo–Dyer](http://bl.ocks.org/mbostock/4476487) (37.5°), and [Tobler world-in-a-square](http://bl.ocks.org/mbostock/4476496) (~55.654°).\n\n<a href=\"#cylindricalEqualArea_parallel\" name=\"cylindricalEqualArea_parallel\">#</a> <i>cylindricalEqualArea</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to approximately 38.58°, fitting the world in a 960×500 rectangle.\n\n<a href=\"#geoCylindricalStereographic\" name=\"geoCylindricalStereographic\">#</a> d3.<b>geoCylindricalStereographic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/cylindricalStereographic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5234763)\n\nThe cylindrical stereographic projection. Depending on the chosen [parallel](#cylindricalStereographic_parallel), this projection is also known as Braun’s stereographic (0°) and Gall’s stereographic (45°).\n\n<a href=\"#cylindricalStereographic_parallel\" name=\"cylindricalStereographic_parallel\">#</a> <i>cylindricalStereographic</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 0°.\n\n<a href=\"#geoEckert1\" name=\"geoEckert1\">#</a> d3.<b>geoEckert1</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eckert1.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734322)\n\nThe Eckert I projection.\n\n<a href=\"#geoEckert2\" name=\"geoEckert2\">#</a> d3.<b>geoEckert2</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eckert2.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734324)\n\nThe Eckert II projection.\n\n<a href=\"#geoEckert3\" name=\"geoEckert3\">#</a> d3.<b>geoEckert3</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eckert3.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734325)\n\nThe Eckert III projection.\n\n<a href=\"#geoEckert4\" name=\"geoEckert4\">#</a> d3.<b>geoEckert4</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eckert4.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734327)\n\nThe Eckert IV projection.\n\n<a href=\"#geoEckert5\" name=\"geoEckert5\">#</a> d3.<b>geoEckert5</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eckert5.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734328)\n\nThe Eckert V projection.\n\n<a href=\"#geoEckert6\" name=\"geoEckert6\">#</a> d3.<b>geoEckert6</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eckert6.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734329)\n\nThe Eckert VI projection.\n\n<a href=\"#geoEisenlohr\" name=\"geoEisenlohr\">#</a> d3.<b>geoEisenlohr</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/eisenlohr.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3797585)\n\nThe Eisenlohr conformal projection.\n\n<a href=\"#geoEquirectangular\" name=\"geoEquirectangular\">#</a> d3.<b>geoEquirectangular</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/equirectangular.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757119)\n\nThe equirectangular (plate carrée) projection; see [d3-geo](https://github.com/d3/d3-geo#geoEquirectangular). The [Cassini projection](http://bl.ocks.org/mbostock/5695142) is the transverse aspect of the equirectangular projection.\n\n<a href=\"#geoFahey\" name=\"geoFahey\">#</a> d3.<b>geoFahey</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/fahey.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4731228)\n\nThe Fahey pseudocylindrical projection.\n\n<a href=\"#geoFoucaut\" name=\"geoFoucaut\">#</a> d3.<b>geoFoucaut</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/foucaut.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/foucaut/)\n\nFoucaut’s stereographic equivalent projection.\n\n<a href=\"#geoGilbert\" name=\"geoGilbert\">#</a> d3.<b>geoGilbert</b>([<i>type</i>])\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/gilbert.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/gilbert/)\n\nGilbert’s two-world perspective projection. Wraps an instance of the specified projection *type*; if not specified, defaults to [d3.geoOrthographic](https://github.com/d3/d3-geo#geoOrthographic).\n\n<a href=\"#geoGingery\" name=\"geoGingery\">#</a> d3.<b>geoGingery</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/gingery.png\" width=\"480\" height=\"250\">](http://www.jasondavies.com/maps/gingery/)\n\nThe U.S.-centric Gingery world projection, as inspired by Cram’s Air Age. Note: requires clipping to the sphere.\n\n<a href=\"#gingery_radius\" name=\"gingery_radius\">#</a> <i>gingery</i>.<b>radius</b>([<i>radius</i>])\n\nDefaults to 30°.\n\n<a href=\"#gingery_lobes\" name=\"gingery_lobes\">#</a> <i>gingery</i>.<b>lobes</b>([<i>lobes</i>])\n\nDefaults to 6.\n\n<a href=\"#geoGinzburg4\" name=\"geoGinzburg4\">#</a> d3.<b>geoGinzburg4</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/ginzburg4.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5288565)\n\nThe Ginzburg IV projection.\n\n<a href=\"#geoGinzburg5\" name=\"geoGinzburg5\">#</a> d3.<b>geoGinzburg5</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/ginzburg5.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5288571)\n\nThe Ginzburg V projection.\n\n<a href=\"#geoGinzburg6\" name=\"geoGinzburg6\">#</a> d3.<b>geoGinzburg6</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/ginzburg6.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5288577)\n\nThe Ginzburg VI projection.\n\n<a href=\"#geoGinzburg8\" name=\"geoGinzburg8\">#</a> d3.<b>geoGinzburg8</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/ginzburg8.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5288583)\n\nThe Ginzburg VIII projection.\n\n<a href=\"#geoGinzburg9\" name=\"geoGinzburg9\">#</a> d3.<b>geoGinzburg9</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/ginzburg9.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5288590)\n\nThe Ginzburg IX projection.\n\n<a href=\"#geoGnomonic\" name=\"geoGnomonic\">#</a> d3.<b>geoGnomonic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/gnomonic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757349)\n\nThe gnomonic projection; see [d3-geo](https://github.com/d3/d3-geo#geoGnomonic).\n\n<a href=\"#geoGringorten\" name=\"geoGringorten\">#</a> d3.<b>geoGringorten</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/gringorten.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4362031)\n\nThe Gringorten square equal-area projection, rearranged to give each hemisphere an entire square.\n\n<a href=\"#geoGringortenQuincuncial\" name=\"geoGringortenQuincuncial\">#</a> d3.<b>geoGringortenQuincuncial</b>()\n\n<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/gringortenQuincuncial.png\" width=\"480\" height=\"250\">\n\nThe Gringorten square equal-area projection.\n\n<a href=\"#geoGuyou\" name=\"geoGuyou\">#</a> d3.<b>geoGuyou</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/guyou.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3763867)\n\nThe Guyou hemisphere-in-a-square projection. Peirce is credited with its [quincuncial form](#geoPeirceQuincuncial).\n\n<a href=\"#geoHammer\" name=\"geoHammer\">#</a> d3.<b>geoHammer</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/hammer.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3712397)\n\nThe Hammer projection. Depending the chosen coefficient and aspect, also known as [Eckert–Greifendorff](http://bl.ocks.org/mbostock/4496212), [quartic authalic](http://bl.ocks.org/mbostock/4463175), and [Briesemeister](http://bl.ocks.org/mbostock/4519926).\n\n<a href=\"#hammer_coefficient\" name=\"hammer_coefficient\">#</a> <i>hammer</i>.<b>coefficient</b>([<i>coefficient</i>])\n\nDefaults to 2.\n\n<a href=\"#geoHammerRetroazimuthal\" name=\"geoHammerRetroazimuthal\">#</a> d3.<b>geoHammerRetroazimuthal</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/hammerRetroazimuthal.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4459130)\n\nThe Hammer retroazimuthal projection. Note: requires clipping to the sphere.\n\n<a href=\"#hammerRetroazimuthal_parallel\" name=\"hammerRetroazimuthal_parallel\">#</a> <i>hammerRetroazimuthal</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 45°.\n\n<a href=\"#geoHealpix\" name=\"geoHealpix\">#</a> d3.<b>geoHealpix</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/healpix.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4463237)\n\nThe HEALPix projection: a <b>H</b>ierarchical <b>E</b>qual <b>A</b>rea iso<b>L</b>atitude <b>Pix</b>elisation of a 2-sphere. In this implementation, the parameter *K* is fixed at 3. Note: requires clipping to the sphere.\n\n<a href=\"#healpix_lobes\" name=\"healpix_lobes\">#</a> <i>healpix</i>.<b>lobes</b>([<i>lobes</i>])\n\nIf *lobes* is specified, sets the number of lobes (the parameter *H* in the literature) and returns this projection. If *lobes* is not specified, returns the current lobe number, which defaults to 4.\n\n<a href=\"#geoHill\" name=\"geoHill\">#</a> d3.<b>geoHill</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/hill.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4479513)\n\nHill eucyclic projection is psuedoconic and equal-area.\n\n<a href=\"hill_ratio\" name=\"hill_ratio\">#</a> <i>hill</i>.<b>ratio</b>([<i>ratio</i>])\n\nDefaults to 1. With a ratio of 0, this projection becomes the [Maurer No. 73](http://bl.ocks.org/mbostock/4479547). As it approaches ∞, the projection converges to the [Eckert IV](#geoEckert4).\n\n<a href=\"#geoHomolosine\" name=\"geoHomolosine\">#</a> d3.<b>geoHomolosine</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/homolosine.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734330)\n\nThe pseudocylindrical, equal-area Goode homolosine projection is normally presented in [interrupted form](#geoInterruptedHomolosine).\n\n<a href=\"#geoKavrayskiy7\" name=\"geoKavrayskiy7\">#</a> d3.<b>geoKavrayskiy7</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/kavrayskiy7.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3710082)\n\nThe Kavrayskiy VII pseudocylindrical projection.\n\n<a href=\"#geoLagrange\" name=\"geoLagrange\">#</a> d3.<b>geoLagrange</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/lagrange.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3797591)\n\nThe Lagrange conformal projection.\n\n<a href=\"#lagrange_spacing\" name=\"lagrange_spacing\">#</a> <i>lagrange</i>.<b>spacing</b>([<i>spacing</i>])\n\nDefaults to 0.5.\n\n<a href=\"#geoLarrivee\" name=\"geoLarrivee\">#</a> d3.<b>geoLarrivee</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/larrivee.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3719042)\n\nThe Larrivée projection.\n\n<a href=\"#geoLaskowski\" name=\"geoLaskowski\">#</a> d3.<b>geoLaskowski</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/laskowski.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4489342)\n\nThe Laskowski tri-optimal projection simultaneously minimizes distance, angular, and areal distortion.\n\n<a href=\"#geoLittrow\" name=\"geoLittrow\">#</a> d3.<b>geoLittrow</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/littrow.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4459071)\n\nThe Littrow projection is the only conformal retroazimuthal map projection. Typically clipped to the geographic extent [[-90°, -60°], [90°, 60°]].\n\n<a href=\"#geoLoximuthal\" name=\"geoLoximuthal\">#</a> d3.<b>geoLoximuthal</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/loximuthal.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3867220)\n\nThe [loximuthal projection](https://en.wikipedia.org/wiki/Loximuthal_projection) is “characterized by the fact that loxodromes (rhumb lines) from one chosen central point (the intersection of the central meridian and central latitude) are shown as straight lines, correct in azimuth from the center, and are ‘true to scale’… It is neither an equal-area projection nor conformal.”\n\n<a href=\"#loximuthal_parallel\" name=\"loximuthal_parallel\">#</a> <i>loximuthal</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 40°.\n\n<a href=\"#geoMercator\" name=\"geoMercator\">#</a> d3.<b>geoMercator</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/mercator.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757132)\n\nThe spherical Mercator projection; see [d3-geo](https://github.com/d3/d3-geo#geoMercator).\n\n<a href=\"#geoMiller\" name=\"geoMiller\">#</a> d3.<b>geoMiller</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/miller.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734333)\n\nThe Miller cylindrical projection is a modified [Mercator](#geoMercator) projection.\n\n<a href=\"#geoModifiedStereographic\" name=\"geoModifiedStereographic\">#</a> d3.<b>geoModifiedStereographic</b>(<i>coefficients</i>, <i>rotate</i>)\n\nThe family of [modified stereographic projections](http://www.jasondavies.com/maps/modified-stereographic/). The default [clip angle](https://github.com/d3/d3-geo#projection_clipAngle) for these projections is 90°. These projections do not support [*projection*.rotate](https://github.com/d3/d3-geo#projection_rotate): a fixed rotation is applied that is specific to the given *coefficients*.\n\n<a href=\"#geoModifiedStereographicAlaska\" name=\"geoModifiedStereographicAlaska\">#</a> d3.<b>geoModifiedStereographicAlaska</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/modifiedStereographicAlaska.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/modified-stereographic/alaska/)\n\nA [modified stereographic](#geoModifiedStereographic) projection for Alaska.\n\n<a href=\"#geoModifiedStereographicGs48\" name=\"geoModifiedStereographicGs48\">#</a> d3.<b>geoModifiedStereographicGs48</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/modifiedStereographicGs48.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/modified-stereographic/gs48/)\n\nA [modified stereographic](#geoModifiedStereographic) projection for the conterminous United States.\n\n<a href=\"#geoModifiedStereographicGs50\" name=\"geoModifiedStereographicGs50\">#</a> d3.<b>geoModifiedStereographicGs50</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/modifiedStereographicGs50.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/modified-stereographic/gs50/)\n\nA [modified stereographic](#geoModifiedStereographic) projection for the United States including Alaska and Hawaii. Typically clipped to the geographic extent [[-180°, 15°], [-50°, 75°]].\n\n<a href=\"#geoModifiedStereographicMiller\" name=\"geoModifiedStereographicMiller\">#</a> d3.<b>geoModifiedStereographicMiller</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/modifiedStereographicMiller.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/modified-stereographic/miller/)\n\nA [modified stereographic](#geoModifiedStereographic) projection for Europe and Africa. Typically clipped to the geographic extent [[-40°, -40°], [80°, 80°]].\n\n<a href=\"#geoModifiedStereographicLee\" name=\"geoModifiedStereographicLee\">#</a> d3.<b>geoModifiedStereographicLee</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/modifiedStereographicLee.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/modified-stereographic/miller/)\n\nA [modified stereographic](#geoModifiedStereographic) projection for the Pacific ocean.\n\n<a href=\"#geoMollweide\" name=\"geoMollweide\">#</a> d3.<b>geoMollweide</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/mollweide.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734336)\n\nThe equal-area, pseudocylindrical Mollweide projection. The oblique aspect is known as the [Atlantis projection](http://bl.ocks.org/mbostock/4519975). [Goode’s interrupted Mollweide](#interruptedMollweide) is also widely known.\n\n<a href=\"#geoMtFlatPolarParabolic\" name=\"geoMtFlatPolarParabolic\">#</a> d3.<b>geoMtFlatPolarParabolic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/mtFlatPolarParabolic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4465130)\n\nThe McBryde–Thomas flat-polar parabolic pseudocylindrical equal-area projection.\n\n<a href=\"#geoMtFlatPolarQuartic\" name=\"geoMtFlatPolarQuartic\">#</a> d3.<b>geoMtFlatPolarQuartic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/mtFlatPolarQuartic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4465137)\n\nThe McBryde–Thomas flat-polar quartic pseudocylindrical equal-area projection.\n\n<a href=\"#geoMtFlatPolarSinusoidal\" name=\"geoMtFlatPolarSinusoidal\">#</a> d3.<b>geoMtFlatPolarSinusoidal</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/mtFlatPolarSinusoidal.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4465140)\n\nThe McBryde–Thomas flat-polar sinusoidal equal-area projection.\n\n<a href=\"#geoNaturalEarth\" name=\"geoNaturalEarth\">#</a> d3.<b>geoNaturalEarth</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/naturalEarth.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4479477)\n\nThe Natural Earth projection.\n\n<a href=\"#geoNellHammer\" name=\"geoNellHammer\">#</a> d3.<b>geoNellHammer</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/nellHammer.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734342)\n\nThe Nell–Hammer projection.\n\n<a href=\"#geoOrthographic\" name=\"geoOrthographic\">#</a> d3.<b>geoOrthographic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/orthographic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757125)\n\nThe orthographic projection; see [d3-geo](https://github.com/d3/d3-geo#geoOrthographic).\n\n<a href=\"#geoPatterson\" name=\"geoPatterson\">#</a> d3.<b>geoPatterson</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/patterson.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/d4021aa4dccfd65edffd)\n\nThe Patterson cylindrical projection.\n\n<a href=\"#geoPeirceQuincuncial\" name=\"geoPeirceQuincuncial\">#</a> d3.<b>geoPeirceQuincuncial</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/peirceQuincuncial.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4310087)\n\nThe Peirce quincuncial projection is the quincuncial form of the [Guyou projection](#geoGuyou).\n\n<a href=\"#geoPolyconic\" name=\"geoPolyconic\">#</a> d3.<b>geoPolyconic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/polyconic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3734343)\n\nThe American polyconic projection.\n\n<a href=\"#geoRectangularPolyconic\" name=\"geoRectangularPolyconic\">#</a> d3.<b>geoRectangularPolyconic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/rectangularPolyconic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5230202)\n\nThe rectangular (War Office) polyconic projection.\n\n<a href=\"#rectangularPolyconic_parallel\" name=\"rectangularPolyconic_parallel\">#</a> <i>rectangularPolyconic</i>.<b>parallel</b>([<i>parallel</i>])\n\nDefaults to 0°.\n\n<a href=\"#geoRobinson\" name=\"geoRobinson\">#</a> d3.<b>geoRobinson</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/robinson.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3710566)\n\nThe Robinson projection.\n\n<a href=\"#geoSatellite\" name=\"geoSatellite\">#</a> d3.<b>geoSatellite</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/satellite.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3790444)\n\nThe satellite (tilted perspective) projection.\n\n<a href=\"#satellite_tilt\" name=\"satellite_tilt\">#</a> <i>satellite</i>.<b>tilt</b>([<i>tilt</i>])\n\nDefaults to 0°.\n\n<a href=\"#satellite_distance\" name=\"satellite_distance\">#</a> <i>satellite</i>.<b>distance</b>([<i>distance</i>])\n\nDistance from the center of the sphere to the point of view, as a proportion of the sphere’s radius; defaults to 2.0. The recommended maximum [clip angle](https://github.com/d3/d3-geo#projection_clipAngle) for a given *distance* is acos(1 / *distance*) converted to degrees. If [tilt](#satellite_tilt) is also applied, then more conservative clipping may be necessary. For exact clipping, the in-development geographic projection pipeline is needed; see the [satellite example](https://bl.ocks.org/mbostock/e48a00d4db5c3b042145).\n\n<a href=\"#geoSinusoidal\" name=\"geoSinusoidal\">#</a> d3.<b>geoSinusoidal</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/sinusoidal.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3712399)\n\nThe sinusoidal projection.\n\n<a href=\"#geoSinuMollweide\" name=\"geoSinuMollweide\">#</a> d3.<b>geoSinuMollweide</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/sinuMollweide.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4319903)\n\nAllen K. Philbrick’s Sinu-Mollweide projection. See also the [interrupted form](#interruptedSinuMollweide).\n\n<a href=\"#geoStereographic\" name=\"geoStereographic\">#</a> d3.<b>geoStereographic</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/stereographic.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3757137)\n\nThe stereographic projection; see [d3-geo](https://github.com/d3/d3-geo#geoStereographic).\n\n<a href=\"#geoTimes\" name=\"geoTimes\">#</a> d3.<b>geoTimes</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/times.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5230564)\n\nJohn Muir’s Times projection.\n\n<a href=\"#geoTransverseMercator\" name=\"geoTransverseMercator\">#</a> d3.<b>geoTransverseMercator</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo/master/img/transverseMercator.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5126418)\n\nThe transverse spherical Mercator projection; see [d3-geo](https://github.com/d3/d3-geo#geoTransverseMercator).\n\n<a href=\"#geoTwoPointAzimuthal\" name=\"geoTwoPointAzimuthal\">#</a> d3.<b>geoTwoPointAzimuthal</b>(<i>point0</i>, <i>point1</i>)\n\nThe two-point azimuthal projection “shows correct azimuths (but not distances) from either of two points to any other point. [It can] be used to locate a ship at sea, given the exact location of two radio transmitters and the direction of the ship to the transmitters.” This projection does not support [*projection*.rotate](https://github.com/d3/d3-geo#projection_rotate), as the rotation is fixed by the two given points.\n\n<a href=\"#geoTwoPointAzimuthalUsa\" name=\"geoTwoPointAzimuthalUsa\">#</a> d3.<b>geoTwoPointAzimuthalUsa</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/twoPointAzimuthalUsa.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/two-point-azimuthal/)\n\nThe two-point azimuthal projection with points [-158°, 21.5°] and [-77°, 39°], approximately representing Honolulu, HI and Washington, D.C.\n\n<a href=\"#geoTwoPointEquidistant\" name=\"geoTwoPointEquidistant\">#</a> d3.<b>geoTwoPointEquidistant</b>(<i>point0</i>, <i>point1</i>)\n\nThe two-point equidistant projection. This projection does not support [*projection*.rotate](https://github.com/d3/d3-geo#projection_rotate), as the rotation is fixed by the two given points. Note: to show the whole Earth, this projection requires clipping to spherical polygons, which is not yet supported in D3. However, you can typically show most of the Earth by using D3’s great-circle clipping.\n\n<a href=\"#geoTwoPointEquidistantUsa\" name=\"geoTwoPointEquidistantUsa\">#</a> d3.<b>geoTwoPointEquidistantUsa</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/twoPointEquidistantUsa.png\" width=\"480\" height=\"250\">](https://www.jasondavies.com/maps/two-point-equidistant/)\n\nThe two-point equidistant projection with points [-158°, 21.5°] and [-77°, 39°], approximately representing Honolulu, HI and Washington, D.C.\n\n<a href=\"#geoVanDerGrinten\" name=\"geoVanDerGrinten\">#</a> d3.<b>geoVanDerGrinten</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/vanDerGrinten.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3796831)\n\nThe Van der Grinten projection.\n\n<a href=\"#geoVanDerGrinten2\" name=\"geoVanDerGrinten2\">#</a> d3.<b>geoVanDerGrinten2</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/vanDerGrinten2.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5230571)\n\nThe Van der Grinten II projection.\n\n<a href=\"#geoVanDerGrinten3\" name=\"geoVanDerGrinten3\">#</a> d3.<b>geoVanDerGrinten3</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/vanDerGrinten3.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/5230580)\n\nThe Van der Grinten III projection.\n\n<a href=\"#geoVanDerGrinten4\" name=\"geoVanDerGrinten4\">#</a> d3.<b>geoVanDerGrinten4</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/vanDerGrinten4.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4489365)\n\nThe Van der Grinten IV projection.\n\n<a href=\"#geoWagner4\" name=\"geoWagner4\">#</a> d3.<b>geoWagner4</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/wagner4.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4487674)\n\nThe Wagner IV projection, also known as Putniṇš P2´.\n\n<a href=\"#geoWagner6\" name=\"geoWagner6\">#</a> d3.<b>geoWagner6</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/wagner6.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3710148)\n\nThe Wagner VI projection.\n\n<a href=\"#geoWagner7\" name=\"geoWagner7\">#</a> d3.<b>geoWagner7</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/wagner7.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4465109)\n\nThe Wagner VII projection.\n\n<a href=\"#geoWiechel\" name=\"geoWiechel\">#</a> d3.<b>geoWiechel</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/wiechel.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4463155)\n\nThe Wiechel projection.\n\n<a href=\"#geoWinkel3\" name=\"geoWinkel3\">#</a> d3.<b>geoWinkel3</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/winkel3.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/3682676)\n\nThe Winkel tripel projection.\n\n### Interrupted Projections\n\n<a href=\"#geoInterrupt\" name=\"geoInterrupt\">#</a> d3.<b>geoInterrupt</b>(<i>project</i>, <i>lobes</i>)\n\nDefines a new interrupted projection for the specified [raw projection](#raw-projections) function *project* and the specified array of *lobes*. The array *lobes* contains two elements representing the hemilobes for the northern hemisphere and the southern hemisphere, respectively. Each hemilobe is an array of triangles, with each triangle represented as three points (in degrees): the start, midpoint, and end. For example, the lobes in [Goode’s interrupted homolosine](#geoInterruptedHomolosine) projection are defined as:\n\n```json\n[\n [\n [[-180, 0], [-100, 90], [ -40, 0]],\n [[ -40, 0], [ 30, 90], [ 180, 0]]\n ],\n [\n [[-180, 0], [-160, -90], [-100, 0]],\n [[-100, 0], [ -60, -90], [ -20, 0]],\n [[ -20, 0], [ 20, -90], [ 80, 0]],\n [[ 80, 0], [ 140, -90], [ 180, 0]]\n ]\n]\n```\n\nNote: interrupted projections typically require clipping to the sphere.\n\n<a href=\"#geoInterruptedHomolosine\" name=\"geoInterruptedHomolosine\">#</a> d3.<b>geoInterruptedHomolosine</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/interruptedHomolosine.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4448587)\n\nGoode’s interrupted [homolosine projection](#geoHomolosine).\n\n<a href=\"#geoInterruptedSinusoidal\" name=\"geoInterruptedSinusoidal\">#</a> d3.<b>geoInterruptedSinusoidal</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/interruptedSinusoidal.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4458991)\n\nAn interrupted [sinusoidal projection](#geoSinusoidal) with asymmetrical lobe boundaries that emphasize land masses over oceans, after the Swedish <i>Nordisk Världs Atlas</i> as reproduced by [C.A. Furuti](http://www.progonos.com/furuti/MapProj/Normal/ProjInt/projInt.html#InterruptedSansonFlamsteed).\n\n<a href=\"#geoInterruptedBoggs\" name=\"geoInterruptedBoggs\">#</a> d3.<b>geoInterruptedBoggs</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/interruptedBoggs.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4481265)\n\nBogg’s interrupted [eumorphic projection](#geoBoggs).\n\n<a href=\"#geoInterruptedSinuMollweide\" name=\"geoInterruptedSinuMollweide\">#</a> d3.<b>geoInterruptedSinuMollweide</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/interruptedSinuMollweide.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4481520)\n\nAlan K. Philbrick’s interrupted [sinu-Mollweide projection](#geoSinuMollweide).\n\n<a href=\"#geoInterruptedMollweide\" name=\"geoInterruptedMollweide\">#</a> d3.<b>geoInterruptedMollweide</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/interruptedMollweide.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4498187)\n\nGoode’s interrupted [Mollweide projection](#geoMollweide).\n\n<a href=\"#geoInterruptedMollweideHemispheres\" name=\"geoInterruptedMollweideHemispheres\">#</a> d3.<b>geoInterruptedMollweideHemispheres</b>()\n\n[<img src=\"https://raw.githubusercontent.com/d3/d3-geo-projection/master/img/interruptedMollweideHemispheres.png\" width=\"480\" height=\"250\">](http://bl.ocks.org/mbostock/4498292)\n\nThe [Mollweide projection](#geoMollweide) interrupted into two (equal-area) hemispheres.\n\n### Raw Projections\n\nRaw projections are used to implement projections; they typically passed to [d3.geoProjection](https://github.com/d3/d3-geo#geoProjection) or [d3.geoProjectionMutator](https://github.com/d3/d3-geo#geoProjectionMutator). They are exposed here to facilitate the derivation of related projections. Raw projections define simple point transformations: they take spherical coordinates [*lambda*, *phi*] in radians and return a point [*x*, *y*], typically in the unit square centered around the origin.\n\n<a href=\"#_project\" name=\"_project\">#</a> <i>project</i>(<i>lambda</i>, <i>phi</i>)\n\nProjects the specified point [<i>lambda</i>, <i>phi</i>] in radians, returning a new point [*x*, *y*] in unitless coordinates.\n\n<a href=\"#project_invert\" name=\"project_invert\">#</a> <i>project</i>.<b>invert</b>(<i>x</i>, <i>y</i>)\n\nThe inverse of [*project*](#_project).\n\n<a href=\"#geoAiryRaw\" name=\"geoAiryRaw\">#</a> d3.<b>geoAiryRaw</b>(<i>beta</i>)\n<br><a href=\"#geoAitoffRaw\" name=\"geoAitoffRaw\">#</a> d3.<b>geoAitoffRaw</b>\n<br><a href=\"#geoArmadilloRaw\" name=\"geoArmadilloRaw\">#</a> d3.<b>geoArmadilloRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoAugustRaw\" name=\"geoAugustRaw\">#</a> d3.<b>geoAugustRaw</b>\n<br><a href=\"#geoBakerRaw\" name=\"geoBakerRaw\">#</a> d3.<b>geoBakerRaw</b>\n<br><a href=\"#geoBerghausRaw\" name=\"geoBerghausRaw\">#</a> d3.<b>geoBerghausRaw</b>(<i>lobes</i>)\n<br><a href=\"#geoBoggsRaw\" name=\"geoBoggsRaw\">#</a> d3.<b>geoBoggsRaw</b>\n<br><a href=\"#geoBonneRaw\" name=\"geoBonneRaw\">#</a> d3.<b>geoBonneRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoBottomleyRaw\" name=\"geoBottomleyRaw\">#</a> d3.<b>geoBottomleyRaw</b>(<i>sinPsi</i>)\n<br><a href=\"#geoBromleyRaw\" name=\"geoBromleyRaw\">#</a> d3.<b>geoBromleyRaw</b>\n<br><a href=\"#geoChamberlinRaw\" name=\"geoChamberlinRaw\">#</a> d3.<b>geoChamberlinRaw</b>(<i>p0</i>, <i>p1</i>, <i>p2</i>)\n<br><a href=\"#geoCollignonRaw\" name=\"geoCollignonRaw\">#</a> d3.<b>geoCollignonRaw</b>\n<br><a href=\"#geoCraigRaw\" name=\"geoCraigRaw\">#</a> d3.<b>geoCraigRaw</b>(<i>phi</i>)\n<br><a href=\"#geoCrasterRaw\" name=\"geoCrasterRaw\">#</a> d3.<b>geoCrasterRaw</b>\n<br><a href=\"#geoCylindricalEqualAreaRaw\" name=\"geoCylindricalEqualAreaRaw\">#</a> d3.<b>geoCylindricalEqualAreaRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoCylindricalStereographicRaw\" name=\"geoCylindricalStereographicRaw\">#</a> d3.<b>geoCylindricalStereographicRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoEckert1Raw\" name=\"geoEckert1Raw\">#</a> d3.<b>geoEckert1Raw</b>\n<br><a href=\"#geoEckert2Raw\" name=\"geoEckert2Raw\">#</a> d3.<b>geoEckert2Raw</b>\n<br><a href=\"#geoEckert3Raw\" name=\"geoEckert3Raw\">#</a> d3.<b>geoEckert3Raw</b>\n<br><a href=\"#geoEckert4Raw\" name=\"geoEckert4Raw\">#</a> d3.<b>geoEckert4Raw</b>\n<br><a href=\"#geoEckert5Raw\" name=\"geoEckert5Raw\">#</a> d3.<b>geoEckert5Raw</b>\n<br><a href=\"#geoEckert6Raw\" name=\"geoEckert6Raw\">#</a> d3.<b>geoEckert6Raw</b>\n<br><a href=\"#geoFaheyRaw\" name=\"geoFaheyRaw\">#</a> d3.<b>geoFaheyRaw</b>\n<br><a href=\"#geoGingeryRaw\" name=\"geoGingeryRaw\">#</a> d3.<b>geoGingeryRaw</b>(<i>rho</i>, <i>lobes</i>)\n<br><a href=\"#geoGinzburg4Raw\" name=\"geoGinzburg4Raw\">#</a> d3.<b>geoGinzburg4Raw</b>\n<br><a href=\"#geoGinzburg5Raw\" name=\"geoGinzburg5Raw\">#</a> d3.<b>geoGinzburg5Raw</b>\n<br><a href=\"#geoGinzburg6Raw\" name=\"geoGinzburg6Raw\">#</a> d3.<b>geoGinzburg6Raw</b>\n<br><a href=\"#geoGinzburg8Raw\" name=\"geoGinzburg8Raw\">#</a> d3.<b>geoGinzburg8Raw</b>\n<br><a href=\"#geoGinzburg9Raw\" name=\"geoGinzburg9Raw\">#</a> d3.<b>geoGinzburg9Raw</b>\n<br><a href=\"#geoHammerRaw\" name=\"geoHammerRaw\">#</a> d3.<b>geoHammerRaw</b>(<i>A</i>, <i>B</i>)\n<br><a href=\"#geoHammerRetroazimuthalRaw\" name=\"geoHammerRetroazimuthalRaw\">#</a> d3.<b>geoHammerRetroazimuthalRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoHillRaw\" name=\"geoHillRaw\">#</a> d3.<b>geoHillRaw</b>(<i>K</i>)\n<br><a href=\"#geoHomolosineRaw\" name=\"geoHomolosineRaw\">#</a> d3.<b>geoHomolosineRaw</b>\n<br><a href=\"#geoKavrayskiy7Raw\" name=\"geoKavrayskiy7Raw\">#</a> d3.<b>geoKavrayskiy7Raw</b>\n<br><a href=\"#geoLagrangeRaw\" name=\"geoLagrangeRaw\">#</a> d3.<b>geoLagrangeRaw</b>(<i>n</i>)\n<br><a href=\"#geoLarriveeRaw\" name=\"geoLarriveeRaw\">#</a> d3.<b>geoLarriveeRaw</b>\n<br><a href=\"#geoLaskowskiRaw\" name=\"geoLaskowskiRaw\">#</a> d3.<b>geoLaskowskiRaw</b>\n<br><a href=\"#geoLittrowRaw\" name=\"geoLittrowRaw\">#</a> d3.<b>geoLittrowRaw</b>\n<br><a href=\"#geoLoximuthalRaw\" name=\"geoLoximuthalRaw\">#</a> d3.<b>geoLoximuthalRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoMillerRaw\" name=\"geoMillerRaw\">#</a> d3.<b>geoMillerRaw</b>\n<br><a href=\"#geoModifiedStereographicRaw\" name=\"geoModifiedStereographicRaw\">#</a> d3.<b>geoModifiedStereographicRaw</b>(<i>coefficients</i>)\n<br><a href=\"#geoMollweideRaw\" name=\"geoMollweideRaw\">#</a> d3.<b>geoMollweideRaw</b>\n<br><a href=\"#geoMtFlatPolarParabolicRaw\" name=\"geoMtFlatPolarParabolicRaw\">#</a> d3.<b>geoMtFlatPolarParabolicRaw</b>\n<br><a href=\"#geoMtFlatPolarQuarticRaw\" name=\"geoMtFlatPolarQuarticRaw\">#</a> d3.<b>geoMtFlatPolarQuarticRaw</b>\n<br><a href=\"#geoMtFlatPolarSinusoidalRaw\" name=\"geoMtFlatPolarSinusoidalRaw\">#</a> d3.<b>geoMtFlatPolarSinusoidalRaw</b>\n<br><a href=\"#geoNaturalEarthRaw\" name=\"geoNaturalEarthRaw\">#</a> d3.<b>geoNaturalEarthRaw</b>\n<br><a href=\"#geoNellHammerRaw\" name=\"geoNellHammerRaw\">#</a> d3.<b>geoNellHammerRaw</b>\n<br><a href=\"#geoPattersonRaw\" name=\"geoPattersonRaw\">#</a> d3.<b>geoPattersonRaw</b>\n<br><a href=\"#geoPolyconicRaw\" name=\"geoPolyconicRaw\">#</a> d3.<b>geoPolyconicRaw</b>\n<br><a href=\"#geoRectangularPolyconicRaw\" name=\"geoRectangularPolyconicRaw\">#</a> d3.<b>geoRectangularPolyconicRaw</b>(<i>phi0</i>)\n<br><a href=\"#geoSatelliteRaw\" name=\"geoSatelliteRaw\">#</a> d3.<b>geoSatelliteRaw</b>(<i>P</i>, <i>omega</i>)\n<br><a href=\"#geoSinuMollweideRaw\" name=\"geoSinuMollweideRaw\">#</a> d3.<b>geoSinuMollweideRaw</b>\n<br><a href=\"#geoSinusoidalRaw\" name=\"geoSinusoidalRaw\">#</a> d3.<b>geoSinusoidalRaw</b>\n<br><a href=\"#geoTimesRaw\" name=\"geoTimesRaw\">#</a> d3.<b>geoTimesRaw</b>\n<br><a href=\"#geoTwoPointAzimuthalRaw\" name=\"geoTwoPointAzimuthalRaw\">#</a> d3.<b>geoTwoPointAzimuthalRaw</b>(<i>d</i>)\n<br><a href=\"#geoTwoPointEquidistantRaw\" name=\"geoTwoPointEquidistantRaw\">#</a> d3.<b>geoTwoPointEquidistantRaw</b>(<i>z0</i>)\n<br><a href=\"#geoVanDerGrinten2Raw\" name=\"geoVanDerGrinten2Raw\">#</a> d3.<b>geoVanDerGrinten2Raw</b>\n<br><a href=\"#geoVanDerGrinten3Raw\" name=\"geoVanDerGrinten3Raw\">#</a> d3.<b>geoVanDerGrinten3Raw</b>\n<br><a href=\"#geoVanDerGrinten4Raw\" name=\"geoVanDerGrinten4Raw\">#</a> d3.<b>geoVanDerGrinten4Raw</b>\n<br><a href=\"#geoVanDerGrintenRaw\" name=\"geoVanDerGrintenRaw\">#</a> d3.<b>geoVanDerGrintenRaw</b>\n<br><a href=\"#geoWagner4Raw\" name=\"geoWagner4Raw\">#</a> d3.<b>geoWagner4Raw</b>\n<br><a href=\"#geoWagner6Raw\" name=\"geoWagner6Raw\">#</a> d3.<b>geoWagner6Raw</b>\n<br><a href=\"#geoWagner7Raw\" name=\"geoWagner7Raw\">#</a> d3.<b>geoWagner7Raw</b>\n<br><a href=\"#geoWiechelRaw\" name=\"geoWiechelRaw\">#</a> d3.<b>geoWiechelRaw</b>\n<br><a href=\"#geoWinkel3Raw\" name=\"geoWinkel3Raw\">#</a> d3.<b>geoWinkel3Raw</b>"},"npm":{"downloads":[{"from":"2016-10-15T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":779},{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":8257},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":29522},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":82207},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":147047},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":254262}],"dependentsCount":9,"starsCount":0},"github":{"starsCount":387,"forksCount":85,"subscribersCount":44,"issues":{"count":71,"openCount":10,"distribution":{"3600":7,"10800":5,"32400":21,"97200":10,"291600":2,"874800":4,"2624400":2,"7873200":7,"23619600":6,"70858800":4,"212576400":3},"isDisabled":false},"contributors":[{"username":"mbostock","commitsCount":130},{"username":"Fil","commitsCount":51},{"username":"jasondavies","commitsCount":14},{"username":"adamhooper","commitsCount":1},{"username":"tmcw","commitsCount":1},{"username":"mattcg","commitsCount":1}],"commits":[{"from":"2016-10-09T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-09-16T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":0},{"from":"2016-07-18T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":2},{"from":"2016-04-19T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":154},{"from":"2015-10-17T00:00:00.000Z","to":"2016-10-16T00:00:00.000Z","count":158}]},"source":{"files":{"readmeSize":47387,"testsSize":1419889,"hasNpmIgnore":true},"repositorySize":7788548,"linters":{"js":["eslint"]}}},"evaluation":{"quality":{"carefulness":0.9199999999999999,"tests":0.6,"health":1,"branding":0.4},"popularity":{"communityInterest":522,"downloadsCount":27402.333333333332,"downloadsAcceleration":101.94450152207003,"dependentsCount":9},"maintenance":{"releasesFrequency":0.9,"commitsFrequency":1,"openIssues":1,"issuesDistribution":0.9}},"score":{"final":0.7221779726913196,"detail":{"quality":0.9260256430415238,"popularity":0.26981420210661916,"maint
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment