Mercurial > repos > immport-devteam > flow_overview
comparison js/boxplotsFlow.js @ 1:b5453d07f740 draft default tip
"planemo upload for repository https://github.com/ImmPortDB/immport-galaxy-tools/tree/master/flowtools/flow_overview commit 65373effef15809f3db0e5f9603ef808f4110aa3"
| author | azomics |
|---|---|
| date | Wed, 29 Jul 2020 17:03:53 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:8283ff163ba6 | 1:b5453d07f740 |
|---|---|
| 1 // Copyright (c) 2016 Northrop Grumman. | |
| 2 // All rights reserved. | |
| 3 var updateBPmfi = function(plotconfig){ | |
| 4 plotconfig.selectedPopulations = []; | |
| 5 $(plotconfig.popSelectj).each(function() { | |
| 6 if (this.checked) { | |
| 7 plotconfig.selectedPopulations.push(parseInt(this.value)); | |
| 8 } | |
| 9 }); | |
| 10 // Update selected markers? | |
| 11 plotconfig.selectedMarkers = []; | |
| 12 $(plotconfig.mrkrSelectj).each(function() { | |
| 13 if (this.checked) { | |
| 14 plotconfig.selectedMarkers.push(parseInt(this.value)); | |
| 15 } | |
| 16 }); | |
| 17 // update plot | |
| 18 updateBoxplotMFI(plotconfig); | |
| 19 }; | |
| 20 | |
| 21 var displayPopulationLegend = function(plotconfig) { | |
| 22 $(plotconfig.table).empty(); | |
| 23 plotconfig.allPopulations.map(function(value,index) { | |
| 24 $(plotconfig.table).append('<tr><td align="center">' | |
| 25 + '<input type="checkbox" checked class=' + plotconfig.popSelect | |
| 26 + ' value=' + value + '/></td><td title="' + newNames[value] + '">' | |
| 27 + newNames[value] + '</td><td><span style="background-color:' | |
| 28 + color_palette[0][value][0] + '"> </span></td></tr>'); | |
| 29 }); | |
| 30 | |
| 31 $(plotconfig.popSelectAll).click(function() { | |
| 32 var checkAll = $(plotconfig.popSelectAll).prop('checked'); | |
| 33 if (checkAll) { | |
| 34 $(plotconfig.popSelectj).prop("checked", true); | |
| 35 } else { | |
| 36 $(plotconfig.popSelectj).prop("checked", false); | |
| 37 } | |
| 38 updateBPmfi(plotconfig); | |
| 39 }); | |
| 40 | |
| 41 $(plotconfig.popSelectj).click(function() { | |
| 42 if ($(plotconfig.popSelectj).length == $(plotconfig.popSelectCheck).length) { | |
| 43 $(plotconfig.popSelectAll).prop("checked",true); | |
| 44 } else { | |
| 45 $(plotconfig.popSelectAll).prop("checked",false); | |
| 46 } | |
| 47 updateBPmfi(plotconfig); | |
| 48 }); | |
| 49 | |
| 50 $(plotconfig.popSelectj).each(function() { | |
| 51 var selectedpopn = parseInt(this.value); | |
| 52 if ($.inArray(selectedpopn,plotconfig.selectedPopulations) > -1) { | |
| 53 this.checked = true; | |
| 54 } else { | |
| 55 this.checked = false; | |
| 56 } | |
| 57 }); | |
| 58 }; | |
| 59 | |
| 60 var displayToolbar = function(plotconfig){ | |
| 61 $(plotconfig.displaybutton).on("click",function() { | |
| 62 $(plotconfig.popSelectAll).prop("checked",true); | |
| 63 $(plotconfig.popSelectj).prop("checked", true); | |
| 64 $(plotconfig.mrkrSelectj).prop("checked", true); | |
| 65 $(plotconfig.mrkrSelectAll).prop("checked",true); | |
| 66 $(plotconfig.displayMFI).prop("checked", false); | |
| 67 $(plotconfig.displayvalues).prop("checked", false); | |
| 68 updateBPmfi(plotconfig); | |
| 69 }); | |
| 70 | |
| 71 $(plotconfig.toggledisplayj).on("click",function() { | |
| 72 var text = document.getElementById(plotconfig.toggledisplay).firstChild; | |
| 73 text.data = text.data == "View per marker" ? "View per population" : "View per marker"; | |
| 74 plotconfig.view = plotconfig.view == "p" ? "m" : "p"; | |
| 75 updateBPmfi(plotconfig); | |
| 76 }); | |
| 77 | |
| 78 $(plotconfig.displayMFI).on("click", function(){ | |
| 79 updateBPmfi(plotconfig); | |
| 80 }); | |
| 81 | |
| 82 $(plotconfig.displayvalues).on("click", function(){ | |
| 83 updateBPmfi(plotconfig); | |
| 84 }); | |
| 85 | |
| 86 displayPlot(plotconfig); | |
| 87 }; | |
| 88 | |
| 89 var displayPlot = function(plotconfig) { | |
| 90 var h = $(window).height() - 200, | |
| 91 nbPop = Object.keys(plotconfig.csdata.mfi[plotconfig.mrkrNames[0]]).length + 2; | |
| 92 | |
| 93 $(plotconfig.plotdivj).empty(); | |
| 94 $(plotconfig.plotdivj).height(h); | |
| 95 | |
| 96 // Get Markers too | |
| 97 for (var i = 0, nbMarkers = plotconfig.mrkrNames.length; i < nbMarkers; i++){ | |
| 98 plotconfig.allMarkers.push(i); | |
| 99 plotconfig.selectedMarkers.push(i); | |
| 100 } | |
| 101 for (var i = 2; i < nbPop; i++) { | |
| 102 plotconfig.allPopulations.push(i - 1); | |
| 103 plotconfig.selectedPopulations.push(i - 1); | |
| 104 } | |
| 105 | |
| 106 $(window).on('resize',function() { | |
| 107 waitForFinalEvent(function() { | |
| 108 updateBoxplotMFI(plotconfig); | |
| 109 }, 500, "resizePlot"); | |
| 110 }); | |
| 111 | |
| 112 displayPopulationLegend(plotconfig); | |
| 113 displayMarkerTable(plotconfig); | |
| 114 updateBoxplotMFI(plotconfig); | |
| 115 }; | |
| 116 | |
| 117 var displayMarkerTable = function(plotconfig){ | |
| 118 var nbm = plotconfig.mrkrNames.length + 1; | |
| 119 $(plotconfig.mtable).empty(); | |
| 120 plotconfig.allMarkers.map(function(v) { | |
| 121 $(plotconfig.mtable).append('<tr>' | |
| 122 + '<td><span style="background-color:rgba(0,0,0,' + (v + 1 )/ nbm + ')' | |
| 123 + '"> </span></td>' | |
| 124 + '<td title="' + plotconfig.mrkrNames[v] + '">' | |
| 125 + plotconfig.mrkrNames[v] + '</td>' | |
| 126 + '<td align="center"><input type="checkbox" checked class=' | |
| 127 + plotconfig.mrkrSelect + ' value=' + v + '/></td></tr>'); | |
| 128 }); | |
| 129 | |
| 130 if (nbm > 5) { | |
| 131 $(plotconfig.mrkrSelectAll).prop('checked', false); | |
| 132 $(plotconfig.mrkrSelectAll).prop('disabled', true); | |
| 133 $('#markerWarning').show(); | |
| 134 $(plotconfig.mrkrSelectj).each(function() { | |
| 135 var selectedMrkr = parseInt(this.value); | |
| 136 if (selectedMrkr > 4){ | |
| 137 this.checked = false; | |
| 138 this.disabled = true; | |
| 139 } else { | |
| 140 this.checked = true; | |
| 141 } | |
| 142 }); | |
| 143 } | |
| 144 | |
| 145 $(plotconfig.mrkrSelectAll).click(function() { | |
| 146 var checkAll = $(plotconfig.mrkrSelectAll).prop('checked'); | |
| 147 if (checkAll) { | |
| 148 $(plotconfig.mrkrSelectj).prop("checked", true); | |
| 149 } else { | |
| 150 $(plotconfig.mrkrSelectj).prop("checked", false); | |
| 151 } | |
| 152 updateBPmfi(plotconfig); | |
| 153 }); | |
| 154 | |
| 155 $(plotconfig.mrkrSelectj).click(function() { | |
| 156 if (nbm < 6){ | |
| 157 if ($(plotconfig.mrkrSelectj).length == $(plotconfig.mrkrSelectCheck).length) { | |
| 158 $(plotconfig.mrkrSelectAll).prop("checked",true); | |
| 159 } else { | |
| 160 $(plotconfig.mrkrSelectAll).prop("checked",false); | |
| 161 } | |
| 162 } else { | |
| 163 var nbSelected = 0; | |
| 164 $(plotconfig.mrkrSelectj).each(function() { | |
| 165 if (this.checked) {nbSelected++} | |
| 166 }); | |
| 167 if (nbSelected < 5) { | |
| 168 $(plotconfig.mrkrSelectj).prop('disabled', false); | |
| 169 } else { | |
| 170 $(plotconfig.mrkrSelectj).each(function() { | |
| 171 if (!this.checked) { | |
| 172 this.disabled = true; | |
| 173 } | |
| 174 }); | |
| 175 } | |
| 176 } | |
| 177 updateBPmfi(plotconfig); | |
| 178 }); | |
| 179 }; | |
| 180 | |
| 181 var updateBoxplotMFI = function(plotconfig){ | |
| 182 var margin = {top: 30, right: 10, bottom: 50, left: 60}, | |
| 183 h = 0, | |
| 184 w = 0, | |
| 185 width = 0, | |
| 186 height = 0, | |
| 187 labels = false, // show the text labels beside individual boxplots? | |
| 188 mfi_option = false, | |
| 189 checkLabels = $(plotconfig.displayvalues).prop("checked"), | |
| 190 checkMFI = $(plotconfig.displayMFI).prop("checked"), | |
| 191 dataToPlot = [], | |
| 192 tmp = [], | |
| 193 nbm = plotconfig.mrkrNames.length + 1, | |
| 194 maxRange = 0, | |
| 195 minRange = 0, | |
| 196 domainx = [], | |
| 197 domainx1 = [], | |
| 198 min = Infinity, | |
| 199 max = -Infinity; | |
| 200 | |
| 201 $(plotconfig.plotdivj).empty(); | |
| 202 h = $(window).height() - 200; | |
| 203 $(plotconfig.plotdivj).height(h); | |
| 204 w = $(plotconfig.plotdivj).width(); | |
| 205 width = w - margin.left - margin.right; | |
| 206 height = h - margin.top - margin.bottom; | |
| 207 | |
| 208 var svg = d3.select(plotconfig.plotdivj).append("svg") | |
| 209 .attr("width", width + margin.left + margin.right) | |
| 210 .attr("height", height + margin.top + margin.bottom) | |
| 211 .attr("class", "box") | |
| 212 .append("g") | |
| 213 .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); | |
| 214 | |
| 215 if (checkLabels) { | |
| 216 labels = true; | |
| 217 }; | |
| 218 if (checkMFI) { | |
| 219 mfi_option = true; | |
| 220 }; | |
| 221 | |
| 222 /* Get the data in proper shape to feed to the boxplot function | |
| 223 want [Object, Object, ..., Object] where Object: | |
| 224 'population': pop | |
| 225 'Data' : [Object, Object, ..., Object] where Object: | |
| 226 'Marker' : marker name | |
| 227 'outliers' : outliers | |
| 228 */ | |
| 229 | |
| 230 if (plotconfig.view == 'p') { | |
| 231 plotconfig.selectedPopulations.forEach(function(p) { | |
| 232 tmpPlot = []; | |
| 233 plotconfig.selectedMarkers.forEach(function(m) { | |
| 234 var markernm = plotconfig.mrkrNames[m], | |
| 235 qtmp = [ | |
| 236 +plotconfig.csdata.q1[markernm][p], | |
| 237 +plotconfig.csdata.q2[markernm][p], | |
| 238 +plotconfig.csdata.q3[markernm][p] | |
| 239 ], | |
| 240 wtmp = [ | |
| 241 +plotconfig.csdata.lower[markernm][p], | |
| 242 +plotconfig.csdata.upper[markernm][p] | |
| 243 ]; | |
| 244 tmp = []; | |
| 245 // Get min and max while we're here | |
| 246 plotconfig.csdata.outliers[markernm][p].forEach(function(outl) { | |
| 247 tmp.push(+outl); | |
| 248 if (+outl > max) {max = +outl}; | |
| 249 if (+outl < min) {min = +outl}; | |
| 250 }); | |
| 251 if (+plotconfig.csdata.upper[markernm][p] > max) { | |
| 252 max = +plotconfig.csdata.upper[markernm][p]; | |
| 253 } | |
| 254 if (+plotconfig.csdata.lower[markernm][p] < min) { | |
| 255 min = +plotconfig.csdata.lower[markernm][p]; | |
| 256 } | |
| 257 tmpPlot.push({ | |
| 258 marker: markernm, | |
| 259 outliers: tmp, | |
| 260 quartiles: qtmp, | |
| 261 whiskers: wtmp, | |
| 262 config: [m,p, nbm], | |
| 263 mfi: +plotconfig.csdata.mfi[markernm][p] | |
| 264 }); | |
| 265 }); | |
| 266 dataToPlot.push({population:p, popdata: tmpPlot}); | |
| 267 }); | |
| 268 } else { | |
| 269 plotconfig.selectedMarkers.forEach(function(m) { | |
| 270 var markernm = plotconfig.mrkrNames[m]; | |
| 271 tmpPlot = []; | |
| 272 plotconfig.selectedPopulations.forEach(function(p) { | |
| 273 var qtmp = [ | |
| 274 +plotconfig.csdata.q1[markernm][p], | |
| 275 +plotconfig.csdata.q2[markernm][p], | |
| 276 +plotconfig.csdata.q3[markernm][p] | |
| 277 ], | |
| 278 wtmp = [ | |
| 279 +plotconfig.csdata.lower[markernm][p], | |
| 280 +plotconfig.csdata.upper[markernm][p] | |
| 281 ]; | |
| 282 // Get min and max while we're here | |
| 283 tmp = []; | |
| 284 plotconfig.csdata.outliers[markernm][p].forEach(function(outl) { | |
| 285 tmp.push(+outl); | |
| 286 if (+outl > max) {max = +outl}; | |
| 287 if (+outl < min) {min = +outl}; | |
| 288 }); | |
| 289 if (+plotconfig.csdata.upper[markernm][p] > max) { | |
| 290 max = +plotconfig.csdata.upper[markernm][p]; | |
| 291 } | |
| 292 if (+plotconfig.csdata.lower[markernm][p] < min) { | |
| 293 min = +plotconfig.csdata.lower[markernm][p]; | |
| 294 } | |
| 295 tmpPlot.push({ | |
| 296 population:p, | |
| 297 outliers: tmp, | |
| 298 quartiles: qtmp, | |
| 299 whiskers: wtmp, | |
| 300 config: [m,p, nbm], | |
| 301 mfi: +plotconfig.csdata.mfi[markernm][p] | |
| 302 }); | |
| 303 }); | |
| 304 dataToPlot.push({marker: markernm, popdata: tmpPlot}); | |
| 305 }); | |
| 306 }; | |
| 307 maxRange = max + 30; | |
| 308 minRange = min - 30; | |
| 309 | |
| 310 if (plotconfig.view == 'p') { | |
| 311 domainx = plotconfig.selectedPopulations; | |
| 312 domainx1 = plotconfig.selectedMarkers.map(function(d){ | |
| 313 return plotconfig.mrkrNames[d] | |
| 314 }); | |
| 315 } else { | |
| 316 domainx1 = plotconfig.selectedPopulations; | |
| 317 domainx = plotconfig.selectedMarkers.map(function(d){ | |
| 318 return plotconfig.mrkrNames[d] | |
| 319 }); | |
| 320 } | |
| 321 // axes | |
| 322 var xScale = d3.scale.ordinal() | |
| 323 .domain(domainx) | |
| 324 .rangeRoundBands([0 , width], 0.2, 0.02); | |
| 325 | |
| 326 var x1Scale = d3.scale.ordinal() | |
| 327 .domain(domainx1) | |
| 328 .rangeRoundBands([0, xScale.rangeBand()], 0.1); | |
| 329 | |
| 330 var xAxis = d3.svg.axis() | |
| 331 .scale(xScale) | |
| 332 .orient("bottom"); | |
| 333 | |
| 334 // the y-axis | |
| 335 var yScale = d3.scale.linear() | |
| 336 .domain([minRange, maxRange]) | |
| 337 .range([height + margin.top, 0 + margin.top]); | |
| 338 | |
| 339 var yAxis = d3.svg.axis() | |
| 340 .scale(yScale) | |
| 341 .orient("left") | |
| 342 .tickFormat(d3.format("d")); | |
| 343 | |
| 344 svg.append("g") | |
| 345 .attr("class", "x axisbp") | |
| 346 .attr("transform", "translate(0," + (height + margin.top) + ")") | |
| 347 .call(xAxis); | |
| 348 | |
| 349 svg.append("g") | |
| 350 .attr("class", "y axisbp") | |
| 351 .call(yAxis) | |
| 352 .append("text") | |
| 353 .attr("class", "ylabel") | |
| 354 .attr("transform", "rotate(-90)") | |
| 355 .attr("y", 0 - margin.left) | |
| 356 .attr("x", 0 - (height / 2)) | |
| 357 .attr("dy", "1em") | |
| 358 .style("text-anchor", "middle") | |
| 359 .text("MFI values"); | |
| 360 | |
| 361 var boxplot = d3.box() | |
| 362 .width(x1Scale.rangeBand()) | |
| 363 .height(height + margin.top) | |
| 364 .domain([minRange, maxRange]) | |
| 365 .showLabels(labels) | |
| 366 .showMFI(mfi_option); | |
| 367 | |
| 368 if (plotconfig.view == 'p'){ | |
| 369 var group = svg.selectAll(".groups") | |
| 370 .data(dataToPlot) | |
| 371 .enter().append("g") | |
| 372 .attr("class", "group") | |
| 373 .attr("transform", function(d) { | |
| 374 return "translate(" + xScale(d.population) + ",0)"; | |
| 375 }); | |
| 376 | |
| 377 group.selectAll(".box") | |
| 378 .data(function(d) { return d.popdata; }) | |
| 379 .enter().append("g") | |
| 380 .attr("transform", function(d) { return "translate(" + x1Scale(d.marker) + ",0)"; }) | |
| 381 .call(boxplot); | |
| 382 } else { | |
| 383 var group = svg.selectAll(".groups") | |
| 384 .data(dataToPlot) | |
| 385 .enter().append("g") | |
| 386 .attr("class", "group") | |
| 387 .attr("transform", function(d) { | |
| 388 return "translate(" + xScale(d.marker) + ",0)"; | |
| 389 }); | |
| 390 | |
| 391 group.selectAll(".box") | |
| 392 .data(function(d) { return d.popdata; }) | |
| 393 .enter().append("g") | |
| 394 .attr("transform", function(d) { return "translate(" + x1Scale(d.population) + ",0)"; }) | |
| 395 .call(boxplot); | |
| 396 } | |
| 397 }; | |
| 398 | |
| 399 (function() { | |
| 400 // Inspired by http://informationandvisualization.de/blog/box-plot | |
| 401 // Modified to fit our data structure. | |
| 402 d3.box = function() { | |
| 403 var width = 1, | |
| 404 height = 1, | |
| 405 duration = 0, | |
| 406 domain = null, | |
| 407 value = Number, | |
| 408 showLabels = true, // whether or not to show text labels | |
| 409 numBars = 4, | |
| 410 curBar = 1, | |
| 411 showMFI = true, // display MFI ? | |
| 412 tickFormat = null; | |
| 413 var margin = {top: 30, right: 10, bottom: 50, left: 60}; | |
| 414 | |
| 415 // For each small multiple… | |
| 416 function box(g) { | |
| 417 g.each(function(data, i) { | |
| 418 var d = data.outliers.sort(d3.ascending); | |
| 419 var g = d3.select(this), | |
| 420 n = d.length, | |
| 421 min = Infinity, | |
| 422 max = -Infinity; | |
| 423 if (n > 0){ | |
| 424 min = d[0], | |
| 425 max = d[n - 1]; | |
| 426 } | |
| 427 // Readjust min and max with upper and lower values | |
| 428 if (data.whiskers[0] < min) {min = data.whiskers[0]} | |
| 429 if (data.whiskers[1] > max) {max = data.whiskers[1]} | |
| 430 // Compute quartiles. Must return exactly 3 elements. | |
| 431 var quartileData = data.quartiles; | |
| 432 // Compute whiskers. Must return exactly 2 elements, or null. | |
| 433 var whiskerData = data.whiskers; | |
| 434 // Compute outliers. here all data in d is an outlier. | |
| 435 // We compute the outliers as indices, so that we can join across transitions! | |
| 436 var outlierIndices = d3.range(n); | |
| 437 var mfiData = data.mfi; | |
| 438 // this is the scale for ONE SET of values | |
| 439 // Compute the new x-scale. | |
| 440 var x1 = d3.scale.linear() | |
| 441 .domain(domain && domain.call(this, d, i) || [min, max]) | |
| 442 .range([height , 0 + margin.top ]); | |
| 443 // Retrieve the old x-scale, if this is an update. | |
| 444 var x0 = this.__chart__ || d3.scale.linear() | |
| 445 .domain([0, Infinity]) | |
| 446 .range(x1.range()); | |
| 447 | |
| 448 // Stash the new scale. | |
| 449 this.__chart__ = x1; | |
| 450 // Note: the box, median, and box tick elements are fixed in number, | |
| 451 // so we only have to handle enter and update. In contrast, the outliers | |
| 452 // and other elements are variable, so we need to exit them! Variable | |
| 453 // elements also fade in and out. | |
| 454 // Update center line: the vertical line spanning the whiskers. | |
| 455 var center = g.selectAll("line.center") | |
| 456 .data(whiskerData ? [whiskerData] : []); | |
| 457 | |
| 458 //vertical line | |
| 459 center.enter().insert("line", "rect") | |
| 460 .attr("class", "center") | |
| 461 .attr("x1", width / 2) | |
| 462 .attr("y1", function(d) { return x0(d[0]); }) | |
| 463 .attr("x2", width / 2) | |
| 464 .attr("y2", function(d) { return x0(d[1]); }) | |
| 465 .style("opacity", 1e-6) | |
| 466 .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) | |
| 467 .transition() | |
| 468 .duration(duration) | |
| 469 .style("opacity", 1) | |
| 470 .attr("y1", function(d) { return x1(d[0]); }) | |
| 471 .attr("y2", function(d) { return x1(d[1]); }); | |
| 472 | |
| 473 center.transition() | |
| 474 .duration(duration) | |
| 475 .style("opacity", 1) | |
| 476 .attr("y1", function(d) { return x1(d[0]); }) | |
| 477 .attr("y2", function(d) { return x1(d[1]); }); | |
| 478 | |
| 479 center.exit().transition() | |
| 480 .duration(duration) | |
| 481 .style("opacity", 1e-6) | |
| 482 .attr("y1", function(d) { return x1(d[0]); }) | |
| 483 .attr("y2", function(d) { return x1(d[1]); }) | |
| 484 .remove(); | |
| 485 | |
| 486 // Update innerquartile box. | |
| 487 var box = g.selectAll("rect.box") | |
| 488 .data([quartileData]); | |
| 489 | |
| 490 box.enter().append("rect") | |
| 491 .attr("class", "box") | |
| 492 .style("fill", function(d) { | |
| 493 var nbm = data.config[2], | |
| 494 pop = data.config[1], | |
| 495 mrkr = data.config[0]; | |
| 496 var color = color_palette[0][pop][1] + (mrkr + 1 )/ nbm + ')'; | |
| 497 return color }) | |
| 498 .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) | |
| 499 .attr("x", 0) | |
| 500 .attr("y", function(d) { return x0(d[2]); }) | |
| 501 .attr("width", width) | |
| 502 .attr("height", function(d) { return x0(d[0]) - x0(d[2]); }) | |
| 503 .transition() | |
| 504 .duration(duration) | |
| 505 .attr("y", function(d) { return x1(d[2]); }) | |
| 506 .attr("height", function(d) { return x1(d[0]) - x1(d[2]); }); | |
| 507 | |
| 508 box.transition() | |
| 509 .duration(duration) | |
| 510 .attr("y", function(d) { return x1(d[2]); }) | |
| 511 .attr("height", function(d) { return x1(d[0]) - x1(d[2]); }); | |
| 512 | |
| 513 // Update median line. | |
| 514 var medianLine = g.selectAll("line.median") | |
| 515 .data([quartileData[1]]); | |
| 516 | |
| 517 medianLine.enter().append("line") | |
| 518 .attr("class", "median") | |
| 519 .attr("x1", 0) | |
| 520 .attr("y1", x0) | |
| 521 .attr("x2", width) | |
| 522 .attr("y2", x0) | |
| 523 .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) | |
| 524 .transition() | |
| 525 .duration(duration) | |
| 526 .attr("y1", x1) | |
| 527 .attr("y2", x1); | |
| 528 | |
| 529 medianLine.transition() | |
| 530 .duration(duration) | |
| 531 .attr("y1", x1) | |
| 532 .attr("y2", x1); | |
| 533 | |
| 534 // Update MFI line. | |
| 535 var MFILine = g.selectAll("line.mfi") | |
| 536 .data([mfiData]); | |
| 537 if (showMFI == true) { | |
| 538 MFILine.enter().append("line") | |
| 539 .attr("class", "mfi") | |
| 540 .style("stroke", function(d){ return color_palette[0][data.config[1]][2]; }) | |
| 541 .attr("x1", 0) | |
| 542 .attr("y1", x0) | |
| 543 .attr("x2", width) | |
| 544 .attr("y2", x0) | |
| 545 .transition() | |
| 546 .duration(duration) | |
| 547 .attr("y1", x1) | |
| 548 .attr("y2", x1); | |
| 549 | |
| 550 MFILine.transition() | |
| 551 .duration(duration) | |
| 552 .attr("y1", x1) | |
| 553 .attr("y2", x1); | |
| 554 } | |
| 555 | |
| 556 // Update whiskers. | |
| 557 var whisker = g.selectAll("line.whisker") | |
| 558 .data(whiskerData || []); | |
| 559 | |
| 560 whisker.enter().insert("line", "circle, text") | |
| 561 .attr("class", "whisker") | |
| 562 .attr("x1", 0) | |
| 563 .attr("y1", x0) | |
| 564 .attr("x2", 0 + width) | |
| 565 .attr("y2", x0) | |
| 566 .style("opacity", 1e-6) | |
| 567 .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) | |
| 568 .transition() | |
| 569 .duration(duration) | |
| 570 .attr("y1", x1) | |
| 571 .attr("y2", x1) | |
| 572 .style("opacity", 1); | |
| 573 | |
| 574 whisker.transition() | |
| 575 .duration(duration) | |
| 576 .attr("y1", x1) | |
| 577 .attr("y2", x1) | |
| 578 .style("opacity", 1); | |
| 579 | |
| 580 whisker.exit().transition() | |
| 581 .duration(duration) | |
| 582 .attr("y1", x1) | |
| 583 .attr("y2", x1) | |
| 584 .style("opacity", 1e-6) | |
| 585 .remove(); | |
| 586 | |
| 587 // Update outliers. | |
| 588 var outlier = g.selectAll("circle.outlier") | |
| 589 .data(outlierIndices, Number); | |
| 590 | |
| 591 outlier.enter().insert("circle", "text") | |
| 592 .attr("class", "outlier") | |
| 593 .attr("r", 3) | |
| 594 .attr("cx", function(d){ | |
| 595 return Math.floor(Math.random() * width); | |
| 596 }) | |
| 597 .attr("cy", function(i) { return x0(d[i]); }) | |
| 598 .style("opacity", 1e-6) | |
| 599 .style("fill", function(d) { | |
| 600 var nbm = data.config[2], | |
| 601 pop = data.config[1], | |
| 602 mrkr = data.config[0]; | |
| 603 var color = color_palette[0][pop][1] + (mrkr + 1 )/ nbm + ')'; | |
| 604 return color; }) | |
| 605 .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) | |
| 606 .transition() | |
| 607 .duration(duration) | |
| 608 .attr("cy", function(i) { return x1(d[i]); }) | |
| 609 .style("opacity", 1); | |
| 610 | |
| 611 outlier.transition() | |
| 612 .duration(duration) | |
| 613 .attr("cy", function(i) { return x1(d[i]); }) | |
| 614 .style("opacity", 1); | |
| 615 | |
| 616 outlier.exit().transition() | |
| 617 .duration(duration) | |
| 618 .attr("cy", function(i) { return x1(d[i]); }) | |
| 619 .style("opacity", 1e-6) | |
| 620 .remove(); | |
| 621 | |
| 622 // Compute the tick format. | |
| 623 var format = tickFormat || x1.tickFormat(8); | |
| 624 // Update box ticks. | |
| 625 var boxTick = g.selectAll("text.box") | |
| 626 .data(quartileData); | |
| 627 | |
| 628 if(showLabels == true) { | |
| 629 boxTick.enter().append("text") | |
| 630 .attr("class", "box") | |
| 631 .attr("dy", ".3em") | |
| 632 .attr("dx", function(d, i) { return i & 1 ? 6 : -6 }) | |
| 633 .attr("x", function(d, i) { return i & 1 ? + width : 0 }) | |
| 634 .attr("y", x0) | |
| 635 .attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; }) | |
| 636 .text(format) | |
| 637 .transition() | |
| 638 .duration(duration) | |
| 639 .attr("y", x1); | |
| 640 } | |
| 641 | |
| 642 boxTick.transition() | |
| 643 .duration(duration) | |
| 644 .text(format) | |
| 645 .attr("y", x1); | |
| 646 | |
| 647 // Update whisker ticks. These are handled separately from the box | |
| 648 // ticks because they may or may not exist, and we want don't want | |
| 649 // to join box ticks pre-transition with whisker ticks post-. | |
| 650 var whiskerTick = g.selectAll("text.whisker") | |
| 651 .data(whiskerData || []); | |
| 652 if(showLabels == true) { | |
| 653 whiskerTick.enter().append("text") | |
| 654 .attr("class", "whisker") | |
| 655 .attr("dy", ".3em") | |
| 656 .attr("dx", 6) | |
| 657 .attr("x", width) | |
| 658 .attr("y", x0) | |
| 659 .text(format) | |
| 660 .style("opacity", 1e-6) | |
| 661 .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) | |
| 662 .transition() | |
| 663 .duration(duration) | |
| 664 .attr("y", x1) | |
| 665 .style("opacity", 1); | |
| 666 } | |
| 667 whiskerTick.transition() | |
| 668 .duration(duration) | |
| 669 .text(format) | |
| 670 .attr("y", x1) | |
| 671 .style("opacity", 1); | |
| 672 | |
| 673 whiskerTick.exit().transition() | |
| 674 .duration(duration) | |
| 675 .attr("y", x1) | |
| 676 .style("opacity", 1e-6) | |
| 677 .remove(); | |
| 678 }); | |
| 679 d3.timer.flush(); | |
| 680 } | |
| 681 | |
| 682 box.width = function(x) { | |
| 683 if (!arguments.length) return width; | |
| 684 width = x; | |
| 685 return box; | |
| 686 }; | |
| 687 box.height = function(x) { | |
| 688 if (!arguments.length) return height; | |
| 689 height = x; | |
| 690 return box; | |
| 691 }; | |
| 692 box.tickFormat = function(x) { | |
| 693 if (!arguments.length) return tickFormat; | |
| 694 tickFormat = x; | |
| 695 return box; | |
| 696 }; | |
| 697 box.duration = function(x) { | |
| 698 if (!arguments.length) return duration; | |
| 699 duration = x; | |
| 700 return box; | |
| 701 }; | |
| 702 box.domain = function(x) { | |
| 703 if (!arguments.length) return domain; | |
| 704 domain = x == null ? x : d3.functor(x); | |
| 705 return box; | |
| 706 }; | |
| 707 box.value = function(x) { | |
| 708 if (!arguments.length) return value; | |
| 709 value = x; | |
| 710 return box; | |
| 711 }; | |
| 712 box.showLabels = function(x) { | |
| 713 if (!arguments.length) return showLabels; | |
| 714 showLabels = x; | |
| 715 return box; | |
| 716 }; | |
| 717 box.showMFI = function(x) { | |
| 718 if (!arguments.length) return showMFI; | |
| 719 showMFI = x; | |
| 720 return box; | |
| 721 }; | |
| 722 return box; | |
| 723 }; | |
| 724 })(); |
