Skip to content

Instantly share code, notes, and snippets.

@tomshanley
Last active August 11, 2016 23:01
Show Gist options
  • Save tomshanley/6e6cef56bd49710ca99ccfde33f4b33c to your computer and use it in GitHub Desktop.
Save tomshanley/6e6cef56bd49710ca99ccfde33f4b33c to your computer and use it in GitHub Desktop.
Beeswarm to line chart

Example of switching between a 'beeswarm' plot to line chart. The beeswarm shows the final values, with each node's position on the Y axis close to its proper value, but shifted to accommodate many nodes. Switch to line chart to show how each node tracked over time.

Uses d3.force to generated the beeswarm plot.

TO DO: remove or amend the voronoi when switching to line chart view.

// https://d3js.org Version 4.1.0. Copyright 2016 Mike Bostock.
(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';
var version = "4.1.0";
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 keys(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
}
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) q._call(q._error, q._data);
}
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) {
if (!callback && typeof data === "function") callback = data, data = null;
if (callback && callback.length === 1) callback = fixCallback(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) 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;
}
};
return callback
? request.get(callback)
: 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);
return callback ? r.get(callback) : 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(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(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(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(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(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(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 width = scale.bandwidth() / 2;
return function(d) {
return scale(d) + width;
};
}
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 ? ".71em" : ".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[1][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"),
mousemoving,
mousePoint,
mouseLocation,
touchstarting,
touchending,
touchDelay = 500,
wheelTimer,
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;
}
Gesture.prototype = {
start: function() {
if (++this.active === 1) {
this.index = gestures.push(this) - 1;
this.emit("start");
}
return this;
},
zoom: function(key, transform) {
if (mousePoint && key !== "mouse") mouseLocation = transform.invert(mousePoint);
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);
mousePoint = mouseLocation = null;
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)));
// If the mouse is in the same location as before, reuse it.
// If there were recent wheel events, reset the wheel idle timeout.
if (wheelTimer) {
var point = mouse(this);
if (mousePoint[0] !== point[0] || mousePoint[1] !== point[1]) {
mouseLocation = t.invert(mousePoint = point);
}
clearTimeout(wheelTimer);
}
// 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.extent = extent.apply(this, arguments);
mouseLocation = t.invert(mousePoint = mouse(this));
interrupt(this);
g.start();
}
noevent$1();
wheelTimer = setTimeout(wheelidled, wheelDelay);
g.zoom("mouse", constrain(translate(scale(t, k), mousePoint, mouseLocation), g.extent));
function wheelidled() {
wheelTimer = 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);
dragDisable(exports.event.view);
nopropagation$1();
mousemoving = false;
g.extent = extent.apply(this, arguments);
mouseLocation = this.__zoom.invert(mousePoint = mouse(this));
interrupt(this);
g.start();
function mousemoved() {
noevent$1();
mousemoving = true;
g.zoom("mouse", constrain(translate(g.that.__zoom, mousePoint = mouse(g.that), mouseLocation), g.extent));
}
function mouseupped() {
v.on("mousemove.zoom mouseup.zoom", null);
dragEnable(exports.event.view, mousemoving);
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.extent = extent.apply(this, arguments);
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;
}
var cos = Math.cos;
var sin = Math.sin;
var pi$3 = Math.PI;
var halfPi$2 = pi$3 / 2;
var tau$3 = pi$3 * 2;
var max$1 = Math.max;
function compareValue(compare) {
return function(a, b) {
return compare(
a.source.value + a.target.value,
b.source.value + b.target.value
);
};
}
function chord() {
var padAngle = 0,
sortGroups = null,
sortSubgroups = null,
sortChords = null;
function chord(matrix) {
var n = matrix.length,
groupSums = [],
groupIndex = range(n),
subgroupIndex = [],
chords = [],
groups = chords.groups = new Array(n),
subgroups = new Array(n * n),
k,
x,
x0,
dx,
i,
j;
// Compute the sum.
k = 0, i = -1; while (++i < n) {
x = 0, j = -1; while (++j < n) {
x += matrix[i][j];
}
groupSums.push(x);
subgroupIndex.push(range(n));
k += x;
}
// Sort groups…
if (sortGroups) groupIndex.sort(function(a, b) {
return sortGroups(groupSums[a], groupSums[b]);
});
// Sort subgroups…
if (sortSubgroups) subgroupIndex.forEach(function(d, i) {
d.sort(function(a, b) {
return sortSubgroups(matrix[i][a], matrix[i][b]);
});
});
// Convert the sum to scaling factor for [0, 2pi].
// TODO Allow start and end angle to be specified?
// TODO Allow padding to be specified as percentage?
k = max$1(0, tau$3 - padAngle * n) / k;
dx = k ? padAngle : tau$3 / n;
// Compute the start and end angle for each group and subgroup.
// Note: Opera has a bug reordering object literal properties!
x = 0, i = -1; while (++i < n) {
x0 = x, j = -1; while (++j < n) {
var di = groupIndex[i],
dj = subgroupIndex[di][j],
v = matrix[di][dj],
a0 = x,
a1 = x += v * k;
subgroups[dj * n + di] = {
index: di,
subindex: dj,
startAngle: a0,
endAngle: a1,
value: v
};
}
groups[di] = {
index: di,
startAngle: x0,
endAngle: x,
value: groupSums[di]
};
x += dx;
}
// Generate chords for each (non-empty) subgroup-subgroup link.
i = -1; while (++i < n) {
j = i - 1; while (++j < n) {
var source = subgroups[j * n + i],
target = subgroups[i * n + j];
if (source.value || target.value) {
chords.push(source.value < target.value
? {source: target, target: source}
: {source: source, target: target});
}
}
}
return sortChords ? chords.sort(sortChords) : chords;
}
chord.padAngle = function(_) {
return arguments.length ? (padAngle = max$1(0, _), chord) : padAngle;
};
chord.sortGroups = function(_) {
return arguments.length ? (sortGroups = _, chord) : sortGroups;
};
chord.sortSubgroups = function(_) {
return arguments.length ? (sortSubgroups = _, chord) : sortSubgroups;
};
chord.sortChords = function(_) {
return arguments.length ? (_ == null ? sortChords = null : (sortChords = compareValue(_))._ = _, chord) : sortChords && sortChords._;
};
return chord;
}
var slice$5 = Array.prototype.slice;
function constant$11(x) {
return function() {
return x;
};
}
function defaultSource(d) {
return d.source;
}
function defaultTarget(d) {
return d.target;
}
function defaultRadius$1(d) {
return d.radius;
}
function defaultStartAngle(d) {
return d.startAngle;
}
function defaultEndAngle(d) {
return d.endAngle;
}
function ribbon() {
var source = defaultSource,
target = defaultTarget,
radius = defaultRadius$1,
startAngle = defaultStartAngle,
endAngle = defaultEndAngle,
context = null;
function ribbon() {
var buffer,
argv = slice$5.call(arguments),
s = source.apply(this, argv),
t = target.apply(this, argv),
sr = +radius.apply(this, (argv[0] = s, argv)),
sa0 = startAngle.apply(this, argv) - halfPi$2,
sa1 = endAngle.apply(this, argv) - halfPi$2,
sx0 = sr * cos(sa0),
sy0 = sr * sin(sa0),
tr = +radius.apply(this, (argv[0] = t, argv)),
ta0 = startAngle.apply(this, argv) - halfPi$2,
ta1 = endAngle.apply(this, argv) - halfPi$2;
if (!context) context = buffer = path();
context.moveTo(sx0, sy0);
context.arc(0, 0, sr, sa0, sa1);
if (sa0 !== ta0 || sa1 !== ta1) { // TODO sr !== tr?
context.quadraticCurveTo(0, 0, tr * cos(ta0), tr * sin(ta0));
context.arc(0, 0, tr, ta0, ta1);
}
context.quadraticCurveTo(0, 0, sx0, sy0);
context.closePath();
if (buffer) return context = null, buffer + "" || null;
}
ribbon.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$11(+_), ribbon) : radius;
};
ribbon.startAngle = function(_) {
return arguments.length ? (startAngle = typeof _ === "function" ? _ : constant$11(+_), ribbon) : startAngle;
};
ribbon.endAngle = function(_) {
return arguments.length ? (endAngle = typeof _ === "function" ? _ : constant$11(+_), ribbon) : endAngle;
};
ribbon.source = function(_) {
return arguments.length ? (source = _, ribbon) : source;
};
ribbon.target = function(_) {
return arguments.length ? (target = _, ribbon) : target;
};
ribbon.context = function(_) {
return arguments.length ? ((context = _ == null ? null : _), ribbon) : context;
};
return ribbon;
}
// 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$4 = Math.PI;
var halfPi$3 = pi$4 / 2;
var quarterPi = pi$4 / 4;
var tau$4 = pi$4 * 2;
var degrees$1 = 180 / pi$4;
var radians = pi$4 / 180;
var abs = Math.abs;
var atan = Math.atan;
var atan2 = Math.atan2;
var cos$1 = Math.cos;
var ceil = Math.ceil;
var exp = Math.exp;
var log$1 = Math.log;
var pow$1 = Math.pow;
var sin$1 = 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$4 : Math.acos(x);
}
function asin$1(x) {
return x > 1 ? halfPi$3 : x < -1 ? -halfPi$3 : Math.asin(x);
}
function haversin(x) {
return (x = sin$1(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 stream(object, stream) {
if (object && streamObjectType.hasOwnProperty(object.type)) {
streamObjectType[object.type](object, stream);
} else {
streamGeometry(object, stream);
}
}
var areaRingSum;
var areaSum;
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$4 + areaRing : areaRing);
this.lineStart = this.lineEnd = this.point = noop$2;
},
sphere: function() {
areaSum.add(tau$4);
}
};
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$1(phi = phi / 2 + quarterPi), sinPhi0 = sin$1(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$1(phi),
sinPhi = sin$1(phi),
k = sinPhi0 * sinPhi,
u = cosPhi0 * cosPhi + k * cos$1(adLambda),
v = k * sdLambda * sin$1(adLambda);
areaRingSum.add(atan2(v, u));
// Advance the previous points.
lambda0 = lambda, cosPhi0 = cosPhi, sinPhi0 = sinPhi;
}
function area$2(object) {
if (areaSum) areaSum.reset();
else areaSum = adder(), areaRingSum = adder();
stream(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$1(phi);
return [cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(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;
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;
if (deltaSum) deltaSum.reset();
else deltaSum = adder();
phi1 = lambda1 = -(lambda0$1 = phi0 = Infinity);
ranges = [];
stream(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$1(phi);
centroidPointCartesian(cosPhi * cos$1(lambda), cosPhi * sin$1(lambda), sin$1(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$1(phi);
x0 = cosPhi * cos$1(lambda);
y0 = cosPhi * sin$1(lambda);
z0 = sin$1(phi);
centroidStream.point = centroidLinePoint;
centroidPointCartesian(x0, y0, z0);
}
function centroidLinePoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos$1(phi),
x = cosPhi * cos$1(lambda),
y = cosPhi * sin$1(lambda),
z = sin$1(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$1(phi);
x0 = cosPhi * cos$1(lambda);
y0 = cosPhi * sin$1(lambda);
z0 = sin$1(phi);
centroidPointCartesian(x0, y0, z0);
}
function centroidRingPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var cosPhi = cos$1(phi),
x = cosPhi * cos$1(lambda),
y = cosPhi * sin$1(lambda),
z = sin$1(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;
stream(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$12(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$4 ? lambda - tau$4 : lambda < -pi$4 ? lambda + tau$4 : lambda, phi];
}
rotationIdentity.invert = rotationIdentity;
function rotateRadians(deltaLambda, deltaPhi, deltaGamma) {
return (deltaLambda %= tau$4) ? (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$4 ? lambda - tau$4 : lambda < -pi$4 ? lambda + tau$4 : lambda, phi];
};
}
function rotationLambda(deltaLambda) {
var rotation = forwardRotationLambda(deltaLambda);
rotation.invert = forwardRotationLambda(-deltaLambda);
return rotation;
}
function rotationPhiGamma(deltaPhi, deltaGamma) {
var cosDeltaPhi = cos$1(deltaPhi),
sinDeltaPhi = sin$1(deltaPhi),
cosDeltaGamma = cos$1(deltaGamma),
sinDeltaGamma = sin$1(deltaGamma);
function rotation(lambda, phi) {
var cosPhi = cos$1(phi),
x = cos$1(lambda) * cosPhi,
y = sin$1(lambda) * cosPhi,
z = sin$1(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$1(phi),
x = cos$1(lambda) * cosPhi,
y = sin$1(lambda) * cosPhi,
z = sin$1(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$1(radius),
sinRadius = sin$1(radius),
step = direction * delta;
if (t0 == null) {
t0 = radius + direction * tau$4;
t1 = radius - step / 2;
} else {
t0 = circleRadius(cosRadius, t0);
t1 = circleRadius(cosRadius, t1);
if (direction > 0 ? t0 < t1 : t0 > t1) t0 += direction * tau$4;
}
for (var point, t = t0; direction > 0 ? t > t1 : t < t1; t -= step) {
point = spherical([cosRadius, -sinRadius * cos$1(t), -sinRadius * sin$1(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$4 - epsilon$4) % tau$4;
}
function circle$1() {
var center = constant$12([0, 0]),
radius = constant$12(90),
precision = constant$12(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$12([+_[0], +_[1]]), circle) : center;
};
circle.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant$12(+_), circle) : radius;
};
circle.precision = function(_) {
return arguments.length ? (precision = typeof _ === "function" ? _ : constant$12(+_), 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;
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$1(phi), cosPhi0$1 = cos$1(phi);
lengthStream.point = lengthPoint;
}
function lengthPoint(lambda, phi) {
lambda *= radians, phi *= radians;
var sinPhi = sin$1(phi),
cosPhi = cos$1(phi),
delta = abs(lambda - lambda0$2),
cosDelta = cos$1(delta),
sinDelta = sin$1(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) {
if (lengthSum) lengthSum.reset();
else lengthSum = adder();
stream(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$1(y0),
sy0 = sin$1(y0),
cy1 = cos$1(y1),
sy1 = sin$1(y1),
kx0 = cy0 * cos$1(x0),
ky0 = cy0 * sin$1(x0),
kx1 = cy1 * cos$1(x1),
ky1 = cy1 * sin$1(x1),
d = 2 * asin$1(sqrt$1(haversin(y1 - y0) + cy0 * cy1 * haversin(x1 - x0))),
k = sin$1(d);
var interpolate = d ? function(t) {
var B = sin$1(t *= d) / k,
A = sin$1(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$4);
}
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));
stream(object, projectionStream(contextStream));
}
return contextStream.result();
}
path.area = function(object) {
stream(object, projectionStream(areaStream$1));
return areaStream$1.result();
};
path.bounds = function(object) {
stream(object, projectionStream(boundsStream$1));
return boundsStream$1.result();
};
path.centroid = function(object) {
stream(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$1(lambda), -cos$1(lambda), 0],
angle = 0,
winding = 0;
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$1(phi0),
cosPhi0 = cos$1(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$1(phi1),
cosPhi1 = cos$1(phi1),
delta = lambda1 - lambda0,
sign = delta >= 0 ? 1 : -1,
absDelta = sign * delta,
antimeridian = absDelta > pi$4,
k = sinPhi0 * sinPhi1;
sum$2.add(atan2(k * sign * sin$1(absDelta), cosPhi0 * cosPhi1 + k * cos$1(absDelta)));
angle += antimeridian ? delta + sign * tau$4 : 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.
var contains = (angle < -epsilon$4 || angle < epsilon$4 && sum$2 < -epsilon$4) ^ (winding & 1);
sum$2.reset();
return contains;
}
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$3 - epsilon$4 : halfPi$3 - a[1])
- ((b = b.x)[0] < 0 ? b[1] - halfPi$3 - epsilon$4 : halfPi$3 - b[1]);
}
var clipAntimeridian = clip(
function() { return true; },
clipAntimeridianLine,
clipAntimeridianInterpolate,
[-pi$4, -halfPi$3]
);
// 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$4 : -pi$4,
delta = abs(lambda1 - lambda0);
if (abs(delta - pi$4) < epsilon$4) { // line crosses a pole
stream.point(lambda0, phi0 = (phi0 + phi1) / 2 > 0 ? halfPi$3 : -halfPi$3);
stream.point(sign0, phi0);
stream.lineEnd();
stream.lineStart();
stream.point(sign1, phi0);
stream.point(lambda1, phi0);
clean = 0;
} else if (sign0 !== sign1 && delta >= pi$4) { // 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$1(lambda0 - lambda1);
return abs(sinLambda0Lambda1) > epsilon$4
? atan((sin$1(phi0) * (cosPhi1 = cos$1(phi1)) * sin$1(lambda1)
- sin$1(phi1) * (cosPhi0 = cos$1(phi0)) * sin$1(lambda0))
/ (cosPhi0 * cosPhi1 * sinLambda0Lambda1))
: (phi0 + phi1) / 2;
}
function clipAntimeridianInterpolate(from, to, direction, stream) {
var phi;
if (from == null) {
phi = direction * halfPi$3;
stream.point(-pi$4, phi);
stream.point(0, phi);
stream.point(pi$4, phi);
stream.point(pi$4, 0);
stream.point(pi$4, -phi);
stream.point(0, -phi);
stream.point(-pi$4, -phi);
stream.point(-pi$4, 0);
stream.point(-pi$4, phi);
} else if (abs(from[0] - to[0]) > epsilon$4) {
var lambda = from[0] < to[0] ? pi$4 : -pi$4;
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$1(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$1(lambda) * cos$1(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$4 : -pi$4), 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$4) < 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$4 ^ (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$4 - 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$4, radius - pi$4]);
}
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(); }
};
var maxDepth = 16;
var cosMinDistance = cos$1(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);
};
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$4 / 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$1(y0),
n = (sy0 + sin$1(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$1(y)) / n;
return [r * sin$1(x *= n), r0 - r * cos$1(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(151)
.translate([480, 347]);
}
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. Also works quite well at 960×600 with scale 1285. 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;
};
return albersUsa.scale(1070);
}
function azimuthalRaw(scale) {
return function(x, y) {
var cx = cos$1(x),
cy = cos$1(y),
k = scale(cx * cy);
return [
k * cy * sin$1(x),
k * sin$1(y)
];
}
}
function azimuthalInvert(angle) {
return function(x, y) {
var z = sqrt$1(x * x + y * y),
c = angle(z),
sc = sin$1(c),
cc = cos$1(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(120)
.clipAngle(180 - 1e-3);
}
var azimuthalEquidistantRaw = azimuthalRaw(function(c) {
return (c = acos(c)) && c / sin$1(c);
});
azimuthalEquidistantRaw.invert = azimuthalInvert(function(z) {
return z;
});
function azimuthalEquidistant() {
return projection(azimuthalEquidistantRaw)
.scale(480 / tau$4)
.clipAngle(180 - 1e-3);
}
function mercatorRaw(lambda, phi) {
return [lambda, log$1(tan((halfPi$3 + phi) / 2))];
}
mercatorRaw.invert = function(x, y) {
return [x, 2 * atan(exp(y)) - halfPi$3];
};
function mercator() {
return mercatorProjection(mercatorRaw);
}
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$4 * scale(), t = translate();
_ = [[t[0] - k, t[1] - k], [t[0] + k, t[1] + k]];
}
clipExtent(_);
return m;
};
return m.clipExtent(null).scale(961 / tau$4);
}
function tany(y) {
return tan((halfPi$3 + y) / 2);
}
function conicConformalRaw(y0, y1) {
var cy0 = cos$1(y0),
n = y0 === y1 ? sin$1(y0) : log$1(cy0 / cos$1(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$3 + epsilon$4) y = -halfPi$3 + epsilon$4; }
else { if (y > halfPi$3 - epsilon$4) y = halfPi$3 - epsilon$4; }
var r = f / pow$1(tany(y), n);
return [r * sin$1(n * x), f - r * cos$1(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$3];
};
return project;
}
function conicConformal() {
return conicProjection(conicConformalRaw);
}
function equirectangularRaw(lambda, phi) {
return [lambda, phi];
}
equirectangularRaw.invert = equirectangularRaw;
function equirectangular() {
return projection(equirectangularRaw).scale(480 / pi$4);
}
function conicEquidistantRaw(y0, y1) {
var cy0 = cos$1(y0),
n = y0 === y1 ? sin$1(y0) : (cy0 - cos$1(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$1(nx), g - gy * cos$1(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(128)
.translate([480, 280]);
}
function gnomonicRaw(x, y) {
var cy = cos$1(y), k = cos$1(x) * cy;
return [cy * sin$1(x) / k, sin$1(y) / k];
}
gnomonicRaw.invert = azimuthalInvert(atan);
function gnomonic() {
return projection(gnomonicRaw)
.scale(139)
.clipAngle(60);
}
function orthographicRaw(x, y) {
return [cos$1(y) * sin$1(x), sin$1(y)];
}
orthographicRaw.invert = azimuthalInvert(asin$1);
function orthographic() {
return projection(orthographicRaw)
.scale(240)
.clipAngle(90 + epsilon$4);
}
function stereographicRaw(x, y) {
var cy = cos$1(y), k = 1 + cos$1(x) * cy;
return [cy * sin$1(x) / k, sin$1(y) / k];
}
stereographicRaw.invert = azimuthalInvert(function(z) {
return 2 + atan(z);
});
function stereographic() {
return projection(stereographicRaw)
.scale(240)
.clipAngle(142);
}
function transverseMercatorRaw(lambda, phi) {
return [log$1(tan((halfPi$3 + phi) / 2)), -lambda];
}
transverseMercatorRaw.invert = function(x, y) {
return [-y, 2 * atan(exp(x)) - halfPi$3];
};
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]);
}
exports.version = version;
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 = keys;
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.interpolateDate = date;
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;
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.chord = chord;
exports.ribbon = ribbon;
exports.geoAlbers = albers;
exports.geoAlbersUsa = albersUsa;
exports.geoArea = area$2;
exports.geoAzimuthalEqualArea = azimuthalEqualArea;
exports.geoAzimuthalEqualAreaRaw = azimuthalEqualAreaRaw;
exports.geoAzimuthalEquidistant = azimuthalEquidistant;
exports.geoAzimuthalEquidistantRaw = azimuthalEquidistantRaw;
exports.geoBounds = bounds;
exports.geoCentroid = centroid$1;
exports.geoCircle = circle$1;
exports.geoClipExtent = extent$1;
exports.geoConicConformal = conicConformal;
exports.geoConicConformalRaw = conicConformalRaw;
exports.geoConicEqualArea = conicEqualArea;
exports.geoConicEqualAreaRaw = conicEqualAreaRaw;
exports.geoConicEquidistant = conicEquidistant;
exports.geoConicEquidistantRaw = conicEquidistantRaw;
exports.geoDistance = distance;
exports.geoEquirectangular = equirectangular;
exports.geoEquirectangularRaw = equirectangularRaw;
exports.geoGnomonic = gnomonic;
exports.geoGnomonicRaw = gnomonicRaw;
exports.geoGraticule = graticule;
exports.geoInterpolate = interpolate$2;
exports.geoLength = length$2;
exports.geoMercator = mercator;
exports.geoMercatorRaw = mercatorRaw;
exports.geoOrthographic = orthographic;
exports.geoOrthographicRaw = orthographicRaw;
exports.geoPath = index$3;
exports.geoProjection = projection;
exports.geoProjectionMutator = projectionMutator;
exports.geoRotation = rotation;
exports.geoStereographic = stereographic;
exports.geoStereographicRaw = stereographicRaw;
exports.geoStream = stream;
exports.geoTransform = transform$1;
exports.geoTransverseMercator = transverseMercator;
exports.geoTransverseMercatorRaw = transverseMercatorRaw;
Object.defineProperty(exports, '__esModule', { value: true });
}));
<html><head><meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="siu.css">
<link rel="stylesheet" type="text/css" href="siu-roi.css">
</head>
<body>
<h1>PROTOTYPE BEESWARM TO LINE CHART VIEW</h1>
<h2>Outcomes</h2>
<div><p>
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere
</p></div>
<div class="selector">Parents: <select id="no-of-parents">
<option value="All">All</option>
<option value="1">1</option>
<option value="2">2</option>
</select></div>
<div class="selector">Children: <select id="no-of-children">
<option value="All">All</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select></div>
<div class="selector">Region: <select id="region">
<option value="All">All</option>
<option value="Auckland">Auckland</option>
<option value="Upper North Island">Upper North Island</option>
<option value="Lower North Island">Lower North Island</option>
<option value="South Island">South Island</option>
</select></div>
<div class="selector">Income: <select id="income">
<option value="All">All</option>
<option value="0 to 15000">0 to 15000</option>
<option value="over 15000">over 15000</option>
</select></div>
<div class="selector">Ethnicity: <select id="ethnicity">
<option value="All">All</option>
<option value="Maori">Maori</option>
<option value="NZEuropean">NZ European</option>
<option value="Other">Other</option>
</select></div>
<div class="selector"><button id="change-button" onclick="resetChart()">Reset</button></div>
<div class="selector"><button id="line-button" onclick="switchChart()">Switch chart</button></div>
<div id="roi-chart"></div>
<h2>Technical reports</h2>
<p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime placeat facere
</p>
<h2><a href="#">Download the data</a></h2>
<script src="d3.js"></script>
<script src="siu-helper-functions.js"></script>
<script src="roi-to-line.js"></script>
</body></html>
var screenWidth = document.documentElement.clientWidth;
var screenHeight = document.documentElement.clientHeight;
var maxWidth = 600;
var preferredWidth = Math.min(600, screenWidth);
var nestedData;
var margin = {top: 30, right: 30, bottom: 10, left: 65},
width = preferredWidth - margin.left - margin.right,
height = 2000 - margin.top - margin.bottom;
var lineChartIndent = width/5;
var lineChartWidth = width - lineChartIndent;
const radius = preferredWidth > 200 ? 5 : 3;
const opacity = {normal: 0.7, focus: 1, muted: 0.2, hidden: 0};
var currentChart = "bee";
var yScaleBee = d3.scaleLinear()
.rangeRound([height/5, 0]); //TO CONVERT "5" TO FUNCTION
var yScaleOutcome = d3.scaleBand()
.range([height, 0]);
var yAxisRight = d3.axisRight(yScaleBee).tickSize(1);
var xScaleLine = d3.scaleLinear()
.range([0, lineChartWidth])
.domain([0, 7]); //correct
var colourOutcome = d3.scaleOrdinal()
.range([siuColours.orange10, siuColours.teal10, siuColours.purple10, siuColours.green10, siuColours.greyDark]);
var colourRegion = d3.scaleOrdinal()
.range([siuColours.orange10, siuColours.teal10, siuColours.purple10, siuColours.green10, siuColours.greyDark]);
var roiLine = d3.line()
.x(function(d) { return xScaleLine(d.x); })
.y(function(d) { return yScaleBee(d.y); })
.curve(d3.curveLinear);
var lineChartData;
var svg = d3.select("#roi-chart")
.append("svg")
//.attr("viewBox", "0 0 "+ preferredWidth + " " + (height + margin.top + margin.bottom) )
//.attr("preserveAspectRatio", "xMidYMid meet");
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.on("click", function() {
resetChart();
});
var lineG = svg.append("g")
.attr("transform", "translate(" + (margin.left + lineChartIndent) + "," + margin.top + ")");
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
// LOAD DATA AND CREATE CHARTS
d3.csv("roi4.csv", convertTextToNumbers, function(error, data) {
if (error) throw error;
// ENABLE THE DROP DOWN SELECTS
var select = d3.selectAll("select");
select.on("change", function(d) {
var selectedParents = d3.select("#no-of-parents").property("value");
var selectedChildren = d3.select("#no-of-children").property("value");
var selectedRegion = d3.select("#region").property("value");
var selectedIncome = d3.select("#income").property("value");
var selectedEthnicity = d3.select("#ethnicity").property("value");
highlightFamilies(selectedParents, selectedChildren, selectedRegion, selectedIncome, selectedEthnicity);
});
//SET THE SCALES
yScaleBee.domain([
Math.floor(d3.min(data, function(d) { return d.roi; } )),
Math.ceil(d3.max(data, function(d) { return d.roi; } )),
]);
yScaleOutcome.domain(data.sort(function(a, b) { return b.roi - a.roi; })
.map(function(d) { return d.outcome; }) );
colourOutcome.domain(yScaleBee.domain());
colourRegion.domain(data.sort(function(a, b) { return b.roi - a.roi; })
.map(function(d) { return d.region; }) );
lineChartData = d3.nest()
.key(function(d) {return d.familyID;})
.key(function(d) {return d.outcome;})
.rollup(function(d) {
var points = []
points =
[ { x: 1, y: d3.mean(d, function(g) {return +g.year1;}) }
, { x: 2, y: d3.mean(d, function(g) {return +g.year2;}) }
, { x: 3, y: d3.mean(d, function(g) {return +g.year3;}) }
, { x: 4, y: d3.mean(d, function(g) {return +g.year4;}) }
, { x: 5, y: d3.mean(d, function(g) {return +g.year5;}) }
, { x: 6, y: d3.mean(d, function(g) {return +g.year6;}) }
];
return points;
})
.entries(data);
var averageROI = d3.nest()
.key(function(d) { return d.outcome; } )
.rollup(function(v) { return d3.mean(v, function(d) { return d.roi; } ); } )
.entries(data);
// SET THE SCALES
//xAxisTop.ticks( (yScaleBee.domain()[1] - yScaleBee.domain()[0] + 1) );
//xAxisBottom.ticks( (yScaleBee.domain()[1] - yScaleBee.domain()[0] + 1) );
// DRAW THE LABELS AND GRID LINES
var yLabels = g.selectAll(".y-label")
.data(yScaleOutcome.domain())
.enter()
.append("text")
.attr("class", "y-label")
.attr("y", function(d) { return yScaleOutcome(d) + yScaleOutcome.bandwidth()/2; })
.attr("x", -10)
.text(function(d){ return capitalizeFirstLetter(d); });
var yAxes = g.selectAll("axis-right")
.data(averageROI)
.enter()
.append("g")
.attr("class", "axis-right")
.attr("transform", function(d) { return "translate("+ (width) +"," + yScaleOutcome(d.key) + ")" ; })
.call(yAxisRight);
var gridLines = g.selectAll(".axis-right").selectAll(".tick")
.append("line")
.attr("class", "gridLine")
.attr("x1", -lineChartWidth)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", 0 );
var avgLines = g.selectAll(".avg-line")
.data(averageROI)
.enter()
.append("g")
.attr("class", "avg-line")
.attr("transform", function(d) { return "translate(0," + ( yScaleOutcome(d.key) + yScaleBee(d.value) ) + ")"; });
avgLines.append("line")
.attr("x1", lineChartIndent)
.attr("x2", width)
.attr("y1", 0)
.attr("y2", 0);
avgLines.append("text")
.text(function(d) { return "avg: "+ oneDecimalPlace(d.value); } )
.attr("x", lineChartIndent - 10 )
.attr("y", "-0.2em" );
var FamilyLineCharts = lineG.selectAll(".g-family-line-charts")
.data(lineChartData)
.enter()
.append("g")
.attr("class", ".g-family-line-charts")
.attr("id", function(d) { return "line-chart-" + d.key; } );
var outcomeGroups = FamilyLineCharts.selectAll(".g-outcome-lines")
.data(function(d) {return d.values;} )
.enter()
.append("g")
.attr("class", "g-outcome-lines" )
.attr("transform", function(d) { return "translate(0,"+ yScaleOutcome(d.key) +")" } );
outcomeGroups.append('path')
.datum(function(d) { return d.value; } )
.attr("d", roiLine)
.style("opacity", opacity.hidden);
// CREATE THE FORCE, TO LAYOUT THE CIRCLES - IE. SET THE X,Y COORDS.
var simulation = d3.forceSimulation(data)
.force("x", d3.forceX(xScaleLine(6) + lineChartIndent) )
.force("y", d3.forceY(function(d) { return yScaleOutcome(d.outcome) + yScaleBee(d.roi); }))
.force("collide", d3.forceCollide(radius+1) )
//.on('tick', ticked)
.stop();
for (var i = 0; i < 120; ++i) simulation.tick();
// CREATE THE VORONOI LAYOUT TO ENABLE EASIER SELECTION
var voronoi = d3.voronoi()
.extent([[-margin.left, -margin.top], [width + margin.right, height + margin.top]])
.x(function(d) { return d.x; })
.y(function(d) { return d.y; });
voronoiData = voronoi(data).polygons();
// DRAW THE THE CIRCLES
var cell = g.append("g")
.attr("class", "cells")
.selectAll("g").data(voronoiData)
.enter()
.append("g")
.attr("class", "polys");
cell.append("circle")
.attr("r", radius)
.attr("cx", function(d) { return d.data.x; })
.attr("cy", function(d) { return d.data.y; })
.style("fill", function(d) { return colourRegion(d.data.region); } )
.style("fill-opacity", opacity.normal );
var researchClip = g.append("defs").selectAll("clipPath")
.data(voronoiData)
.enter()
.append("clipPath")
.attr("id", function(d) { return "clip-research-" + d.data.id; })
.append("circle")
.attr("cx", function(d) { return d.data.x; })
.attr("cy", function(d) { return d.data.y; })
.attr("r", radius + 20 );
cell.append("path")
.attr("class", "clipped-paths")
//.style("stroke", "grey")
.attr("d", function(d) { return "M" + d.join("L") + "Z"; })
.attr("clip-path", function(d) { return "url(#clip-research-" + d.data.id + ")"; })
.on("click", showHideCircles);
cell.append("title")
.text(function(d) { return d.data.roi + "%" +
"\nParents: " + d.data.parents +
"\nChildren: " + d.data.children; });
});
// FUNCTIONS
// RESET THE CIRCLE FORMATTING
function resetChart() {
setSelectValues("All", "All", "All", "All", "All");
resetLineCircles();
d3.selectAll(".clipped-paths")
.each(function(d) { d.data.highlighted = false; } );
if(currentChart === "line") {
d3.selectAll(".g-outcome-lines").selectAll("path")
.transition()
.duration(500)
.style("opacity", opacity.muted)
}
};
function resetLineCircles() {
d3.selectAll(".family-line")
.style("stroke-opacity", opacity.hidden );
d3.selectAll(".polys")
.selectAll("circle")
.style("stroke", "none")
.style("fill-opacity", opacity.normal );
if(currentChart === "line") {
d3.selectAll(".g-outcome-lines").selectAll("path")
.style("opacity", opacity.muted)
}
};
// handle the click
function showHideCircles (d) {
resetLineCircles();
if (d.data.highlighted) {
d3.selectAll(".clipped-paths")
.each(function(d) { d.data.highlighted = false; } );
setSelectValues("All", "All", "All", "All", "All");
} else {
var thisFamily = d.data.familyID;
console.log(d.data.ethnicity);
d3.selectAll(".clipped-paths").filter(function(d) { return d.data.familyID === thisFamily; } )
.each(function(d) { d.data.highlighted = true; } );
d.data.highlighted = true;
highlightFamily(d.data.familyID);
setSelectValues(d.data.parents, d.data.children, d.data.region, d.data.income, d.data.ethnicity);
};
d3.event.stopPropagation();
} ;
// HIGHLIGHT ALL FAMILIES THAT MATCH THE SELECTED VALUES
function highlightFamilies(noOfParents, noOfChildren, region, income, ethnicity) {
var thisParents = noOfParents;
var thisChildren = noOfChildren;
var thisRegion = region;
var thisIncome = income;
var thisEthnicity = ethnicity;
resetLineCircles();
if (thisParents !== "All" && thisChildren !== "All" && thisRegion !== "All" && thisIncome !== "All" && thisEthnicity !== "All") {
var thisID = "" + thisParents + thisChildren + thisRegion + thisIncome + thisEthnicity;
thisID = thisID.replace(/\s/g, ''); //remove white spaces
highlightFamily(thisID);
} else if (thisParents !== "All" || thisChildren !== "All" || thisRegion !== "All" || thisIncome !== "All" || thisEthnicity !== "All") {
d3.selectAll(".polys")
.selectAll("circle")
.style("stroke", "none")
.style("fill-opacity", opacity.muted);
var filteredSelection = d3.selectAll(".polys")
.selectAll("circle");
if (thisParents !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.parents == thisParents; }) };
if (thisChildren !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.children == thisChildren; }) };
if (thisRegion !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.region == thisRegion; }) };
if (thisIncome !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.income == thisIncome; }) };
if (thisEthnicity !== "All") { filteredSelection = filteredSelection.filter(function(d) { return d.data.ethnicity == thisEthnicity; }) };
filteredSelection
.style("stroke", "black")
.style("fill-opacity", opacity.focus)
.each(function(d) {
console.log("yyy");
if (currentChart === "line") {
console.log(d.data.familyID);
d3.selectAll("#line-chart-" + d.data.familyID).selectAll("path")
.style("opacity", opacity.focus );
};
});
};
}; // end of function highlightFamilies
// HIGHLIGHT A CERTAIN FAMILY TYPE
function highlightFamily(selectedFamilyID) {
var thisID = selectedFamilyID;
d3.selectAll(".polys")
.selectAll("circle")
.style("stroke", function (d) { return d.data.familyID === thisID ? "black" : "none" ; })
.style("fill-opacity", function (d) { return d.data.familyID === thisID ? opacity.focus : opacity.muted ; });
d3.selectAll("#family-line-"+thisID)
.style("stroke-opacity", opacity.focus );
if (currentChart === 'line' ) {
d3.selectAll("#line-chart-" + thisID).selectAll("path")
.style("opacity", opacity.focus );
};
}; // end of function highlightFamily
// SET THE DROP DOWN VALUES BASED ON HIGHLIGHED CIRCLES
function setSelectValues(parentToSelect, childrenToSelect, regionToSelect, incomeToSelect, ethnicityToSelect) {
d3.select("#no-of-parents").property("value", parentToSelect);
d3.select("#no-of-children").property("value", childrenToSelect);
d3.select("#region").property("value", regionToSelect);
d3.select("#income").property("value", incomeToSelect);
d3.select("#ethnicity").property("value", ethnicityToSelect);
};
function switchChart() {
console.log("here");
resetLineCircles();
if (currentChart === "bee") {
d3.selectAll(".polys")
.selectAll("circle")
.transition()
.duration(500)
.attr("cx", xScaleLine(6) + lineChartIndent)
.attr("cy", function(d) { return yScaleBee(d.data.roi) + yScaleOutcome(d.data.outcome); });
d3.selectAll(".g-outcome-lines").selectAll("path")
.transition()
.duration(500)
.style("opacity", opacity.muted)
currentChart = "line";
} else {
d3.selectAll(".g-outcome-lines").selectAll("path")
.transition()
.duration(500)
.style("opacity", opacity.hidden)
d3.selectAll(".polys")
.selectAll("circle")
.transition()
.duration(500)
.attr("cx", function(d) { return d.data.x; })
.attr("cy", function(d) { return d.data.y; });
currentChart = "bee";
};
};
//CONVERT CSV TEXT TO NUMBERS
function convertTextToNumbers(d) {
d.id = +d.id;
d.parents = +d.parents;
d.children = +d.children;
d.roi = +d.roi;
d.year1 = +d.year1;
d.year2 = +d.year2;
d.year3 = +d.year3;
d.year4 = +d.year4;
d.year5 = +d.year5;
d.year6 = +d.year6;
return d;
};
// RESIZE LISTENER
addEvent(window, "resize", function(event) {
console.log('resized');
screenWidth = document.documentElement.clientWidth;
screenHeight = document.documentElement.clientHeight;
console.log("w: " + screenWidth + " h: " + screenHeight );
preferredWidth = Math.min(600, screenWidth);
console.log("p: " + preferredWidth);
});
id familyID parents children region income ethnicity outcome roi year1 year2 year3 year4 year5 year6
1 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori health 1.536 1.011209033 0.991381405 1.166331064 1.154783232 1.2417024 1.536
2 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori health 1.521 1.049027218 1.152777163 1.340438561 1.396290168 1.3425867 1.521
3 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori health 1.269 0.898413686 0.863859314 0.99294174 1.1032686 1.225854 1.269
4 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori health 1.313 0.883043331 0.919836803 1.069577678 1.028440075 1.0602475 1.313
5 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori health 2.443 1.530698325 1.779881774 1.744982131 1.836823296 1.9133576 2.443
6 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori health 2.484 1.907122599 1.851575339 1.851575339 2.15299458 2.5329348 2.484
7 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori health 1.578 1.167213145 1.144326613 1.121888836 1.206332082 1.1943882 1.578
8 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori health 0.785 0.536742879 0.624119627 0.617940225 0.63055125 0.741825 0.785
9 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori education 0.844 0.46134665 0.470761887 0.523068764 0.568553004 0.6535092 0.844
10 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori education 1.389 0.789427634 0.858073515 1.009498253 1.16034282 1.275102 1.389
11 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori education 0.78 0.484244725 0.569699676 0.63299964 0.695604 0.695604 0.78
12 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori education 0.848 0.554497686 0.61610854 0.586770038 0.67444832 0.741152 0.848
13 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori education 0.82 0.515654652 0.592706496 0.69730176 0.676992 0.7052 0.82
14 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori education 2.171 1.549160733 1.665764229 1.71728271 1.8268965 2.14929 2.171
15 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori education 1.8 1.583503714 1.799436038 1.78161984 1.729728 1.64736 1.8
16 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori education 1.756 1.181788864 1.205907004 1.230517351 1.33751886 1.5735516 1.756
17 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori crime 2.063 1.447853648 1.645288236 1.750306634 1.682987148 1.6499874 2.063
18 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori crime 0.821 0.580601744 0.592450759 0.592450759 0.65104479 0.7233831 0.821
19 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori crime 2.274 1.841383587 2.045981763 2.131231003 2.08944216 2.1994128 2.274
20 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori crime 1.668 1.110774566 1.088994673 1.146310182 1.332918816 1.5499056 1.668
21 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori crime 0.885 0.492595544 0.566201774 0.608819112 0.6027912 0.70092 0.885
22 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori crime 1.29 0.820237175 0.820237175 0.901359533 0.93891618 1.054962 1.29
23 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori crime 2.409 1.631037278 1.73514604 1.971756864 2.0539134 2.09583 2.409
24 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori crime 0.989 0.611357601 0.686918653 0.763242948 0.89793288 0.925704 0.989
25 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori income 2.469 2.702769739 2.598817057 2.887574508 2.75007096 2.696148 2.469
26 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori income 1.094 0.751043527 0.743607453 0.766605622 0.82430712 0.905832 1.094
27 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori income 0.726 0.606958352 0.674398169 0.681210272 0.688091184 0.6745992 0.726
28 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori income 0.786 0.494300278 0.568161239 0.591834624 0.664982724 0.7471716 0.786
29 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori income 2.211 1.489341769 1.584406138 1.82115648 2.069496 1.9899 2.211
30 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori income 1.676 1.242043158 1.461227245 1.405026197 1.633751392 1.5861664 1.676
31 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori income 2.065 1.458521064 1.6027704 1.63548 1.8585 1.8585 2.065
32 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori income 0.924 0.606820161 0.612949657 0.704539836 0.7189182 0.756756 0.924
33 11Auckland0to15000Maori 1 1 Auckland 0 to 15000 Maori housing 1.489 1.11639395 1.187653139 1.250161199 1.436966895 1.5790845 1.489
34 12Auckland0to15000Maori 1 2 Auckland 0 to 15000 Maori housing 1.965 1.448765127 1.448765127 1.379776312 1.60439106 1.588506 1.965
35 13Auckland0to15000Maori 1 3 Auckland 0 to 15000 Maori housing 1.402 0.931965987 0.913692144 0.904645687 0.93262442 1.0972052 1.402
36 14Auckland0to15000Maori 1 4 Auckland 0 to 15000 Maori housing 1.335 0.929679849 1.010521575 1.1354175 1.261575 1.261575 1.335
37 21Auckland0to15000Maori 2 1 Auckland 0 to 15000 Maori housing 1.283 0.890745926 0.989717696 1.009916016 1.009916016 1.0859312 1.283
38 22Auckland0to15000Maori 2 2 Auckland 0 to 15000 Maori housing 1.277 0.908296869 1.044019389 1.05456504 1.212143724 1.1883762 1.277
39 23Auckland0to15000Maori 2 3 Auckland 0 to 15000 Maori housing 1.453 0.819289474 0.900318104 1.059197769 1.11494502 1.281546 1.453
40 24Auckland0to15000Maori 2 4 Auckland 0 to 15000 Maori housing 1.811 1.284232139 1.351823304 1.55381989 1.8280234 1.86533 1.811
41 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori health 1.162 0.671210342 0.691969424 0.665355216 0.782770842 0.8997366 1.162
42 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori health 2.289 1.297361821 1.526308025 1.659030462 1.675788345 1.9715157 2.289
43 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori health 1.924 1.378642399 1.325617691 1.456722738 1.58339428 1.684462 1.924
44 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori health 2.264 1.771059957 1.736333291 1.995785392 2.01594484 2.215324 2.264
45 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori health 2.156 1.587703194 1.76411466 1.781934 2.0482 2.156 2.156
46 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori health 2.31 1.843062017 1.940065281 2.04217398 2.105334 2.105334 2.31
47 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori health 1.742 1.282589157 1.379128126 1.532364584 1.613015352 1.8123768 1.742
48 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori health 1.847 1.869969304 1.798047408 1.892681482 2.05726248 1.978137 1.847
49 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori education 1.483 0.881868906 0.958553159 1.030702321 1.184715312 1.1614856 1.483
50 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori education 1.418 0.84654599 0.910264505 1.058447099 1.16312868 1.186866 1.418
51 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori education 1.727 1.218040805 1.230344247 1.337330704 1.422692238 1.5297766 1.727
52 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori education 1.27 0.938162056 0.99804474 0.99804474 1.018413 1.0287 1.27
53 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori education 1.904 1.471963413 1.731721663 1.862066304 1.8255552 1.94208 1.904
54 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori education 1.076 0.739355954 0.84983443 0.809366124 0.9411234 0.896308 1.076
55 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori education 0.868 0.510675027 0.549112933 0.538346012 0.598162236 0.6875428 0.868
56 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori education 1.001 0.928206019 0.937581837 0.95671616 0.93795702 0.966966 1.001
57 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori crime 1.022 0.744676037 0.752198018 0.874648858 0.920683008 0.9026304 1.022
58 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori crime 0.828 0.834025318 0.842449816 0.868504965 0.851475456 0.8869536 0.828
59 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori crime 0.752 0.772429774 0.821733802 0.790128656 0.7823056 0.7823056 0.752
60 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori crime 1.264 0.734924485 0.807609324 0.917737868 1.031166144 1.1990304 1.264
61 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori crime 2.168 1.445159496 1.6422267 1.610026176 1.8506048 2.10296 2.168
62 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori crime 2.481 1.334550783 1.499495262 1.703971889 1.75667205 2.066673 2.481
63 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori crime 2.18 1.743719575 1.761332904 1.693589331 1.96928992 1.893548 2.18
64 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori crime 0.908 0.641442756 0.668169537 0.759283565 0.834377544 0.8428056 0.908
65 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori income 2.372 2.008910787 2.049908966 2.157798912 2.3454336 2.27712 2.372
66 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori income 0.799 0.53050888 0.546916371 0.601007001 0.57238762 0.584069 0.799
67 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori income 2.169 1.173270901 1.275294457 1.401422481 1.629561024 1.8948384 2.169
68 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori income 1.11 0.926035026 1.040488793 1.13096608 1.09802532 1.120434 1.11
69 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori income 1.22 0.888752967 0.916240172 0.898274678 0.90734816 0.965264 1.22
70 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori income 1.921 1.70273224 1.669345334 1.589852699 1.574111583 1.7686647 1.921
71 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori income 1.795 1.350029542 1.377581165 1.513825456 1.5606448 1.77346 1.795
72 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori income 1.351 1.077203746 1.122087236 1.193709825 1.1368665 1.1368665 1.351
73 11UpperNorthIsland0to15000Maori 1 1 Upper North Island 0 to 15000 Maori housing 0.978 0.813729276 0.946196833 1.100228875 1.08933552 1.0374624 0.978
74 12UpperNorthIsland0to15000Maori 1 2 Upper North Island 0 to 15000 Maori housing 2.399 1.830463848 1.743298903 1.835051477 2.038946085 2.3987601 2.399
75 13UpperNorthIsland0to15000Maori 1 3 Upper North Island 0 to 15000 Maori housing 2.043 1.561181626 1.609465594 1.609465594 1.65924288 1.765152 2.043
76 14UpperNorthIsland0to15000Maori 1 4 Upper North Island 0 to 15000 Maori housing 1.619 1.197655498 1.409006468 1.367967444 1.315353312 1.3701597 1.619
77 21UpperNorthIsland0to15000Maori 2 1 Upper North Island 0 to 15000 Maori housing 2.093 1.676335358 1.926822251 1.966145154 2.286215295 2.1773479 2.093
78 22UpperNorthIsland0to15000Maori 2 2 Upper North Island 0 to 15000 Maori housing 0.793 0.589894723 0.57832816 0.590130775 0.590130775 0.6942715 0.793
79 23UpperNorthIsland0to15000Maori 2 3 Upper North Island 0 to 15000 Maori housing 1.936 1.441169149 1.426900147 1.62147744 1.724976 1.91664 1.936
80 24UpperNorthIsland0to15000Maori 2 4 Upper North Island 0 to 15000 Maori housing 2.371 1.804720688 1.786852166 2.030513825 2.071952883 2.1360339 2.371
81 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori health 1.675 1.318137125 1.373059505 1.386928793 1.524097575 1.5090075 1.675
82 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori health 2.186 1.223033623 1.343992992 1.279993326 1.471256696 1.6167656 2.186
83 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori health 0.741 0.531057398 0.564954678 0.641993953 0.68297229 0.7189182 0.741
84 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori health 1.928 1.302805008 1.264859231 1.389955199 1.478675744 1.5088528 1.928
85 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori health 1.738 1.152355171 1.266324364 1.422836364 1.635444096 1.5725424 1.738
86 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori health 1.117 0.805388455 0.904930848 0.904930848 0.9426363 0.9426363 1.117
87 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori health 1.574 1.017996609 0.978842894 1.075651532 1.18203465 1.390629 1.574
88 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori health 1.338 0.640433439 0.753451105 0.810162479 0.953132328 1.0709352 1.338
89 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori education 1.698 1.261746866 1.3422839 1.412930421 1.34564802 1.387266 1.698
90 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori education 1.157 0.672824074 0.773361005 0.86894495 1.022288176 1.1111828 1.157
91 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori education 0.94 0.75622299 0.879329058 0.837456246 0.93050694 0.939906 0.94
92 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori education 1.425 1.320329954 1.320329954 1.33366662 1.347138 1.295325 1.425
93 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori education 1.562 1.088647086 1.122316584 1.193953812 1.356765696 1.5595008 1.562
94 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori education 2.196 1.811557708 1.776036969 2.041421803 2.10455856 2.2153248 2.196
95 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori education 1.307 1.110407765 1.099413629 1.27838794 1.24115334 1.3064772 1.307
96 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori education 2.257 1.818281959 2.114281347 2.225559313 2.24803971 2.2039605 2.257
97 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori crime 1.718 1.069757815 1.138040228 1.210681094 1.360315836 1.5817626 1.718
98 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori crime 0.841 0.555010022 0.584221076 0.679326833 0.646977936 0.6882744 0.841
99 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori crime 2.349 1.745418554 1.799400571 1.713714829 1.904127588 1.9233612 2.349
100 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori crime 0.984 0.691448601 0.658522477 0.693181555 0.71462016 0.744396 0.984
101 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori crime 2.016 1.215429426 1.279399395 1.390651517 1.636060608 1.6694496 2.016
102 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori crime 1.595 1.052607626 1.085162501 1.261816861 1.484490425 1.5304025 1.595
103 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori crime 1.758 1.579811258 1.645636727 1.66225932 1.66225932 1.613844 1.758
104 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori crime 1.643 1.122570571 1.32067126 1.294775745 1.505553192 1.6916328 1.643
105 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori income 2.245 1.608210723 1.64103135 1.783729728 1.8017472 1.87682 2.245
106 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori income 2.431 2.113066527 2.0515209 2.35807 2.35807 2.35807 2.431
107 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori income 0.959 0.675901556 0.711475322 0.790528135 0.840987378 0.9778923 0.959
108 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori income 2.155 1.405272939 1.634038301 1.571190674 1.65388492 1.705036 2.155
109 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori income 1.919 1.852840059 1.76460958 1.747138198 1.679940575 1.7683585 1.919
110 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori income 2.25 1.576007345 1.83256668 1.869966 1.78092 1.836 2.25
111 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori income 0.857 0.453643126 0.493090355 0.547878172 0.602063925 0.6920275 0.857
112 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori income 2.388 1.687596864 1.917723709 1.997628864 1.997628864 2.2700328 2.388
113 11LowerNorthIsland0to15000Maori 1 1 Lower North Island 0 to 15000 Maori housing 0.797 0.649027587 0.713217128 0.80136756 0.8435448 0.803376 0.797
114 12LowerNorthIsland0to15000Maori 1 2 Lower North Island 0 to 15000 Maori housing 1.126 0.946007523 1.05111947 1.020504339 0.990780912 1.0007888 1.126
115 13LowerNorthIsland0to15000Maori 1 3 Lower North Island 0 to 15000 Maori housing 1.643 1.303387085 1.316552611 1.415647969 1.444538744 1.4024648 1.643
116 14LowerNorthIsland0to15000Maori 1 4 Lower North Island 0 to 15000 Maori housing 2.388 2.234914138 2.191092292 2.235808462 2.40409512 2.557548 2.388
117 21LowerNorthIsland0to15000Maori 2 1 Lower North Island 0 to 15000 Maori housing 0.991 0.912218338 0.877133017 0.904260842 0.951853518 0.9614682 0.991
118 22LowerNorthIsland0to15000Maori 2 2 Lower North Island 0 to 15000 Maori housing 1.343 0.956815628 1.112576311 1.209322078 1.272970608 1.3687856 1.343
119 23LowerNorthIsland0to15000Maori 2 3 Lower North Island 0 to 15000 Maori housing 2.111 1.663699931 1.647227655 1.937914888 1.8633797 2.04767 2.111
120 24LowerNorthIsland0to15000Maori 2 4 Lower North Island 0 to 15000 Maori housing 2.474 1.546383459 1.594209752 1.771344169 2.083934316 2.2169514 2.474
121 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori health 1.2 0.867231369 0.942642792 1.0135944 0.965328 0.9282 1.2
122 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori health 2.006 1.810651201 2.105408373 2.105408373 2.064125856 2.1279648 2.006
123 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori health 1.815 0.899538709 0.881900696 1.025465925 1.114636875 1.3113375 1.815
124 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori health 1.359 0.969843544 0.969843544 1.077603938 1.066934592 1.2263616 1.359
125 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori health 1.049 0.818119385 0.929681119 0.902603029 0.87631362 0.962982 1.049
126 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori health 1.258 1.063735421 1.143801528 1.143801528 1.24326253 1.207051 1.258
127 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori health 1.061 0.656564034 0.656564034 0.772428276 0.764780471 0.8404181 1.061
128 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori health 1.627 1.547552349 1.488031105 1.566348531 1.535635815 1.4625103 1.627
129 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori education 1.758 1.565461714 1.505251648 1.60133154 1.634011776 1.7383104 1.758
130 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori education 1.149 0.620837597 0.667567309 0.785373304 0.892469664 0.9596448 1.149
131 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori education 2.391 1.735529204 1.770948167 1.864155966 1.827603888 2.0768226 2.391
132 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori education 2.441 2.143823599 2.280663403 2.45232624 2.665572 2.665572 2.441
133 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori education 1.561 1.055127633 1.02439576 1.045301796 1.1744964 1.304996 1.561
134 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori education 1.325 0.735339041 0.817043378 0.851086853 0.84266025 0.968575 1.325
135 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori education 2.219 1.311556058 1.366204227 1.53506093 1.61585361 1.7953929 2.219
136 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori education 2.229 2.104441978 2.215202082 2.171766747 2.108511405 2.1298095 2.229
137 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori crime 1.996 1.693289192 1.660087443 1.596237926 1.66274784 1.8474976 1.996
138 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori crime 0.862 0.505924817 0.562138686 0.653649635 0.634611296 0.7211492 0.862
139 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori crime 0.84 0.484517 0.526648913 0.548592618 0.6163962 0.69258 0.84
140 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori crime 2.374 1.960953666 2.131471377 2.069389686 2.0091162 2.20782 2.374
141 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori crime 2.465 1.533863895 1.614593574 1.79399286 1.849477175 2.0323925 2.465
142 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori crime 1.281 0.943947888 1.00419988 1.057052506 1.01639664 1.0698912 1.281
143 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori crime 2.181 1.230846289 1.2689137 1.39441066 1.584557568 1.8006336 2.181
144 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori crime 2.293 1.844292336 1.756468891 1.792315195 1.866994995 2.1964647 2.293
145 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori income 1.112 0.886951169 1.019484102 0.97093724 0.97093724 0.961324 1.112
146 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori income 1.801 0.997032097 1.146013905 1.273348783 1.22437383 1.4404398 1.801
147 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori income 2.349 2.010684544 1.952120917 1.895263026 1.822368294 1.9595358 2.349
148 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori income 1.02 0.703002161 0.808048461 0.868869313 0.88660134 0.914022 1.02
149 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori income 2.357 1.479457721 1.573891192 1.558308111 1.811986176 1.9911936 2.357
150 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori income 0.83 0.459374941 0.534156908 0.51859894 0.6101164 0.717784 0.83
151 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori income 0.758 0.437850234 0.503276131 0.578478312 0.6649176 0.65188 0.758
152 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori income 1.734 1.067372495 1.067372495 1.185969439 1.347692544 1.4648832 1.734
153 11SouthIsland0to15000Maori 1 1 South Island 0 to 15000 Maori housing 2.183 1.57126787 1.555710762 1.690989959 1.966267394 2.1607334 2.183
154 12SouthIsland0to15000Maori 1 2 South Island 0 to 15000 Maori housing 1.135 1.046077532 1.124814551 1.071251953 1.04005044 1.168596 1.135
155 13SouthIsland0to15000Maori 1 3 South Island 0 to 15000 Maori housing 1.265 0.903217226 0.885507084 1.0296594 1.083852 1.1290125 1.265
156 14SouthIsland0to15000Maori 1 4 South Island 0 to 15000 Maori housing 1.481 1.385208683 1.505661612 1.58490696 1.523949 1.45138 1.481
157 21SouthIsland0to15000Maori 2 1 South Island 0 to 15000 Maori housing 2.479 1.509712141 1.755479234 1.950532482 2.19160953 2.3069574 2.479
158 22SouthIsland0to15000Maori 2 2 South Island 0 to 15000 Maori housing 1.263 0.89946071 0.864866068 1.005658218 1.129953054 1.0970418 1.263
159 23SouthIsland0to15000Maori 2 3 South Island 0 to 15000 Maori housing 1.728 1.481253818 1.466587939 1.666577203 1.60247808 1.669248 1.728
160 24SouthIsland0to15000Maori 2 4 South Island 0 to 15000 Maori housing 1.975 1.554501697 1.65372521 1.77819915 1.7433325 1.7433325 1.975
161 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean health 1.726 1.389486537 1.389486537 1.61568202 1.63200204 1.600002 1.726
162 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean health 0.906 0.79763503 0.866994598 0.833648652 0.8173026 0.87882 0.906
163 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean health 2.074 1.49261659 1.571175358 1.785426544 1.82186382 2.047038 2.074
164 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean health 2.415 1.887120857 1.887120857 1.832156172 1.7787924 1.91268 2.415
165 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean health 2.349 1.743319708 1.743319708 1.981045123 1.90485108 1.963764 2.349
166 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean health 0.727 0.388375063 0.417607594 0.474554085 0.545464465 0.5994115 0.727
167 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean health 2.295 1.842832623 1.960460237 2.13093504 2.13093504 2.219724 2.295
168 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean health 2.19 1.413267963 1.519642971 1.44727902 1.5234516 1.731195 2.19
169 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean education 1.758 1.567708638 1.493055846 1.65895094 1.67570802 1.5959124 1.758
170 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean education 1.842 1.371576686 1.33162785 1.33162785 1.566621 1.74069 1.842
171 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean education 1.862 1.624521056 1.692209434 1.611628032 1.6445184 1.71304 1.862
172 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean education 1.148 0.878221337 0.852642075 0.870042934 0.956091136 1.0864672 1.148
173 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean education 2.134 1.878694702 1.956973648 1.863784427 2.004069276 2.1549132 2.134
174 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean education 2.179 1.707587477 1.897319419 2.040128408 2.17034937 2.1277935 2.179
175 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean education 2 1.670315627 1.687187502 1.8540522 1.87278 1.7836 2
176 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean education 1.428 0.965285688 0.984985396 1.047856804 1.218438144 1.2063744 1.428
177 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean crime 1.968 1.536985486 1.521767808 1.521767808 1.7491584 1.98768 1.968
178 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean crime 1.379 0.861884773 0.979414514 1.076279686 1.251488007 1.2150369 1.379
179 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean crime 1.673 1.361812417 1.418554601 1.351004382 1.299042675 1.2371835 1.673
180 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean crime 2.46 1.768780459 1.861874167 2.023776269 2.29974576 2.211294 2.46
181 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean crime 1.242 1.054796726 1.024074491 0.984687011 1.025715636 1.1926926 1.242
182 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean crime 1.34 0.925401758 0.881335007 0.957972834 0.91235508 1.048684 1.34
183 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean crime 1.221 0.919193265 0.977865176 0.987742602 1.122434775 1.3205115 1.221
184 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean crime 1.722 1.264463503 1.436890344 1.651598096 1.61921382 1.603182 1.722
185 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean income 1.936 1.405091237 1.448547667 1.627581648 1.6607976 1.748208 1.936
186 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean income 2.423 1.902793918 2.002940966 2.08639684 2.025628 2.13224 2.423
187 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean income 1.459 1.034498808 1.124455226 1.081206949 1.049715484 1.2205994 1.459
188 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean income 2.31 1.191633564 1.385620423 1.458547814 1.67649174 1.949409 2.31
189 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean income 1.529 1.280392933 1.471716015 1.471716015 1.4288505 1.60545 1.529
190 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean income 1.465 0.982420627 0.953806434 1.071692622 1.2318306 1.35366 1.465
191 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean income 1.374 1.183136646 1.148676355 1.19653787 1.22095701 1.1628162 1.374
192 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean income 1.369 0.932731038 1.013838085 1.165331132 1.165331132 1.3550362 1.369
193 11Auckland0to15000NZEuropean 1 1 Auckland 0 to 15000 NZEuropean housing 1.043 0.903258781 1.038228484 1.081488004 1.092412125 1.1499075 1.043
194 12Auckland0to15000NZEuropean 1 2 Auckland 0 to 15000 NZEuropean housing 2.404 1.390394781 1.479143384 1.661958859 1.826328416 2.0753732 2.404
195 13Auckland0to15000NZEuropean 1 3 Auckland 0 to 15000 NZEuropean housing 0.972 1.059779023 1.019018292 1.008929002 0.98914608 0.960336 0.972
196 14Auckland0to15000NZEuropean 1 4 Auckland 0 to 15000 NZEuropean housing 1.164 0.898689857 0.936135267 1.051837379 1.073303448 1.1064984 1.164
197 21Auckland0to15000NZEuropean 2 1 Auckland 0 to 15000 NZEuropean housing 1.961 1.53661542 1.463443258 1.644318267 1.749274752 1.7319552 1.961
198 22Auckland0to15000NZEuropean 2 2 Auckland 0 to 15000 NZEuropean housing 1.444 0.730970602 0.840196094 0.893825632 1.027385784 1.0929636 1.444
199 23Auckland0to15000NZEuropean 2 3 Auckland 0 to 15000 NZEuropean housing 2.156 1.395713731 1.395713731 1.642016154 1.865927448 2.0063736 2.156
200 24Auckland0to15000NZEuropean 2 4 Auckland 0 to 15000 NZEuropean housing 1.142 1.133023364 1.144468045 1.089969566 1.04804766 1.058634 1.142
201 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean health 2.294 1.694660248 1.970535172 1.990439568 2.21159952 2.4573328 2.294
202 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean health 1.745 0.999166132 1.175489568 1.30609952 1.34649435 1.3200925 1.745
203 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean health 0.978 0.681786907 0.695700926 0.66257231 0.736191456 0.8365812 0.978
204 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean health 1.181 0.947099812 1.064157092 1.053620883 1.03296165 1.215249 1.181
205 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean health 1.411 0.979812217 0.98970931 1.087592648 1.250106492 1.2377292 1.411
206 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean health 1.707 1.152479224 1.213136026 1.166476948 1.310648256 1.4092992 1.707
207 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean health 0.779 0.630531481 0.64339947 0.6127614 0.680846 0.71668 0.779
208 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean health 2.265 1.371413473 1.507047773 1.553657498 1.53827475 1.809735 2.265
209 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean education 0.756 0.489166926 0.525985942 0.61161156 0.61161156 0.605556 0.756
210 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean education 0.759 0.617311623 0.611199626 0.679110696 0.7896636 0.77418 0.759
211 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean education 0.802 0.674703705 0.766708756 0.774453289 0.744666624 0.7756944 0.802
212 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean education 0.903 0.630534734 0.716516743 0.778822546 0.855848952 0.9302706 0.903
213 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean education 1.765 1.627309292 1.768814447 1.71729558 1.6355196 1.572615 1.765
214 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean education 2.476 1.373972477 1.509859865 1.755651006 1.97264158 2.3207548 2.476
215 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean education 2.464 1.628523693 1.871866314 1.910067667 1.94904864 1.968736 2.464
216 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean education 1.701 1.130528928 1.076694217 1.076694217 1.25197002 1.439046 1.701
217 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean crime 1.97 1.590257655 1.543939471 1.559534819 1.67691916 1.660316 1.97
218 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean crime 1.591 1.156374566 1.314062007 1.263521161 1.358624904 1.4767662 1.591
219 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean crime 1.425 1.462347154 1.492190973 1.42113426 1.36647525 1.438395 1.425
220 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean crime 1.765 1.266415173 1.241583503 1.364377476 1.55042895 1.6493925 1.765
221 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean crime 1.466 1.099810802 1.078245884 1.184885587 1.161652536 1.3352328 1.466
222 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean crime 2.049 1.799048024 1.746648567 1.919394029 1.900390128 2.0883408 2.049
223 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean crime 1.933 1.166717262 1.325815071 1.425607603 1.62000864 1.8000096 1.933
224 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean crime 2.225 1.800783369 1.71503178 1.994223 2.0559 2.0559 2.225
225 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean income 1.579 1.478052103 1.449070689 1.558140526 1.589939312 1.6914248 1.579
226 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean income 1.057 0.894783061 0.852174344 0.819398408 0.811285552 0.9219154 1.057
227 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean income 0.727 0.70665566 0.721077204 0.735793065 0.72136575 0.687015 0.727
228 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean income 1.334 1.025930949 1.165830624 1.11031488 1.11031488 1.088544 1.334
229 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean income 0.874 0.658366167 0.645457027 0.725232614 0.75545064 0.770868 0.874
230 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean income 1.642 1.119050428 1.177947819 1.253135977 1.33312338 1.374354 1.642
231 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean income 1.323 1.275676479 1.342817347 1.329522125 1.445132745 1.4308245 1.323
232 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean income 2.497 1.581698569 1.777189403 1.910956347 2.248183938 2.3177154 2.497
233 11UpperNorthIsland0to15000NZEuropean 1 1 Upper North Island 0 to 15000 NZEuropean housing 2.239 1.410717398 1.62151425 1.57428568 1.788961 1.788961 2.239
234 12UpperNorthIsland0to15000NZEuropean 1 2 Upper North Island 0 to 15000 NZEuropean housing 1.672 1.338099307 1.423509901 1.423509901 1.617624888 1.7393816 1.672
235 13UpperNorthIsland0to15000NZEuropean 1 3 Upper North Island 0 to 15000 NZEuropean housing 1.483 1.099773554 1.067741314 1.14810894 1.3507164 1.3507164 1.483
236 14UpperNorthIsland0to15000NZEuropean 1 4 Upper North Island 0 to 15000 NZEuropean housing 1.223 1.055467688 1.045017513 0.995254775 0.94786169 0.977177 1.223
237 21UpperNorthIsland0to15000NZEuropean 2 1 Upper North Island 0 to 15000 NZEuropean housing 0.873 0.73648025 0.775242368 0.752662494 0.845688195 0.8542305 0.873
238 22UpperNorthIsland0to15000NZEuropean 2 2 Upper North Island 0 to 15000 NZEuropean housing 1.068 0.699489712 0.73630496 0.86624113 0.98436492 0.994308 1.068
239 23UpperNorthIsland0to15000NZEuropean 2 3 Upper North Island 0 to 15000 NZEuropean housing 2.138 1.245276875 1.43135273 1.590391922 1.87104932 1.9695256 2.138
240 24UpperNorthIsland0to15000NZEuropean 2 4 Upper North Island 0 to 15000 NZEuropean housing 2.332 1.986315234 2.090858141 2.323175712 2.2338228 2.40196 2.332
241 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean health 2.49 1.570346625 1.688544758 1.963424138 2.11120875 2.010675 2.49
242 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean health 1.522 1.010453802 1.09831935 1.180988549 1.357458102 1.3711698 1.522
243 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean health 1.137 0.856784193 0.931287166 0.886940159 0.89589915 1.053999 1.137
244 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean health 1.786 1.270171338 1.411301486 1.35702066 1.4284428 1.4284428 1.786
245 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean health 0.96 0.686793553 0.666789857 0.724771584 0.7877952 0.81216 0.96
246 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean health 1.119 0.787654665 0.820473609 0.828761221 0.872380233 0.8469711 1.119
247 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean health 0.958 0.769726765 0.777501783 0.91470798 1.0163422 0.98674 0.958
248 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean health 1.462 1.215860352 1.215860352 1.22814177 1.44487267 1.5209186 1.462
249 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean education 1.662 1.456643084 1.501693901 1.548138042 1.548138042 1.5960186 1.662
250 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean education 2.468 1.730264605 1.880722396 2.000768507 2.273600576 2.2073792 2.468
251 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean education 0.844 0.606357503 0.606357503 0.583036061 0.640698968 0.7449988 0.844
252 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean education 2.158 1.371161076 1.371161076 1.523512307 1.570631244 1.6888508 2.158
253 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean education 2.048 1.165801616 1.295335129 1.523923681 1.508835328 1.7145856 2.048
254 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean education 0.815 0.518573985 0.534612355 0.55688787 0.5303694 0.60962 0.815
255 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean education 0.95 0.790695045 0.760283697 0.752756136 0.8008044 0.77748 0.95
256 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean education 1.988 1.630815161 1.734909746 1.865494351 1.903565664 1.8303516 1.988
257 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean crime 0.819 0.644655876 0.724332445 0.81385668 0.7825545 0.7825545 0.819
258 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean crime 1.923 1.91880826 1.938190162 1.91900016 1.938384 1.84608 1.923
259 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean crime 2.405 1.520601585 1.600633248 1.758937635 1.95437515 2.147665 2.405
260 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean crime 2.03 1.302806853 1.532713945 1.532713945 1.6133831 1.698298 2.03
261 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean crime 2.377 1.672214343 1.798079939 1.892715725 2.103017472 2.1906432 2.377
262 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean crime 2.264 1.34639112 1.294606846 1.471144144 1.69097028 1.943644 2.264
263 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean crime 2.154 1.571573996 1.848910583 1.795058819 2.087277696 2.0264832 2.154
264 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean crime 1.546 1.182729798 1.244978734 1.464680864 1.57492566 1.590834 1.546
265 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean income 2.451 1.514085113 1.560912487 1.57667928 1.57667928 1.833348 2.451
266 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean income 1.323 0.8541443 0.908664149 0.882198203 0.991233936 1.0012464 1.323
267 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean income 1.494 1.714826603 1.664880197 1.648396235 1.569901176 1.5391188 1.494
268 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean income 2.081 1.347776078 1.418711661 1.404665011 1.49432448 1.556588 2.081
269 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean income 2.13 1.582578245 1.631523964 1.681983468 1.97880408 2.150874 2.13
270 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean income 1.242 0.867056524 0.867056524 0.952809367 1.002957228 1.1528244 1.242
271 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean income 0.933 0.728557194 0.766902309 0.798856572 0.877864365 0.8522955 0.933
272 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean income 2.11 1.334709371 1.55198764 1.804636791 1.8604503 2.067167 2.11
273 11LowerNorthIsland0to15000NZEuropean 1 1 Lower North Island 0 to 15000 NZEuropean housing 0.832 0.505915538 0.555951141 0.591437384 0.585581568 0.6809088 0.832
274 12LowerNorthIsland0to15000NZEuropean 1 2 Lower North Island 0 to 15000 NZEuropean housing 1.476 0.962507414 1.046203711 1.124950226 1.13631336 1.208844 1.476
275 13LowerNorthIsland0to15000NZEuropean 1 3 Lower North Island 0 to 15000 NZEuropean housing 0.844 0.456260257 0.495935062 0.533263507 0.59917248 0.7049088 0.844
276 14LowerNorthIsland0to15000NZEuropean 1 4 Lower North Island 0 to 15000 NZEuropean housing 2.057 1.33393592 1.569336376 1.669506783 1.636771356 1.7790993 2.057
277 21LowerNorthIsland0to15000NZEuropean 2 1 Lower North Island 0 to 15000 NZEuropean housing 0.916 0.557741945 0.648537145 0.675559526 0.69645312 0.791424 0.916
278 22LowerNorthIsland0to15000NZEuropean 2 2 Lower North Island 0 to 15000 NZEuropean housing 1.123 0.933825138 0.993430998 1.056841487 1.006515702 0.9867801 1.123
279 23LowerNorthIsland0to15000NZEuropean 2 3 Lower North Island 0 to 15000 NZEuropean housing 0.771 0.436368956 0.507405763 0.551528004 0.641311632 0.6895824 0.771
280 24LowerNorthIsland0to15000NZEuropean 2 4 Lower North Island 0 to 15000 NZEuropean housing 2.133 1.558696637 1.62364233 1.656777888 1.7258103 1.85571 2.133
281 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean health 1.991 1.545416068 1.679800074 1.615192379 1.58352194 1.6668652 1.991
282 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean health 1.49 1.142291264 1.142291264 1.312978464 1.4118048 1.50192 1.49
283 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean health 1.388 1.092201443 1.040191851 0.990658906 1.15192896 1.199926 1.388
284 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean health 1.314 0.926773868 1.0073629 1.049336354 1.12831866 1.0745892 1.314
285 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean health 2.026 1.585623072 1.822555255 1.73576691 2.018333616 1.9595472 2.026
286 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean health 0.993 0.79210263 0.76903168 0.76903168 0.904743153 0.9728421 0.993
287 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean health 0.729 0.648865168 0.623908816 0.636641649 0.663168384 0.6908004 0.729
288 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean health 2.127 1.631006572 1.812229524 1.9698147 2.188683 2.188683 2.127
289 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean education 2.192 1.517983546 1.502954006 1.768181184 2.0092968 1.913616 2.192
290 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean education 1.075 0.839867601 0.922931429 0.896049932 0.878480325 1.0097475 1.075
291 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean education 2.459 1.79149708 1.926340946 2.116858183 2.016055412 2.2652308 2.459
292 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean education 2.288 1.883271942 1.828419361 1.846888243 2.02954752 2.114112 2.288
293 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean education 0.818 0.89351367 0.884667 0.84254 0.84254 0.84254 0.818
294 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean education 1.545 1.044180268 1.076474503 1.145185642 1.25844576 1.430052 1.545
295 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean education 1.18 0.959255393 1.065839325 1.055286461 1.04483808 1.055392 1.18
296 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean education 1.152 0.677644932 0.778902221 0.771190318 0.896732928 0.9539712 1.152
297 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean crime 1.064 0.67011751 0.698039073 0.767075904 0.8248128 0.85918 1.064
298 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean crime 2.075 1.94925407 2.24052192 2.154348 2.154348 2.2441125 2.075
299 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean crime 2.16 1.751900152 1.787653217 1.76995368 1.903176 2.1384 2.16
300 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean crime 2.266 1.727962247 1.986163502 1.986163502 1.891584288 2.1495276 2.266
301 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean crime 1.792 1.444745907 1.389178757 1.578612224 1.7737216 1.7737216 1.792
302 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean crime 1.65 1.250916261 1.289604393 1.289604393 1.4823039 1.43913 1.65
303 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean crime 2.088 1.997018925 2.080228046 2.21300856 2.148552 2.148552 2.088
304 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean crime 2.05 1.368481405 1.555092506 1.60318815 1.587315 1.8245 2.05
305 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean income 1.651 1.161986559 1.305602875 1.305602875 1.41913356 1.631188 1.651
306 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean income 2.456 1.88223567 1.960662156 2.085810804 2.1068796 2.006552 2.456
307 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean income 1.507 1.500150263 1.500150263 1.442452176 1.4141688 1.53714 1.507
308 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean income 1.864 1.42408914 1.483426188 1.74520728 1.727928 1.91992 1.864
309 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean income 1.44 0.987365617 1.073223497 1.129708944 1.0968048 1.17936 1.44
310 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean income 1.625 1.191020411 1.203050921 1.38281715 1.589445 1.6731 1.625
311 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean income 1.605 1.130217313 1.284337856 1.246929957 1.3407849 1.47339 1.605
312 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean income 1.71 1.524836275 1.58837112 1.58837112 1.65455325 1.741635 1.71
313 11SouthIsland0to15000NZEuropean 1 1 South Island 0 to 15000 NZEuropean housing 0.766 0.444128991 0.493476656 0.548307396 0.6025356 0.669484 0.766
314 12SouthIsland0to15000NZEuropean 1 2 South Island 0 to 15000 NZEuropean housing 2.289 1.87839139 2.134535671 2.398354686 2.52458388 2.4274845 2.289
315 13SouthIsland0to15000NZEuropean 1 3 South Island 0 to 15000 NZEuropean housing 1.007 0.593786275 0.587907203 0.683613027 0.75957003 0.8936118 1.007
316 14SouthIsland0to15000NZEuropean 1 4 South Island 0 to 15000 NZEuropean housing 1.994 1.401190441 1.523033088 1.711273133 1.78257618 1.800582 1.994
317 21SouthIsland0to15000NZEuropean 2 1 South Island 0 to 15000 NZEuropean housing 0.826 0.43506879 0.494396353 0.55550152 0.603806 0.7021 0.826
318 22SouthIsland0to15000NZEuropean 2 2 South Island 0 to 15000 NZEuropean housing 1.783 1.122082143 1.320096639 1.434887651 1.464171072 1.6089792 1.783
319 23SouthIsland0to15000NZEuropean 2 3 South Island 0 to 15000 NZEuropean housing 1.192 1.306673194 1.256416532 1.380677508 1.3536054 1.289148 1.192
320 24SouthIsland0to15000NZEuropean 2 4 South Island 0 to 15000 NZEuropean housing 0.826 0.72776936 0.856199247 0.831261405 0.814962162 0.7912254 0.826
321 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other health 1.012 0.567302287 0.652071594 0.658658176 0.658658176 0.7658816 1.012
322 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other health 1.232 1.076782525 1.266802971 1.319586428 1.306521216 1.3197184 1.232
323 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other health 1.836 1.383191395 1.589875167 1.766527963 1.682407584 1.8903456 1.836
324 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other health 1.837 1.920025897 2.000026976 1.904787596 1.814083425 1.7276985 1.837
325 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other health 1.163 0.908151004 0.945990629 1.017194225 0.99724924 1.028092 1.163
326 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other health 1.832 1.233433312 1.385880126 1.630447207 1.75316904 1.6696848 1.832
327 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other health 2.379 1.496349756 1.66261084 1.827044879 1.79122047 1.739049 2.379
328 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other health 1.198 1.282152161 1.269457585 1.30871916 1.30871916 1.2463992 1.198
329 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other education 0.703 0.431778934 0.445132922 0.52368579 0.588411 0.588411 0.703
330 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other education 2.061 1.367953847 1.590644009 1.639839184 1.69055586 1.725057 2.061
331 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other education 1.286 1.016888159 0.977777076 1.150325971 1.12777056 1.296288 1.286
332 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other education 1.092 0.657233107 0.738464165 0.839163824 0.865117344 0.8827728 1.092
333 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other education 1.67 1.124219452 1.277522104 1.330752192 1.5122184 1.440208 1.67
334 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other education 1.778 1.220356492 1.173419704 1.161801687 1.197733698 1.3767054 1.778
335 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other education 1.386 0.946922733 1.114026745 1.14848118 1.160082 1.160082 1.386
336 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other education 1.736 0.98637482 1.146947466 1.26038183 1.22367168 1.390536 1.736
337 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other crime 1.544 1.162465849 1.198418401 1.261493054 1.274235408 1.2492504 1.544
338 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other crime 1.353 1.128930901 1.175969689 1.292274383 1.31864733 1.449063 1.353
339 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other crime 0.745 0.608085126 0.608085126 0.640089607 0.73573518 0.782697 0.745
340 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other crime 2.257 1.526694017 1.696326686 1.843833354 2.07172287 1.9730694 2.257
341 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other crime 0.772 0.593590104 0.565323908 0.548858163 0.630871452 0.6246252 0.772
342 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other crime 2.49 1.743818248 1.660779284 1.628214984 1.7507688 2.059728 2.49
343 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other crime 2.3 1.536728317 1.477623382 1.588842346 1.7459806 1.91866 2.3
344 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other crime 1.93 1.334148201 1.48238689 1.528233907 1.67937792 1.908384 1.93
345 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other income 1.274 0.990713395 1.042856205 1.07510949 1.0239138 1.077804 1.274
346 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other income 0.903 0.603070657 0.634811218 0.713271031 0.792523368 0.7620417 0.903
347 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other income 1.19 0.839248852 0.822792992 0.831104033 0.87484635 0.940695 1.19
348 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other income 1.428 0.993928645 1.155730983 1.133069591 1.079113896 1.2403608 1.428
349 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other income 1.782 1.363386609 1.298463437 1.475526633 1.621457838 1.6054038 1.782
350 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other income 0.932 0.54599092 0.620444227 0.602373036 0.63407688 0.728824 0.932
351 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other income 0.955 0.603700151 0.656195817 0.754248065 0.811019425 0.9541405 0.955
352 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other income 2.106 1.436984019 1.651705768 1.795332357 1.8508581 1.99017 2.106
353 11Auckland0to15000Other 1 1 Auckland 0 to 15000 Other housing 0.937 0.689408231 0.710730135 0.764225952 0.839808738 0.9652974 0.937
354 12Auckland0to15000Other 1 2 Auckland 0 to 15000 Other housing 2.321 1.818944553 1.977113645 2.172652357 2.414058174 2.3667237 2.321
355 13Auckland0to15000Other 1 3 Auckland 0 to 15000 Other housing 1.327 0.89125918 0.848818266 0.875070378 1.017523695 1.0941115 1.327
356 14Auckland0to15000Other 1 4 Auckland 0 to 15000 Other housing 1.263 0.682294855 0.80269983 0.944352741 1.015433055 1.0918635 1.263
357 21Auckland0to15000Other 2 1 Auckland 0 to 15000 Other housing 1.586 1.521158293 1.55220234 1.55220234 1.6338972 1.6338972 1.586
358 22Auckland0to15000Other 2 2 Auckland 0 to 15000 Other housing 0.816 0.524343831 0.569938947 0.606318029 0.68899776 0.7252608 0.816
359 23Auckland0to15000Other 2 3 Auckland 0 to 15000 Other housing 0.863 0.834583525 0.860395387 0.887005553 0.852889955 0.8444455 0.863
360 24Auckland0to15000Other 2 4 Auckland 0 to 15000 Other housing 2.208 1.773502019 1.705290403 1.722515558 1.83246336 1.9289088 2.208
361 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other health 2.313 1.468675966 1.425898996 1.620339768 1.90628208 2.2426848 2.313
362 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other health 1.2 0.810877055 0.881388104 0.990323712 0.9709056 1.12896 1.2
363 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other health 1.534 1.229421619 1.254511856 1.229913585 1.281159984 1.3925652 1.534
364 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other health 1.72 1.226308971 1.214167298 1.41182244 1.5686916 1.82406 1.72
365 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other health 2.408 1.43463912 1.559390347 1.752123986 1.991049984 2.0740104 2.408
366 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other health 1.142 0.945852102 0.909473175 1.069968441 1.091804532 1.0600044 1.142
367 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other health 2.087 1.691263588 1.658101557 1.7829049 1.80091404 2.0010156 2.087
368 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other health 1.779 1.603214911 1.571779325 1.690085295 1.724576832 1.7964342 1.779
369 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other education 1.844 1.294787704 1.40737794 1.353248019 1.439625552 1.4113976 1.844
370 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other education 1.3 1.030066456 1.030066456 1.144518284 1.1111828 1.24852 1.3
371 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other education 2.39 1.455463746 1.653936075 1.705088738 2.00598675 2.111565 2.39
372 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other education 0.72 0.512796395 0.517976156 0.539558496 0.59950944 0.697104 0.72
373 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other education 1.401 1.070535471 1.216517581 1.192664295 1.3708785 1.44303 1.401
374 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other education 0.727 0.415826906 0.447125705 0.508097392 0.53483936 0.607772 0.727
375 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other education 1.781 1.554838076 1.50955153 1.58900161 1.54272001 1.6239158 1.781
376 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other education 0.762 0.603468192 0.574731612 0.592506816 0.6303264 0.71628 0.762
377 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other crime 0.977 0.81359522 0.81359522 0.830199204 0.82197941 0.9670346 0.977
378 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other crime 1.284 0.90542547 0.973575774 1.003686365 1.02416976 1.113228 1.284
379 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other crime 2.391 1.857960389 1.976553605 1.956983767 2.27556252 2.5858665 2.391
380 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other crime 1.139 0.737340611 0.801457186 0.880722182 0.85507008 0.890698 1.139
381 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other crime 1.698 1.144095153 1.110771993 1.30679058 1.484989296 1.5152952 1.698
382 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other crime 1.644 1.024448176 1.034796138 1.175904702 1.3516146 1.501794 1.644
383 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other crime 2.346 1.615683858 1.568625105 1.705027288 1.95980148 2.1775572 2.346
384 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other crime 2.085 1.35329083 1.439671096 1.411442251 1.53417636 1.667583 2.085
385 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other income 0.706 0.547485869 0.536750852 0.531436487 0.590484986 0.6488846 0.706
386 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other income 1.105 0.694599833 0.687722607 0.79967745 0.940797 0.9503 1.105
387 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other income 1.689 1.32900002 1.476666689 1.71705429 1.667043 1.58766 1.689
388 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other income 1.977 1.35419437 1.327641539 1.561931222 1.837566144 1.9141314 1.977
389 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other income 2.394 1.711859237 1.729150745 1.820158679 1.93633902 2.251557 2.394
390 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other income 0.93 0.615940227 0.655255561 0.720061056 0.6923664 0.769296 0.93
391 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other income 0.731 0.523006424 0.562372499 0.585804686 0.58000464 0.6041715 0.731
392 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other income 2.407 2.07372119 2.356501352 2.404593217 2.334556521 2.3581379 2.407
393 11UpperNorthIsland0to15000Other 1 1 Upper North Island 0 to 15000 Other housing 2.296 1.789854845 1.924575102 1.984098043 2.088524256 2.2950816 2.296
394 12UpperNorthIsland0to15000Other 1 2 Upper North Island 0 to 15000 Other housing 1.971 1.370331585 1.557194983 1.730216648 1.663669854 1.9122642 1.971
395 13UpperNorthIsland0to15000Other 1 3 Upper North Island 0 to 15000 Other housing 0.813 0.658924855 0.658924855 0.646004759 0.717783066 0.7324317 0.813
396 14UpperNorthIsland0to15000Other 1 4 Upper North Island 0 to 15000 Other housing 1.917 1.516149669 1.45783622 1.472561838 1.692599814 1.8199998 1.917
397 21UpperNorthIsland0to15000Other 2 1 Upper North Island 0 to 15000 Other housing 1.947 1.720055577 1.703025324 1.62192888 1.62192888 1.8021432 1.947
398 22UpperNorthIsland0to15000Other 2 2 Upper North Island 0 to 15000 Other housing 2.4 1.685844109 1.720249091 1.737625344 1.9094784 2.07552 2.4
399 23UpperNorthIsland0to15000Other 2 3 Upper North Island 0 to 15000 Other housing 2.267 1.868874631 1.850370921 1.850370921 1.989646152 2.2869496 2.267
400 24UpperNorthIsland0to15000Other 2 4 Upper North Island 0 to 15000 Other housing 1.727 1.172807379 1.161195424 1.319540255 1.4826295 1.46795 1.727
401 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other health 1.464 0.855543596 0.919939351 0.938713623 1.031553432 1.1335752 1.464
402 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other health 0.718 0.587088353 0.581275597 0.569878036 0.5815082 0.5815082 0.718
403 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other health 1.812 1.729260659 1.695353587 1.695353587 1.614622464 1.7743104 1.812
404 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other health 1.25 0.873571098 0.98154056 1.115387 1.0724875 1.094375 1.25
405 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other health 1.467 1.078664389 1.057514107 1.101577195 1.280903715 1.4075865 1.467
406 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other health 1.938 1.61576251 1.665734547 1.665734547 1.71725211 1.770363 1.938
407 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other health 1.045 0.98425953 1.014700547 1.140112974 1.1753742 1.14114 1.045
408 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other health 1.849 1.585070701 1.686245427 1.605948026 1.59004755 1.747305 1.849
409 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other education 1.391 1.014005452 1.024247932 0.975474221 1.083860245 1.2178205 1.391
410 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other education 2.142 1.847724677 1.811494781 1.867520393 1.830902346 2.0119806 2.142
411 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other education 1.076 0.728398975 0.728398975 0.783224704 0.783224704 0.8513312 1.076
412 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other education 1.21 1.088518622 1.07774121 1.067070505 1.17260495 1.160995 1.21
413 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other education 0.806 0.479395865 0.526808643 0.57261809 0.665834988 0.7316868 0.806
414 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other education 2.132 1.454331444 1.398395619 1.441644968 1.696052904 1.8237128 2.132
415 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other education 1.824 1.447334854 1.626218938 1.61011776 1.594176 1.7328 1.824
416 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other education 0.826 0.545244387 0.550751906 0.561991741 0.556427466 0.6395718 0.826
417 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other crime 0.967 0.564406557 0.648743169 0.728924909 0.743800928 0.8648848 0.967
418 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other crime 1.568 1.027222402 1.017051883 1.048507096 1.1522056 1.355536 1.568
419 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other crime 1.797 1.685279476 1.668593541 1.813688631 1.778126109 1.7605209 1.797
420 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other crime 2.085 1.30637205 1.293437673 1.469815538 1.54717425 1.820205 2.085
421 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other crime 2.422 1.851547876 2.12821595 2.086486225 2.292842006 2.2701406 2.422
422 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other crime 1.057 0.876560653 0.876560653 0.942538337 0.933206274 0.9522513 1.057
423 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other crime 1.864 1.661678771 1.597768049 1.61390712 1.61390712 1.646844 1.864
424 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other crime 1.249 0.920721112 0.930021325 1.094142735 1.21571415 1.157823 1.249
425 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other income 1.755 1.390075035 1.544527817 1.795962578 1.71044055 1.6769025 1.755
426 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other income 1.062 0.78833004 0.796292969 0.765666317 0.87007536 0.887832 1.062
427 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other income 1.842 1.384030696 1.398010804 1.570798656 1.6710624 1.591488 1.842
428 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other income 1.217 0.880085677 0.946328685 0.909931428 0.86660136 0.9628904 1.217
429 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other income 1.042 0.806944332 0.858451417 0.849951898 0.98831616 1.029496 1.042
430 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other income 1.473 1.32612634 1.275121481 1.262496516 1.3015428 1.38462 1.473
431 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other income 2.287 1.515649178 1.595420187 1.792606952 1.907028672 2.2174752 2.287
432 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other income 2.319 1.888943158 1.927493018 2.007805227 2.028086088 2.0694756 2.319
433 11LowerNorthIsland0to15000Other 1 1 Lower North Island 0 to 15000 Other housing 1.043 0.744762474 0.783960499 0.834000531 0.8257431 0.8257431 1.043
434 12LowerNorthIsland0to15000Other 1 2 Lower North Island 0 to 15000 Other housing 1.144 0.821711451 0.830011566 0.932597266 1.07195088 1.165164 1.144
435 13LowerNorthIsland0to15000Other 1 3 Lower North Island 0 to 15000 Other housing 0.758 0.645959055 0.687190484 0.667175227 0.70976088 0.7886232 0.758
436 14LowerNorthIsland0to15000Other 1 4 Lower North Island 0 to 15000 Other housing 2.474 1.462304317 1.606927821 1.847043472 1.904168528 2.1395152 2.474
437 21LowerNorthIsland0to15000Other 2 1 Lower North Island 0 to 15000 Other housing 1.605 1.124739946 1.249711051 1.237337675 1.39026705 1.4790075 1.605
438 22LowerNorthIsland0to15000Other 2 2 Lower North Island 0 to 15000 Other housing 2.125 1.399992189 1.505367946 1.750427844 1.733096875 1.8243125 2.125
439 23LowerNorthIsland0to15000Other 2 3 Lower North Island 0 to 15000 Other housing 1.019 0.93504248 0.916708313 0.985707864 0.956997926 0.9865958 1.019
440 24LowerNorthIsland0to15000Other 2 4 Lower North Island 0 to 15000 Other housing 2.237 1.890053945 1.890053945 2.223592876 2.117707501 2.0967401 2.237
441 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other health 0.978 0.739487457 0.869985244 0.828557375 0.881444016 0.9377064 0.978
442 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other health 0.74 0.597220449 0.694442382 0.708614676 0.7230762 0.73038 0.74
443 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other health 1.81 1.264059128 1.316728259 1.496282112 1.4387328 1.56384 1.81
444 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other health 1.68 1.28630152 1.236828385 1.224582559 1.40756616 1.546776 1.68
445 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other health 2.306 1.782560857 1.730641608 1.989243228 2.1162162 2.015444 2.306
446 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other health 2.091 1.338631326 1.556548053 1.768804606 1.943741325 1.8871275 2.091
447 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other health 2.262 2.182426937 2.273361393 2.185924416 2.3760048 2.3760048 2.262
448 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other health 0.785 0.553591425 0.553591425 0.595259597 0.67643136 0.704616 0.785
449 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other education 2.233 1.622224677 1.78266448 1.819045388 2.115169056 2.2990968 2.233
450 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other education 1.19 0.872908455 0.890722913 0.957766573 1.05249074 1.119671 1.19
451 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other education 1.644 1.032600589 1.032600589 1.147333988 1.334109288 1.3753704 1.644
452 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other education 0.994 0.980108485 0.942412004 0.923933338 0.96243056 0.982072 0.994
453 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other education 2.355 1.403104468 1.541873042 1.64029047 1.64029047 1.802517 2.355
454 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other education 1.379 1.061473904 1.129227557 1.21422318 1.178857456 1.1671856 1.379
455 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other education 2.298 1.742148711 2.025754315 2.178230446 2.094452352 2.1817212 2.298
456 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other education 1.507 1.224028909 1.275030113 1.356415014 1.370116176 1.4732432 1.507
457 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other crime 1.865 1.193825041 1.404500049 1.614367872 1.6816332 1.616955 1.865
458 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other crime 1.208 1.040528986 1.030226719 1.144696355 1.122251328 1.1002464 1.208
459 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other crime 0.916 0.621296246 0.660953454 0.768550527 0.817606944 0.8258656 0.916
460 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other crime 2.4 1.267172073 1.423788846 1.564603128 1.7983944 2.06712 2.4
461 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other crime 1.142 0.781723625 0.840563037 0.866559832 0.952263552 1.1072832 1.142
462 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other crime 2.33 1.76821952 1.822906722 2.0031942 1.907804 1.907804 2.33
463 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other crime 2.125 1.709511295 1.762382778 1.980205369 1.960599375 1.8672375 2.125
464 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other crime 1.412 0.869203433 1.022592275 1.175393419 1.119422304 1.2301344 1.412
465 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other income 1.994 1.377864872 1.42047925 1.614180966 1.834296552 1.8161352 1.994
466 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other income 2.383 2.260287749 2.430416934 2.430416934 2.3827617 2.35917 2.383
467 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other income 1.011 0.796079291 0.796079291 0.765460856 0.74316588 0.8743128 1.011
468 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other income 1.04 0.704995189 0.67142399 0.789910576 0.8143408 0.83096 1.04
469 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other income 2.06 1.505383795 1.710663404 1.629203242 1.85136732 1.870068 2.06
470 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other income 2.069 1.429089575 1.605718624 1.76452596 1.76452596 1.917963 2.069
471 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other income 2.242 1.504652505 1.690620792 1.988965638 2.2861674 2.21958 2.242
472 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other income 1.092 0.563921988 0.593602093 0.645219666 0.75908196 0.8930376 1.092
473 11SouthIsland0to15000Other 1 1 South Island 0 to 15000 Other housing 1.266 0.899060437 0.872874211 0.89068797 0.957729 1.12674 1.266
474 12SouthIsland0to15000Other 1 2 South Island 0 to 15000 Other housing 1.792 1.206349829 1.325659152 1.395430687 1.423908864 1.5310848 1.792
475 13SouthIsland0to15000Other 1 3 South Island 0 to 15000 Other housing 1.321 0.910731093 1.011923437 1.124359375 1.222129755 1.2344745 1.321
476 14SouthIsland0to15000Other 1 4 South Island 0 to 15000 Other housing 1.812 1.206983627 1.195033294 1.160226499 1.26111576 1.370778 1.812
477 21SouthIsland0to15000Other 2 1 South Island 0 to 15000 Other housing 1.396 0.959212503 0.988878869 1.051998797 1.07346816 1.1927424 1.396
478 22SouthIsland0to15000Other 2 2 South Island 0 to 15000 Other housing 2.206 1.853174735 1.781898783 1.958130531 1.86488622 2.0720958 2.206
479 23SouthIsland0to15000Other 2 3 South Island 0 to 15000 Other housing 2.492 1.516050291 1.501039892 1.72533321 1.65897424 1.864016 2.492
480 24SouthIsland0to15000Other 2 4 South Island 0 to 15000 Other housing 1.321 0.986378703 1.027477816 0.978550301 1.01932323 0.9993365 1.321
481 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori health 2.105 1.621544649 1.743596396 1.676534996 1.905153405 1.8496635 2.105
482 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori health 1.852 1.374844343 1.38873166 1.633801953 1.617625696 1.6016096 1.852
483 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori health 1.503 1.39332065 1.451375677 1.451375677 1.560619008 1.6256448 1.503
484 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori health 1.782 1.365656649 1.500721593 1.485862963 1.58070528 1.5054336 1.782
485 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori health 1.829 0.954361224 1.084501391 1.261048129 1.483586034 1.5138633 1.829
486 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori health 0.842 0.646014297 0.63334735 0.711626236 0.69767278 0.711911 0.842
487 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori health 1.969 1.471460825 1.532771693 1.548254235 1.7396115 1.7396115 1.969
488 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori health 2.213 1.741088147 1.690376842 1.857556969 2.159949964 2.0970388 2.213
489 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori education 2.336 1.24548156 1.415319954 1.645720877 1.936142208 2.1045024 2.336
490 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori education 2.011 1.716952562 1.770054188 1.824798132 1.789017776 1.7202094 2.011
491 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori education 0.871 0.554954694 0.560560297 0.616000326 0.655319496 0.7532408 0.871
492 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori education 1.106 0.853194178 0.870606304 0.853535592 1.00415952 1.035216 1.106
493 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori education 2.045 1.488960267 1.418057397 1.5247929 1.773015 1.773015 2.045
494 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori education 1.759 1.353018463 1.394864395 1.452983745 1.482636474 1.4976126 1.759
495 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori education 1.322 1.22490391 1.331417293 1.331417293 1.280208936 1.2675336 1.322
496 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori education 1.956 1.325203083 1.352248044 1.454030155 1.710623712 1.8593736 1.956
497 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori crime 1.599 1.338559525 1.352080329 1.287695551 1.369888884 1.3978458 1.599
498 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori crime 1.315 0.986187235 0.976423005 1.08491445 1.219005 1.35445 1.315
499 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori crime 0.891 0.744917385 0.709445128 0.682158777 0.802539738 0.8819118 0.891
500 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori crime 2.07 1.287268352 1.327080776 1.561271501 1.77417216 1.848096 2.07
501 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori crime 2.23 1.169557797 1.37595035 1.618765117 1.88228502 1.901298 2.23
502 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori crime 1.107 0.853073707 0.844627433 0.879820242 0.862568865 0.9691785 1.107
503 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori crime 2.149 1.752707278 2.062008563 2.082836932 2.169621804 2.1481404 2.149
504 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori crime 1.961 1.581192265 1.565536896 1.49098752 1.49098752 1.694304 1.961
505 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori income 2.04 1.449664453 1.510067139 1.623728106 1.7843166 1.80234 2.04
506 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori income 1.293 0.956163135 0.910631557 0.919829856 1.0695696 1.21542 1.293
507 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori income 0.751 0.53803326 0.618429034 0.594643302 0.6394014 0.6394014 0.751
508 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori income 0.761 0.542146869 0.609153786 0.648035942 0.73640448 0.767088 0.761
509 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori income 2.437 1.689203933 1.741447353 1.892877558 2.201020416 2.2459392 2.437
510 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori income 1.26 0.992521939 1.055874404 1.160301542 1.17202176 1.126944 1.26
511 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori income 1.903 1.28895048 1.356789979 1.474771716 1.55239128 1.507176 1.903
512 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori income 1.61 1.105086828 1.255780487 1.28140866 1.256283 1.47798 1.61
513 11Aucklandover15000Maori 1 1 Auckland over 15000 Maori housing 0.871 0.629457425 0.669635559 0.68330159 0.719264832 0.8173464 0.871
514 12Aucklandover15000Maori 1 2 Auckland over 15000 Maori housing 1.64 1.234565482 1.27274792 1.312111258 1.26164544 1.433688 1.64
515 13Aucklandover15000Maori 1 3 Auckland over 15000 Maori housing 2.295 2.150132283 2.087507071 2.026705894 2.133374625 2.2456575 2.295
516 14Aucklandover15000Maori 1 4 Auckland over 15000 Maori housing 1.449 1.118657143 1.065387755 1.183764173 1.30083975 1.4453775 1.449
517 21Aucklandover15000Maori 2 1 Auckland over 15000 Maori housing 2.449 2.335797812 2.224569344 2.202543905 2.15935677 2.3992853 2.449
518 22Aucklandover15000Maori 2 2 Auckland over 15000 Maori housing 0.993 0.547069635 0.614684983 0.633695859 0.70410651 0.8283606 0.993
519 23Aucklandover15000Maori 2 3 Auckland over 15000 Maori housing 1.048 0.83591763 0.803766952 0.893074391 0.875563128 1.0063944 1.048
520 24Aucklandover15000Maori 2 4 Auckland over 15000 Maori housing 1.289 1.181764593 1.147344265 1.233703511 1.174955725 1.2367955 1.289
521 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori health 2.004 1.271002148 1.352129945 1.365787823 1.50086574 1.516026 2.004
522 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori health 2.441 2.350474734 2.26007186 2.173146019 2.556642375 2.4348975 2.441
523 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori health 0.912 0.921354827 0.903289046 0.860275282 0.87783192 0.852264 0.912
524 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori health 2.032 1.418168987 1.390361752 1.511262774 1.496299776 1.6264128 2.032
525 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori health 2.253 1.71243848 1.802566821 1.917624278 2.15463402 2.3419935 2.253
526 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori health 1.066 0.776801799 0.761570391 0.801653043 0.852822386 0.9582274 1.066
527 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori health 1.907 1.413541469 1.399546009 1.442830937 1.414540134 1.6259082 1.907
528 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori health 1.982 1.552952448 1.600981906 1.72148592 1.72148592 1.6395104 1.982
529 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori education 2.075 1.642154379 1.625895425 1.74827465 1.730965 1.730965 2.075
530 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori education 0.922 0.574831256 0.611522613 0.624002667 0.725584496 0.7718984 0.922
531 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori education 2.112 1.763508832 2.074716273 2.014287644 1.974791808 1.9360704 2.112
532 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori education 1.753 1.296184528 1.424378602 1.531589894 1.683065818 1.7174141 1.753
533 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori education 2.099 1.270973617 1.477876299 1.523583813 1.508498825 1.5878935 2.099
534 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori education 0.859 0.671263753 0.789722062 0.858393546 0.8498946 0.87618 0.859
535 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori education 0.917 0.769943419 0.895283046 0.860849082 0.835775808 0.8275008 0.917
536 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori education 1.211 0.646504213 0.69516582 0.781085191 0.918923754 1.0324986 1.211
537 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori crime 1.287 0.803668165 0.892964628 0.920582091 1.0343619 1.088802 1.287
538 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori crime 0.842 0.62651052 0.720127034 0.774330144 0.8416632 0.85884 0.842
539 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori crime 0.749 0.531771065 0.590856739 0.590856739 0.56813148 0.579726 0.749
540 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori crime 0.776 0.749022361 0.734335648 0.74175318 0.727209 0.69258 0.776
541 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori crime 1.247 0.904512266 0.869723332 0.925237588 1.028041764 0.9980988 1.247
542 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori crime 1.75 1.034677164 1.189284096 1.39915776 1.345344 1.4784 1.75
543 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori crime 2.434 1.884834386 1.943128233 2.112095906 2.030861448 2.0513752 2.434
544 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori crime 2.02 1.413477536 1.536388626 1.506263359 1.65523446 1.671954 2.02
545 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori income 1.376 1.060807293 1.24800858 1.211658816 1.211658816 1.3614144 1.376
546 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori income 1.744 1.569874575 1.706385408 1.6407552 1.6407552 1.67424 1.744
547 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori income 1.173 1.241680445 1.307032047 1.256761584 1.2321192 1.18473 1.173
548 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori income 2.166 1.275936252 1.371974464 1.614087605 1.793430672 1.8488976 2.166
549 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori income 1.908 1.714130196 1.785552287 1.89952371 2.2087485 2.10357 1.908
550 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori income 2.243 2.284008141 2.354647568 2.354647568 2.4027016 2.31029 2.243
551 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori income 1.741 1.316136651 1.29033005 1.449809045 1.7056577 1.7056577 1.741
552 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori income 2.483 2.117508041 2.182997981 2.079045696 2.3360064 2.3360064 2.483
553 11UpperNorthIslandover15000Maori 1 1 Upper North Island over 15000 Maori housing 2.047 1.175882969 1.367305778 1.519228643 1.787327815 1.8813977 2.047
554 12UpperNorthIslandover15000Maori 1 2 Upper North Island over 15000 Maori housing 1.014 0.692379884 0.678803808 0.72213171 0.77648571 0.784329 1.014
555 13UpperNorthIslandover15000Maori 1 3 Upper North Island over 15000 Maori housing 1.412 1.17208734 1.19600749 1.34382864 1.2798368 1.45436 1.412
556 14UpperNorthIslandover15000Maori 1 4 Upper North Island over 15000 Maori housing 1.44 0.936149985 1.063806801 1.022891155 1.01276352 1.164096 1.44
557 21UpperNorthIslandover15000Maori 2 1 Upper North Island over 15000 Maori housing 1.85 1.765478235 1.858398142 1.87716984 1.7877808 1.77008 1.85
558 22UpperNorthIslandover15000Maori 2 2 Upper North Island over 15000 Maori housing 2.374 1.60032044 1.538769654 1.690955664 1.798889004 2.0917314 2.374
559 23UpperNorthIslandover15000Maori 2 3 Upper North Island over 15000 Maori housing 1.547 1.248141766 1.371584358 1.318831114 1.26810684 1.378377 1.547
560 24UpperNorthIslandover15000Maori 2 4 Upper North Island over 15000 Maori housing 1.038 0.73442171 0.741840111 0.780884328 0.830728008 0.9659628 1.038
561 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori health 1.999 1.428729272 1.488259658 1.566589114 1.63186366 1.665167 1.999
562 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori health 1.896 1.432204072 1.591337858 1.544988211 1.79649792 1.7109504 1.896
563 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori health 1.029 0.712130905 0.800147085 0.930403587 1.06942941 1.0912545 1.029
564 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori health 1.781 1.180914134 1.29770784 1.29770784 1.410552 1.56728 1.781
565 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori health 1.966 1.472685802 1.732571531 1.650068125 1.736913816 1.7906328 1.966
566 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori health 1.673 1.162658044 1.263758744 1.469486911 1.66987149 1.721517 1.673
567 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori health 2.453 1.648726792 1.717423742 2.02049852 2.322412092 2.2768746 2.453
568 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori health 1.204 0.737845569 0.838460874 0.94209087 1.1083422 1.166676 1.204
569 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori education 1.387 1.083270523 1.051718954 1.095540577 1.084693641 1.0739541 1.387
570 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori education 2.082 1.684735334 1.892961049 1.855844166 1.974302304 1.8983676 2.082
571 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori education 0.962 0.741500858 0.756633529 0.749142108 0.83238012 0.840788 0.962
572 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori education 2.048 1.84581995 2.050911056 2.010697114 1.95213312 1.913856 2.048
573 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori education 1.294 0.946833865 0.956397843 1.099307866 1.14511236 1.0905832 1.294
574 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori education 1.599 1.105328872 1.256055537 1.322163723 1.349146656 1.3226928 1.599
575 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori education 1.645 1.277894944 1.404280159 1.577842875 1.577842875 1.5027075 1.645
576 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori education 1.559 1.339912502 1.576367649 1.515738124 1.703076544 1.6862144 1.559
577 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori crime 2.013 1.243875585 1.184643414 1.331060016 1.56595296 1.8422976 2.013
578 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori crime 1.192 0.999670291 1.020071726 0.990360899 1.064904192 1.0756608 1.192
579 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori crime 1.593 1.107427443 1.230474937 1.35217026 1.35217026 1.2877812 1.593
580 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori crime 1.006 0.544872257 0.598760722 0.704424378 0.757445568 0.8144576 1.006
581 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori crime 2.1 1.684240977 1.830696714 1.830696714 2.0569626 2.07774 2.1
582 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori crime 1.84 1.358314299 1.579435232 1.533432264 1.6850904 1.604848 1.84
583 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori crime 2.296 1.690523493 1.965724992 2.0911968 2.0911968 2.27304 2.296
584 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori crime 0.828 0.578662513 0.622217756 0.707065632 0.67339584 0.647496 0.828
585 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori income 0.836 0.539621617 0.562105851 0.631579608 0.70175512 0.746548 0.836
586 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori income 0.928 0.688021813 0.731938099 0.83174784 0.83174784 0.857472 0.928
587 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori income 1.63 1.419382354 1.419382354 1.478523285 1.4354595 1.51101 1.63
588 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori income 2.42 1.801523135 1.896340142 1.954989837 2.22157936 2.136134 2.42
589 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori income 1.579 1.118003859 1.256184111 1.295035166 1.26964232 1.380046 1.579
590 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori income 0.878 0.543692938 0.63220109 0.665474832 0.6721968 0.6721968 0.878
591 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori income 1.382 0.958433174 0.988075437 1.018634471 1.03942293 1.194739 1.382
592 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori income 1.546 1.000532608 1.075841514 1.250978505 1.405593826 1.4490658 1.546
593 11LowerNorthIslandover15000Maori 1 1 Lower North Island over 15000 Maori housing 1.437 1.491156949 1.447725193 1.40555844 1.4795352 1.42263 1.437
594 12LowerNorthIslandover15000Maori 1 2 Lower North Island over 15000 Maori housing 1.936 1.177826799 1.338439545 1.574634758 1.59054016 1.692064 1.936
595 13LowerNorthIslandover15000Maori 1 3 Lower North Island over 15000 Maori housing 1.468 0.966500445 1.062088402 1.051572675 1.155574368 1.3282464 1.468
596 14LowerNorthIslandover15000Maori 1 4 Lower North Island over 15000 Maori housing 2.272 1.936767765 1.917591847 1.997491507 2.08072032 2.337888 2.272
597 21LowerNorthIslandover15000Maori 2 1 Lower North Island over 15000 Maori housing 1.373 1.205439783 1.181803709 1.13634972 1.2913065 1.35927 1.373
598 22LowerNorthIslandover15000Maori 2 2 Lower North Island over 15000 Maori housing 0.898 0.714993979 0.714993979 0.680946647 0.709319424 0.6954112 0.898
599 23LowerNorthIslandover15000Maori 2 3 Lower North Island over 15000 Maori housing 2.41 1.231491829 1.448813916 1.52506728 1.6945192 1.993552 2.41
600 24LowerNorthIslandover15000Maori 2 4 Lower North Island over 15000 Maori housing 1.01 0.771203924 0.820429706 0.87279756 0.864156 0.864156 1.01
601 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori health 2.136 1.444767386 1.444767386 1.570399332 1.618968384 1.8608832 2.136
602 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori health 1.257 0.733377124 0.862796616 0.937822409 0.997683414 1.1209926 1.257
603 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori health 0.957 0.559486823 0.565138205 0.657137448 0.73015272 0.829719 0.957
604 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori health 0.736 0.560656697 0.577996595 0.550472947 0.54502272 0.6412032 0.736
605 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori health 0.829 0.695539331 0.709734012 0.739306262 0.778217118 0.7940991 0.829
606 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori health 2.446 1.53724949 1.708054989 1.85658151 2.01802338 2.2422482 2.446
607 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori health 2.406 2.302039245 2.349019637 2.258672728 2.352784092 2.5029618 2.406
608 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori health 1.343 0.986955681 0.99692493 1.172852859 1.274840064 1.3279584 1.343
609 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori education 1.682 1.236667196 1.200647763 1.14347406 1.14347406 1.329621 1.682
610 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori education 1.874 1.192203167 1.241878299 1.395368875 1.468809342 1.6882866 1.874
611 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori education 1.035 0.694258405 0.788930005 0.848311834 0.85688064 0.874368 1.035
612 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori education 1.52 0.996429564 1.132306322 1.21753368 1.309176 1.3224 1.52
613 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori education 1.615 1.15959239 1.274277352 1.355614204 1.3832798 1.41151 1.615
614 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori education 1.346 0.935554539 0.899571672 1.010754687 1.075270944 1.2218988 1.346
615 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori education 0.716 0.542379066 0.559153676 0.553617501 0.582755264 0.6776224 0.716
616 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori education 1.167 0.914766451 0.943058197 0.92456686 1.075077744 1.0337286 1.167
617 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori crime 2.146 1.155953191 1.270278232 1.25770122 1.445633586 1.6616478 2.146
618 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori crime 1.008 0.809362421 0.879741762 0.935895492 1.10105352 1.068984 1.008
619 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori crime 0.874 0.497386335 0.565211745 0.649668672 0.7467456 0.77786 0.874
620 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori crime 2.383 1.17631431 1.212695165 1.378062687 1.5839801 1.7217175 2.383
621 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori crime 1.484 1.137439699 1.22305344 1.22305344 1.210944 1.210944 1.484
622 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori crime 1.194 1.020289406 1.01018753 0.962083362 0.925080156 0.9344244 1.194
623 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori crime 1.097 0.796634222 0.926318863 0.935675619 1.05132092 1.0108855 1.097
624 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori crime 1.098 0.891852081 1.013468274 1.1137014 1.1137014 1.060668 1.098
625 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori income 2.004 1.578048998 1.753387776 1.7891712 1.92384 1.92384 2.004
626 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori income 0.975 0.546504874 0.587639649 0.645757856 0.626949375 0.7375875 0.975
627 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori income 1.103 0.964796116 1.037415179 1.04789412 1.0075905 0.95961 1.103
628 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori income 1.375 1.00790085 0.988138088 1.085866031 1.248121875 1.3138125 1.375
629 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori income 0.83 0.725294343 0.755514941 0.763146405 0.7268061 0.712555 0.83
630 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori income 1.362 1.05189607 1.143365293 1.154914438 1.16658024 1.2279792 1.362
631 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori income 1.648 1.508111671 1.450107376 1.464754925 1.42209216 1.5801024 1.648
632 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori income 1.282 0.851961396 0.96813795 0.958552426 0.97811472 1.111494 1.282
633 11SouthIslandover15000Maori 1 1 South Island over 15000 Maori housing 1.96 1.503018317 1.56564408 1.779141 1.87278 1.87278 1.96
634 12SouthIslandover15000Maori 1 2 South Island over 15000 Maori housing 1.447 1.095944616 1.21771624 1.399673839 1.333022704 1.2941968 1.447
635 13SouthIslandover15000Maori 1 3 South Island over 15000 Maori housing 1.686 1.089555182 1.057820565 1.230023913 1.41382059 1.553649 1.686
636 14SouthIslandover15000Maori 1 4 South Island over 15000 Maori housing 1.842 1.083159974 1.217033678 1.308638364 1.470380184 1.6158024 1.842
637 21SouthIslandover15000Maori 2 1 South Island over 15000 Maori housing 0.952 0.676725871 0.704922782 0.77464042 0.832946688 0.8676528 0.952
638 22SouthIslandover15000Maori 2 2 South Island over 15000 Maori housing 0.798 0.593073215 0.697733194 0.719312572 0.73399242 0.712614 0.798
639 23SouthIslandover15000Maori 2 3 South Island over 15000 Maori housing 0.753 0.602047933 0.596087063 0.669760745 0.66312945 0.698031 0.753
640 24SouthIslandover15000Maori 2 4 South Island over 15000 Maori housing 1.413 1.117627974 1.117627974 1.299567412 1.286700408 1.3129596 1.413
641 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean health 0.947 0.747394313 0.778535743 0.905274119 0.983993608 0.9553336 0.947
642 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean health 1.497 1.151795144 1.339296679 1.409785978 1.60202952 1.5257424 1.497
643 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean health 0.896 0.624599536 0.717930501 0.697019904 0.77446656 0.790272 0.896
644 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean health 0.935 0.583149146 0.589039541 0.620041622 0.673958285 0.7572565 0.935
645 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean health 1.746 1.251264668 1.226730067 1.305031986 1.3883319 1.542591 1.746
646 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean health 2.3 1.647464401 1.938193412 2.22780852 2.184126 2.1413 2.3
647 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean health 2.152 1.877650859 1.89661703 1.823670221 1.98225024 2.0865792 2.152
648 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean health 0.775 0.552388354 0.581461425 0.559097524 0.5947846 0.69161 0.775
649 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean education 2.329 1.501463292 1.687037407 1.739213822 1.932459802 2.1235822 2.329
650 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean education 1.229 0.840504509 0.848994454 0.987202853 1.0177349 1.0177349 1.229
651 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean education 1.417 0.795187399 0.855040214 0.994232807 1.14279633 1.2697737 1.417
652 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean education 1.547 1.074486891 1.14307116 1.329152512 1.527761508 1.4978054 1.547
653 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean education 1.355 1.235714818 1.199723125 1.31837706 1.26767025 1.4085225 1.355
654 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean education 2.41 2.187239778 2.103115171 2.082292249 2.26336114 2.197438 2.41
655 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean education 1.43 1.033657145 1.161412522 1.262404915 1.31500512 1.276704 1.43
656 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean education 1.067 0.747869222 0.840302496 0.815827667 0.93773295 0.893079 1.067
657 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean crime 1.901 1.79851434 1.729340711 1.662827607 1.714255265 1.6643255 1.901
658 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean crime 2.087 1.32821015 1.475789055 1.490696016 1.713443696 1.7664368 2.087
659 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean crime 2.17 1.340505121 1.47308255 1.601176685 1.81951896 1.977738 2.17
660 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean crime 0.92 0.631708753 0.619322306 0.69586776 0.799848 0.8694 0.92
661 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean crime 2.116 1.384254827 1.343936725 1.399934089 1.627830336 1.7317344 2.116
662 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean crime 1.193 0.646823625 0.621945793 0.706756583 0.785285092 0.9131222 1.193
663 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean crime 2.066 2.103561722 2.082734379 2.022072212 2.042497184 2.0841808 2.066
664 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean crime 2.39 1.478172707 1.478172707 1.642414118 1.86637968 2.145264 2.39
665 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean income 1.409 0.979760804 0.970060202 1.043075486 1.171994928 1.1269182 1.409
666 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean income 1.83 1.733150549 1.863602741 1.80932305 1.75662432 1.774368 1.83
667 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean income 2.228 1.471296665 1.65314232 1.620727764 1.688258088 1.9630908 2.228
668 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean income 1.941 1.273800274 1.213143118 1.225397089 1.424880336 1.6191822 1.941
669 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean income 0.956 0.635381926 0.690632529 0.775991605 0.90231582 0.8593484 0.956
670 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean income 1.662 1.186162929 1.275444009 1.22638847 1.40964192 1.468377 1.662
671 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean income 1.113 0.895944814 0.869849334 0.896751891 0.99639099 1.0167255 1.113
672 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean income 1.874 1.256005361 1.365223219 1.606144964 1.52966187 1.545113 1.874
673 11Aucklandover15000NZEuropean 1 1 Auckland over 15000 NZEuropean housing 2.316 1.506964504 1.603153728 1.7425584 1.936176 1.936176 2.316
674 12Aucklandover15000NZEuropean 1 2 Auckland over 15000 NZEuropean housing 2.367 1.705357095 1.688472372 1.918718604 1.918718604 2.0855637 2.367
675 13Aucklandover15000NZEuropean 1 3 Auckland over 15000 NZEuropean housing 1.063 0.779283156 0.749310727 0.871291543 0.957463234 1.0521574 1.063
676 14Aucklandover15000NZEuropean 1 4 Auckland over 15000 NZEuropean housing 1.322 1.283571984 1.246186392 1.221751365 1.174760928 1.1517264 1.322
677 21Aucklandover15000NZEuropean 2 1 Auckland over 15000 NZEuropean housing 1.947 1.155242222 1.132590414 1.316965597 1.51375356 1.7201745 1.947
678 22Aucklandover15000NZEuropean 2 2 Auckland over 15000 NZEuropean housing 1.796 1.550584531 1.535232209 1.490516708 1.520935416 1.5362984 1.796
679 23Aucklandover15000NZEuropean 2 3 Auckland over 15000 NZEuropean housing 1.571 1.026120052 1.057855724 1.149843178 1.21036124 1.3754105 1.571
680 24Aucklandover15000NZEuropean 2 4 Auckland over 15000 NZEuropean housing 1.605 1.069269819 1.069269819 1.188077576 1.153473375 1.3570275 1.605
681 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean health 0.993 0.627343258 0.721084204 0.728367883 0.758716545 0.8926077 0.993
682 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean health 2.127 1.477282462 1.717770305 1.73512152 1.73512152 1.684584 2.127
683 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean health 2.004 1.98218261 1.887792962 1.832808701 1.745532096 1.9835592 2.004
684 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean health 2.474 1.762559144 2.049487377 2.134882684 2.271151792 2.4957712 2.474
685 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean health 0.743 0.702013882 0.754853636 0.718908225 0.718908225 0.7567455 0.743
686 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean health 2.06 1.624470095 1.59261774 1.576849248 1.5162012 1.61298 2.06
687 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean health 1.076 0.595306128 0.654182558 0.735036582 0.70003484 0.786556 1.076
688 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean health 1.785 1.668453789 1.619858048 1.799842275 1.799842275 1.7141355 1.785
689 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean education 1.058 0.613403005 0.589810581 0.65534509 0.72015944 0.8472464 1.058
690 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean education 1.828 1.103050567 1.282616939 1.425129932 1.566076848 1.5980376 1.828
691 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean education 1.944 1.822071714 1.840476479 1.786870368 1.7348256 1.88568 1.944
692 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean education 1.829 1.085367086 1.043622198 1.15958022 1.302899124 1.4975852 1.829
693 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean education 1.235 1.170357062 1.125343329 1.071755551 1.04053937 1.072721 1.235
694 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean education 0.717 0.557520904 0.580750941 0.638187848 0.693682443 0.6734781 0.717
695 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean education 1.923 1.260649141 1.416459709 1.573844121 1.542984432 1.6414728 1.923
696 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean education 1.195 0.88903618 0.863141923 0.871860528 0.9275112 0.94644 1.195
697 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean crime 1.803 1.317944997 1.480837075 1.51105824 1.574019 1.74891 1.803
698 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean crime 1.439 1.303976165 1.278408005 1.331675005 1.431908608 1.5564224 1.439
699 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean crime 2.201 2.239410683 2.153279503 2.219875776 2.1763488 2.11296 2.201
700 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean crime 2.33 2.021036427 2.062282068 2.34350235 2.519895 2.519895 2.33
701 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean crime 2.333 1.563613395 1.776833404 1.725080975 1.982851695 2.0028805 2.333
702 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean crime 2.293 1.830338351 1.926671949 1.852569182 1.890376716 2.0547573 2.293
703 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean crime 2.006 1.443484143 1.519456993 1.726655674 1.74409664 1.981928 2.006
704 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean crime 1.8 1.093218851 1.214687612 1.190870208 1.2805056 1.48896 1.8
705 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean income 1.122 0.830941639 0.903197434 0.91232064 1.036728 1.1781 1.122
706 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean income 1.723 1.22763168 1.26559967 1.36085986 1.4791955 1.4791955 1.723
707 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean income 0.763 0.663052249 0.690679427 0.65778993 0.65778993 0.707301 0.763
708 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean income 1.537 0.960739166 1.091749052 1.173923712 1.1287728 1.175805 1.537
709 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean income 0.79 0.589941566 0.678093754 0.779418108 0.7953246 0.77973 0.79
710 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean income 2.26 1.487212225 1.549179401 1.580795307 1.66399506 1.828566 2.26
711 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean income 2.163 1.552985279 1.669876644 1.653343212 1.589753088 1.8273024 2.163
712 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean income 1.477 1.251008824 1.345170779 1.401219561 1.5066877 1.49177 1.477
713 11UpperNorthIslandover15000NZEuropean 1 1 Upper North Island over 15000 NZEuropean housing 2.068 1.626545654 1.891332156 1.818588612 1.800582784 1.7313296 2.068
714 12UpperNorthIslandover15000NZEuropean 1 2 Upper North Island over 15000 NZEuropean housing 0.889 0.601761173 0.699722295 0.714002341 0.736084888 0.7588504 0.889
715 13UpperNorthIslandover15000NZEuropean 1 3 Upper North Island over 15000 NZEuropean housing 2.27 1.322680956 1.469645507 1.597440768 1.6640008 1.957648 2.27
716 14UpperNorthIslandover15000NZEuropean 1 4 Upper North Island over 15000 NZEuropean housing 1.022 0.9138218 0.887205631 0.914644981 0.90558909 0.933597 1.022
717 21UpperNorthIslandover15000NZEuropean 2 1 Upper North Island over 15000 NZEuropean housing 1.397 0.896193482 0.984828002 0.99477576 0.99477576 1.156716 1.397
718 22UpperNorthIslandover15000NZEuropean 2 2 Upper North Island over 15000 NZEuropean housing 1.792 1.355390591 1.540216581 1.711351757 1.66150656 1.645056 1.792
719 23UpperNorthIslandover15000NZEuropean 2 3 Upper North Island over 15000 NZEuropean housing 1.814 1.021381371 1.011268684 1.099205091 1.22133899 1.372291 1.814
720 24UpperNorthIslandover15000NZEuropean 2 4 Upper North Island over 15000 NZEuropean housing 1.876 1.124218402 1.221976524 1.299975025 1.460646096 1.5876588 1.876
721 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean health 1.574 1.147201395 1.220427016 1.386848882 1.33350854 1.465394 1.574
722 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean health 0.845 0.627087067 0.627087067 0.620878284 0.6087042 0.676338 0.845
723 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean health 1.119 0.816500519 0.887500564 0.944149536 0.944149536 1.0044144 1.119
724 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean health 2.303 1.876023015 2.017229048 2.058396988 2.10040509 2.4423315 2.303
725 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean health 0.956 0.744479829 0.709028408 0.814975182 0.8763174 0.90342 0.956
726 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean health 2.309 1.692281616 1.880312907 1.91868664 1.91868664 2.041156 2.309
727 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean health 1.737 1.172544335 1.208808593 1.173600576 1.2225006 1.328805 1.737
728 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean health 1.189 0.815024167 0.876370072 0.903474301 1.026675342 1.0370458 1.189
729 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean education 1.011 0.692567041 0.713986641 0.743736084 0.8648094 0.8648094 1.011
730 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean education 1.907 0.923733127 1.086744855 1.168542855 1.3129695 1.458855 1.907
731 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean education 2.18 1.910228816 1.836758477 1.76611392 1.76611392 1.839702 2.18
732 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean education 1.372 1.024493191 1.17757838 1.353538368 1.3014792 1.39944 1.372
733 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean education 1.067 0.880419957 0.978244396 1.008499378 0.96971094 0.950697 1.067
734 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean education 2.025 1.187265368 1.141601315 1.25450694 1.441962 1.60218 2.025
735 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean education 2.128 1.432989242 1.432989242 1.685869696 1.9603136 2.00032 2.128
736 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean education 1.759 1.505451118 1.461603027 1.660912531 1.59703128 1.646424 1.759
737 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean crime 2.015 1.20226361 1.29275657 1.485927092 1.74814952 1.802216 2.015
738 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean crime 2.31 1.53760698 1.553138364 1.725709293 1.9835739 2.110185 2.31
739 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean crime 1.041 0.841821931 0.841821931 0.886128348 1.0303818 1.02018 1.041
740 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean crime 1.208 0.929016685 0.9198185 0.938590306 0.967618872 1.1122056 1.208
741 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean crime 2.238 1.651682673 1.651682673 1.720502784 1.9551168 2.14848 2.238
742 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean crime 1.833 1.385411521 1.4282593 1.623021931 1.575749448 1.6079076 1.833
743 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean crime 0.864 0.794822628 0.827940238 0.87151604 0.837996192 0.8464608 0.864
744 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean crime 1.582 0.954132221 1.096703703 1.29023965 1.517929 1.5029 1.582
745 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean income 1.956 1.523945438 1.587443165 1.763825738 1.856658672 1.8202536 1.956
746 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean income 0.987 0.827974504 0.819776737 0.931564474 1.046701656 1.0162152 0.987
747 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean income 1.705 0.936499272 1.076435945 1.157458005 1.3304115 1.478235 1.705
748 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean income 1.317 0.991679206 0.953537698 1.059486332 1.177207035 1.2136155 1.317
749 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean income 1.928 1.450236997 1.495089687 1.541329574 1.712588416 1.9461232 1.928
750 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean income 1.028 0.92510476 0.915945307 0.934638068 0.934638068 0.9635444 1.028
751 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean income 2.25 1.310429431 1.541681683 1.67574096 1.801872 2.0952 2.25
752 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean income 2.361 1.960869449 1.867494714 1.986696504 2.2835592 2.45544 2.361
753 11LowerNorthIslandover15000NZEuropean 1 1 Lower North Island over 15000 NZEuropean housing 1.886 1.61508409 1.700088516 1.789566859 1.737443552 2.0202832 1.886
754 12LowerNorthIslandover15000NZEuropean 1 2 Lower North Island over 15000 NZEuropean housing 2.373 1.679773626 1.86641514 2.028712109 2.04920415 2.2768935 2.373
755 13LowerNorthIslandover15000NZEuropean 1 3 Lower North Island over 15000 NZEuropean housing 2.428 1.926137036 1.985708285 1.946772828 2.1393108 2.1393108 2.428
756 14LowerNorthIslandover15000NZEuropean 1 4 Lower North Island over 15000 NZEuropean housing 1.933 1.51332105 1.739449483 1.830999456 1.830999456 1.7605764 1.933
757 21LowerNorthIslandover15000NZEuropean 2 1 Lower North Island over 15000 NZEuropean housing 2.376 2.477940765 2.359943586 2.5933446 2.5933446 2.469852 2.376
758 22LowerNorthIslandover15000NZEuropean 2 2 Lower North Island over 15000 NZEuropean housing 1.573 0.956608788 0.996467488 1.158683126 1.18232972 1.374802 1.573
759 23LowerNorthIslandover15000NZEuropean 2 3 Lower North Island over 15000 NZEuropean housing 0.89 0.66667872 0.68729765 0.72347121 0.78638175 0.925155 0.89
760 24LowerNorthIslandover15000NZEuropean 2 4 Lower North Island over 15000 NZEuropean housing 1.055 0.833240068 0.793561969 0.901774965 0.8928465 0.98115 1.055
761 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean health 1.85 0.915130818 1.064105603 1.108443336 1.2180696 1.41636 1.85
762 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean health 0.728 0.493874707 0.484190889 0.56963634 0.558467 0.65702 0.728
763 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean health 1.245 0.907821073 0.881379683 0.847480464 0.8736912 1.01592 1.245
764 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean health 0.915 0.616173848 0.641847758 0.66169872 0.711504 0.74115 0.915
765 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean health 2.14 1.630196703 1.614056142 1.598075388 1.77563932 1.830556 2.14
766 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean health 1.363 1.245328176 1.245328176 1.431411696 1.3763574 1.34937 1.363
767 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean health 0.931 0.666807305 0.784479183 0.769097238 0.73247356 0.8617336 0.931
768 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean health 1.612 1.273950986 1.26133761 1.4839266 1.562028 1.5314 1.612
769 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean education 1.928 1.755602137 1.809899111 1.723713439 1.758891264 2.0452224 1.928
770 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean education 2.14 1.336469705 1.392155942 1.546839936 1.7380224 1.81044 2.14
771 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean education 1.04 0.762807597 0.829138692 0.83751383 0.86341632 0.938496 1.04
772 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean education 1.46 1.160427659 1.196317175 1.18447245 1.3160805 1.25341 1.46
773 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean education 1.489 0.90922901 0.947113552 1.0762654 1.157274624 1.2054944 1.489
774 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean education 1.982 1.58497844 1.842998186 1.93999809 2.020831344 1.9812072 1.982
775 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean education 1.423 1.059461669 1.203933715 1.323004082 1.27211931 1.4792085 1.423
776 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean education 2.011 1.655802146 1.655802146 1.780432415 1.711954245 1.6620915 2.011
777 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean crime 2.333 1.475945057 1.677210292 1.803451927 2.02635048 2.302671 2.333
778 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean crime 2.393 1.838009866 2.137220775 2.203320387 2.160118026 2.1819374 2.393
779 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean crime 1.451 1.085858334 1.034150794 1.004029897 1.07960204 1.1364232 1.451
780 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean crime 1.92 1.437935578 1.634017702 1.856838298 1.99660032 2.016768 1.92
781 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean crime 1.207 0.855064932 0.994261549 0.946915761 1.04056677 1.010259 1.207
782 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean crime 0.971 0.755272889 0.726223932 0.798048276 0.831300288 0.8659378 0.971
783 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean crime 1.97 1.519748714 1.504701697 1.690676064 1.7077536 1.98576 1.97
784 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean crime 1 0.878671411 0.91528272 0.924528 0.924528 0.8976 1
785 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean income 1.714 1.332552574 1.388075598 1.347646212 1.41857496 1.432904 1.714
786 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean income 2.076 1.514545303 1.76109919 1.743662564 1.692876276 1.8603036 2.076
787 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean income 0.841 0.579126191 0.636402408 0.677023838 0.74398224 0.766992 0.841
788 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean income 0.946 0.581915468 0.646572742 0.646572742 0.74318706 0.854238 0.946
789 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean income 1.83 1.273070226 1.273070226 1.273070226 1.46329911 1.681953 1.83
790 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean income 0.801 0.618835222 0.651405497 0.657985351 0.739309383 0.7177761 0.801
791 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean income 2.294 1.559801848 1.835060997 1.931643155 2.246096692 2.1806764 2.294
792 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean income 1.689 1.431692895 1.417517718 1.461358472 1.554636672 1.5241536 1.689
793 11SouthIslandover15000NZEuropean 1 1 South Island over 15000 NZEuropean housing 1.977 1.160237745 1.208580984 1.421859982 1.579844424 1.7172222 1.977
794 12SouthIslandover15000NZEuropean 1 2 South Island over 15000 NZEuropean housing 0.832 0.727133839 0.719934494 0.705818131 0.79305408 0.777504 0.832
795 13SouthIslandover15000NZEuropean 1 3 South Island over 15000 NZEuropean housing 1.049 0.685046376 0.72877274 0.809747489 0.771188085 0.8292345 1.049
796 14SouthIslandover15000NZEuropean 1 4 South Island over 15000 NZEuropean housing 1.989 1.350940155 1.501044617 1.429566302 1.41541218 1.555398 1.989
797 21SouthIslandover15000NZEuropean 2 1 South Island over 15000 NZEuropean housing 1.876 1.358596113 1.331956974 1.567008205 1.615472376 1.5994776 1.876
798 22SouthIslandover15000NZEuropean 2 2 South Island over 15000 NZEuropean housing 1.009 0.652812422 0.6944813 0.789183296 0.8967992 1.01909 1.009
799 23SouthIslandover15000NZEuropean 2 3 South Island over 15000 NZEuropean housing 0.821 0.886412223 0.877635864 0.8689464 0.827568 0.78816 0.821
800 24SouthIslandover15000NZEuropean 2 4 South Island over 15000 NZEuropean housing 1.828 1.028789793 1.182517004 1.12620667 1.30954264 1.5406384 1.828
801 11Aucklandover15000Other 1 1 Auckland over 15000 Other health 1.147 0.832080317 0.934921704 0.916589906 0.996293376 0.9579744 1.147
802 12Aucklandover15000Other 1 2 Auckland over 15000 Other health 2.056 1.645799424 1.567428022 1.703726111 1.738496032 1.7212832 2.056
803 13Aucklandover15000Other 1 3 Auckland over 15000 Other health 2.439 1.846539054 2.007107667 2.181638769 2.118095892 2.4629022 2.439
804 14Aucklandover15000Other 1 4 Auckland over 15000 Other health 1.292 1.133337739 1.192987094 1.296725102 1.234976288 1.1874772 1.292
805 21Aucklandover15000Other 2 1 Auckland over 15000 Other health 1.991 1.959786031 2.084878756 2.004691112 1.94630205 1.853621 1.991
806 22Aucklandover15000Other 2 2 Auckland over 15000 Other health 1.627 1.422309343 1.481572232 1.481572232 1.481572232 1.5118084 1.627
807 23Aucklandover15000Other 2 3 Auckland over 15000 Other health 1.245 0.872075221 1.014040954 1.056292661 1.22824728 1.320696 1.245
808 24Aucklandover15000Other 2 4 Auckland over 15000 Other health 1.728 1.327209203 1.288552624 1.227192975 1.394537472 1.6215552 1.728
809 11Aucklandover15000Other 1 1 Auckland over 15000 Other education 2.018 1.284141478 1.297112604 1.235345338 1.32832832 1.5627392 2.018
810 12Aucklandover15000Other 1 2 Auckland over 15000 Other education 1.539 0.893555151 0.981928738 1.115828111 1.282561047 1.3790979 1.539
811 13Aucklandover15000Other 1 3 Auckland over 15000 Other education 0.807 0.41147225 0.47295661 0.531411921 0.6108183 0.6108183 0.807
812 14Aucklandover15000Other 1 4 Auckland over 15000 Other education 1.658 0.845670568 0.960989282 0.970696245 1.11574281 1.226091 1.658
813 21Aucklandover15000Other 2 1 Auckland over 15000 Other education 1.037 0.742774818 0.714206556 0.830472739 0.89298144 0.858636 1.037
814 22Aucklandover15000Other 2 2 Auckland over 15000 Other education 2.216 1.637485294 1.904052668 1.848594823 1.830291904 1.8676448 2.216
815 23Aucklandover15000Other 2 3 Auckland over 15000 Other education 1.158 0.627055711 0.704556979 0.765822803 0.900968004 1.0123236 1.158
816 24Aucklandover15000Other 2 4 Auckland over 15000 Other education 2.418 2.009599097 2.093332393 2.012819609 2.03315112 2.234232 2.418
817 11Aucklandover15000Other 1 1 Auckland over 15000 Other crime 1.963 1.649720246 1.71845859 1.701444148 1.754066132 1.7898634 1.963
818 12Aucklandover15000Other 1 2 Auckland over 15000 Other crime 1.255 0.895643576 0.995159529 1.05868035 1.05868035 1.027845 1.255
819 13Aucklandover15000Other 1 3 Auckland over 15000 Other crime 1.961 1.35215128 1.35215128 1.32563851 1.489481472 1.7319552 1.961
820 14Aucklandover15000Other 1 4 Auckland over 15000 Other crime 2.183 1.847429724 1.924405962 1.868355303 1.849856736 1.9070688 2.183
821 21Aucklandover15000Other 2 1 Auckland over 15000 Other crime 1.018 0.589517205 0.620544426 0.705164121 0.81995828 0.9646568 1.018
822 22Aucklandover15000Other 2 2 Auckland over 15000 Other crime 1.88 1.366753577 1.570981123 1.726352883 1.70926028 1.659476 1.88
823 23Aucklandover15000Other 2 3 Auckland over 15000 Other crime 1.095 0.789945802 0.840367875 0.954963494 0.94550841 1.062369 1.095
824 24Aucklandover15000Other 2 4 Auckland over 15000 Other crime 2.414 1.535867313 1.551381124 1.650405451 1.737268896 1.9741692 2.414
825 11Aucklandover15000Other 1 1 Auckland over 15000 Other income 1.44 1.039298314 1.093998226 1.08316656 1.105272 1.30032 1.44
826 12Aucklandover15000Other 1 2 Auckland over 15000 Other income 0.784 0.630358051 0.606113511 0.658819034 0.67226432 0.646408 0.784
827 13Aucklandover15000Other 1 3 Auckland over 15000 Other income 0.882 0.527293876 0.532620077 0.585296788 0.57382038 0.6750828 0.882
828 14Aucklandover15000Other 1 4 Auckland over 15000 Other income 1.169 0.746739179 0.732097234 0.787201327 0.80326666 0.854539 1.169
829 21Aucklandover15000Other 2 1 Auckland over 15000 Other income 1.494 1.209933717 1.186209526 1.129723358 1.08627246 1.193706 1.494
830 22Aucklandover15000Other 2 2 Auckland over 15000 Other income 1.814 1.607315732 1.530776888 1.719974031 1.68624905 1.774999 1.814
831 23Aucklandover15000Other 2 3 Auckland over 15000 Other income 2.314 1.396578231 1.470082349 1.70939808 1.780623 1.97847 2.314
832 24Aucklandover15000Other 2 4 Auckland over 15000 Other income 2.335 1.453130893 1.614589881 1.647540695 1.66418252 1.828772 2.335
833 11Aucklandover15000Other 1 1 Auckland over 15000 Other housing 2.09 1.860394465 1.937910901 1.863375866 1.96144828 1.942028 2.09
834 12Aucklandover15000Other 1 2 Auckland over 15000 Other housing 2.23 1.286063094 1.397894667 1.412014815 1.56890535 1.686995 2.23
835 13Aucklandover15000Other 1 3 Auckland over 15000 Other housing 2.497 2.093704536 2.093704536 2.2512952 2.2512952 2.44706 2.497
836 14Aucklandover15000Other 1 4 Auckland over 15000 Other housing 1.267 1.081773528 1.081773528 1.126847425 1.094026626 1.1163537 1.267
837 21Aucklandover15000Other 2 1 Auckland over 15000 Other housing 1.296 1.163018606 1.224230112 1.224230112 1.2492144 1.388016 1.296
838 22Aucklandover15000Other 2 2 Auckland over 15000 Other housing 1.01 0.866728358 0.849733685 0.93377328 0.93377328 0.915464 1.01
839 23Aucklandover15000Other 2 3 Auckland over 15000 Other housing 0.843 0.605337827 0.61769166 0.686324066 0.653641968 0.7104804 0.843
840 24Aucklandover15000Other 2 4 Auckland over 15000 Other housing 2.426 2.141014983 2.039061889 2.24072735 2.28645648 2.598246 2.426
841 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other health 1.781 1.285520671 1.339084032 1.5045888 1.56728 1.56728 1.781
842 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other health 1.973 1.305299597 1.331938364 1.331938364 1.35912078 1.5101342 1.973
843 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other health 2.284 1.610463675 1.563556966 1.563556966 1.77676928 2.0903168 2.284
844 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other health 1.898 1.515859921 1.684288801 1.850866814 1.814575308 1.7617236 1.898
845 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other health 2.361 1.41714176 1.431456323 1.522825876 1.553903955 1.8281223 2.361
846 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other health 1.745 1.149880734 1.185444056 1.317160062 1.43169572 1.556191 1.745
847 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other health 0.819 0.57180796 0.595633291 0.633652438 0.62122788 0.6902532 0.819
848 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other health 1.14 0.800996349 0.785290538 0.882348919 1.01419416 1.139544 1.14
849 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other education 1.259 0.72812197 0.809024411 0.889037814 0.96634545 1.136877 1.259
850 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other education 0.821 0.49408987 0.567919391 0.591582699 0.679980114 0.6868486 0.821
851 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other education 2.184 1.484525952 1.74650112 1.74650112 2.0547072 2.09664 2.184
852 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other education 1.822 1.057501531 1.201706285 1.381271592 1.625025402 1.6414398 1.822
853 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other education 2.046 1.487258692 1.51761091 1.705180798 1.794927156 1.7771556 2.046
854 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other education 2.378 1.138394381 1.293629979 1.437366643 1.69101958 1.900022 2.378
855 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other education 2.199 1.577142801 1.642857085 1.825396761 1.862649756 1.8814644 2.199
856 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other education 1.121 0.706963539 0.693101508 0.77876574 0.905541558 0.9737006 1.121
857 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other crime 1.887 1.256639057 1.196799102 1.300868589 1.413987597 1.6252731 1.887
858 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other crime 1.539 1.081336453 1.138248898 1.173452472 1.261776852 1.3423158 1.539
859 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other crime 1.315 0.88056936 0.967658637 1.06336114 1.143399075 1.2564825 1.315
860 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other crime 2.157 1.423348289 1.581498099 1.506188666 1.73125134 1.9236126 2.157
861 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other crime 0.843 0.590492793 0.671014537 0.664370829 0.65134395 0.644895 0.843
862 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other crime 2.462 1.815276012 1.95190969 2.144955704 2.35709418 2.2448516 2.462
863 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other crime 1.624 1.349128061 1.362755617 1.419537101 1.37819136 1.435616 1.624
864 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other crime 1.258 0.623393506 0.71654426 0.778852457 0.88505961 1.0412466 1.258
865 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other income 2.4 1.636752054 1.779078319 2.06869572 2.273292 2.4444 2.4
866 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other income 1.645 1.303028156 1.26507588 1.252550376 1.3614678 1.5471225 1.645
867 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other income 1.607 1.254696257 1.409771075 1.584012444 1.568329152 1.5375776 1.607
868 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other income 1.687 1.119674534 1.108588648 1.154779842 1.29750544 1.474438 1.687
869 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other income 0.89 0.553363381 0.643445792 0.6993976 0.6993976 0.736208 0.89
870 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other income 1.415 1.100153222 1.122605328 1.181689819 1.230926895 1.4148585 1.415
871 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other income 0.713 0.488595418 0.548983616 0.596721322 0.663023691 0.6564591 0.713
872 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other income 0.909 0.622269213 0.67637958 0.697298536 0.71886447 0.711747 0.909
873 11UpperNorthIslandover15000Other 1 1 Upper North Island over 15000 Other housing 1.425 1.429328542 1.387697613 1.524942432 1.4950416 1.43754 1.425
874 12UpperNorthIslandover15000Other 1 2 Upper North Island over 15000 Other housing 2.092 1.429564572 1.570950079 1.570950079 1.785170544 2.0058096 2.092
875 13UpperNorthIslandover15000Other 1 3 Upper North Island over 15000 Other housing 2.412 1.574680411 1.693204743 1.840439938 1.82221776 2.1437856 2.412
876 14UpperNorthIslandover15000Other 1 4 Upper North Island over 15000 Other housing 0.818 0.523640686 0.508389016 0.57771479 0.608120832 0.6334592 0.818
877 21UpperNorthIslandover15000Other 2 1 Upper North Island over 15000 Other housing 2.346 1.811803421 1.830104465 2.056297152 2.0982624 2.43984 2.346
878 22UpperNorthIslandover15000Other 2 2 Upper North Island over 15000 Other housing 1.541 0.827073482 0.973027626 1.131427472 1.21658868 1.3517652 1.541
879 23UpperNorthIslandover15000Other 2 3 Upper North Island over 15000 Other housing 1.746 1.389950515 1.323762395 1.454683951 1.598553792 1.8165384 1.746
880 24UpperNorthIslandover15000Other 2 4 Upper North Island over 15000 Other housing 1.198 0.692300215 0.760769467 0.826923334 0.90870696 0.927252 1.198
881 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other health 1.619 1.305469588 1.40373074 1.417909838 1.476989415 1.5226695 1.619
882 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other health 1.889 1.401310211 1.444649702 1.641647388 1.746433392 1.7121896 1.889
883 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other health 1.416 1.184728248 1.273901341 1.224905136 1.2499032 1.37352 1.416
884 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other health 1.116 0.716514723 0.738674972 0.753749971 0.84691008 0.882198 1.116
885 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other health 1.114 0.588353977 0.67626894 0.704446812 0.8191242 0.910138 1.114
886 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other health 2.107 1.541007525 1.81295003 1.99225278 1.953189 2.17021 2.107
887 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other health 1.211 0.892200435 0.939158353 1.10489218 1.1630444 1.1630444 1.211
888 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other health 1.285 0.681684427 0.695596354 0.818348652 0.8266148 0.939335 1.285
889 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other education 0.762 0.508023783 0.56447087 0.537591305 0.61089921 0.702183 0.762
890 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other education 0.887 0.694838685 0.701857257 0.738797113 0.869173074 0.8779526 0.887
891 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other education 1.547 1.459429978 1.474171695 1.459575936 1.4034384 1.336608 1.547
892 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other education 2.247 1.46237383 1.607004209 1.65670537 1.882619739 2.0688129 2.247
893 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other education 2.146 1.529384382 1.778353933 1.693670412 1.9693842 1.875604 2.146
894 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other education 0.828 0.590637842 0.621724044 0.675787005 0.682613136 0.6627312 0.828
895 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other education 2.402 1.640634985 1.708994777 2.01058209 2.259081 2.37798 2.402
896 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other education 2.024 1.803460418 1.750932445 1.750932445 1.90318744 1.942028 2.024
897 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other crime 1.589 1.210916528 1.274648977 1.370590297 1.398561528 1.3447707 1.589
898 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other crime 0.926 0.638943142 0.726071752 0.780722314 0.77299239 0.765339 0.926
899 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other crime 0.722 0.532842556 0.605502904 0.582214331 0.632841664 0.6457568 0.722
900 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other crime 2.239 1.808738684 1.864679056 1.846216887 1.827937512 1.7920956 2.239
901 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other crime 1.759 1.006561402 1.130967867 1.142391785 1.131080975 1.3306835 1.759
902 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other crime 1.079 0.779185683 0.86576187 0.89253801 0.980811 0.9711 1.079
903 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other crime 1.6 1.094931966 1.105991885 1.15207488 1.324224 1.5048 1.6
904 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other crime 2.249 1.834523103 1.816359508 1.763455833 2.026960728 2.1563412 2.249
905 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other income 1.263 0.946617653 0.928056522 1.00875709 1.17297336 1.2347088 1.263
906 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other income 0.905 0.606010927 0.658707529 0.679079927 0.68593932 0.7794765 0.905
907 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other income 1.407 0.811442122 0.922093321 1.024548134 1.06723764 1.089018 1.407
908 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other income 1.726 1.352353571 1.312964632 1.396770885 1.343048928 1.5616848 1.726
909 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other income 1.647 0.862690969 0.958545521 1.041897306 1.17067113 1.345599 1.647
910 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other income 1.974 1.182928963 1.314365515 1.383542647 1.35641436 1.577226 1.974
911 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other income 1.084 0.805978094 0.848397994 0.998115287 0.969043968 0.9990144 1.084
912 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other income 1.7 1.003741911 1.1277999 1.150816224 1.2508872 1.45452 1.7
913 11LowerNorthIslandover15000Other 1 1 Lower North Island over 15000 Other housing 0.901 0.63645043 0.656134464 0.754177545 0.7617955 0.85595 0.901
914 12LowerNorthIslandover15000Other 1 2 Lower North Island over 15000 Other housing 1.319 0.673876518 0.76576877 0.870191784 0.96687976 1.098727 1.319
915 13LowerNorthIslandover15000Other 1 3 Lower North Island over 15000 Other housing 2.479 1.477939434 1.539520244 1.655398112 1.94752719 2.2645665 2.479
916 14LowerNorthIslandover15000Other 1 4 Lower North Island over 15000 Other housing 1.338 0.965994035 0.995870139 1.082467542 1.071750042 1.1524194 1.338
917 21LowerNorthIslandover15000Other 2 1 Lower North Island over 15000 Other housing 1.734 1.141247314 1.342643899 1.342643899 1.561213836 1.5306018 1.734
918 22LowerNorthIslandover15000Other 2 2 Lower North Island over 15000 Other housing 1.615 1.048408 1.038027723 1.166323284 1.3104756 1.42443 1.615
919 23LowerNorthIslandover15000Other 2 3 Lower North Island over 15000 Other housing 1.291 1.090349596 1.048413073 0.998488641 1.008574385 1.1865581 1.291
920 24LowerNorthIslandover15000Other 2 4 Lower North Island over 15000 Other housing 1.92 1.21021981 1.260645635 1.355532941 1.55808384 1.657536 1.92
921 11SouthIslandover15000Other 1 1 South Island over 15000 Other health 1.743 1.325980571 1.457121506 1.533812112 1.5812496 1.505952 1.743
922 12SouthIslandover15000Other 1 2 South Island over 15000 Other health 1.96 1.934182502 1.99400258 1.97425998 1.994202 1.9551 1.96
923 13SouthIslandover15000Other 1 3 South Island over 15000 Other health 2.459 1.980542673 2.106960291 2.172124011 2.262629178 2.4329346 2.459
924 14SouthIslandover15000Other 1 4 South Island over 15000 Other health 1.923 1.531909479 1.531909479 1.781290092 1.696466754 1.8241578 1.923
925 21SouthIslandover15000Other 2 1 South Island over 15000 Other health 1.102 0.80784 0.784310679 0.825590189 0.89738064 1.031472 1.102
926 22SouthIslandover15000Other 2 2 South Island over 15000 Other health 1.964 1.422457511 1.466451042 1.6476978 1.6476978 1.569236 1.964
927 23SouthIslandover15000Other 2 3 South Island over 15000 Other health 2.009 1.32183975 1.502090625 1.458340413 1.695744666 1.7303517 2.009
928 24SouthIslandover15000Other 2 4 South Island over 15000 Other health 1.6 0.88218167 0.88218167 1.02579264 1.179072 1.3248 1.6
929 11SouthIslandover15000Other 1 1 South Island over 15000 Other education 0.815 0.635729503 0.68358011 0.751186934 0.74374944 0.774739 0.815
930 12SouthIslandover15000Other 1 2 South Island over 15000 Other education 1.402 0.956809256 0.976335976 1.14863056 1.14863056 1.2090848 1.402
931 13SouthIslandover15000Other 1 3 South Island over 15000 Other education 1.351 1.19417924 1.326865822 1.411559386 1.35726864 1.2926368 1.351
932 14SouthIslandover15000Other 1 4 South Island over 15000 Other education 1.197 0.875786141 0.921880148 0.991268977 1.101409974 1.1354742 1.197
933 21SouthIslandover15000Other 2 1 South Island over 15000 Other education 1.884 1.433315483 1.378187964 1.338046567 1.36535364 1.6062984 1.884
934 22SouthIslandover15000Other 2 2 South Island over 15000 Other education 2.416 2.106218281 2.005922173 2.005922173 2.20431008 2.249296 2.416
935 23SouthIslandover15000Other 2 3 South Island over 15000 Other education 2.177 1.560691982 1.773513616 1.809707772 1.865678115 2.0061055 2.177
936 24SouthIslandover15000Other 2 4 South Island over 15000 Other education 0.831 0.481087974 0.540548285 0.594009104 0.61238052 0.688068 0.831
937 11SouthIslandover15000Other 1 1 South Island over 15000 Other crime 1.881 1.181619324 1.342749232 1.384277558 1.57304268 1.557468 1.881
938 12SouthIslandover15000Other 1 2 South Island over 15000 Other crime 2.26 1.498171552 1.762554767 1.89522018 1.858059 2.06451 2.26
939 13SouthIslandover15000Other 1 3 South Island over 15000 Other crime 1.3 1.100309697 1.089415542 1.134807856 1.2072424 1.17208 1.3
940 14SouthIslandover15000Other 1 4 South Island over 15000 Other crime 0.715 0.448858625 0.448858625 0.498731805 0.5867433 0.651937 0.715
941 21SouthIslandover15000Other 2 1 South Island over 15000 Other crime 2.025 1.310871895 1.489627153 1.636952915 1.881555075 2.0231775 2.025
942 22SouthIslandover15000Other 2 2 South Island over 15000 Other crime 0.976 0.729830308 0.701759911 0.806620588 0.916614304 0.8899168 0.976
943 23SouthIslandover15000Other 2 3 South Island over 15000 Other crime 1.032 0.7176452 0.710539802 0.683211348 0.7676532 0.88236 1.032
944 24SouthIslandover15000Other 2 4 South Island over 15000 Other crime 1.49 0.985301958 0.947405729 1.064500819 1.22356416 1.301664 1.49
945 11SouthIslandover15000Other 1 1 South Island over 15000 Other income 1.717 1.159183518 1.273828042 1.498621226 1.544970336 1.6093441 1.717
946 12SouthIslandover15000Other 1 2 South Island over 15000 Other income 1.324 0.789861349 0.897569715 0.906636076 0.954353764 1.0487404 1.324
947 13SouthIslandover15000Other 1 3 South Island over 15000 Other income 1.354 1.152688256 1.266690392 1.305866383 1.26783144 1.4087016 1.354
948 14SouthIslandover15000Other 1 4 South Island over 15000 Other income 2.248 1.555982463 1.604105632 1.653717146 1.77819048 2.0919888 2.248
949 21SouthIslandover15000Other 2 1 South Island over 15000 Other income 1.939 1.321798115 1.348773587 1.404972487 1.391061868 1.6175138 1.939
950 22SouthIslandover15000Other 2 2 South Island over 15000 Other income 1.983 1.219158212 1.256864136 1.444671421 1.53688449 1.8080994 1.983
951 23SouthIslandover15000Other 2 3 South Island over 15000 Other income 0.831 0.677771362 0.671060754 0.78948324 0.907452 0.87255 0.831
952 24SouthIslandover15000Other 2 4 South Island over 15000 Other income 1.132 0.838820324 0.921780576 0.877886263 1.032807368 1.0027256 1.132
953 11SouthIslandover15000Other 1 1 South Island over 15000 Other housing 1.723 1.142190082 1.269100091 1.49305893 1.421960886 1.6344378 1.723
954 12SouthIslandover15000Other 1 2 South Island over 15000 Other housing 1.633 1.196230716 1.329145241 1.34257095 1.34257095 1.4917455 1.633
955 13SouthIslandover15000Other 1 3 South Island over 15000 Other housing 1.412 1.065104794 1.238493946 1.251003986 1.437935616 1.4097408 1.412
956 14SouthIslandover15000Other 1 4 South Island over 15000 Other housing 1.659 1.120734705 1.077629524 1.21081969 1.235530296 1.3577256 1.659
957 21SouthIslandover15000Other 2 1 South Island over 15000 Other housing 1.212 0.756645384 0.796468825 0.884965361 0.941452512 1.0698324 1.212
958 22SouthIslandover15000Other 2 2 South Island over 15000 Other housing 1.476 1.264136209 1.276905262 1.239713846 1.203605676 1.3226436 1.476
959 23SouthIslandover15000Other 2 3 South Island over 15000 Other housing 1.486 0.89303164 0.911256775 1.072066794 1.165289994 1.1770606 1.486
960 24SouthIslandover15000Other 2 4 South Island over 15000 Other housing 1.395 0.955573561 1.098360415 1.144125432 1.20434256 1.309068 1.395
var siuColours = { black: "#262638",
purple: "#414258",
purple10: "#5B5C72",
purple20: "#74758B",
purple30: "#8E8FA5",
teal: "#588D97",
teal10: "#72A7B1",
teal20: "#8BC0CA",
teal30: "#A5DAE4",
green: "#315259",
green10: "#4B6C73",
green20: "#64858C",
green30: "#7E9FA6",
orange: "#F47C20",
orange10: "#FF963A",
orange20: "#FFAF53",
orange30: "#FFC96D",
greyDark: "#BDBAC0",
greyLight: "#D1D3D4"
};
function roundUpToNearestFive(n) {
return 5 * ( Math.ceil(n/5) );;
};
function formatNumberWithCommas(n) {
var numberSegment = n.toString().split(".");
numberSegment[0] = numberSegment[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return numberSegment.join(".");
}
//http://trentrichardson.com/2010/04/06/compute-linear-regressions-in-javascript/
function linearRegression(y,x){
var lr = {};
var n = y.length;
var sum_x = 0;
var sum_y = 0;
var sum_xy = 0;
var sum_xx = 0;
var sum_yy = 0;
for (var i = 0; i < y.length; i++) {
sum_x += x[i];
sum_y += y[i];
sum_xy += (x[i]*y[i]);
sum_xx += (x[i]*x[i]);
sum_yy += (y[i]*y[i]);
}
lr['slope'] = (n * sum_xy - sum_x * sum_y) / (n*sum_xx - sum_x * sum_x);
lr['intercept'] = (sum_y - lr.slope * sum_x)/n;
lr['r2'] = Math.pow((n*sum_xy - sum_x*sum_y)/Math.sqrt((n*sum_xx-sum_x*sum_x)*(n*sum_yy-sum_y*sum_y)),2);
return lr;
};
//http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
function capitalizeFirstLetter(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
};
var addEvent = function(object, type, callback) {
if (object == null || typeof(object) == 'undefined') return;
if (object.addEventListener) {
object.addEventListener(type, callback, false);
} else if (object.attachEvent) {
object.attachEvent("on" + type, callback);
} else {
object["on"+type] = callback;
}
};
var oneDecimalPlace = d3.format(".1f");
/*.axis-top path,
.axis-bottom path,
.axis-top line,
.axis-bottom line {
fill: none;
stroke: #D1D3D4;
}*/
.domain {
fill: none;
stroke: #BDBAC0;
}
.axis-right {
shape-rendering: auto;
stroke: #D1D3D4;
fill: none;
}
.gridLine {
stroke-dasharray: 2, 2;
stroke: #D1D3D4;
fill: none;
}
.axis-right text,
.tick text {
font: 10px sans-serif;
fill: #D1D3D4;
}
.cells path {
fill: none;
pointer-events: all;
}
.cells :hover circle {
stroke: #262638;
}
.x-label {
text-anchor: middle;
}
.positive-label {
text-anchor: start;
}
.y-label,
.negative-label {
text-anchor: end;
}
.x-label,
.avg-label
{
text-anchor: middle;
}
.g-family-line,
.family-line {
stroke: #BDBAC0;
fill: none;
}
.selector {
display: inline-block;
margin: 1em;
}
.avg-line line {
stroke: black;
fill: none;
stroke-dasharray: 4, 4;
}
.avg-line text {
fill: black;
}
.g-outcome-lines path {
fill: none;
stroke: #262638;
}
:root {
--siu-black: #262638;
--siu-purple: #414258;
--siu-purple10: #5B5C72;
--siu-purple20: #74758B;
--siu-purple30: #8E8FA5;
--siu-teal: #588D97;
--siu-teal10: #72A7B1;
--siu-teal20: #8BC0CA;
--siu-teal30: #A5DAE4;
--siu-green: #315259;
--siu-green10: #4B6C73;
--siu-green20: #64858C;
--siu-green30: #7E9FA6;
--siu-orange: #F47C20;
--siu-orange10: #FF963A;
--siu-orange20: #FFAF53;
--siu-orange30: #FFC96D;
--siu-greyDark: #BDBAC0;
--siu-greyLight: #D1D3D4;
}
body {
font-family: "Arial", sans-serif;
font-size: 12px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment