├── LICENSE ├── README.md ├── dv.js ├── examples ├── profile │ ├── benchmark.html │ ├── dv.profile.js │ └── splom.html └── query │ ├── benchmark.html │ ├── generate_data.js │ └── query.html └── lib └── d3.v2.min.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Stanford University 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * The name Stanford University may not be used to endorse or promote products 15 | derived from this software without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 | DISCLAIMED. IN NO EVENT SHALL STANFORD UNIVERSITY BE LIABLE FOR ANY DIRECT, 21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Datavore 2 | 3 | **Datavore** is a small in-browser database engine written in JavaScript. 4 | Datavore enables you to perform fast aggregation queries within web-based 5 | analytics or visualization applications. Datavore consists of an in-memory 6 | column-oriented database implemented using standard JavaScript arrays. The 7 | system provides support for filtering and group-by aggregation queries. When 8 | run within an optimized JavaScript environment, Datavore can complete queries 9 | over million-element data tables at interactive (sub-100ms) rates. 10 | 11 | ### Getting Started 12 | 13 | Simply reference the script `dv.js` within your web page to import Datavore. 14 | The included example files include demonstrations of Datavore's functionality 15 | along with performance benchmarks. The `profile` example shows how Datavore 16 | can be used to support high-performance brushing and linking among 17 | visualizations using the [D3](http://github.com/mbostock/d3) framework. 18 | 19 | ### Creating A Datavore Table 20 | 21 | A Datavore table is simply a collection of data columns, each realized as a 22 | JavaScript array. To create a table instance, you can either initialize the 23 | full table through the constructor or add columns one-by-one. For instance: 24 | 25 | var colA = ["a","a","b","b","c"]; 26 | var colB = [0,1,2,3,4]; 27 | 28 | // create a table in one call by bundling up columns 29 | var tab1 = dv.table([ 30 | {name:"A", values:colA, type:dv.type.nominal}, 31 | {name:"B", values:colB, type:dv.type.numeric} 32 | ]); 33 | 34 | // create a table adding one column at a time 35 | // the resulting 'tab2' should be identical to 'tab1' 36 | var tab2 = dv.table(); 37 | tab2.addColumn("A", colA, dv.type.nominal); 38 | tab2.addColumn("B", colB, dv.type.numeric); 39 | 40 | In addition to the column name and array of values, each column must have a 41 | specified data type, one of `dv.type.nominal`, `dv.type.ordinal`, 42 | `dv.type.numeric`, or `dv.type.unknown`. Numeric means the column contains numbers 43 | that can be aggregated (e.g., summed, averaged, etc). Nominal values are 44 | category labels without a meaningful sort order, while ordinal values can be 45 | meaningfully sorted. 46 | 47 | Datavore treats nominal and ordinal data in a special way: it recodes the 48 | input array values as zero-based integers (much like a 49 | [star schema](http://en.wikipedia.org/wiki/Star_schema)). The unique values 50 | in the input array are sorted and placed into a lookup table. Mapping strings 51 | and other data types to integer codes enables faster query performance. 52 | 53 | ### Accessing Table Values 54 | 55 | You can access values within a Datavore table directly via array indices or 56 | through the table `get` method. For nominal or ordinal types, direct access will 57 | return coded integers. The `get` method always returns the original value. 58 | 59 | // both array indices and the "get" method use (column, row) ordering 60 | alert(tab1[0][1]); // 1st column, 2nd row, coded --> prints "0" 61 | alert(tab1.get(0,1)); // 1st column, 2nd row, uncoded --> prints "a" 62 | 63 | // directly accessing the lookup table (lut) to decode a value 64 | // included for demo purposes only; use the "get" method instead! 65 | // 1st column, 2nd row, uncoded --> prints "a" 66 | alert(tab1[0].lut[tab1[0][1]]); 67 | 68 | You can either access columns by their numerical index (as above) or by name: 69 | 70 | // accessing table values by column name 71 | alert(tab1["A"][1]); // 1st column, 2nd row, coded --> prints "0" 72 | alert(tab1.get("A",1)); // 1st column, 2nd row, uncoded --> prints "a" 73 | 74 | **WARNING**: *Datavore column names should NOT be numbers.* If you use column 75 | names that JavaScript can interpret as integer values ("00") you will likely 76 | experience unexpected (and undesirable) behavior. 77 | 78 | ### Filtering Queries 79 | 80 | Datavore tables support two kinds of queries: filtering operations and 81 | group-by aggregation. Filtering queries simply filter table contents 82 | according to a predicate function; these are similar to simple SQL queries 83 | with a WHERE clause. The filtering function takes a table instance and row 84 | number as arguments and returns a new Datavore table instance. 85 | 86 | // creates a new table with 3 rows: [["b","b","c"], [2,3,4]] 87 | var filtered_table = tab1.where(function(table, row) { 88 | return table.get("B", row) > 1; 89 | }); 90 | 91 | *NOTE*: To ensure that tables created by various filtering queries are 92 | compatible with each other, nominal and ordinal columns within the result 93 | tables will always have the same lookup table as the original table, even if 94 | some unique values have been completely filtered out. As a result you may 95 | see some unexpected zero values returned when running dense aggregation 96 | queries on filtered tables. 97 | 98 | ### Aggregation Queries 99 | 100 | The primary use case for Datavore is running aggregation queries. These queries 101 | allow you to calculate counts, sums, averages, standard deviations, and minimum 102 | or maximum values for a column, optionally grouped according to nominal or 103 | ordinal dimensions. These queries are similar to SQL queries with group-by clauses. 104 | 105 | // count all rows in the table -> returns [[5]] 106 | var counts = tab1.query({vals:[dv.count()]}); 107 | 108 | // count rows and sum values in 2nd column, grouped by 1st column 109 | // returns -> [["a","b","c"], [2,2,1], [1,5,4]]] 110 | var groups = tab1.query({dims:[0], vals:[dv.count(), dv.sum(1)]}); 111 | 112 | // same as before, but now with extra parameter "code:true" 113 | // nominal/ordinal types remain coded integers, NOT original values 114 | // returns -> [[0,1,2], [2,2,1], [1,5,4]]] 115 | var uncode = tab1.query({dims:[0], vals:[dv.count(), dv.sum(1)], code:true}); 116 | 117 | // count all table rows where first column != "a" 118 | // returns -> [["a","b","c"], [0,2,1]] 119 | var filter = tab1.query({dims:[0], vals:[dv.count()], where: 120 | function(table, row) { return table.get("A",row) != "a"; } 121 | }); 122 | 123 | The return value of the `query` method is an array of arrays. Note that the 124 | return value is *not* a Datavore table object. The input to the query method 125 | should be a JavaScript object with up to four parameters: `vals` (required), 126 | `dims`, `where`, and `code`. 127 | 128 | The `vals` parameter indicates the aggregation functions to run. The 129 | available operators are `dv.count`, `dv.sum`, `dv.min`, `dv.max`, `dv.avg`, 130 | `dv.variance`, and `dv.stdev`. All aggregation operators accept a single column 131 | index or name as input (except for `dv.count`, which ignores any input). 132 | 133 | The `dims` parameter indicates the dimensions to group by. This 134 | should be an array containing column indices, column names or special dimension 135 | query operators (`dv.bin` or `dv.quantile`). 136 | 137 | The `where` parameter specifies a predicate function for filtering the 138 | table (as in `where` queries). Filtering is performed *prior* to aggregation. 139 | 140 | If true, the `code` parameter indicates that nominal and ordinal values 141 | should be left as coded integers. If false (the default), coded integers are 142 | mapped back to the original values in the query result arrays. 143 | 144 | #### Dense Queries vs. Sparse Queries 145 | 146 | The standard aggregate query uses a *dense* representation of the resulting 147 | data space. What this means is that all dimensions are realized, even if the 148 | resulting aggregate values are zero. So if you group by columns A and B, 149 | and column A has 3 unique values and column B has 4 unique values, then 150 | the resulting aggregate table will have 3*4=12 rows, including zero values. 151 | 152 | Datavore also supports a *sparse* representation that does not include rows 153 | for zero values. To use a sparse representation, use the `sparse_query` 154 | function, like so: 155 | 156 | // non-zero counts of all table rows where first column != "a" 157 | // returns -> [["b","c"], [2,1]] 158 | var sparse = tab1.sparse_query({dims:[0], vals:[dv.count()], where: 159 | function(table, row) { return table.get("A",row) != "a"; } 160 | }); 161 | 162 | So why the different query types? Dense queries can be calculated faster 163 | – by "materializing" the full dimensionality of the aggregated data one 164 | can use an array to store all the intermediate results. The sparse 165 | representation instead uses an associative array (a JavaScript object 166 | instance), which induces a higher overhead for object value lookups. On the 167 | other hand, dense queries over high-dimensional data can produce very large 168 | result arrays; sometimes these can be too large to fit in the browser's memory 169 | footprint. So, if you are dealing with high-dimensional aggregates (concretely, 170 | if the product of the set sizes of your group-by dimensions is > 100,000 rows) 171 | you should consider using `sparse_query`. However, if the total number of 172 | aggregate rows is reasonable (as is typically the case), or you want to 173 | explicitly include zero-valued cells, use the normal `query` method for faster 174 | performance. 175 | 176 | *NOTE:* Dense queries are processed by the `dense_query` function. The 177 | `query` function is simply an alias for `dense_query`. 178 | 179 | ### Extensibility 180 | 181 | Datavore can be extended with new dimensional and (with some effort) 182 | aggregate operators. To create your own dimensional operator, view the source 183 | code for `dv.bin` and `dv.quantile`, and follow their example. Adding new 184 | aggregate operators is possible but more complex. You will need to add a new 185 | module (following in the foot steps of `dv.sum`, `dv.avg`, etc) and add new 186 | logic to the inner loop of the query processor (for both dense and sparse 187 | queries). *This is not for the faint of heart!* The query processor avoids 188 | making function calls within its inner loop — this helps make Datavore 189 | much faster, but at some cost to extensibility. You will have to modify the 190 | guts of the engine to add new aggregate operators. -------------------------------------------------------------------------------- /dv.js: -------------------------------------------------------------------------------- 1 | var dv = (function() { 2 | /** 3 | * The top-level Datavore namespace. All public methods and fields should be 4 | * registered on this object. Note that core Datavore source is surrounded by an 5 | * anonymous function, so any other declared globals will not be visible outside 6 | * of core methods. This also allows multiple versions of Datavore to coexist, 7 | * since each version will see their own dv namespace. 8 | * 9 | * @namespace The top-level Datavore namespace, dv. 10 | */ 11 | var dv = {version: "1.0.0"}; 12 | 13 | dv.array = function(n) { 14 | var a = Array(n); 15 | for (var i = n; --i >= 0;) { a[i] = 0; } 16 | return a; 17 | } 18 | 19 | // -- RANDOM NUMBER GENERATORS ------------------------------------------------ 20 | 21 | dv.rand = {}; 22 | 23 | dv.rand.uniform = function(min, max) { 24 | min = min || 0; 25 | max = max || 1; 26 | var delta = max - min; 27 | return function() { 28 | return min + delta * Math.random(); 29 | } 30 | }; 31 | 32 | dv.rand.integer = function(a, b) { 33 | if (b === undefined) { 34 | b = a; 35 | a = 0; 36 | } 37 | return function() { 38 | return a + Math.max(0, Math.floor(b * (Math.random() - 0.001))); 39 | } 40 | } 41 | 42 | dv.rand.normal = function(mean, stdev) { 43 | mean = mean || 0; 44 | stdev = stdev || 1; 45 | var next = undefined; 46 | return function() { 47 | var x = 0, y = 0, rds, c; 48 | if (next !== undefined) { 49 | x = next; 50 | next = undefined; 51 | return x; 52 | } 53 | do { 54 | x = Math.random() * 2 - 1; 55 | y = Math.random() * 2 - 1; 56 | rds = x * x + y * y; 57 | } while (rds == 0 || rds > 1); 58 | c = Math.sqrt(-2 * Math.log(rds) / rds); // Box-Muller transform 59 | next = mean + y * c * stdev; 60 | return mean + x * c * stdev; 61 | } 62 | } 63 | // -- DATA TABLE -------------------------------------------------------------- 64 | 65 | dv.type = { 66 | nominal: "nominal", 67 | ordinal: "ordinal", 68 | numeric: "numeric", 69 | unknown: "unknown" 70 | }; 71 | 72 | dv.table = function(input) 73 | { 74 | var table = []; // the data table 75 | 76 | table.addColumn = function(name, values, type, iscolumn) { 77 | type = type || dv.type.unknown; 78 | var compress = (type === dv.type.nominal || type === dv.type.ordinal); 79 | var vals = values; 80 | 81 | if (compress && !iscolumn) { 82 | vals = []; 83 | vals.lut = code(values); 84 | for (var i = 0, map=dict(vals.lut); i < values.length; ++i) { 85 | vals.push(map[values[i]]); 86 | } 87 | vals.get = function(idx) { return this.lut[this[idx]]; } 88 | } else if (!iscolumn) { 89 | vals.get = function(idx) { return this[idx]; } 90 | } 91 | vals.name = name; 92 | vals.index = table.length; 93 | vals.type = type; 94 | 95 | table.push(vals); 96 | table[name] = vals; 97 | }; 98 | 99 | table.removeColumn = function(col) { 100 | col = table[col] || null; 101 | if (col != null) { 102 | delete table[col.name]; 103 | table.splice(col.index, 1); 104 | } 105 | return col; 106 | }; 107 | 108 | table.rows = function() { return table[0] ? table[0].length : 0; }; 109 | 110 | table.cols = function() { return table.length; }; 111 | 112 | table.get = function(col, row) { return table[col].get(row); } 113 | 114 | table.dense_query = function(q) { 115 | var tab = q.where ? table.where(q.where) : table; 116 | var dims = [], sz = [1], hasDims = q.dims; 117 | if (hasDims) { 118 | sz = []; 119 | for (i = 0; i < q.dims.length; ++i) { 120 | var dim = q.dims[i], type = typeof dim; 121 | if (type === "string" || type === "number") { 122 | col = tab[dim]; 123 | } else if (dim.array) { 124 | col = dim.array(tab[dim.value]); 125 | } 126 | dims.push(col); 127 | sz.push(col.lut.length); 128 | } 129 | } 130 | 131 | var vals = q.vals, // aggregate query operators 132 | C = sz.reduce(function(a,b) { return a * b; }, 1), // cube cardinality 133 | N = tab[0].length, p, col, v, name, expr, // temp vars 134 | cnt, sum, ssq, min, max, // aggregate values 135 | _cnt, _sum, _ssq, _min, _max, // aggregate flags 136 | ctx = {}, emap = {}, exp = [], lut, // aggregate state vars 137 | i = 0, j = 0, k = 0, l = 0, idx = 0, len, slen = sz.length; // indices 138 | 139 | // Identify Requested Aggregates 140 | var star = false; 141 | for (i = 0; i < vals.length; ++i) { 142 | var req = vals[i].init(); 143 | for (expr in req) { 144 | if (expr == "*") { 145 | req[expr].map(function(func) { 146 | ctx[func] = dv.array(C); 147 | }); 148 | star = true; 149 | } else { 150 | idx = tab[expr].index; 151 | name = tab[expr].name; 152 | req[expr].map(function(func) { 153 | ctx[func + "_" + name] = (ctx[func + "_" + idx] = dv.array(C)); 154 | }); 155 | if (!emap[idx]) { 156 | emap[idx] = true; 157 | exp.push(idx); 158 | } 159 | } 160 | } 161 | } 162 | if (exp.length == 0 && star) { exp.push(-1) }; 163 | 164 | // Compute Cube Index Coefficients 165 | for (i = 0, p = [1]; i < slen; ++i) { 166 | p.push(p[i] * sz[i]); 167 | } 168 | 169 | // Execute Query: Compute Aggregates 170 | for (j = 0, len = exp.length; j < len; ++j) { 171 | expr = exp[j]; 172 | cnt = ctx["cnt"]; _cnt = (cnt && j==0); 173 | sum = ctx["sum_" + expr]; _sum = (sum !== undefined); 174 | ssq = ctx["ssq_" + expr]; _ssq = (ssq !== undefined); 175 | min = ctx["min_" + expr]; _min = (min !== undefined); 176 | max = ctx["max_" + expr]; _max = (max !== undefined); 177 | col = tab[expr]; 178 | outer: 179 | for (i = 0; i < N; ++i) { 180 | for (idx = 0, k = 0; k < slen; ++k) { 181 | // compute cube index 182 | l = (hasDims ? dims[k][i] : 0); 183 | if (l < 0) continue outer; 184 | idx += p[k] * l; 185 | } 186 | if (col) { v = col[i]; } 187 | if (_cnt) { cnt[idx] += 1; } 188 | if (_sum) { sum[idx] += v; } 189 | if (_ssq) { ssq[idx] += v * v; } 190 | if (_min && v < min[idx]) { min[idx] = v; } 191 | if (_max && v > max[idx]) { max[idx] = v; } 192 | } 193 | } 194 | 195 | // Generate Results 196 | var result = [], stride = 1, s, val, code = q.code || false; 197 | for (i = 0; i < dims.length; ++i) { 198 | col = []; 199 | lut = dims[i].lut; 200 | s = sz[i]; 201 | val = 0; 202 | for (j = 0, k = 0, c = -1; j < C; ++j, ++k) { 203 | if (k == stride) { k = 0; val = (val + 1) % s; } 204 | col[j] = code ? val : lut[val]; 205 | } 206 | stride *= s; 207 | col.unique = lut.length; 208 | result.push(col); 209 | } 210 | vals.map(function(op) { result.push(op.done(ctx)); }); 211 | return result; 212 | }; 213 | 214 | table.query = table.dense_query; 215 | 216 | table.sparse_query = function(q) { 217 | var tab = q.where ? table.where(q.where) : table; 218 | var dims = [], sz = [1], hasDims = q.dims; 219 | if (hasDims) { 220 | sz = []; 221 | for (i=0; i max[idx])) { 304 | max[idx] = v; 305 | } 306 | } 307 | } 308 | 309 | // Generate Results 310 | var rr = vals.map(function(op) { return op.done(ctx); }); 311 | var keys = rr[0]; 312 | if (rr.length > 1) { 313 | keys = {}; 314 | rr.forEach(function(o) { for (var k in o) keys[k] = 1; }); 315 | } 316 | var result = dims.map(function() { return []; }); 317 | vals.forEach(function() { result.push([]); }); 318 | len = dims.length; 319 | 320 | for (k in keys) { 321 | // map index i to dimensional indices 322 | var nn = C, uv, div; 323 | for (i = k, j = len; --j >= 0;) { 324 | uv = dims[j].lut.length; 325 | div = ~~(nn / uv); 326 | result[j].push(dims[j].lut[~~(i / div)]); 327 | i = i % div; 328 | nn = ~~(nn / uv); 329 | } 330 | for (j = 0; j < rr.length; ++j) { 331 | val = rr[j][k]; 332 | result[len + j].push(val === undefined ? 0 : val); 333 | } 334 | } 335 | return result; 336 | }; 337 | 338 | table.where = function(f) { 339 | var nrows = table.rows(), 340 | ncols = table.cols(); 341 | 342 | // initialize result table 343 | var result = dv.table([]); 344 | for (var i = 0; i < ncols; ++i) { 345 | result.push([]); 346 | result[i].name = table[i].name; 347 | result[i].type = table[i].type; 348 | result[i].index = i; 349 | result[table[i].name] = result[i]; 350 | if (table[i].lut) { result[i].lut = table[i].lut; } 351 | } 352 | 353 | // populate result table 354 | for (var row = 0, j = -1; row < nrows; ++row) { 355 | if (f(table, row)) { 356 | for (i = 0, ++j; i < ncols; ++i) { 357 | result[i][j] = table[i][row]; 358 | } 359 | } 360 | } 361 | return result; 362 | }; 363 | 364 | /** @private */ 365 | function code(a) { 366 | var c = [], d = {}, v; 367 | for (var i=0, len=a.length; i maxv) { maxv = val; } 515 | } 516 | if (minb) { minv = Math.floor(minv / step) * step; } 517 | if (maxb) { maxv = Math.ceil(maxv / step) * step; } 518 | } 519 | // compute index array 520 | var a = [], lut = (a.lut = []), 521 | range = (maxv - minv), unique = Math.ceil(range / step); 522 | for (i = 0; i < N; ++i) { 523 | val = values[i]; 524 | if (val < minv || val > maxv) { a.push(-1); } 525 | else if (val == maxv) { a.push(unique - 1); } 526 | else { a.push(~~((values[i] - minv) / step)); } 527 | } 528 | for (i = 0; i < unique; ++i) { 529 | // multiply b/c adding garners round-off error 530 | lut.push(minv + i * step); 531 | } 532 | return a; 533 | }; 534 | op.step = function(x) { 535 | if (x === undefined) return step; 536 | step = x; 537 | return op; 538 | }; 539 | op.min = function(x) { 540 | if (x === undefined) return min; 541 | min = x; 542 | return op; 543 | }; 544 | op.max = function(x) { 545 | if (x === undefined) return max; 546 | max = x; 547 | return op; 548 | }; 549 | op.value = expr; 550 | return op; 551 | }; 552 | 553 | dv.quantile = function(expr, n) { 554 | function search(array, value) { 555 | var low = 0, high = array.length - 1; 556 | while (low <= high) { 557 | var mid = (low + high) >> 1, midValue = array[mid]; 558 | if (midValue < value) { low = mid + 1; } 559 | else if (midValue > value) { high = mid - 1; } 560 | else { return mid; } 561 | } 562 | var i = -low - 1; 563 | return (i < 0) ? (-i - 1) : i; 564 | } 565 | 566 | var op = {}; 567 | op.array = function(values) { 568 | // get sorted data values 569 | var i, d = values.sorted; 570 | if (!d) { 571 | var cmp; 572 | if (values.type && values.type === "numeric") { 573 | cmp = function(a,b) { return a - b; } 574 | } else { 575 | cmp = function(a,b) { return a < b ? -1 : a > b ? 1 : 0; } 576 | } 577 | values.sorted = (d = values.slice().sort(cmp)); 578 | } 579 | // compute quantile boundaries 580 | var q = [d[0]], a = [], lut = (a.lut = []); 581 | for (i = 1; i <= n; ++i) { 582 | q[i] = d[~~(i * (d.length - 1) / n)]; 583 | lut.push(i - 1); 584 | } 585 | // iterate through data and label quantiles 586 | for (i = 0; i < values.length; ++i) { 587 | a.push(Math.max(0, search(q, values[i]) - 1)); 588 | } 589 | return a; 590 | } 591 | op.bins = function(x) { 592 | if (x === undefined) return n; 593 | n = x; 594 | return op; 595 | } 596 | op.value = expr; 597 | return op; 598 | }; 599 | 600 | return dv; })(); -------------------------------------------------------------------------------- /examples/profile/benchmark.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Profiler Benchmarks 4 | 5 | 6 | 7 | 24 | 25 | 26 | Data Profiler Benchmarks 27 |
28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 | 51 | 52 |
53 |
54 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /examples/profile/dv.profile.js: -------------------------------------------------------------------------------- 1 | dv.EPSILON = 1e-9; 2 | 3 | dv.logFloor = function(x, b) { 4 | return (x > 0) 5 | ? Math.pow(b, Math.floor(Math.log(x) / Math.log(b))) 6 | : -Math.pow(b, -Math.floor(-Math.log(-x) / Math.log(b))); 7 | }; 8 | 9 | function dv_bins(data, bins, min, max, step) { 10 | var bmin = min !== undefined, 11 | bmax = max !== undefined; 12 | min = bmin ? min : d3.min(data); 13 | max = bmax ? max : d3.max(data); 14 | var span = max - min; 15 | 16 | /* Special case: empty, invalid or infinite span. */ 17 | if (!span || !isFinite(span)) return [min, min, 1]; 18 | 19 | var s = Math.pow(10, Math.round(Math.log(span) / Math.log(10)) - 1), 20 | d = [Math.floor(min / s) * s, Math.ceil(max / s) * s]; 21 | if (bmin) d[0] = min; 22 | if (bmax) d[1] = max; 23 | 24 | if (step === undefined) { 25 | step = dv.logFloor((d[1]-d[0])/bins, 10); 26 | var err = bins / ((d[1]-d[0]) / step); 27 | if (err <= .15) step *= 10; 28 | else if (err <= .35) step *= 5; 29 | else if (err <= .75) step *= 2; 30 | } 31 | d.push(step); 32 | 33 | return d; 34 | } 35 | 36 | // query for brushing & linking data, checking cache first 37 | function dv_profile_cache(evt, query) { 38 | //if (!dv.profile.cache) return evt.data.query(query); 39 | 40 | var cmp = function(a,b) { 41 | return keys[a] < keys[b] ? -1 : (keys[a] > keys[b] ? 1 : 0); 42 | } 43 | var dims = query.dims, idx = [], i, dat 44 | keys = dims.map(function(d,i) { idx.push(i); return d/*.key*/; }); 45 | idx.sort(cmp); 46 | var key = idx.map(function(j) { return keys[j]; }).join("__"); 47 | 48 | if (!(dat = evt.cache[key])) { 49 | // cache miss: execute the query 50 | dims = idx.map(function(j) { return dims[j]; }); 51 | window.dat = {evt:evt, dims:dims, vals:query.vals}; 52 | dat = evt.data.query({dims:dims, vals:query.vals}); 53 | evt.cache[key] = dat; 54 | } 55 | // return table columns in correct order 56 | idx.push(idx.length); // include count column 57 | return idx.map(function(j) { return dat[j]; }); 58 | } 59 | 60 | // Profiler instace to manage plots and coordinate linked selections 61 | dv.profile = function(data) { 62 | var g = [], 63 | add = function(vis) { qdata = null; g.push(vis); return vis; }, 64 | qdata = null, // rolled-up data to serve as base for all queries 65 | timeoutID; 66 | 67 | // retrieve query data 68 | g.qdata = function() { return qdata; }; 69 | 70 | // compute rollup of query data 71 | function qrollup(g, data) { 72 | // first collect all the bins 73 | var bins = {}, keys, qd; 74 | g.forEach(function(p) { p.fields().forEach(function(f,i) { 75 | bins[f] = p.query().dims[i]; 76 | }); }); 77 | keys = d3.keys(bins).sort(); 78 | qd = data.sparse_query({ 79 | dims: keys.map(function(k) { return bins[k]; }), 80 | vals: [dv.count("*")] 81 | }); 82 | var table = dv.table(); 83 | qd.forEach(function(c,i) { 84 | table.addColumn(i, c, dv.type[i==qd.length-1?"numeric":"ordinal"]); 85 | }); 86 | return table; 87 | } 88 | 89 | // initialize this profiler instance 90 | g.init = function() { 91 | qdata = qrollup(g, data); 92 | g.forEach(function(p) { p.update(); }); 93 | } 94 | 95 | // run a performance benchmark on the current instance 96 | g.benchmark = function(callback) { 97 | if (!console || !window.webkitRequestAnimationFrame) { 98 | alert("Sorry, the benchmarks require Google Chrome."); 99 | return; 100 | } 101 | var bd = {}; 102 | bd.frames = []; 103 | bd.select = []; 104 | bd.render = []; 105 | 106 | var gi=-1, f; 107 | var bins = qdata[0].lut, idx=0, inc=0, count=0; 108 | var t0, t1, t2; 109 | 110 | function printstats() { 111 | var af = d3.sum(bd.frames) / bd.frames.length; 112 | var as = d3.sum(bd.select) / bd.select.length; 113 | var ar = d3.sum(bd.render) / bd.render.length; 114 | var sf = bd.frames.reduce(function(a,b) { return a + b*b; }, 0); 115 | var ss = bd.select.reduce(function(a,b) { return a + b*b; }, 0); 116 | var sr = bd.render.reduce(function(a,b) { return a + b*b; }, 0); 117 | var df = Math.sqrt(sf/bd.frames.length - af*af); 118 | var ds = Math.sqrt(ss/bd.frames.length - as*as); 119 | var dr = Math.sqrt(sr/bd.frames.length - ar*ar); 120 | console.log([af,df,as,ds,ar,dr] 121 | .map(function(d) { return d.toFixed(3); }).join(",")); 122 | } 123 | 124 | var next = function() { 125 | for (++gi; g[gi] && g[gi].fields().length==2; ++gi); 126 | if (gi >= g.length) { 127 | printstats(); 128 | callback(); 129 | return; 130 | } 131 | f = g[gi].fields()[0]; 132 | bins = qdata[f].lut; 133 | idx = 0; count = 0; inc = bins[1]-bins[0]; 134 | step(); 135 | } 136 | 137 | var step = function() { 138 | t0 = Date.now(); 139 | if (count > 0) { 140 | bd.frames.push(t0-t1); 141 | bd.render.push(t0-t2); 142 | } 143 | var r = {}; 144 | r[f] = [bins[idx], bins[idx]+inc]; 145 | r[f].ex = (idx == bins.length-1); 146 | idx = (idx + 1) % (bins.length); 147 | count++; 148 | t1 = Date.now(); 149 | g.select({source:g[gi], range:r}, -1); 150 | t2 = Date.now(); 151 | if (count < 5*(qdata[f].lut.length)+1) { 152 | bd.select.push(t2-t1); 153 | window.webkitRequestAnimationFrame(step); 154 | } else { next(); } 155 | } 156 | next(); 157 | return bd; 158 | } 159 | 160 | // add a plot to this profiler instance 161 | g.plot = function() { 162 | var type = arguments[0], args = []; 163 | for (var i=1; i v || v > x[1] || (!x.ex && v == x[1])) 195 | return false; 196 | } 197 | return true; 198 | }; 199 | } 200 | e.data = qdata.where(filter); 201 | } 202 | for (var i=0; i 0 && val < 2 ? 2 : val; 302 | }); 303 | } else { 304 | vis.selectAll("rect.brush") 305 | .attr("height", 0); 306 | } 307 | }; 308 | 309 | hist.rollup = function() { return roll; }; 310 | 311 | hist.fields = function() { 312 | if (arguments.length == 0) return fields; 313 | fields = arguments; 314 | field = fields[0]; 315 | return hist; 316 | }; 317 | 318 | hist.options = function() { 319 | if (arguments.length == 0) return fields; 320 | opt = arguments[0]; 321 | bins = opt.bins || bins; 322 | w = opt.width || w; 323 | h = opt.height || h; 324 | hist.update(); 325 | return hist; 326 | }; 327 | 328 | hist.type = function() { return "histogram"; }; 329 | 330 | hist.initUI(); 331 | hist.initBins(); 332 | return hist; 333 | }; 334 | 335 | // Binned scatterplot visualization component 336 | dv.scatter = function(id, fields, opt) 337 | { 338 | var group = this, 339 | scat = {}, 340 | data = group.data, roll, sroll, 341 | xfield = fields[0], 342 | yfield = fields[1], 343 | bins = opt.bins || 10, 344 | xbins = 0, ybins = 0, 345 | w = opt.width || 400, 346 | h = opt.height || 400, 347 | bx, by, xstep, ystep, q, qb, 348 | x, y, o, vis, xmin, xmax, ymin, ymax, squareWidth, squareHeight; 349 | 350 | scat.query = function() { return q; }; 351 | 352 | function indices(t) { 353 | var idx = [], len = t[2].length; 354 | for (var i=0; i 0) idx.push(i); 356 | } 357 | return idx; 358 | } 359 | 360 | scat.initUI = function() { 361 | d3.select("#"+id+" svg").remove(); 362 | vis = d3.select("#"+id).append("svg:svg") 363 | .attr("width", w) 364 | .attr("height", h); 365 | }; 366 | 367 | scat.initBins = function() { 368 | var xbin = dv_bins(data[xfield], bins, 369 | opt.xmin, opt.xmax, opt.xstep); 370 | xmin = xbin[0]; xmax = xbin[1]; xstep = xbin[2]; 371 | bx = dv.bin(xfield, xstep, xmin, xmax); 372 | 373 | var ybin = dv_bins(data[yfield], bins, 374 | opt.ymin, opt.ymax, opt.ystep); 375 | ymin = ybin[0]; ymax = ybin[1]; ystep = ybin[2]; 376 | by = dv.bin(yfield, ystep, ymin, ymax); 377 | 378 | scat.xbin = xbin; 379 | scat.ybin = ybin; 380 | xbins = Math.ceil((xmax-xmin)/xstep); 381 | ybins = Math.ceil((ymax-ymin)/ystep); 382 | 383 | q = {dims:[bx, by], vals:[dv.count("*")]}; 384 | qb = {dims:[xfield, yfield], vals:[dv.sum(data.length)]}; 385 | }; 386 | 387 | scat.update = function() { 388 | function opacity(i) { 389 | var v = roll[2][i]; 390 | return v==0 ? 0 : o(v); 391 | } 392 | function mouseout() { 393 | d3.select(this) 394 | .style("fill", null) 395 | .attr("fill-opacity", opacity); 396 | group.select({source:scat}); 397 | } 398 | function mouseover(i) { 399 | d3.select(this) 400 | .style("fill", "red") 401 | .attr("fill-opacity", 1); 402 | var vx = roll[0][i], vy = roll[1][i], r = {}; 403 | r[xfield] = [vx, vx + xstep]; 404 | r[xfield].ex = Math.abs(vx + xstep - xmax) < dv.EPSILON; 405 | r[yfield] = [vy, vy + ystep]; 406 | r[yfield].ex = Math.abs(vy + ystep - ymax) < dv.EPSILON; 407 | group.select({source:scat, range: r}); 408 | } 409 | 410 | roll = group.qdata().query(qb); //data.query(q); 411 | 412 | var sx = Math.floor((w-10)/xbins + 0.5), 413 | sy = Math.floor(h/ybins + 0.5), 414 | sw = sx * xbins, 415 | sh = sy * ybins; 416 | 417 | x = d3.scale.linear().domain([xmin, xmax]).range([0, sw]); 418 | y = d3.scale.linear().domain([ymin, ymax]).range([sh-sy, -sy]); 419 | o = d3.scale.linear().domain([0, d3.max(roll[2])]).range([0.15,1]); 420 | 421 | var sel = vis.selectAll("rect.base") 422 | .data(indices(roll)); 423 | sel.enter().append("svg:rect") 424 | .attr("class", "base") 425 | .on("mouseover", mouseover) 426 | .on("mouseout", mouseout); 427 | sel.exit().remove(); 428 | 429 | vis.selectAll("rect.base") 430 | .attr("x", function(i) { return x(roll[0][i]); }) 431 | .attr("y", function(i) { return y(roll[1][i]); }) 432 | .attr("width", sx) 433 | .attr("height", sy) 434 | .attr("fill-opacity", opacity); 435 | 436 | squareWidth = Math.floor((w-10)/xbins + 0.5) 437 | squareHeight = Math.floor(h/ybins + 0.5) 438 | vis.selectAll("rect.brush") 439 | .data(indices(roll)) 440 | .enter().append("svg:rect") 441 | .attr("class", "brush") 442 | .attr("pointer-events", "none") 443 | .attr("fill-opacity", 0) 444 | .attr("x", 0) 445 | .attr("y", 0) 446 | .attr("width", squareWidth) 447 | .attr("height", squareHeight); 448 | }; 449 | 450 | scat.select = function(e) { 451 | if (e.data) { 452 | var sd = dv_profile_cache(e, qb); // selected data 453 | var c = d3.scale.linear() 454 | .domain([0,d3.max(sd[2])]) 455 | .range([0.15,1]); 456 | var sel = vis.selectAll("rect.brush") 457 | .data(indices(sd)) 458 | .attr("x", function(i) { return x(sd[0][i]); }) 459 | .attr("y", function(i) { return y(sd[1][i]); }) 460 | .attr("fill-opacity", function(i) { return c(sd[2][i]); }); 461 | sel.exit() 462 | .attr("fill-opacity", 0); 463 | } else { 464 | vis.selectAll("rect.brush") 465 | .attr("fill-opacity", 0); 466 | } 467 | }; 468 | 469 | scat.rollup = function() { return roll; }; 470 | 471 | scat.fields = function() { 472 | if (arguments.length == 0) return fields; 473 | fields = arguments; 474 | xfield = fields[0]; 475 | yfield = fields[1] || xfield; 476 | return scat; 477 | }; 478 | 479 | scat.options = function() { 480 | if (arguments.length == 0) return fields; 481 | opt = arguments[0]; 482 | bins = opt.bins || bins; 483 | w = opt.width || w; 484 | h = opt.height || h; 485 | scat.update(); 486 | return scat; 487 | }; 488 | 489 | scat.type = function() { return "scatter"; }; 490 | 491 | scat.initUI(); 492 | scat.initBins(); 493 | return scat; 494 | }; -------------------------------------------------------------------------------- /examples/profile/splom.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Profiler Scatterplot Matrix 4 | 5 | 6 | 7 | 24 | 25 | 26 | Data Profiler Scatter Plot Matrix (SPLOM) 27 |
28 | 29 | 30 | 31 | 32 |
33 | 34 | 35 | 36 | 37 |
38 | 39 | 40 | 41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 | 51 | 52 |
53 |
54 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /examples/query/benchmark.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Datavore Query Benchmarks 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 |
15 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /examples/query/generate_data.js: -------------------------------------------------------------------------------- 1 | function generate_data(N) { 2 | function randn(n) { 3 | return Math.max(0, Math.floor(n*(Math.random()-0.001))); 4 | } 5 | 6 | // generate synthetic data set 7 | var cols = [[],[],[]], // data columns 8 | am = ["a","b","c"], // domain of 1st col 9 | bm = d3.range(1,6); // domain of 2nd col 10 | 11 | // generate rows from random data 12 | for (var i=0; i 2 | 3 | Datavore Query Examples 4 | 5 | 6 | 7 | 12 | 13 | 14 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /lib/d3.v2.min.js: -------------------------------------------------------------------------------- 1 | (function(){function e(a,b){try{for(var c in b)Object.defineProperty(a.prototype,c,{value:b[c],enumerable:!1})}catch(d){a.prototype=b}}function g(a){var b=-1,c=a.length,d=[];while(++b=0?a.substring(b):(b=a.length,""),d=[];while(b>0)d.push(a.substring(b-=3,b+3));return d.reverse().join(",")+c}function F(a,b){return{scale:Math.pow(10,(8-b)*3),symbol:a}}function L(a){return function(b){return b<=0?0:b>=1?1:a(b)}}function M(a){return function(b){return 1-a(1-b)}}function N(a){return function(b){return.5*(b<.5?a(2*b):2-a(2-2*b))}}function O(a){return a}function P(a){return function(b){return Math.pow(b,a)}}function Q(a){return 1-Math.cos(a*Math.PI/2)}function R(a){return Math.pow(2,10*(a-1))}function S(a){return 1-Math.sqrt(1-a*a)}function T(a,b){var c;return arguments.length<2&&(b=.45),arguments.length<1?(a=1,c=b/4):c=b/(2*Math.PI)*Math.asin(1/a),function(d){return 1+a*Math.pow(2,10*-d)*Math.sin((d-c)*2*Math.PI/b)}}function U(a){return a||(a=1.70158),function(b){return b*b*((a+1)*b-a)}}function V(a){return a<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375}function W(){d3.event.stopPropagation(),d3.event.preventDefault()}function X(){var a=d3.event,b;while(b=a.sourceEvent)a=b;return a}function Y(a){var b=new x,c=0,d=arguments.length;while(++c360?a-=360:a<0&&(a+=360),a<60?d+(e-d)*a/60:a<180?e:a<240?d+(e-d)*(240-a)/60:d}function g(a){return Math.round(f(a)*255)}var d,e;return a%=360,a<0&&(a+=360),b=b<0?0:b>1?1:b,c=c<0?0:c>1?1:c,e=c<=.5?c*(1+b):c+b-c*b,d=2*c-e,bb(g(a+120),g(a),g(a-120))}function bl(a){return j(a,br),a}function bs(a){return function(){return bm(a,this)}}function bt(a){return function(){return bn(a,this)}}function bv(a,b){function f(){if(b=this.classList)return b.add(a);var b=this.className,d=b.baseVal!=null,e=d?b.baseVal:b;c.lastIndex=0,c.test(e)||(e=t(e+" "+a),d?b.baseVal=e:this.className=e)}function g(){if(b=this.classList)return b.remove(a);var b=this.className,d=b.baseVal!=null,e=d?b.baseVal:b;e=t(e.replace(c," ")),d?b.baseVal=e:this.className=e}function h(){(b.apply(this,arguments)?f:g).call(this)}var c=new RegExp("(^|\\s+)"+d3.requote(a)+"(\\s+|$)","g");if(arguments.length<2){var d=this.node();if(e=d.classList)return e.contains(a);var e=d.className;return c.lastIndex=0,c.test(e.baseVal!=null?e.baseVal:e)}return this.each(typeof b=="function"?h:b?f:g)}function bw(a){return{__data__:a}}function bx(a){return function(){return bq(this,a)}}function by(a){return arguments.length||(a=d3.ascending),function(b,c){return a(b&&b.__data__,c&&c.__data__)}}function bA(a){return j(a,bB),a}function bC(a,b,c){j(a,bG);var d=new k,e=d3.dispatch("start","end"),f=bO;return a.id=b,a.time=c,a.tween=function(b,c){return arguments.length<2?d.get(b):(c==null?d.remove(b):d.set(b,c),a)},a.ease=function(b){return arguments.length?(f=typeof b=="function"?b:d3.ease.apply(d3,arguments),a):f},a.each=function(b,c){return arguments.length<2?bP.call(a,b):(e.on(b,c),a)},d3.timer(function(g){return a.each(function(h,i,j){function p(a){return o.active>b?r():(o.active=b,d.forEach(function(a,b){(tween=b.call(l,h,i))&&k.push(tween)}),e.start.call(l,h,i),q(a)||d3.timer(q,0,c),1)}function q(a){if(o.active!==b)return r();var c=(a-m)/n,d=f(c),g=k.length;while(g>0)k[--g].call(l,d);if(c>=1)return r(),bI=b,e.end.call(l,h,i),bI=0,1}function r(){return--o.count||delete l.__transition__,1}var k=[],l=this,m=a[j][i].delay,n=a[j][i].duration,o=l.__transition__||(l.__transition__={active:0,count:0});++o.count,m<=g?p(g):d3.timer(p,m,c)}),1},0,c),a}function bE(a,b,c){return c!=""&&bD}function bF(a,b){function d(a,d,e){var f=b.call(this,a,d);return f==null?e!=""&&bD:e!=f&&c(e,f)}function e(a,d,e){return e!=b&&c(e,b)}var c=$(a);return typeof b=="function"?d:b==null?bE:(b+="",e)}function bP(a){var b=bI,c=bO,d=bM,e=bN;bI=this.id,bO=this.ease();for(var f=0,g=this.length;f=c.delay&&(c.flush=c.callback(a)),c=c.next;var d=bU()-b;d>24?(isFinite(d)&&(clearTimeout(bS),bS=setTimeout(bT,d)),bR=0):(bR=1,bV(bT))}function bU(){var a=null,b=bQ,c=Infinity;while(b)b.flush?b=a?a.next=b.next:bQ=b.next:(c=Math.min(c,b.then+b.delay),b=(a=b).next);return c}function bW(a){var b=[a.a,a.b],c=[a.c,a.d],d=bY(b),e=bX(b,c),f=bY(bZ(c,b,-e))||0;b[0]*c[1]2?cn:cm,i=d?ba:_;return e=g(a,b,i,c),f=g(b,a,i,d3.interpolate),h}function h(a){return e(a)}var e,f;return h.invert=function(a){return f(a)},h.domain=function(b){return arguments.length?(a=b.map(Number),g()):a},h.range=function(a){return arguments.length?(b=a,g()):b},h.rangeRound=function(a){return h.range(a).interpolate(d3.interpolateRound)},h.clamp=function(a){return arguments.length?(d=a,g()):d},h.interpolate=function(a){return arguments.length?(c=a,g()):c},h.ticks=function(b){return ck(a,b)},h.tickFormat=function(b){return cl(a,b)},h.nice=function(){return ce(a,ci),g()},h.copy=function(){return cg(a,b,c,d)},g()}function ch(a,b){return d3.rebind(a,b,"range","rangeRound","interpolate","clamp")}function ci(a){return a=Math.pow(10,Math.round(Math.log(a)/Math.LN10)-1),{floor:function(b){return Math.floor(b/a)*a},ceil:function(b){return Math.ceil(b/a)*a}}}function cj(a,b){var c=cc(a),d=c[1]-c[0],e=Math.pow(10,Math.floor(Math.log(d/b)/Math.LN10)),f=b/d*e;return f<=.15?e*=10:f<=.35?e*=5:f<=.75&&(e*=2),c[0]=Math.ceil(c[0]/e)*e,c[1]=Math.floor(c[1]/e)*e+e*.5,c[2]=e,c}function ck(a,b){return d3.range.apply(d3,cj(a,b))}function cl(a,b){return d3.format(",."+Math.max(0,-Math.floor(Math.log(cj(a,b)[2])/Math.LN10+.01))+"f")}function cm(a,b,c,d){var e=c(a[0],a[1]),f=d(b[0],b[1]);return function(a){return f(e(a))}}function cn(a,b,c,d){var e=[],f=[],g=0,h=Math.min(a.length,b.length)-1;a[h]0;j--)e.push(c(f)*j)}else{for(;fi;g--);e=e.slice(f,g)}return e},d.tickFormat=function(a,e){arguments.length<2&&(e=cp);if(arguments.length<1)return e;var f=a/d.ticks().length,g=b===cr?(h=-1e-12,Math.floor):(h=1e-12,Math.ceil),h;return function(a){return a/c(g(b(a)+h))0?0:-a)/Math.LN10}function cs(a,b){function e(b){return a(c(b))}var c=ct(b),d=ct(1/b);return e.invert=function(b){return d(a.invert(b))},e.domain=function(b){return arguments.length?(a.domain(b.map(c)),e):a.domain().map(d)},e.ticks=function(a){return ck(e.domain(),a)},e.tickFormat=function(a){return cl(e.domain(),a)},e.nice=function(){return e.domain(ce(e.domain(),ci))},e.exponent=function(a){if(!arguments.length)return b;var f=e.domain();return c=ct(b=a),d=ct(1/b),e.domain(f)},e.copy=function(){return cs(a.copy(),b)},ch(e,a)}function ct(a){return function(b){return b<0?-Math.pow(-b,a):Math.pow(b,a)}}function cu(a,b){function f(b){return d[((c.get(b)||c.set(b,a.push(b)))-1)%d.length]}function g(b,c){return d3.range(a.length).map(function(a){return b+c*a})}var c,d,e;return f.domain=function(d){if(!arguments.length)return a;a=[],c=new k;var e=-1,g=d.length,h;while(++e1){h=b[1],f=a[i],i++,d+="C"+(e[0]+g[0])+","+(e[1]+g[1])+","+(f[0]-h[0])+","+(f[1]-h[1])+","+f[0]+","+f[1];for(var j=2;j9&&(f=c*3/Math.sqrt(f),g[h]=f*d,g[h+1]=f*e));h=-1;while(++h<=i)f=(a[Math.min(i,h+1)][0]-a[Math.max(0,h-1)][0])/(6*(1+g[h]*g[h])),b.push([f||0,g[h]*f||0]);return b}function dg(a){return a.length<3?cO(a):a[0]+cU(a,df(a))}function dh(a){var b,c=-1,d=a.length,e,f;while(++c1){var d=cc(a.domain()),e,f=-1,g=b.length,h=(b[1]-b[0])/++c,i,j;while(++f0;)(j=+b[f]-i*h)>=d[0]&&e.push(j);for(--f,i=0;++id&&(c=b,d=e);return c}function ea(a){return a.reduce(eb,0)}function eb(a,b){return a+b[1]}function ec(a,b){return ed(a,Math.ceil(Math.log(b.length)/Math.LN2+1))}function ed(a,b){var c=-1,d=+a[0],e=(a[1]-d)/b,f=[];while(++c<=b)f[c]=e*c+d;return f}function ee(a){return[d3.min(a),d3.max(a)]}function ef(a,b){return d3.rebind(a,b,"sort","children","value"),a.links=ej,a.nodes=function(b){return ek=!0,(a.nodes=a)(b)},a}function eg(a){return a.children}function eh(a){return a.value}function ei(a,b){return b.value-a.value}function ej(a){return d3.merge(a.map(function(a){return(a.children||[]).map(function(b){return{source:a,target:b}})}))}function el(a,b){return a.value-b.value}function em(a,b){var c=a._pack_next;a._pack_next=b,b._pack_prev=a,b._pack_next=c,c._pack_prev=b}function en(a,b){a._pack_next=b,b._pack_prev=a}function eo(a,b){var c=b.x-a.x,d=b.y-a.y,e=a.r+b.r;return e*e-c*c-d*d>.001}function ep(a){function l(a){b=Math.min(a.x-a.r,b),c=Math.max(a.x+a.r,c),d=Math.min(a.y-a.r,d),e=Math.max(a.y+a.r,e)}var b=Infinity,c=-Infinity,d=Infinity,e=-Infinity,f=a.length,g,h,i,j,k;a.forEach(eq),g=a[0],g.x=-g.r,g.y=0,l(g);if(f>1){h=a[1],h.x=h.r,h.y=0,l(h);if(f>2){i=a[2],eu(g,h,i),l(i),em(g,i),g._pack_prev=i,em(i,h),h=g._pack_next;for(var m=3;m0&&(a=d)}return a}function eD(a,b){return a.x-b.x}function eE(a,b){return b.x-a.x}function eF(a,b){return a.depth-b.depth}function eG(a,b){function c(a,d){var e=a.children;if(e&&(i=e.length)){var f,g=null,h=-1,i;while(++h=0)f=d[e]._tree,f.prelim+=b,f.mod+=b,b+=f.shift+(c+=f.change)}function eI(a,b,c){a=a._tree,b=b._tree;var d=c/(b.number-a.number);a.change+=d,b.change-=d,b.shift+=c,b.prelim+=c,b.mod+=c}function eJ(a,b,c){return a._tree.ancestor.parent==b.parent?a._tree.ancestor:c}function eK(a){return{x:a.x,y:a.y,dx:a.dx,dy:a.dy}}function eL(a,b){var c=a.x+b[3],d=a.y+b[0],e=a.dx-b[1]-b[3],f=a.dy-b[0]-b[2];return e<0&&(c+=e/2,e=0),f<0&&(d+=f/2,f=0),{x:c,y:d,dx:e,dy:f}}function eM(a){return a.map(eN).join(",")}function eN(a){return/[",\n]/.test(a)?'"'+a.replace(/\"/g,'""')+'"':a}function eP(a,b){return function(c){return c&&a.hasOwnProperty(c.type)?a[c.type](c):b}}function eQ(a){return"m0,"+a+"a"+a+","+a+" 0 1,1 0,"+ -2*a+"a"+a+","+a+" 0 1,1 0,"+2*a+"z"}function eR(a,b){eS.hasOwnProperty(a.type)&&eS[a.type](a,b)}function eT(a,b){eR(a.geometry,b)}function eU(a,b){for(var c=a.features,d=0,e=c.length;d0}function fg(a,b,c){return(c[0]-b[0])*(a[1]-b[1])<(c[1]-b[1])*(a[0]-b[0])}function fh(a,b,c,d){var e=a[0],f=b[0],g=c[0],h=d[0],i=a[1],j=b[1],k=c[1],l=d[1],m=e-g,n=f-e,o=h-g,p=i-k,q=j-i,r=l-k,s=(o*p-r*m)/(r*n-o*q);return[e+s*n,i+s*q]}function fj(a,b){var c={list:a.map(function(a,b){return{index:b,x:a[0],y:a[1]}}).sort(function(a,b){return a.yb.y?1:a.xb.x?1:0}),bottomSite:null},d={list:[],leftEnd:null,rightEnd:null,init:function(){d.leftEnd=d.createHalfEdge(null,"l"),d.rightEnd=d.createHalfEdge(null,"l"),d.leftEnd.r=d.rightEnd,d.rightEnd.l=d.leftEnd,d.list.unshift(d.leftEnd,d.rightEnd)},createHalfEdge:function(a,b){return{edge:a,side:b,vertex:null,l:null,r:null}},insert:function(a,b){b.l=a,b.r=a.r,a.r.l=b,a.r=b},leftBound:function(a){var b=d.leftEnd;do b=b.r;while(b!=d.rightEnd&&e.rightOf(b,a));return b=b.l,b},del:function(a){a.l.r=a.r,a.r.l=a.l,a.edge=null},right:function(a){return a.r},left:function(a){return a.l},leftRegion:function(a){return a.edge==null?c.bottomSite:a.edge.region[a.side]},rightRegion:function(a){return a.edge==null?c.bottomSite:a.edge.region[fi[a.side]]}},e={bisect:function(a,b){var c={region:{l:a,r:b},ep:{l:null,r:null}},d=b.x-a.x,e=b.y-a.y,f=d>0?d:-d,g=e>0?e:-e;return c.c=a.x*d+a.y*e+(d*d+e*e)*.5,f>g?(c.a=1,c.b=e/d,c.c/=d):(c.b=1,c.a=d/e,c.c/=e),c},intersect:function(a,b){var c=a.edge,d=b.edge;if(!c||!d||c.region.r==d.region.r)return null;var e=c.a*d.b-c.b*d.a;if(Math.abs(e)<1e-10)return null;var f=(c.c*d.b-d.c*c.b)/e,g=(d.c*c.a-c.c*d.a)/e,h=c.region.r,i=d.region.r,j,k;h.y=k.region.r.x;return l&&j.side==="l"||!l&&j.side==="r"?null:{x:f,y:g}},rightOf:function(a,b){var c=a.edge,d=c.region.r,e=b.x>d.x;if(e&&a.side==="l")return 1;if(!e&&a.side==="r")return 0;if(c.a===1){var f=b.y-d.y,g=b.x-d.x,h=0,i=0;!e&&c.b<0||e&&c.b>=0?i=h=f>=c.b*g:(i=b.x+b.y*c.b>c.c,c.b<0&&(i=!i),i||(h=1));if(!h){var j=d.x-c.region.l.x;i=c.b*(g*g-f*f)m*m+n*n}return a.side==="l"?i:!i},endPoint:function(a,c,d){a.ep[c]=d;if(!a.ep[fi[c]])return;b(a)},distance:function(a,b){var c=a.x-b.x,d=a.y-b.y;return Math.sqrt(c*c+d*d)}},f={list:[],insert:function(a,b,c){a.vertex=b,a.ystar=b.y+c;for(var d=0,e=f.list,g=e.length;dh.ystar||a.ystar==h.ystar&&b.x>h.vertex.x)continue;break}e.splice(d,0,a)},del:function(a){for(var b=0,c=f.list,d=c.length;bo.y&&(p=n,n=o,o=p,t="r"),s=e.bisect(n,o),m=d.createHalfEdge(s,t),d.insert(k,m),e.endPoint(s,fi[t],r),q=e.intersect(k,m),q&&(f.del(k),f.insert(k,q,e.distance(q,n))),q=e.intersect(m,l),q&&f.insert(m,q,e.distance(q,n));else break}for(i=d.right(d.leftEnd);i!=d.rightEnd;i=d.right(i))b(i.edge)}function fk(){return{leaf:!0,nodes:[],point:null}}function fl(a,b,c,d,e,f){if(!a(b,c,d,e,f)){var g=(c+e)*.5,h=(d+f)*.5,i=b.nodes;i[0]&&fl(a,i[0],c,d,g,h),i[1]&&fl(a,i[1],g,d,e,h),i[2]&&fl(a,i[2],c,h,g,f),i[3]&&fl(a,i[3],g,h,e,f)}}function fm(a){return{x:a[0],y:a[1]}}function fo(){this._=new Date(arguments.length>1?Date.UTC.apply(this,arguments):arguments[0])}function fq(a,b,c,d){var e,f,g=0,h=b.length,i=c.length;while(g=i)return-1;e=b.charCodeAt(g++);if(e==37){f=fw[b.charAt(g++)];if(!f||(d=f(a,c,d))<0)return-1}else if(e!=c.charCodeAt(d++))return-1}return d}function fx(a,b,c){return fz.test(b.substring(c,c+=3))?c:-1}function fy(a,b,c){fA.lastIndex=0;var d=fA.exec(b.substring(c,c+10));return d?c+=d[0].length:-1}function fB(a,b,c){var d=fC.get(b.substring(c,c+=3).toLowerCase());return d==null?-1:(a.m=d,c)}function fD(a,b,c){fE.lastIndex=0;var d=fE.exec(b.substring(c,c+12));return d?(a.m=fF.get(d[0].toLowerCase()),c+=d[0].length):-1}function fH(a,b,c){return fq(a,fv.c.toString(),b,c)}function fI(a,b,c){return fq(a,fv.x.toString(),b,c)}function fJ(a,b,c){return fq(a,fv.X.toString(),b,c)}function fK(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+4));return d?(a.y=+d[0],c+=d[0].length):-1}function fL(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+2));return d?(a.y=fM()+ +d[0],c+=d[0].length):-1}function fM(){return~~((new Date).getFullYear()/1e3)*1e3}function fN(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+2));return d?(a.m=d[0]-1,c+=d[0].length):-1}function fO(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+2));return d?(a.d=+d[0],c+=d[0].length):-1}function fP(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+2));return d?(a.H=+d[0],c+=d[0].length):-1}function fQ(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+2));return d?(a.M=+d[0],c+=d[0].length):-1}function fR(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+2));return d?(a.S=+d[0],c+=d[0].length):-1}function fS(a,b,c){fT.lastIndex=0;var d=fT.exec(b.substring(c,c+3));return d?(a.L=+d[0],c+=d[0].length):-1}function fU(a,b,c){var d=fV.get(b.substring(c,c+=2).toLowerCase());return d==null?-1:(a.p=d,c)}function fW(a){var b=a.getTimezoneOffset(),c=b>0?"-":"+",d=~~(Math.abs(b)/60),e=Math.abs(b)%60;return c+fr(d)+fr(e)}function fY(a){return a.toISOString()}function fZ(a,b,c){function d(b){var c=a(b),d=f(c,1);return b-c1)while(gb?1:a>=b?0:NaN},d3.descending=function(a,b){return ba?1:b>=a?0:NaN},d3.mean=function(a,b){var c=a.length,d,e=0,f=-1,g=0;if(arguments.length===1)while(++f1&&(a=a.map(b)),a=a.filter(p),a.length?d3.quantile(a.sort(d3.ascending),.5):undefined},d3.min=function(a,b){var c=-1,d=a.length,e,f;if(arguments.length===1){while(++cf&&(e=f)}else{while(++cf&&(e=f)}return e},d3.max=function(a,b){var c=-1,d=a.length,e,f;if(arguments.length===1){while(++ce&&(e=f)}else{while(++ce&&(e=f)}return e},d3.extent=function(a,b){var c=-1,d=a.length,e,f,g;if(arguments.length===1){while(++cf&&(e=f),gf&&(e=f),g1);return a+b*c*Math.sqrt(-2*Math.log(e)/e)}}},d3.sum=function(a,b){var c=0,d=a.length,e,f=-1;if(arguments.length===1)while(++f>1;a.call(b,b[f],f)>1;c0&&(e=f);return e},d3.last=function(a,b){var c=0,d=a.length,e=a[0],f;arguments.length===1&&(b=d3.ascending);while(++c=b.length)return e?e.call(a,c):d?c.sort(d):c;var h=-1,i=c.length,j=b[g++],l,m,n=new k,o,p={};while(++h=b.length)return a;var e=[],f=c[d++],h;for(h in a)e.push({key:h,values:g(a[h],d)});return f&&e.sort(function(a,b){return f(a.key,b.key)}),e}var a={},b=[],c=[],d,e;return a.map=function(a){return f(a,0)},a.entries=function(a){return g(f(a,0),0)},a.key=function(c){return b.push(c),a},a.sortKeys=function(d){return c[b.length-1]=d,a},a.sortValues=function(b){return d=b,a},a.rollup=function(b){return e=b,a},a},d3.keys=function(a){var b=[];for(var c in a)b.push(c);return b},d3.values=function(a){var b=[];for(var c in a)b.push(a[c]);return b},d3.entries=function(a){var b=[];for(var c in a)b.push({key:c,value:a[c]});return b},d3.permute=function(a,b){var c=[],d=-1,e=b.length;while(++db)d.push(g/e);else while((g=a+c*++f)=0&&(c=a.substring(0,b),a=a.substring(b+1)),w.hasOwnProperty(c)?{space:w[c],local:a}:a}},d3.dispatch=function(){var a=new x,b=-1,c=arguments.length;while(++b0&&(d=a.substring(c+1),a=a.substring(0,c)),arguments.length<2?this[a].on(d):this[a].on(d,b)},d3.format=function(a){var b=z.exec(a),c=b[1]||" ",d=b[3]||"",e=b[5],f=+b[6],g=b[7],h=b[8],i=b[9],j=1,k="",l=!1;h&&(h=+h.substring(1)),e&&(c="0",g&&(f-=Math.floor((f-1)/4)));switch(i){case"n":g=!0,i="g";break;case"%":j=100,k="%",i="f";break;case"p":j=100,k="%",i="r";break;case"d":l=!0,h=0;break;case"s":j=-1,i="r"}return i=="r"&&!h&&(i="g"),i=A.get(i)||C,function(a){if(l&&a%1)return"";var b=a<0&&(a=-a)?"−":d;if(j<0){var m=d3.formatPrefix(a,h);a*=m.scale,k=m.symbol}else a*=j;a=i(a,h);if(e){var n=a.length+b.length;n=^]))?([+\- ])?(#)?(0)?([0-9]+)?(,)?(\.[0-9]+)?([a-zA-Z%])?/,A=d3.map({g:function(a,b){return a.toPrecision(b)},e:function(a,b){return a.toExponential(b)},f:function(a,b){return a.toFixed(b)},r:function(a,b){return d3.round(a,b=B(a,b)).toFixed(Math.max(0,Math.min(20,b)))}}),E=["y","z","a","f","p","n","μ","m","","k","M","G","T","P","E","Z","Y"].map(F);d3.formatPrefix=function(a,b){var c=0;return a&&(a<0&&(a*=-1),b&&(a=d3.round(a,B(a,b))),c=1+Math.floor(1e-12+Math.log(a)/Math.LN10),c=Math.max(-24,Math.min(24,Math.floor((c<=0?c+1:c-1)/3)*3))),E[8+c/3]};var G=P(2),H=P(3),I=function(){return O},J=d3.map({linear:I,poly:P,quad:function(){return G},cubic:function(){return H},sin:function(){return Q},exp:function(){return R},circle:function(){return S},elastic:T,back:U,bounce:function(){return V}}),K=d3.map({"in":O,out:M,"in-out":N,"out-in":function(a){return N(M(a))}});d3.ease=function(a){var b=a.indexOf("-"),c=b>=0?a.substring(0,b):a,d=b>=0?a.substring(b+1):"in";return c=J.get(c)||I,d=K.get(d)||O,L(d(c.apply(null,Array.prototype.slice.call(arguments,1))))},d3.event=null,d3.interpolate=function(a,b){var c=d3.interpolators.length,d;while(--c>=0&&!(d=d3.interpolators[c](a,b)));return d},d3.interpolateNumber=function(a,b){return b-=a,function(c){return a+b*c}},d3.interpolateRound=function(a,b){return b-=a,function(c){return Math.round(a+b*c)}},d3.interpolateString=function(a,b){var c,d,e,f=0,g=0,h=[],i=[],j,k;Z.lastIndex=0;for(d=0;c=Z.exec(b);++d)c.index&&h.push(b.substring(f,g=c.index)),i.push({i:h.length,x:c[0]}),h.push(null),f=Z.lastIndex;f1){while(++e=0;)if(f=c[d])e&&e!==f.nextSibling&&e.parentNode.insertBefore(f,e),e=f;return this},br.sort=function(a){a=by.apply(this,arguments);for(var b=-1,c=this.length;++b0&&(a=a.substring(0,e)),arguments.length<2?(e=this.node()[d])&&e._:this.each(function(e,f){function i(a){var c=d3.event;d3.event=a;try{b.call(g,g.__data__,f)}finally{d3.event=c}}var g=this,h=g[d];h&&(g.removeEventListener(a,h,h.$),delete g[d]),b&&(g.addEventListener(a,g[d]=i,i.$=c),i._=b)})},br.each=function(a){for(var b=-1,c=this.length;++b=cD?e?"M0,"+f+"A"+f+","+f+" 0 1,1 0,"+ -f+"A"+f+","+f+" 0 1,1 0,"+f+"M0,"+e+"A"+e+","+e+" 0 1,0 0,"+ -e+"A"+e+","+e+" 0 1,0 0,"+e+"Z":"M0,"+f+"A"+f+","+f+" 0 1,1 0,"+ -f+"A"+f+","+f+" 0 1,1 0,"+f+"Z":e?"M"+f*k+","+f*l+"A"+f+","+f+" 0 "+j+",1 "+f*m+","+f*n+"L"+e*m+","+e*n+"A"+e+","+e+" 0 "+j+",0 "+e*k+","+e*l+"Z":"M"+f*k+","+f*l+"A"+f+","+f+" 0 "+j+",1 "+f*m+","+f*n+"L0,0"+"Z"}var a=cE,b=cF,c=cG,d=cH;return e.innerRadius=function(b){return arguments.length?(a=d3.functor(b),e):a},e.outerRadius=function(a){return arguments.length?(b=d3.functor(a),e):b},e.startAngle=function(a){return arguments.length?(c=d3.functor(a),e):c},e.endAngle=function(a){return arguments.length?(d=d3.functor(a),e):d},e.centroid=function(){var e=(a.apply(this,arguments)+b.apply(this,arguments))/2,f=(c.apply(this,arguments)+d.apply(this,arguments))/2+cC;return[Math.cos(f)*e,Math.sin(f)*e]},e};var cC=-Math.PI/2,cD=2*Math.PI-1e-6;d3.svg.line=function(){return cI(Object)};var cM="linear",cN=d3.map({linear:cO,"step-before":cP,"step-after":cQ,basis:cW,"basis-open":cX,"basis-closed":cY,bundle:cZ,cardinal:cT,"cardinal-open":cR,"cardinal-closed":cS,monotone:dg}),c_=[0,2/3,1/3,0],da=[0,1/3,2/3,0],db=[0,1/6,2/3,1/6];d3.svg.line.radial=function(){var a=cI(dh);return a.radius=a.x,delete a.x,a.angle=a.y,delete a.y,a},cP.reverse=cQ,cQ.reverse=cP,d3.svg.area=function(){return di(Object)},d3.svg.area.radial=function(){var a=di(dh);return a.radius=a.x,delete a.x,a.innerRadius=a.x0,delete a.x0,a.outerRadius=a.x1,delete a.x1,a.angle=a.y,delete a.y,a.startAngle=a.y0,delete a.y0,a.endAngle=a.y1,delete a.y1,a},d3.svg.chord=function(){function f(c,d){var e=g(this,a,c,d),f=g(this,b,c,d);return"M"+e.p0+i(e.r,e.p1,e.a1-e.a0)+(h(e,f)?j(e.r,e.p1,e.r,e.p0):j(e.r,e.p1,f.r,f.p0)+i(f.r,f.p1,f.a1-f.a0)+j(f.r,f.p1,e.r,e.p0))+"Z"}function g(a,b,f,g){var h=b.call(a,f,g),i=c.call(a,h,g),j=d.call(a,h,g)+cC,k=e.call(a,h,g)+cC;return{r:i,a0:j,a1:k,p0:[i*Math.cos(j),i*Math.sin(j)],p1:[i*Math.cos(k),i*Math.sin(k)]}}function h(a,b){return a.a0==b.a0&&a.a1==b.a1}function i(a,b,c){return"A"+a+","+a+" 0 "+ +(c>Math.PI)+",1 "+b}function j(a,b,c,d){return"Q 0,0 "+d}var a=dl,b=dm,c=dn,d=cG,e=cH;return f.radius=function(a){return arguments.length?(c=d3.functor(a),f):c},f.source=function(b){return arguments.length?(a=d3.functor(b),f):a},f.target=function(a){return arguments.length?(b=d3.functor(a),f):b},f.startAngle=function(a){return arguments.length?(d=d3.functor(a),f):d},f.endAngle=function(a){return arguments.length?(e=d3.functor(a),f):e},f},d3.svg.diagonal=function(){function d(d,e){var f=a.call(this,d,e),g=b.call(this,d,e),h=(f.y+g.y)/2,i=[f,{x:f.x,y:h},{x:g.x,y:h},g];return i=i.map(c),"M"+i[0]+"C"+i[1]+" "+i[2]+" "+i[3]}var a=dl,b=dm,c=dr;return d.source=function(b){return arguments.length?(a=d3.functor(b),d):a},d.target=function(a){return arguments.length?(b=d3.functor(a),d):b},d.projection=function(a){return arguments.length?(c=a,d):c},d},d3.svg.diagonal.radial=function(){var a=d3.svg.diagonal(),b=dr,c=a.projection;return a.projection=function(a){return arguments.length?c(ds(b=a)):b},a},d3.svg.mouse=d3.mouse,d3.svg.touches=d3.touches,d3.svg.symbol=function(){function c(c,d){return(dw.get(a.call(this,c,d))||dv)(b.call(this,c,d))}var a=du,b=dt;return c.type=function(b){return arguments.length?(a=d3.functor(b),c):a},c.size=function(a){return arguments.length?(b=d3.functor(a),c):b},c};var dw=d3.map({circle 3 | :dv,cross:function(a){var b=Math.sqrt(a/5)/2;return"M"+ -3*b+","+ -b+"H"+ -b+"V"+ -3*b+"H"+b+"V"+ -b+"H"+3*b+"V"+b+"H"+b+"V"+3*b+"H"+ -b+"V"+b+"H"+ -3*b+"Z"},diamond:function(a){var b=Math.sqrt(a/(2*dy)),c=b*dy;return"M0,"+ -b+"L"+c+",0"+" 0,"+b+" "+ -c+",0"+"Z"},square:function(a){var b=Math.sqrt(a)/2;return"M"+ -b+","+ -b+"L"+b+","+ -b+" "+b+","+b+" "+ -b+","+b+"Z"},"triangle-down":function(a){var b=Math.sqrt(a/dx),c=b*dx/2;return"M0,"+c+"L"+b+","+ -c+" "+ -b+","+ -c+"Z"},"triangle-up":function(a){var b=Math.sqrt(a/dx),c=b*dx/2;return"M0,"+ -c+"L"+b+","+c+" "+ -b+","+c+"Z"}});d3.svg.symbolTypes=dw.keys();var dx=Math.sqrt(3),dy=Math.tan(30*Math.PI/180);d3.svg.axis=function(){function k(k){k.each(function(){var k=d3.select(this),l=h==null?a.ticks?a.ticks.apply(a,g):a.domain():h,m=i==null?a.tickFormat?a.tickFormat.apply(a,g):String:i,n=dB(a,l,j),o=k.selectAll(".minor").data(n,String),p=o.enter().insert("line","g").attr("class","tick minor").style("opacity",1e-6),q=d3.transition(o.exit()).style("opacity",1e-6).remove(),r=d3.transition(o).style("opacity",1),s=k.selectAll("g").data(l,String),t=s.enter().insert("g","path").style("opacity",1e-6),u=d3.transition(s.exit()).style("opacity",1e-6).remove(),v=d3.transition(s).style("opacity",1),w,x=cd(a),y=k.selectAll(".domain").data([0]),z=y.enter().append("path").attr("class","domain"),A=d3.transition(y),B=a.copy(),C=this.__chart__||B;this.__chart__=B,t.append("line").attr("class","tick"),t.append("text"),v.select("text").text(m);switch(b){case"bottom":w=dz,p.attr("y2",d),r.attr("x2",0).attr("y2",d),t.select("line").attr("y2",c),t.select("text").attr("y",Math.max(c,0)+f),v.select("line").attr("x2",0).attr("y2",c),v.select("text").attr("x",0).attr("y",Math.max(c,0)+f).attr("dy",".71em").attr("text-anchor","middle"),A.attr("d","M"+x[0]+","+e+"V0H"+x[1]+"V"+e);break;case"top":w=dz,p.attr("y2",-d),r.attr("x2",0).attr("y2",-d),t.select("line").attr("y2",-c),t.select("text").attr("y",-(Math.max(c,0)+f)),v.select("line").attr("x2",0).attr("y2",-c),v.select("text").attr("x",0).attr("y",-(Math.max(c,0)+f)).attr("dy","0em").attr("text-anchor","middle"),A.attr("d","M"+x[0]+","+ -e+"V0H"+x[1]+"V"+ -e);break;case"left":w=dA,p.attr("x2",-d),r.attr("x2",-d).attr("y2",0),t.select("line").attr("x2",-c),t.select("text").attr("x",-(Math.max(c,0)+f)),v.select("line").attr("x2",-c).attr("y2",0),v.select("text").attr("x",-(Math.max(c,0)+f)).attr("y",0).attr("dy",".32em").attr("text-anchor","end"),A.attr("d","M"+ -e+","+x[0]+"H0V"+x[1]+"H"+ -e);break;case"right":w=dA,p.attr("x2",d),r.attr("x2",d).attr("y2",0),t.select("line").attr("x2",c),t.select("text").attr("x",Math.max(c,0)+f),v.select("line").attr("x2",c).attr("y2",0),v.select("text").attr("x",Math.max(c,0)+f).attr("y",0).attr("dy",".32em").attr("text-anchor","start"),A.attr("d","M"+e+","+x[0]+"H0V"+x[1]+"H"+e)}if(a.ticks)t.call(w,C),v.call(w,B),u.call(w,B),p.call(w,C),r.call(w,B),q.call(w,B);else{var D=B.rangeBand()/2,E=function(a){return B(a)+D};t.call(w,E),v.call(w,E)}})}var a=d3.scale.linear(),b="bottom",c=6,d=6,e=6,f=3,g=[10],h=null,i,j=0;return k.scale=function(b){return arguments.length?(a=b,k):a},k.orient=function(a){return arguments.length?(b=a,k):b},k.ticks=function(){return arguments.length?(g=arguments,k):g},k.tickValues=function(a){return arguments.length?(h=a,k):h},k.tickFormat=function(a){return arguments.length?(i=a,k):i},k.tickSize=function(a,b,f){if(!arguments.length)return c;var g=arguments.length-1;return c=+a,d=g>1?+b:c,e=g>0?+arguments[g]:c,k},k.tickPadding=function(a){return arguments.length?(f=+a,k):f},k.tickSubdivide=function(a){return arguments.length?(j=+a,k):j},k},d3.svg.brush=function(){function g(a){a.each(function(){var a=d3.select(this),e=a.selectAll(".background").data([0]),f=a.selectAll(".extent").data([0]),l=a.selectAll(".resize").data(d,String),m;a.style("pointer-events","all").on("mousedown.brush",k).on("touchstart.brush",k),e.enter().append("rect").attr("class","background").style("visibility","hidden").style("cursor","crosshair"),f.enter().append("rect").attr("class","extent").style("cursor","move"),l.enter().append("g").attr("class",function(a){return"resize "+a}).style("cursor",function(a){return dC[a]}).append("rect").attr("x",function(a){return/[ew]$/.test(a)?-3:null}).attr("y",function(a){return/^[ns]/.test(a)?-3:null}).attr("width",6).attr("height",6).style("visibility","hidden"),l.style("display",g.empty()?"none":null),l.exit().remove(),b&&(m=cd(b),e.attr("x",m[0]).attr("width",m[1]-m[0]),i(a)),c&&(m=cd(c),e.attr("y",m[0]).attr("height",m[1]-m[0]),j(a)),h(a)})}function h(a){a.selectAll(".resize").attr("transform",function(a){return"translate("+e[+/e$/.test(a)][0]+","+e[+/^s/.test(a)][1]+")"})}function i(a){a.select(".extent").attr("x",e[0][0]),a.selectAll(".extent,.n>rect,.s>rect").attr("width",e[1][0]-e[0][0])}function j(a){a.select(".extent").attr("y",e[0][1]),a.selectAll(".extent,.e>rect,.w>rect").attr("height",e[1][1]-e[0][1])}function k(){function x(){var a=d3.event.changedTouches;return a?d3.touches(d,a)[0]:d3.mouse(d)}function y(){d3.event.keyCode==32&&(q||(r=null,s[0]-=e[1][0],s[1]-=e[1][1],q=2),W())}function z(){d3.event.keyCode==32&&q==2&&(s[0]+=e[1][0],s[1]+=e[1][1],q=0,W())}function A(){var a=x(),d=!1;t&&(a[0]+=t[0],a[1]+=t[1]),q||(d3.event.altKey?(r||(r=[(e[0][0]+e[1][0])/2,(e[0][1]+e[1][1])/2]),s[0]=e[+(a[0]0?e=c:e=0:c>0&&(b.start({type:"start",alpha:e=c}),d3.timer(a.tick)),a):e},a.start=function(){function s(a,c){var d=t(b),e=-1,f=d.length,g;while(++ee&&(e=h),d.push(h)}for(g=0;g=i[0]&&o<=i[1]&&(k=g[d3.bisect(j,o,1,m)-1],k.y+=n,k.push(e[f]));return g}var a=!0,b=Number,c=ee,d=ec;return e.value=function(a){return arguments.length?(b=a,e):b},e.range=function(a){return arguments.length?(c=d3.functor(a),e):c},e.bins=function(a){return arguments.length?(d=typeof a=="number"?function(b){return ed(b,a)}:d3.functor(a),e):d},e.frequency=function(b){return arguments.length?(a=!!b,e):a},e},d3.layout.hierarchy=function(){function e(f,h,i){var j=b.call(g,f,h),k=ek?f:{data:f};k.depth=h,i.push(k);if(j&&(m=j.length)){var l=-1,m,n=k.children=[],o=0,p=h+1;while(++l0&&(eI(eJ(g,a,d),a,m),i+=m,j+=m),k+=g._tree.mod,i+=e._tree.mod,l+=h._tree.mod,j+=f._tree.mod;g&&!eB(f)&&(f._tree.thread=g,f._tree.mod+=k-j),e&&!eA(h)&&(h._tree.thread=e,h._tree.mod+=i-l,d=a)}return d}var f=a.call(this,d,e),g=f[0];eG(g,function(a,b){a._tree={ancestor:a,prelim:0,mod:0,change:0,shift:0,number:b?b._tree.number+1:0}}),h(g),i(g,-g._tree.prelim);var k=eC(g,eE),l=eC(g,eD),m=eC(g,eF),n=k.x-b(k,l)/2,o=l.x+b(l,k)/2,p=m.depth||1;return eG(g,function(a){a.x=(a.x-n)/(o-n)*c[0],a.y=a.depth/p*c[1],delete a._tree}),f}var a=d3.layout.hierarchy().sort(null).value(null),b=ez,c=[1,1];return d.separation=function(a){return arguments.length?(b=a,d):b},d.size=function(a){return arguments.length?(c=a,d):c},ef(d,a)},d3.layout.treemap=function(){function i(a,b){var c=-1,d=a.length,e,f;while(++c0)d.push(g=f[o-1]),d.area+=g.area,(k=l(d,n))<=h?(f.pop(),h=k):(d.area-=d.pop().area,m(d,n,c,!1),n=Math.min(c.dx,c.dy),d.length=d.area=0,h=Infinity);d.length&&(m(d,n,c,!0),d.length=d.area=0),b.forEach(j)}}function k(a){var b=a.children;if(b&&b.length){var c=e(a),d=b.slice(),f,g=[];i(d,c.dx*c.dy/a.value),g.area=0;while(f=d.pop())g.push(f),g.area+=f.area,f.z!=null&&(m(g,f.z?c.dx:c.dy,c,!d.length),g.length=g.area=0);b.forEach(k)}}function l(a,b){var c=a.area,d,e=0,f=Infinity,g=-1,i=a.length;while(++ge&&(e=d)}return c*=c,b*=b,c?Math.max(b*e*h/c,c/(b*f*h)):Infinity}function m(a,c,d,e){var f=-1,g=a.length,h=d.x,i=d.y,j=c?b(a.area/c):0,k;if(c==d.dx){if(e||j>d.dy)j=d.dy;while(++fd.dx)j=d.dx;while(++f=a.length)return d;if(i)return i=!1,c;var b=f.lastIndex;if(a.charCodeAt(b)===34){var e=b;while(e++50?b:f<-140?c:g<21?d:a)(e)}var a=d3.geo.albers(),b=d3.geo.albers().origin([-160,60]).parallels([55,65]),c=d3.geo.albers().origin([-160,20]).parallels([8,18]),d=d3.geo.albers().origin([-60,10]).parallels([8,18]);return e.scale=function(f){return arguments.length?(a.scale(f),b.scale(f*.6),c.scale(f),d.scale(f*1.5),e.translate(a.translate())):a.scale()},e.translate=function(f){if(!arguments.length)return a.translate();var g=a.scale()/1e3,h=f[0],i=f[1];return a.translate(f),b.translate([h-400*g,i+170*g]),c.translate([h-190*g,i+200*g]),d.translate([h+580*g,i+430*g]),e},e.scale(a.scale())},d3.geo.bonne=function(){function g(g){var h=g[0]*eO-c,i=g[1]*eO-d;if(e){var j=f+e-i,k=h*Math.cos(i)/j;h=j*Math.sin(k),i=j*Math.cos(k)-f}else h*=Math.cos(i),i*=-1;return[a*h+b[0],a*i+b[1]]}var a=200,b=[480,250],c,d,e,f;return g.invert=function(d){var g=(d[0]-b[0])/a,h=(d[1]-b[1])/a;if(e){var i=f+h,j=Math.sqrt(g*g+i*i);h=f+e-j,g=c+j*Math.atan2(g,i)/Math.cos(h)}else h*=-1,g/=Math.cos(h);return[g/eO,h/eO]},g.parallel=function(a){return arguments.length?(f=1/Math.tan(e=a*eO),g):e/eO},g.origin=function(a){return arguments.length?(c=a[0]*eO,d=a[1]*eO,g):[c/eO,d/eO]},g.scale=function(b){return arguments.length?(a=+b,g):a},g.translate=function(a){return arguments.length?(b=[+a[0],+a[1]],g):b},g.origin([0,0]).parallel(45)},d3.geo.equirectangular=function(){function c(c){var d=c[0]/360,e=-c[1]/360;return[a*d+b[0],a*e+b[1]]}var a=500,b=[480,250];return c.invert=function(c){var d=(c[0]-b[0])/a,e=(c[1]-b[1])/a;return[360*d,-360*e]},c.scale=function(b){return arguments.length?(a=+b,c):a},c.translate=function(a){return arguments.length?(b=[+a[0],+a[1]],c):b},c},d3.geo.mercator=function(){function c(c){var d=c[0]/360,e=-(Math.log(Math.tan(Math.PI/4+c[1]*eO/2))/eO)/360;return[a*d+b[0],a*Math.max(-0.5,Math.min(.5,e))+b[1]]}var a=500,b=[480,250];return c.invert=function(c){var d=(c[0]-b[0])/a,e=(c[1]-b[1])/a;return[360*d,2*Math.atan(Math.exp(-360*e*eO))/eO-90]},c.scale=function(b){return arguments.length?(a=+b,c):a},c.translate=function(a){return arguments.length?(b=[+a[0],+a[1]],c):b},c},d3.geo.path=function(){function d(c,d){return typeof a=="function"&&(b=eQ(a.apply(this,arguments))),f(c)||null}function e(a){return c(a).join(",")}function h(a){var b=k(a[0]),c=0,d=a.length;while(++c0){b.push("M");while(++h0){b.push("M");while(++kd&&(d=a),fe&&(e=f)}),[[b,c],[d,e]]};var eS={Feature:eT,FeatureCollection:eU,GeometryCollection:eV,LineString:eW,MultiLineString:eX,MultiPoint:eW,MultiPolygon:eY,Point:eZ,Polygon:e$};d3.geo.circle=function(){function e(){}function f(a){return d.distance(a)=k*k+l*l?d[f].index=-1:(d[m].index=-1,o=d[f].angle,m=f,n=g)):(o=d[f].angle,m=f,n=g);e.push(h);for(f=0,g=0;f<2;++g)d[g].index!==-1&&(e.push(d[g].index),f++);p=e.length;for(;g=0?(c=a.ep.r,d=a.ep.l):(c=a.ep.l,d=a.ep.r),a.a===1?(g=c?c.y:-1e6,e=a.c-a.b*g,h=d?d.y:1e6,f=a.c-a.b*h):(e=c?c.x:-1e6,g=a.c-a.a*e,f=d?d.x:1e6,h=a.c-a.a*f);var i=[e,g],j=[f,h];b[a.region.l.index].push(i,j),b[a.region.r.index].push(i,j)}),b.map(function(b,c){var d=a[c][0],e=a[c][1];return b.forEach(function(a){a.angle=Math.atan2(a[0]-d,a[1]-e)}),b.sort(function(a,b){return a.angle-b.angle}).filter(function(a,c){return!c||a.angle-b[c-1].angle>1e-10})})};var fi={l:"r",r:"l"};d3.geom.delaunay=function(a){var b=a.map(function(){return[]}),c=[];return fj(a,function(c){b[c.region.l.index].push(a[c.region.r.index])}),b.forEach(function(b,d){var e=a[d],f=e[0],g=e[1];b.forEach(function(a){a.angle=Math.atan2(a[0]-f,a[1]-g)}),b.sort(function(a,b){return a.angle-b.angle});for(var h=0,i=b.length-1;h=g,j=b.y>=h,l=(j<<1)+i;a.leaf=!1,a=a.nodes[l]||(a.nodes[l]=fk()),i?c=g:e=g,j?d=h:f=h,k(a,b,c,d,e,f)}var f,g=-1,h=a.length;h&&isNaN(a[0].x)&&(a=a.map(fm));if(arguments.length<5)if(arguments.length===3)e=d=c,c=b;else{b=c=Infinity,d=e=-Infinity;while(++gd&&(d=f.x),f.y>e&&(e=f.y);var i=d-b,j=e-c;i>j?e=c+i:d=b+j}var m=fk();return m.add=function(a){k(m,a,b,c,d,e)},m.visit=function(a){fl(a,m,b,c,d,e)},a.forEach(m.add),m},d3.time={};var fn=Date;fo.prototype={getDate:function(){return this._.getUTCDate()},getDay:function(){return this._.getUTCDay()},getFullYear:function(){return this._.getUTCFullYear()},getHours:function(){return this._.getUTCHours()},getMilliseconds:function(){return this._.getUTCMilliseconds()},getMinutes:function(){return this._.getUTCMinutes()},getMonth:function(){return this._.getUTCMonth()},getSeconds:function(){return this._.getUTCSeconds()},getTime:function(){return this._.getTime()},getTimezoneOffset:function(){return 0},valueOf:function(){return this._.valueOf()},setDate:function(){fp.setUTCDate.apply(this._,arguments)},setDay:function(){fp.setUTCDay.apply(this._,arguments)},setFullYear:function(){fp.setUTCFullYear.apply(this._,arguments)},setHours:function(){fp.setUTCHours.apply(this._,arguments)},setMilliseconds:function(){fp.setUTCMilliseconds.apply(this._,arguments)},setMinutes:function(){fp.setUTCMinutes.apply(this._,arguments)},setMonth:function(){fp.setUTCMonth.apply(this._,arguments)},setSeconds:function(){fp.setUTCSeconds.apply(this._,arguments)},setTime:function(){fp.setTime.apply(this._,arguments)}};var fp=Date.prototype;d3.time.format=function(a){function c(c){var d=[],e=-1,f=0,g,h;while(++e=12?"PM":"AM"},S:function(a){return fr(a.getSeconds())},U:function(a){return fr(d3.time.sundayOfYear(a))},w:function(a){return a.getDay()},W:function(a){return fr(d3.time.mondayOfYear(a))},x:d3.time.format("%m/%d/%y"),X:d3.time.format("%H:%M:%S"),y:function(a){return fr(a.getFullYear()%100)},Y:function(a){return ft(a.getFullYear()%1e4)},Z:fW,"%":function(a){return"%"}},fw={a:fx,A:fy,b:fB,B:fD,c:fH,d:fO,e:fO,H:fP,I:fP,L:fS,m:fN,M:fQ,p:fU,S:fR,x:fI,X:fJ,y:fL,Y:fK},fz=/^(?:sun|mon|tue|wed|thu|fri|sat)/i,fA=/^(?:Sunday|Monday|Tuesday|Wednesday|Thursday|Friday|Saturday)/i;d3_time_weekdays=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var fC=d3.map({jan:0,feb:1,mar:2,apr:3,may:4,jun:5,jul:6,aug:7,sep:8,oct:9,nov:10,dec:11}),fE=/^(?:January|February|March|April|May|June|July|August|September|October|November|December)/ig,fF=d3.map({january:0,february:1,march:2,april:3,may:4,june:5,july:6,august:7,september:8,october:9,november:10,december:11}),fG=["January","February","March","April","May","June","July","August","September","October","November","December"],fT=/\s*\d+/,fV=d3.map({am:0,pm:1});d3.time.format.utc=function(a){function c(a){try{fn=fo;var c=new fn;return c._=a,b(c)}finally{fn=Date}}var b=d3.time.format(a);return c.parse=function(a){try{fn=fo;var c=b.parse(a);return c&&c._}finally{fn=Date}},c.toString=b.toString,c};var fX=d3.time.format.utc("%Y-%m-%dT%H:%M:%S.%LZ");d3.time.format.iso=Date.prototype.toISOString?fY:fX,fY.parse=function(a){return new Date(a)},fY.toString=fX.toString,d3.time.second=fZ(function(a){return new fn(Math.floor(a/1e3)*1e3)},function(a,b){a.setTime(a.getTime()+Math.floor(b)*1e3)},function(a){return a.getSeconds()}),d3.time.seconds=d3.time.second.range,d3.time.seconds.utc=d3.time.second.utc.range,d3.time.minute=fZ(function(a){return new fn(Math.floor(a/6e4)*6e4)},function(a,b){a.setTime(a.getTime()+Math.floor(b)*6e4)},function(a){return a.getMinutes()}),d3.time.minutes=d3.time.minute.range,d3.time.minutes.utc=d3.time.minute.utc.range,d3.time.hour=fZ(function(a){var b=a.getTimezoneOffset()/60;return new fn((Math.floor(a/36e5-b)+b)*36e5)},function(a,b){a.setTime(a.getTime()+Math.floor(b)*36e5)},function(a){return a.getHours()}),d3.time.hours=d3.time.hour.range,d3.time.hours.utc=d3.time.hour.utc.range,d3.time.day=fZ(function(a){return new fn(a.getFullYear(),a.getMonth(),a.getDate())},function(a,b){a.setDate(a.getDate()+b)},function(a){return a.getDate()-1}),d3.time.days=d3.time.day.range,d3.time.days.utc=d3.time.day.utc.range,d3.time.dayOfYear=function(a){var b=d3.time.year(a);return Math.floor((a-b)/864e5-(a.getTimezoneOffset()-b.getTimezoneOffset())/1440)},d3_time_weekdays.forEach(function(a,b){a=a.toLowerCase(),b=7-b;var c=d3.time[a]=fZ(function(a){return(a=d3.time.day(a)).setDate(a.getDate()-(a.getDay()+b)%7),a},function(a,b){a.setDate(a.getDate()+Math.floor(b)*7)},function(a){var c=d3.time.year(a).getDay();return Math.floor((d3.time.dayOfYear(a)+(c+b)%7)/7)-(c!==b)});d3.time[a+"s"]=c.range,d3.time[a+"s"].utc=c.utc.range,d3.time[a+"OfYear"]=function(a){var c=d3.time.year(a).getDay();return Math.floor((d3.time.dayOfYear(a)+(c+b)%7)/7)}}),d3.time.week=d3.time.sunday,d3.time.weeks=d3.time.sunday.range,d3.time.weeks.utc=d3.time.sunday.utc.range,d3.time.weekOfYear=d3.time.sundayOfYear,d3.time.month=fZ(function(a){return new fn(a.getFullYear(),a.getMonth(),1)},function(a,b){a.setMonth(a.getMonth()+b)},function(a){return a.getMonth()}),d3.time.months=d3.time.month.range,d3.time.months.utc=d3.time.month.utc.range,d3.time.year=fZ(function(a){return new fn(a.getFullYear(),0,1)},function(a,b){a.setFullYear(a.getFullYear()+b)},function(a){return a.getFullYear()}),d3.time.years=d3.time.year.range,d3.time.years.utc=d3.time.year.utc.range;var gf=[1e3,5e3,15e3,3e4,6e4,3e5,9e5,18e5,36e5,108e5,216e5,432e5,864e5,1728e5,6048e5,2592e6,7776e6,31536e6],gg=[[d3.time.second,1],[d3.time.second,5],[d3.time.second,15],[d3.time.second,30],[d3.time.minute,1],[d3.time.minute,5],[d3.time.minute,15],[d3.time.minute,30],[d3.time.hour,1],[d3.time.hour,3],[d3.time.hour,6],[d3.time.hour,12],[d3.time.day,1],[d3.time.day,2],[d3.time.week,1],[d3.time.month,1],[d3.time.month,3],[d3.time.year,1]],gh=[[d3.time.format("%Y"),function(a){return!0}],[d3.time.format("%B"),function(a){return a.getMonth()}],[d3.time.format("%b %d"),function(a){return a.getDate()!=1}],[d3.time.format("%a %d"),function(a){return a.getDay()&&a.getDate()!=1}],[d3.time.format("%I %p"),function(a){return a.getHours()}],[d3.time.format("%I:%M"),function(a){return a.getMinutes()}],[d3.time.format(":%S"),function(a){return a.getSeconds()}],[d3.time.format(".%L"),function(a){return a.getMilliseconds()}]],gi=d3.scale.linear(),gj=gc(gh);gg.year=function(a,b){return gi.domain(a.map(ge)).ticks(b).map(gd)},d3.time.scale=function(){return f_(d3.scale.linear(),gg,gj)};var gk=gg.map(function(a){return[a[0].utc,a[1]]}),gl=[[d3.time.format.utc("%Y"),function(a){return!0}],[d3.time.format.utc("%B"),function(a){return a.getUTCMonth()}],[d3.time.format.utc("%b %d"),function(a){return a.getUTCDate()!=1}],[d3.time.format.utc("%a %d"),function(a){return a.getUTCDay()&&a.getUTCDate()!=1}],[d3.time.format.utc("%I %p"),function(a){return a.getUTCHours()}],[d3.time.format.utc("%I:%M"),function(a){return a.getUTCMinutes()}],[d3.time.format.utc(":%S"),function(a){return a.getUTCSeconds()}],[d3.time.format.utc(".%L"),function(a){return a.getUTCMilliseconds()}]],gm=gc(gl);gk.year=function(a,b){return gi.domain(a.map(go)).ticks(b).map(gn)},d3.time.scale.utc=function(){return f_(d3.scale.linear(),gk,gm)}})(); --------------------------------------------------------------------------------