Commit 752c1f5a6ed9d9528e4ed1d1a74a16d5976f7f19
1 parent
42187739
updated d3-scatterplot-matrix
Showing
8 changed files
with
571 additions
and
3 deletions
bower.json
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | "iron-icon": "PolymerElements/iron-icon#~1.0.7", | 20 | "iron-icon": "PolymerElements/iron-icon#~1.0.7", |
| 21 | "iron-icons": "PolymerElements/iron-icons#~1.1.2", | 21 | "iron-icons": "PolymerElements/iron-icons#~1.1.2", |
| 22 | "paper-toast": "PolymerElements/paper-toast#~1.2.1", | 22 | "paper-toast": "PolymerElements/paper-toast#~1.2.1", |
| 23 | - "d3-scatterplot-matrix": "^0.1.0", | ||
| 24 | - "d3-scatterplot": "^1.1.0" | 23 | + "d3-scatterplot-matrix": "latest", |
| 24 | + "d3-scatterplot": "latest" | ||
| 25 | } | 25 | } |
| 26 | } | 26 | } |
bower_components/d3-scatterplot-matrix/LICENSE
0 → 100644
| 1 | +The MIT License (MIT) | ||
| 2 | + | ||
| 3 | +Copyright (c) 2016 Michał | ||
| 4 | + | ||
| 5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| 6 | +of this software and associated documentation files (the "Software"), to deal | ||
| 7 | +in the Software without restriction, including without limitation the rights | ||
| 8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| 9 | +copies of the Software, and to permit persons to whom the Software is | ||
| 10 | +furnished to do so, subject to the following conditions: | ||
| 11 | + | ||
| 12 | +The above copyright notice and this permission notice shall be included in all | ||
| 13 | +copies or substantial portions of the Software. | ||
| 14 | + | ||
| 15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| 17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| 18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| 19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| 20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 21 | +SOFTWARE. |
bower_components/d3-scatterplot-matrix/bower.json
0 → 100644
| 1 | +{ | ||
| 2 | + "name": "d3-scatterplot-matrix", | ||
| 3 | + "homepage": "https://github.com/mwasiluk/d3-scatterplot-matrix", | ||
| 4 | + "authors": [ | ||
| 5 | + "Michal Wasiluk" | ||
| 6 | + ], | ||
| 7 | + "description": "", | ||
| 8 | + "main": "", | ||
| 9 | + "keywords": [ | ||
| 10 | + "scatterplot", | ||
| 11 | + "d3", | ||
| 12 | + "matrix" | ||
| 13 | + | ||
| 14 | + ], | ||
| 15 | + "license": "MIT", | ||
| 16 | + "ignore": [ | ||
| 17 | + "**/.*", | ||
| 18 | + "node_modules", | ||
| 19 | + "bower_components", | ||
| 20 | + "test", | ||
| 21 | + "tests" | ||
| 22 | + ], | ||
| 23 | + "dependencies": { | ||
| 24 | + "d3": "^3.5.17" | ||
| 25 | + } | ||
| 26 | +} |
bower_components/d3-scatterplot-matrix/dist/d3-scatterplot-matrix.css
0 → 100644
| 1 | +svg.mw-d3-scatterplot-matrix { | ||
| 2 | + background-color: white; | ||
| 3 | + font-size: 11px; | ||
| 4 | + height: 100%; } | ||
| 5 | + svg.mw-d3-scatterplot-matrix .mw-axis { | ||
| 6 | + shape-rendering: crispEdges; } | ||
| 7 | + svg.mw-d3-scatterplot-matrix .mw-axis path { | ||
| 8 | + display: none; } | ||
| 9 | + svg.mw-d3-scatterplot-matrix .mw-axis line { | ||
| 10 | + stroke: #ddd; } | ||
| 11 | + svg.mw-d3-scatterplot-matrix .mw-axis.mw-no-guides line { | ||
| 12 | + display: none; } | ||
| 13 | + svg.mw-d3-scatterplot-matrix .mw-frame { | ||
| 14 | + shape-rendering: crispEdges; | ||
| 15 | + fill: none; | ||
| 16 | + stroke: #aaa; } | ||
| 17 | + svg.mw-d3-scatterplot-matrix .mw-cell text { | ||
| 18 | + font-weight: bold; | ||
| 19 | + text-transform: capitalize; } | ||
| 20 | + svg.mw-d3-scatterplot-matrix circle { | ||
| 21 | + fill-opacity: .7; } | ||
| 22 | + svg.mw-d3-scatterplot-matrix circle.hidden { | ||
| 23 | + fill: #ccc !important; } | ||
| 24 | + svg.mw-d3-scatterplot-matrix .extent { | ||
| 25 | + fill: #000; | ||
| 26 | + fill-opacity: .125; | ||
| 27 | + stroke: #fff; } | ||
| 28 | + | ||
| 29 | +.mw-tooltip { | ||
| 30 | + position: absolute; | ||
| 31 | + pointer-events: none; | ||
| 32 | + font-size: 11px; | ||
| 33 | + background: #fdfdfd; | ||
| 34 | + padding: 3px 5px; | ||
| 35 | + border-radius: 8px; | ||
| 36 | + box-shadow: 1px 3px 3px #b7b7b7; } |
bower_components/d3-scatterplot-matrix/dist/d3-scatterplot-matrix.js
0 → 100644
| 1 | +function D3ScatterPlotMatrixUtils() { | ||
| 2 | +} | ||
| 3 | + | ||
| 4 | +// usage example deepExtend({}, objA, objB); => should work similar to $.extend(true, {}, objA, objB); | ||
| 5 | +D3ScatterPlotMatrixUtils.prototype.deepExtend = function (out) { //TODO consider using jquery / lo-dash / underscore / ECMA6 ; fallbacks? | ||
| 6 | + | ||
| 7 | + var utils = this; | ||
| 8 | + var emptyOut = {}; | ||
| 9 | + | ||
| 10 | + | ||
| 11 | + if (!out && arguments.length > 1 && Array.isArray(arguments[1])) { | ||
| 12 | + out = []; | ||
| 13 | + } | ||
| 14 | + out = out || {}; | ||
| 15 | + | ||
| 16 | + for (var i = 1; i < arguments.length; i++) { | ||
| 17 | + var source = arguments[i]; | ||
| 18 | + if (!source) | ||
| 19 | + continue; | ||
| 20 | + | ||
| 21 | + for (var key in source) { | ||
| 22 | + if (!source.hasOwnProperty(key)) { | ||
| 23 | + continue; | ||
| 24 | + } | ||
| 25 | + var isArray = Array.isArray(out[key]); | ||
| 26 | + var isObject = utils.isObject(out[key]); | ||
| 27 | + var srcObj = utils.isObject(source[key]); | ||
| 28 | + | ||
| 29 | + if (isObject && !isArray && srcObj) { | ||
| 30 | + utils.deepExtend(out[key], source[key]); | ||
| 31 | + } else { | ||
| 32 | + out[key] = source[key]; | ||
| 33 | + } | ||
| 34 | + } | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + return out; | ||
| 38 | +}; | ||
| 39 | + | ||
| 40 | +D3ScatterPlotMatrixUtils.prototype.cross = function (a, b) { | ||
| 41 | + var c = [], n = a.length, m = b.length, i, j; | ||
| 42 | + for (i = -1; ++i < n;) for (j = -1; ++j < m;) c.push({x: a[i], i: i, y: b[j], j: j}); | ||
| 43 | + return c; | ||
| 44 | +}; | ||
| 45 | + | ||
| 46 | +D3ScatterPlotMatrixUtils.prototype.inferTraits = function (data, categoryKey, includeCategory) { | ||
| 47 | + var res = []; | ||
| 48 | + if (data.length) { | ||
| 49 | + var d = data[0]; | ||
| 50 | + if (d instanceof Array) { | ||
| 51 | + res= d.map(function (v, i) { | ||
| 52 | + return i; | ||
| 53 | + }); | ||
| 54 | + }else if (typeof d === 'object'){ | ||
| 55 | + | ||
| 56 | + for (var prop in d) { | ||
| 57 | + if(!d.hasOwnProperty(prop)) continue; | ||
| 58 | + | ||
| 59 | + res.push(prop); | ||
| 60 | + } | ||
| 61 | + } | ||
| 62 | + } | ||
| 63 | + if(!includeCategory){ | ||
| 64 | + var index = res.indexOf(categoryKey); | ||
| 65 | + if (index > -1) { | ||
| 66 | + res.splice(index, 1); | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | + return res | ||
| 70 | +}; | ||
| 71 | + | ||
| 72 | + | ||
| 73 | +D3ScatterPlotMatrixUtils.prototype.isObject = function(a) { | ||
| 74 | + return a !== null && typeof a === 'object'; | ||
| 75 | +}; | ||
| 76 | +D3ScatterPlotMatrixUtils.prototype.isNumber = function(a) { | ||
| 77 | + return !isNaN(a) && typeof a === 'number'; | ||
| 78 | +}; | ||
| 79 | +D3ScatterPlotMatrixUtils.prototype.isFunction = function(a) { | ||
| 80 | + return typeof a === 'function'; | ||
| 81 | +}; | ||
| 82 | + | ||
| 83 | +D3ScatterPlotMatrixUtils.prototype.selectOrAppend = function (parent, selector, element) { | ||
| 84 | + var selection = parent.select(selector); | ||
| 85 | + if(selection.empty()){ | ||
| 86 | + return parent.append(element || selector); | ||
| 87 | + } | ||
| 88 | + return selection; | ||
| 89 | +}; | ||
| 90 | +function D3ScatterPlotMatrix(placeholderSelector, data, config) { | ||
| 91 | + this.utils = new D3ScatterPlotMatrixUtils(); | ||
| 92 | + this.placeholderSelector = placeholderSelector; | ||
| 93 | + this.svg = null; | ||
| 94 | + this.defaultConfig = { | ||
| 95 | + width: 0, | ||
| 96 | + size: 200, //cell size | ||
| 97 | + padding: 20, //cell padding | ||
| 98 | + brush: true, | ||
| 99 | + guides: true, | ||
| 100 | + tooltip: true, | ||
| 101 | + ticks: null, | ||
| 102 | + margin: { | ||
| 103 | + left: 30, | ||
| 104 | + right: 30, | ||
| 105 | + top: 30, | ||
| 106 | + bottom: 30 | ||
| 107 | + }, | ||
| 108 | + x: {// X axis config | ||
| 109 | + orient: "bottom", | ||
| 110 | + scale: "linear" | ||
| 111 | + }, | ||
| 112 | + y: {// Y axis config | ||
| 113 | + orient: "left", | ||
| 114 | + scale: "linear" | ||
| 115 | + }, | ||
| 116 | + dot: { | ||
| 117 | + radius: 2, | ||
| 118 | + color: null, // string or function returning color's value for color scale | ||
| 119 | + d3ColorCategory: 'category10' | ||
| 120 | + }, | ||
| 121 | + traits: { | ||
| 122 | + labels: [], //optional array of trait labels | ||
| 123 | + keys: [], //optional array of trait keys | ||
| 124 | + categoryKey: null, | ||
| 125 | + includeCategoryInPlot: false, | ||
| 126 | + value: function (d, traitKey) {// trait value accessor | ||
| 127 | + return d[traitKey]; | ||
| 128 | + } | ||
| 129 | + } | ||
| 130 | + }; | ||
| 131 | + | ||
| 132 | + if (config) { | ||
| 133 | + this.setConfig(config); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + if (data) { | ||
| 137 | + this.setData(data); | ||
| 138 | + } | ||
| 139 | + | ||
| 140 | + this.init(); | ||
| 141 | +} | ||
| 142 | + | ||
| 143 | +D3ScatterPlotMatrix.prototype.setData = function (data) { | ||
| 144 | + this.data = data; | ||
| 145 | + | ||
| 146 | + | ||
| 147 | + return this; | ||
| 148 | +}; | ||
| 149 | + | ||
| 150 | +D3ScatterPlotMatrix.prototype.setConfig = function (config) { | ||
| 151 | + this.config = this.utils.deepExtend({}, this.defaultConfig, config); | ||
| 152 | + return this; | ||
| 153 | +}; | ||
| 154 | +D3ScatterPlotMatrix.prototype.initPlot = function () { | ||
| 155 | + | ||
| 156 | + | ||
| 157 | + var self = this; | ||
| 158 | + var margin = this.config.margin; | ||
| 159 | + var conf = this.config; | ||
| 160 | + this.plot = { | ||
| 161 | + x: {}, | ||
| 162 | + y: {}, | ||
| 163 | + dot: { | ||
| 164 | + color: null//color scale mapping function | ||
| 165 | + } | ||
| 166 | + }; | ||
| 167 | + | ||
| 168 | + this.setupTraits(); | ||
| 169 | + | ||
| 170 | + this.plot.size = conf.size; | ||
| 171 | + | ||
| 172 | + | ||
| 173 | + var width = conf.width; | ||
| 174 | + var placeholderNode = d3.select(this.placeholderSelector).node(); | ||
| 175 | + | ||
| 176 | + if (!width) { | ||
| 177 | + var maxWidth = margin.left + margin.right + this.plot.traits.length*this.plot.size; | ||
| 178 | + width = Math.min(placeholderNode.getBoundingClientRect().width, maxWidth); | ||
| 179 | + | ||
| 180 | + } | ||
| 181 | + var height = width; | ||
| 182 | + if (!height) { | ||
| 183 | + height = placeholderNode.getBoundingClientRect().height; | ||
| 184 | + } | ||
| 185 | + | ||
| 186 | + this.plot.width = width - margin.left - margin.right; | ||
| 187 | + this.plot.height = height - margin.top - margin.bottom; | ||
| 188 | + | ||
| 189 | + | ||
| 190 | + | ||
| 191 | + | ||
| 192 | + if(conf.ticks===null){ | ||
| 193 | + conf.ticks = this.plot.size / 40; | ||
| 194 | + } | ||
| 195 | + | ||
| 196 | + this.setupX(); | ||
| 197 | + this.setupY(); | ||
| 198 | + | ||
| 199 | + if (conf.dot.d3ColorCategory) { | ||
| 200 | + this.plot.dot.colorCategory = d3.scale[conf.dot.d3ColorCategory](); | ||
| 201 | + } | ||
| 202 | + var colorValue = conf.dot.color; | ||
| 203 | + if (colorValue) { | ||
| 204 | + this.plot.dot.colorValue = colorValue; | ||
| 205 | + | ||
| 206 | + if (typeof colorValue === 'string' || colorValue instanceof String) { | ||
| 207 | + this.plot.dot.color = colorValue; | ||
| 208 | + } else if (this.plot.dot.colorCategory) { | ||
| 209 | + this.plot.dot.color = function (d) { | ||
| 210 | + return self.plot.dot.colorCategory(self.plot.dot.colorValue(d)); | ||
| 211 | + } | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + | ||
| 215 | + }else if(conf.traits.categoryKey){ | ||
| 216 | + this.plot.dot.color = function (d) { | ||
| 217 | + return self.plot.dot.colorCategory(d[conf.traits.categoryKey]); | ||
| 218 | + } | ||
| 219 | + } | ||
| 220 | + | ||
| 221 | + | ||
| 222 | + | ||
| 223 | + return this; | ||
| 224 | + | ||
| 225 | +}; | ||
| 226 | + | ||
| 227 | +D3ScatterPlotMatrix.prototype.setupTraits = function () { | ||
| 228 | + var traitsConf = this.config.traits; | ||
| 229 | + | ||
| 230 | + var data = this.data; | ||
| 231 | + var plot = this.plot; | ||
| 232 | + plot.domainByTrait = {}; | ||
| 233 | + plot.traits = traitsConf.keys; | ||
| 234 | + if(!plot.traits || !plot.traits.length){ | ||
| 235 | + plot.traits = this.utils.inferTraits(data, traitsConf.categoryKey, traitsConf.includeCategoryInPlot); | ||
| 236 | + } | ||
| 237 | + | ||
| 238 | + plot.labels = []; | ||
| 239 | + plot.labelByTrait = {}; | ||
| 240 | + plot.traits.forEach(function(traitKey, index) { | ||
| 241 | + plot.domainByTrait[traitKey] = d3.extent(data, function(d) { return traitsConf.value(d, traitKey) }); | ||
| 242 | + var label = traitKey; | ||
| 243 | + if(traitsConf.labels && traitsConf.labels.length>index){ | ||
| 244 | + | ||
| 245 | + label = traitsConf.labels[index]; | ||
| 246 | + } | ||
| 247 | + plot.labels.push(label); | ||
| 248 | + plot.labelByTrait[traitKey] = label; | ||
| 249 | + }); | ||
| 250 | + | ||
| 251 | + console.log(plot.labelByTrait); | ||
| 252 | + | ||
| 253 | + plot.subplots = []; | ||
| 254 | +}; | ||
| 255 | + | ||
| 256 | +D3ScatterPlotMatrix.prototype.setupX = function () { | ||
| 257 | + | ||
| 258 | + var plot = this.plot; | ||
| 259 | + var x = plot.x; | ||
| 260 | + var conf = this.config; | ||
| 261 | + | ||
| 262 | + x.value = conf.traits.value; | ||
| 263 | + x.scale = d3.scale[conf.x.scale]().range([conf.padding / 2, plot.size - conf.padding / 2]); | ||
| 264 | + x.map = function (d, trait) { | ||
| 265 | + return x.scale(x.value(d, trait)); | ||
| 266 | + }; | ||
| 267 | + x.axis = d3.svg.axis().scale(x.scale).orient(conf.x.orient).ticks(conf.ticks); | ||
| 268 | + x.axis.tickSize(plot.size * plot.traits.length); | ||
| 269 | + | ||
| 270 | +}; | ||
| 271 | + | ||
| 272 | +D3ScatterPlotMatrix.prototype.setupY = function () { | ||
| 273 | + | ||
| 274 | + var plot = this.plot; | ||
| 275 | + var y = plot.y; | ||
| 276 | + var conf = this.config; | ||
| 277 | + | ||
| 278 | + y.value = conf.traits.value; | ||
| 279 | + y.scale = d3.scale[conf.y.scale]().range([ plot.size - conf.padding / 2, conf.padding / 2]); | ||
| 280 | + y.map = function (d, trait) { | ||
| 281 | + return y.scale(y.value(d, trait)); | ||
| 282 | + }; | ||
| 283 | + y.axis= d3.svg.axis().scale(y.scale).orient(conf.y.orient).ticks(conf.ticks); | ||
| 284 | + y.axis.tickSize(-plot.size * plot.traits.length); | ||
| 285 | +}; | ||
| 286 | + | ||
| 287 | + | ||
| 288 | +D3ScatterPlotMatrix.prototype.drawPlot = function () { | ||
| 289 | + var self =this; | ||
| 290 | + var n = self.plot.traits.length; | ||
| 291 | + var conf = this.config; | ||
| 292 | + self.svgG.selectAll(".mw-axis-x.mw-axis") | ||
| 293 | + .data(self.plot.traits) | ||
| 294 | + .enter().append("g") | ||
| 295 | + .attr("class", "mw-axis-x mw-axis"+(conf.guides ? '' : ' mw-no-guides')) | ||
| 296 | + .attr("transform", function(d, i) { return "translate(" + (n - i - 1) * self.plot.size + ",0)"; }) | ||
| 297 | + .each(function(d) { self.plot.x.scale.domain(self.plot.domainByTrait[d]); d3.select(this).call(self.plot.x.axis); }); | ||
| 298 | + | ||
| 299 | + self.svgG.selectAll(".mw-axis-y.mw-axis") | ||
| 300 | + .data(self.plot.traits) | ||
| 301 | + .enter().append("g") | ||
| 302 | + .attr("class", "mw-axis-y mw-axis"+(conf.guides ? '' : ' mw-no-guides')) | ||
| 303 | + .attr("transform", function(d, i) { return "translate(0," + i * self.plot.size + ")"; }) | ||
| 304 | + .each(function(d) { self.plot.y.scale.domain(self.plot.domainByTrait[d]); d3.select(this).call(self.plot.y.axis); }); | ||
| 305 | + | ||
| 306 | + | ||
| 307 | + if(conf.tooltip){ | ||
| 308 | + self.plot.tooltip = this.utils.selectOrAppend(d3.select(self.placeholderSelector), 'div.mw-tooltip', 'div') | ||
| 309 | + .attr("class", "mw-tooltip") | ||
| 310 | + .style("opacity", 0); | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + var cell = self.svgG.selectAll(".mw-cell") | ||
| 314 | + .data(self.utils.cross(self.plot.traits, self.plot.traits)) | ||
| 315 | + .enter().append("g") | ||
| 316 | + .attr("class", "mw-cell") | ||
| 317 | + .attr("transform", function(d) { return "translate(" + (n - d.i - 1) * self.plot.size + "," + d.j * self.plot.size + ")"; }); | ||
| 318 | + | ||
| 319 | + if(conf.brush){ | ||
| 320 | + this.drawBrush(cell); | ||
| 321 | + } | ||
| 322 | + | ||
| 323 | + cell.each(plotSubplot); | ||
| 324 | + | ||
| 325 | + | ||
| 326 | + | ||
| 327 | + //Labels | ||
| 328 | + cell.filter(function(d) { return d.i === d.j; }).append("text") | ||
| 329 | + .attr("x", conf.padding) | ||
| 330 | + .attr("y", conf.padding) | ||
| 331 | + .attr("dy", ".71em") | ||
| 332 | + .text(function(d) { return self.plot.labelByTrait[d.x]; }); | ||
| 333 | + | ||
| 334 | + | ||
| 335 | + | ||
| 336 | + | ||
| 337 | + function plotSubplot(p) { | ||
| 338 | + var plot = self.plot; | ||
| 339 | + plot.subplots.push(p); | ||
| 340 | + var cell = d3.select(this); | ||
| 341 | + | ||
| 342 | + plot.x.scale.domain(plot.domainByTrait[p.x]); | ||
| 343 | + plot.y.scale.domain(plot.domainByTrait[p.y]); | ||
| 344 | + | ||
| 345 | + cell.append("rect") | ||
| 346 | + .attr("class", "mw-frame") | ||
| 347 | + .attr("x", conf.padding / 2) | ||
| 348 | + .attr("y", conf.padding / 2) | ||
| 349 | + .attr("width", conf.size - conf.padding) | ||
| 350 | + .attr("height", conf.size - conf.padding); | ||
| 351 | + | ||
| 352 | + | ||
| 353 | + p.update = function(){ | ||
| 354 | + var subplot = this; | ||
| 355 | + var dots = cell.selectAll("circle") | ||
| 356 | + .data(self.data); | ||
| 357 | + | ||
| 358 | + dots.enter().append("circle"); | ||
| 359 | + | ||
| 360 | + dots.attr("cx", function(d){return plot.x.map(d, subplot.x)}) | ||
| 361 | + .attr("cy", function(d){return plot.y.map(d, subplot.y)}) | ||
| 362 | + .attr("r", self.config.dot.radius); | ||
| 363 | + | ||
| 364 | + if (plot.dot.color) { | ||
| 365 | + dots.style("fill", plot.dot.color) | ||
| 366 | + } | ||
| 367 | + | ||
| 368 | + if(plot.tooltip){ | ||
| 369 | + dots.on("mouseover", function(d) { | ||
| 370 | + plot.tooltip.transition() | ||
| 371 | + .duration(200) | ||
| 372 | + .style("opacity", .9); | ||
| 373 | + plot.tooltip.html("(" + plot.x.value(d, subplot.x) | ||
| 374 | + + ", " +plot.y.value(d, subplot.y) + ")") | ||
| 375 | + .style("left", (d3.event.pageX + 5) + "px") | ||
| 376 | + .style("top", (d3.event.pageY - 28) + "px"); | ||
| 377 | + }) | ||
| 378 | + .on("mouseout", function(d) { | ||
| 379 | + plot.tooltip.transition() | ||
| 380 | + .duration(500) | ||
| 381 | + .style("opacity", 0); | ||
| 382 | + }); | ||
| 383 | + } | ||
| 384 | + | ||
| 385 | + dots.exit().remove(); | ||
| 386 | + }; | ||
| 387 | + | ||
| 388 | + p.update(); | ||
| 389 | + } | ||
| 390 | + | ||
| 391 | + | ||
| 392 | +}; | ||
| 393 | + | ||
| 394 | +D3ScatterPlotMatrix.prototype.update = function () { | ||
| 395 | + this.plot.subplots.forEach(function(p){p.update()}); | ||
| 396 | +}; | ||
| 397 | + | ||
| 398 | + | ||
| 399 | +D3ScatterPlotMatrix.prototype.initSvg = function () { | ||
| 400 | + | ||
| 401 | + var self = this; | ||
| 402 | + var config = this.config; | ||
| 403 | + | ||
| 404 | + | ||
| 405 | + | ||
| 406 | + var width = self.plot.width+ config.margin.left + config.margin.right; | ||
| 407 | + var height = self.plot.height+ config.margin.top + config.margin.bottom; | ||
| 408 | + var aspect = width / height; | ||
| 409 | + | ||
| 410 | + | ||
| 411 | + | ||
| 412 | + self.svg = d3.select(self.placeholderSelector).select("svg"); | ||
| 413 | + if(!self.svg.empty()){ | ||
| 414 | + self.svg.remove(); | ||
| 415 | + | ||
| 416 | + } | ||
| 417 | + self.svg = d3.select(self.placeholderSelector).append("svg"); | ||
| 418 | + | ||
| 419 | + self.svg | ||
| 420 | + .attr("width", width) | ||
| 421 | + .attr("height", height) | ||
| 422 | + .attr("viewBox", "0 0 "+" "+width+" "+height) | ||
| 423 | + .attr("preserveAspectRatio", "xMidYMid meet") | ||
| 424 | + .attr("class", "mw-d3-scatterplot-matrix"); | ||
| 425 | + | ||
| 426 | + self.svgG = self.svg.append("g") | ||
| 427 | + .attr("class", "mw-container") | ||
| 428 | + .attr("transform", "translate(" + config.margin.left + "," + config.margin.top + ")"); | ||
| 429 | + | ||
| 430 | + | ||
| 431 | + if(!config.width || config.height ){ | ||
| 432 | + d3.select(window) | ||
| 433 | + .on("resize", function() { | ||
| 434 | + //TODO add responsiveness if width/height not specified | ||
| 435 | + }); | ||
| 436 | + } | ||
| 437 | +}; | ||
| 438 | + | ||
| 439 | +D3ScatterPlotMatrix.prototype.init = function () { | ||
| 440 | + var self = this; | ||
| 441 | + self.initPlot(); | ||
| 442 | + self.initSvg(); | ||
| 443 | + self.drawPlot(); | ||
| 444 | +}; | ||
| 445 | + | ||
| 446 | +D3ScatterPlotMatrix.prototype.drawBrush = function (cell) { | ||
| 447 | + var self = this; | ||
| 448 | + var brush = d3.svg.brush() | ||
| 449 | + .x(self.plot.x.scale) | ||
| 450 | + .y(self.plot.y.scale) | ||
| 451 | + .on("brushstart", brushstart) | ||
| 452 | + .on("brush", brushmove) | ||
| 453 | + .on("brushend", brushend); | ||
| 454 | + | ||
| 455 | + cell.append("g").call(brush); | ||
| 456 | + | ||
| 457 | + | ||
| 458 | + var brushCell; | ||
| 459 | + | ||
| 460 | + // Clear the previously-active brush, if any. | ||
| 461 | + function brushstart(p) { | ||
| 462 | + if (brushCell !== this) { | ||
| 463 | + d3.select(brushCell).call(brush.clear()); | ||
| 464 | + self.plot.x.scale.domain(self.plot.domainByTrait[p.x]); | ||
| 465 | + self.plot.y.scale.domain(self.plot.domainByTrait[p.y]); | ||
| 466 | + brushCell = this; | ||
| 467 | + } | ||
| 468 | + } | ||
| 469 | + | ||
| 470 | + // Highlight the selected circles. | ||
| 471 | + function brushmove(p) { | ||
| 472 | + var e = brush.extent(); | ||
| 473 | + self.svgG.selectAll("circle").classed("hidden", function (d) { | ||
| 474 | + return e[0][0] > d[p.x] || d[p.x] > e[1][0] | ||
| 475 | + || e[0][1] > d[p.y] || d[p.y] > e[1][1]; | ||
| 476 | + }); | ||
| 477 | + } | ||
| 478 | + // If the brush is empty, select all circles. | ||
| 479 | + function brushend() { | ||
| 480 | + if (brush.empty()) self.svgG.selectAll(".hidden").classed("hidden", false); | ||
| 481 | + } | ||
| 482 | +}; | ||
| 483 | + |
bower_components/d3-scatterplot-matrix/dist/d3-scatterplot-matrix.min.css
0 → 100644
| 1 | +svg.mw-d3-scatterplot-matrix .mw-axis path,svg.mw-d3-scatterplot-matrix .mw-axis.mw-no-guides line{display:none}svg.mw-d3-scatterplot-matrix{background-color:#fff;font-size:11px;height:100%}svg.mw-d3-scatterplot-matrix .mw-axis{shape-rendering:crispEdges}svg.mw-d3-scatterplot-matrix .mw-axis line{stroke:#ddd}svg.mw-d3-scatterplot-matrix .mw-frame{shape-rendering:crispEdges;fill:none;stroke:#aaa}svg.mw-d3-scatterplot-matrix .mw-cell text{font-weight:700;text-transform:capitalize}svg.mw-d3-scatterplot-matrix circle{fill-opacity:.7}svg.mw-d3-scatterplot-matrix circle.hidden{fill:#ccc!important}svg.mw-d3-scatterplot-matrix .extent{fill:#000;fill-opacity:.125;stroke:#fff}.mw-tooltip{position:absolute;pointer-events:none;font-size:11px;background:#fdfdfd;padding:3px 5px;border-radius:8px;box-shadow:1px 3px 3px #b7b7b7} | ||
| 0 | \ No newline at end of file | 2 | \ No newline at end of file |
bower_components/d3-scatterplot-matrix/dist/d3-scatterplot-matrix.min.js
0 → 100644
| 1 | +function D3ScatterPlotMatrixUtils(){}D3ScatterPlotMatrixUtils.prototype.deepExtend=function(t){var r=this;!t&&arguments.length>1&&Array.isArray(arguments[1])&&(t=[]),t=t||{};for(var e=1;e<arguments.length;e++){var i=arguments[e];if(i)for(var n in i)if(i.hasOwnProperty(n)){var o=Array.isArray(t[n]),a=r.isObject(t[n]),p=r.isObject(i[n]);a&&!o&&p?r.deepExtend(t[n],i[n]):t[n]=i[n]}}return t},D3ScatterPlotMatrixUtils.prototype.cross=function(t,r){var e,i,n=[],o=t.length,a=r.length;for(e=-1;++e<o;)for(i=-1;++i<a;)n.push({x:t[e],i:e,y:r[i],j:i});return n},D3ScatterPlotMatrixUtils.prototype.inferTraits=function(t,r,e){var i=[];if(t.length){var n=t[0];if(n instanceof Array)i=n.map(function(t,r){return r});else if("object"==typeof n)for(var o in n)n.hasOwnProperty(o)&&i.push(o)}if(!e){var a=i.indexOf(r);a>-1&&i.splice(a,1)}return i},D3ScatterPlotMatrixUtils.prototype.isObject=function(t){return null!==t&&"object"==typeof t},D3ScatterPlotMatrixUtils.prototype.isNumber=function(t){return!isNaN(t)&&"number"==typeof t},D3ScatterPlotMatrixUtils.prototype.isFunction=function(t){return"function"==typeof t},D3ScatterPlotMatrixUtils.prototype.selectOrAppend=function(t,r,e){var i=t.select(r);return i.empty()?t.append(e||r):i}; | ||
| 2 | +function D3ScatterPlotMatrix(t,i,e){this.utils=new D3ScatterPlotMatrixUtils,this.placeholderSelector=t,this.svg=null,this.defaultConfig={width:0,size:200,padding:20,brush:!0,guides:!0,tooltip:!0,ticks:null,margin:{left:30,right:30,top:30,bottom:30},x:{orient:"bottom",scale:"linear"},y:{orient:"left",scale:"linear"},dot:{radius:2,color:null,d3ColorCategory:"category10"},traits:{labels:[],keys:[],categoryKey:null,includeCategoryInPlot:!1,value:function(t,i){return t[i]}}},e&&this.setConfig(e),i&&this.setData(i),this.init()}D3ScatterPlotMatrix.prototype.setData=function(t){return this.data=t,this},D3ScatterPlotMatrix.prototype.setConfig=function(t){return this.config=this.utils.deepExtend({},this.defaultConfig,t),this},D3ScatterPlotMatrix.prototype.initPlot=function(){var t=this,i=this.config.margin,e=this.config;this.plot={x:{},y:{},dot:{color:null}},this.setupTraits(),this.plot.size=e.size;var a=e.width,o=d3.select(this.placeholderSelector).node();if(!a){var l=i.left+i.right+this.plot.traits.length*this.plot.size;a=Math.min(o.getBoundingClientRect().width,l)}var r=a;r||(r=o.getBoundingClientRect().height),this.plot.width=a-i.left-i.right,this.plot.height=r-i.top-i.bottom,null===e.ticks&&(e.ticks=this.plot.size/40),this.setupX(),this.setupY(),e.dot.d3ColorCategory&&(this.plot.dot.colorCategory=d3.scale[e.dot.d3ColorCategory]());var s=e.dot.color;return s?(this.plot.dot.colorValue=s,"string"==typeof s||s instanceof String?this.plot.dot.color=s:this.plot.dot.colorCategory&&(this.plot.dot.color=function(i){return t.plot.dot.colorCategory(t.plot.dot.colorValue(i))})):e.traits.categoryKey&&(this.plot.dot.color=function(i){return t.plot.dot.colorCategory(i[e.traits.categoryKey])}),this},D3ScatterPlotMatrix.prototype.setupTraits=function(){var t=this.config.traits,i=this.data,e=this.plot;e.domainByTrait={},e.traits=t.keys,e.traits&&e.traits.length||(e.traits=this.utils.inferTraits(i,t.categoryKey,t.includeCategoryInPlot)),e.labels=[],e.labelByTrait={},e.traits.forEach(function(a,o){e.domainByTrait[a]=d3.extent(i,function(i){return t.value(i,a)});var l=a;t.labels&&t.labels.length>o&&(l=t.labels[o]),e.labels.push(l),e.labelByTrait[a]=l}),void 0,e.subplots=[]},D3ScatterPlotMatrix.prototype.setupX=function(){var t=this.plot,i=t.x,e=this.config;i.value=e.traits.value,i.scale=d3.scale[e.x.scale]().range([e.padding/2,t.size-e.padding/2]),i.map=function(t,e){return i.scale(i.value(t,e))},i.axis=d3.svg.axis().scale(i.scale).orient(e.x.orient).ticks(e.ticks),i.axis.tickSize(t.size*t.traits.length)},D3ScatterPlotMatrix.prototype.setupY=function(){var t=this.plot,i=t.y,e=this.config;i.value=e.traits.value,i.scale=d3.scale[e.y.scale]().range([t.size-e.padding/2,e.padding/2]),i.map=function(t,e){return i.scale(i.value(t,e))},i.axis=d3.svg.axis().scale(i.scale).orient(e.y.orient).ticks(e.ticks),i.axis.tickSize(-t.size*t.traits.length)},D3ScatterPlotMatrix.prototype.drawPlot=function(){function t(t){var e=i.plot;e.subplots.push(t);var o=d3.select(this);e.x.scale.domain(e.domainByTrait[t.x]),e.y.scale.domain(e.domainByTrait[t.y]),o.append("rect").attr("class","mw-frame").attr("x",a.padding/2).attr("y",a.padding/2).attr("width",a.size-a.padding).attr("height",a.size-a.padding),t.update=function(){var t=this,a=o.selectAll("circle").data(i.data);a.enter().append("circle"),a.attr("cx",function(i){return e.x.map(i,t.x)}).attr("cy",function(i){return e.y.map(i,t.y)}).attr("r",i.config.dot.radius),e.dot.color&&a.style("fill",e.dot.color),e.tooltip&&a.on("mouseover",function(i){e.tooltip.transition().duration(200).style("opacity",.9),e.tooltip.html("("+e.x.value(i,t.x)+", "+e.y.value(i,t.y)+")").style("left",d3.event.pageX+5+"px").style("top",d3.event.pageY-28+"px")}).on("mouseout",function(t){e.tooltip.transition().duration(500).style("opacity",0)}),a.exit().remove()},t.update()}var i=this,e=i.plot.traits.length,a=this.config;i.svgG.selectAll(".mw-axis-x.mw-axis").data(i.plot.traits).enter().append("g").attr("class","mw-axis-x mw-axis"+(a.guides?"":" mw-no-guides")).attr("transform",function(t,a){return"translate("+(e-a-1)*i.plot.size+",0)"}).each(function(t){i.plot.x.scale.domain(i.plot.domainByTrait[t]),d3.select(this).call(i.plot.x.axis)}),i.svgG.selectAll(".mw-axis-y.mw-axis").data(i.plot.traits).enter().append("g").attr("class","mw-axis-y mw-axis"+(a.guides?"":" mw-no-guides")).attr("transform",function(t,e){return"translate(0,"+e*i.plot.size+")"}).each(function(t){i.plot.y.scale.domain(i.plot.domainByTrait[t]),d3.select(this).call(i.plot.y.axis)}),a.tooltip&&(i.plot.tooltip=this.utils.selectOrAppend(d3.select(i.placeholderSelector),"div.mw-tooltip","div").attr("class","mw-tooltip").style("opacity",0));var o=i.svgG.selectAll(".mw-cell").data(i.utils.cross(i.plot.traits,i.plot.traits)).enter().append("g").attr("class","mw-cell").attr("transform",function(t){return"translate("+(e-t.i-1)*i.plot.size+","+t.j*i.plot.size+")"});a.brush&&this.drawBrush(o),o.each(t),o.filter(function(t){return t.i===t.j}).append("text").attr("x",a.padding).attr("y",a.padding).attr("dy",".71em").text(function(t){return i.plot.labelByTrait[t.x]})},D3ScatterPlotMatrix.prototype.update=function(){this.plot.subplots.forEach(function(t){t.update()})},D3ScatterPlotMatrix.prototype.initSvg=function(){var t=this,i=this.config,e=t.plot.width+i.margin.left+i.margin.right,a=t.plot.height+i.margin.top+i.margin.bottom;t.svg=d3.select(t.placeholderSelector).select("svg"),t.svg.empty()||t.svg.remove(),t.svg=d3.select(t.placeholderSelector).append("svg"),t.svg.attr("width",e).attr("height",a).attr("viewBox","0 0 "+e+" "+a).attr("preserveAspectRatio","xMidYMid meet").attr("class","mw-d3-scatterplot-matrix"),t.svgG=t.svg.append("g").attr("class","mw-container").attr("transform","translate("+i.margin.left+","+i.margin.top+")"),i.width&&!i.height||d3.select(window).on("resize",function(){})},D3ScatterPlotMatrix.prototype.init=function(){var t=this;t.initPlot(),t.initSvg(),t.drawPlot()},D3ScatterPlotMatrix.prototype.drawBrush=function(t){function i(t){r!==this&&(d3.select(r).call(l.clear()),o.plot.x.scale.domain(o.plot.domainByTrait[t.x]),o.plot.y.scale.domain(o.plot.domainByTrait[t.y]),r=this)}function e(t){var i=l.extent();o.svgG.selectAll("circle").classed("hidden",function(e){return i[0][0]>e[t.x]||e[t.x]>i[1][0]||i[0][1]>e[t.y]||e[t.y]>i[1][1]})}function a(){l.empty()&&o.svgG.selectAll(".hidden").classed("hidden",!1)}var o=this,l=d3.svg.brush().x(o.plot.x.scale).y(o.plot.y.scale).on("brushstart",i).on("brush",e).on("brushend",a);t.append("g").call(l);var r}; | ||
| 0 | \ No newline at end of file | 3 | \ No newline at end of file |
datalets/scatterplot-datalet/scatterplot-datalet.html