Mercurial > repos > immport-devteam > flow_overview
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/boxplotsFlow.js Wed Jul 29 17:03:53 2020 -0400 @@ -0,0 +1,724 @@ +// Copyright (c) 2016 Northrop Grumman. +// All rights reserved. +var updateBPmfi = function(plotconfig){ + plotconfig.selectedPopulations = []; + $(plotconfig.popSelectj).each(function() { + if (this.checked) { + plotconfig.selectedPopulations.push(parseInt(this.value)); + } + }); + // Update selected markers? + plotconfig.selectedMarkers = []; + $(plotconfig.mrkrSelectj).each(function() { + if (this.checked) { + plotconfig.selectedMarkers.push(parseInt(this.value)); + } + }); + // update plot + updateBoxplotMFI(plotconfig); +}; + +var displayPopulationLegend = function(plotconfig) { + $(plotconfig.table).empty(); + plotconfig.allPopulations.map(function(value,index) { + $(plotconfig.table).append('<tr><td align="center">' + + '<input type="checkbox" checked class=' + plotconfig.popSelect + + ' value=' + value + '/></td><td title="' + newNames[value] + '">' + + newNames[value] + '</td><td><span style="background-color:' + + color_palette[0][value][0] + '"> </span></td></tr>'); + }); + + $(plotconfig.popSelectAll).click(function() { + var checkAll = $(plotconfig.popSelectAll).prop('checked'); + if (checkAll) { + $(plotconfig.popSelectj).prop("checked", true); + } else { + $(plotconfig.popSelectj).prop("checked", false); + } + updateBPmfi(plotconfig); + }); + + $(plotconfig.popSelectj).click(function() { + if ($(plotconfig.popSelectj).length == $(plotconfig.popSelectCheck).length) { + $(plotconfig.popSelectAll).prop("checked",true); + } else { + $(plotconfig.popSelectAll).prop("checked",false); + } + updateBPmfi(plotconfig); + }); + + $(plotconfig.popSelectj).each(function() { + var selectedpopn = parseInt(this.value); + if ($.inArray(selectedpopn,plotconfig.selectedPopulations) > -1) { + this.checked = true; + } else { + this.checked = false; + } + }); +}; + +var displayToolbar = function(plotconfig){ + $(plotconfig.displaybutton).on("click",function() { + $(plotconfig.popSelectAll).prop("checked",true); + $(plotconfig.popSelectj).prop("checked", true); + $(plotconfig.mrkrSelectj).prop("checked", true); + $(plotconfig.mrkrSelectAll).prop("checked",true); + $(plotconfig.displayMFI).prop("checked", false); + $(plotconfig.displayvalues).prop("checked", false); + updateBPmfi(plotconfig); + }); + + $(plotconfig.toggledisplayj).on("click",function() { + var text = document.getElementById(plotconfig.toggledisplay).firstChild; + text.data = text.data == "View per marker" ? "View per population" : "View per marker"; + plotconfig.view = plotconfig.view == "p" ? "m" : "p"; + updateBPmfi(plotconfig); + }); + + $(plotconfig.displayMFI).on("click", function(){ + updateBPmfi(plotconfig); + }); + + $(plotconfig.displayvalues).on("click", function(){ + updateBPmfi(plotconfig); + }); + + displayPlot(plotconfig); +}; + +var displayPlot = function(plotconfig) { + var h = $(window).height() - 200, + nbPop = Object.keys(plotconfig.csdata.mfi[plotconfig.mrkrNames[0]]).length + 2; + + $(plotconfig.plotdivj).empty(); + $(plotconfig.plotdivj).height(h); + + // Get Markers too + for (var i = 0, nbMarkers = plotconfig.mrkrNames.length; i < nbMarkers; i++){ + plotconfig.allMarkers.push(i); + plotconfig.selectedMarkers.push(i); + } + for (var i = 2; i < nbPop; i++) { + plotconfig.allPopulations.push(i - 1); + plotconfig.selectedPopulations.push(i - 1); + } + + $(window).on('resize',function() { + waitForFinalEvent(function() { + updateBoxplotMFI(plotconfig); + }, 500, "resizePlot"); + }); + + displayPopulationLegend(plotconfig); + displayMarkerTable(plotconfig); + updateBoxplotMFI(plotconfig); +}; + +var displayMarkerTable = function(plotconfig){ + var nbm = plotconfig.mrkrNames.length + 1; + $(plotconfig.mtable).empty(); + plotconfig.allMarkers.map(function(v) { + $(plotconfig.mtable).append('<tr>' + + '<td><span style="background-color:rgba(0,0,0,' + (v + 1 )/ nbm + ')' + + '"> </span></td>' + + '<td title="' + plotconfig.mrkrNames[v] + '">' + + plotconfig.mrkrNames[v] + '</td>' + + '<td align="center"><input type="checkbox" checked class=' + + plotconfig.mrkrSelect + ' value=' + v + '/></td></tr>'); + }); + + if (nbm > 5) { + $(plotconfig.mrkrSelectAll).prop('checked', false); + $(plotconfig.mrkrSelectAll).prop('disabled', true); + $('#markerWarning').show(); + $(plotconfig.mrkrSelectj).each(function() { + var selectedMrkr = parseInt(this.value); + if (selectedMrkr > 4){ + this.checked = false; + this.disabled = true; + } else { + this.checked = true; + } + }); + } + + $(plotconfig.mrkrSelectAll).click(function() { + var checkAll = $(plotconfig.mrkrSelectAll).prop('checked'); + if (checkAll) { + $(plotconfig.mrkrSelectj).prop("checked", true); + } else { + $(plotconfig.mrkrSelectj).prop("checked", false); + } + updateBPmfi(plotconfig); + }); + + $(plotconfig.mrkrSelectj).click(function() { + if (nbm < 6){ + if ($(plotconfig.mrkrSelectj).length == $(plotconfig.mrkrSelectCheck).length) { + $(plotconfig.mrkrSelectAll).prop("checked",true); + } else { + $(plotconfig.mrkrSelectAll).prop("checked",false); + } + } else { + var nbSelected = 0; + $(plotconfig.mrkrSelectj).each(function() { + if (this.checked) {nbSelected++} + }); + if (nbSelected < 5) { + $(plotconfig.mrkrSelectj).prop('disabled', false); + } else { + $(plotconfig.mrkrSelectj).each(function() { + if (!this.checked) { + this.disabled = true; + } + }); + } + } + updateBPmfi(plotconfig); + }); +}; + +var updateBoxplotMFI = function(plotconfig){ + var margin = {top: 30, right: 10, bottom: 50, left: 60}, + h = 0, + w = 0, + width = 0, + height = 0, + labels = false, // show the text labels beside individual boxplots? + mfi_option = false, + checkLabels = $(plotconfig.displayvalues).prop("checked"), + checkMFI = $(plotconfig.displayMFI).prop("checked"), + dataToPlot = [], + tmp = [], + nbm = plotconfig.mrkrNames.length + 1, + maxRange = 0, + minRange = 0, + domainx = [], + domainx1 = [], + min = Infinity, + max = -Infinity; + + $(plotconfig.plotdivj).empty(); + h = $(window).height() - 200; + $(plotconfig.plotdivj).height(h); + w = $(plotconfig.plotdivj).width(); + width = w - margin.left - margin.right; + height = h - margin.top - margin.bottom; + + var svg = d3.select(plotconfig.plotdivj).append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .attr("class", "box") + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + if (checkLabels) { + labels = true; + }; + if (checkMFI) { + mfi_option = true; + }; + + /* Get the data in proper shape to feed to the boxplot function + want [Object, Object, ..., Object] where Object: + 'population': pop + 'Data' : [Object, Object, ..., Object] where Object: + 'Marker' : marker name + 'outliers' : outliers + */ + + if (plotconfig.view == 'p') { + plotconfig.selectedPopulations.forEach(function(p) { + tmpPlot = []; + plotconfig.selectedMarkers.forEach(function(m) { + var markernm = plotconfig.mrkrNames[m], + qtmp = [ + +plotconfig.csdata.q1[markernm][p], + +plotconfig.csdata.q2[markernm][p], + +plotconfig.csdata.q3[markernm][p] + ], + wtmp = [ + +plotconfig.csdata.lower[markernm][p], + +plotconfig.csdata.upper[markernm][p] + ]; + tmp = []; + // Get min and max while we're here + plotconfig.csdata.outliers[markernm][p].forEach(function(outl) { + tmp.push(+outl); + if (+outl > max) {max = +outl}; + if (+outl < min) {min = +outl}; + }); + if (+plotconfig.csdata.upper[markernm][p] > max) { + max = +plotconfig.csdata.upper[markernm][p]; + } + if (+plotconfig.csdata.lower[markernm][p] < min) { + min = +plotconfig.csdata.lower[markernm][p]; + } + tmpPlot.push({ + marker: markernm, + outliers: tmp, + quartiles: qtmp, + whiskers: wtmp, + config: [m,p, nbm], + mfi: +plotconfig.csdata.mfi[markernm][p] + }); + }); + dataToPlot.push({population:p, popdata: tmpPlot}); + }); + } else { + plotconfig.selectedMarkers.forEach(function(m) { + var markernm = plotconfig.mrkrNames[m]; + tmpPlot = []; + plotconfig.selectedPopulations.forEach(function(p) { + var qtmp = [ + +plotconfig.csdata.q1[markernm][p], + +plotconfig.csdata.q2[markernm][p], + +plotconfig.csdata.q3[markernm][p] + ], + wtmp = [ + +plotconfig.csdata.lower[markernm][p], + +plotconfig.csdata.upper[markernm][p] + ]; + // Get min and max while we're here + tmp = []; + plotconfig.csdata.outliers[markernm][p].forEach(function(outl) { + tmp.push(+outl); + if (+outl > max) {max = +outl}; + if (+outl < min) {min = +outl}; + }); + if (+plotconfig.csdata.upper[markernm][p] > max) { + max = +plotconfig.csdata.upper[markernm][p]; + } + if (+plotconfig.csdata.lower[markernm][p] < min) { + min = +plotconfig.csdata.lower[markernm][p]; + } + tmpPlot.push({ + population:p, + outliers: tmp, + quartiles: qtmp, + whiskers: wtmp, + config: [m,p, nbm], + mfi: +plotconfig.csdata.mfi[markernm][p] + }); + }); + dataToPlot.push({marker: markernm, popdata: tmpPlot}); + }); + }; + maxRange = max + 30; + minRange = min - 30; + + if (plotconfig.view == 'p') { + domainx = plotconfig.selectedPopulations; + domainx1 = plotconfig.selectedMarkers.map(function(d){ + return plotconfig.mrkrNames[d] + }); + } else { + domainx1 = plotconfig.selectedPopulations; + domainx = plotconfig.selectedMarkers.map(function(d){ + return plotconfig.mrkrNames[d] + }); + } + // axes + var xScale = d3.scale.ordinal() + .domain(domainx) + .rangeRoundBands([0 , width], 0.2, 0.02); + + var x1Scale = d3.scale.ordinal() + .domain(domainx1) + .rangeRoundBands([0, xScale.rangeBand()], 0.1); + + var xAxis = d3.svg.axis() + .scale(xScale) + .orient("bottom"); + + // the y-axis + var yScale = d3.scale.linear() + .domain([minRange, maxRange]) + .range([height + margin.top, 0 + margin.top]); + + var yAxis = d3.svg.axis() + .scale(yScale) + .orient("left") + .tickFormat(d3.format("d")); + + svg.append("g") + .attr("class", "x axisbp") + .attr("transform", "translate(0," + (height + margin.top) + ")") + .call(xAxis); + + svg.append("g") + .attr("class", "y axisbp") + .call(yAxis) + .append("text") + .attr("class", "ylabel") + .attr("transform", "rotate(-90)") + .attr("y", 0 - margin.left) + .attr("x", 0 - (height / 2)) + .attr("dy", "1em") + .style("text-anchor", "middle") + .text("MFI values"); + + var boxplot = d3.box() + .width(x1Scale.rangeBand()) + .height(height + margin.top) + .domain([minRange, maxRange]) + .showLabels(labels) + .showMFI(mfi_option); + + if (plotconfig.view == 'p'){ + var group = svg.selectAll(".groups") + .data(dataToPlot) + .enter().append("g") + .attr("class", "group") + .attr("transform", function(d) { + return "translate(" + xScale(d.population) + ",0)"; + }); + + group.selectAll(".box") + .data(function(d) { return d.popdata; }) + .enter().append("g") + .attr("transform", function(d) { return "translate(" + x1Scale(d.marker) + ",0)"; }) + .call(boxplot); + } else { + var group = svg.selectAll(".groups") + .data(dataToPlot) + .enter().append("g") + .attr("class", "group") + .attr("transform", function(d) { + return "translate(" + xScale(d.marker) + ",0)"; + }); + + group.selectAll(".box") + .data(function(d) { return d.popdata; }) + .enter().append("g") + .attr("transform", function(d) { return "translate(" + x1Scale(d.population) + ",0)"; }) + .call(boxplot); + } +}; + +(function() { + // Inspired by http://informationandvisualization.de/blog/box-plot + // Modified to fit our data structure. + d3.box = function() { + var width = 1, + height = 1, + duration = 0, + domain = null, + value = Number, + showLabels = true, // whether or not to show text labels + numBars = 4, + curBar = 1, + showMFI = true, // display MFI ? + tickFormat = null; + var margin = {top: 30, right: 10, bottom: 50, left: 60}; + + // For each small multiple… + function box(g) { + g.each(function(data, i) { + var d = data.outliers.sort(d3.ascending); + var g = d3.select(this), + n = d.length, + min = Infinity, + max = -Infinity; + if (n > 0){ + min = d[0], + max = d[n - 1]; + } + // Readjust min and max with upper and lower values + if (data.whiskers[0] < min) {min = data.whiskers[0]} + if (data.whiskers[1] > max) {max = data.whiskers[1]} + // Compute quartiles. Must return exactly 3 elements. + var quartileData = data.quartiles; + // Compute whiskers. Must return exactly 2 elements, or null. + var whiskerData = data.whiskers; + // Compute outliers. here all data in d is an outlier. + // We compute the outliers as indices, so that we can join across transitions! + var outlierIndices = d3.range(n); + var mfiData = data.mfi; + // this is the scale for ONE SET of values + // Compute the new x-scale. + var x1 = d3.scale.linear() + .domain(domain && domain.call(this, d, i) || [min, max]) + .range([height , 0 + margin.top ]); + // Retrieve the old x-scale, if this is an update. + var x0 = this.__chart__ || d3.scale.linear() + .domain([0, Infinity]) + .range(x1.range()); + + // Stash the new scale. + this.__chart__ = x1; +// Note: the box, median, and box tick elements are fixed in number, +// so we only have to handle enter and update. In contrast, the outliers +// and other elements are variable, so we need to exit them! Variable +// elements also fade in and out. + // Update center line: the vertical line spanning the whiskers. + var center = g.selectAll("line.center") + .data(whiskerData ? [whiskerData] : []); + + //vertical line + center.enter().insert("line", "rect") + .attr("class", "center") + .attr("x1", width / 2) + .attr("y1", function(d) { return x0(d[0]); }) + .attr("x2", width / 2) + .attr("y2", function(d) { return x0(d[1]); }) + .style("opacity", 1e-6) + .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) + .transition() + .duration(duration) + .style("opacity", 1) + .attr("y1", function(d) { return x1(d[0]); }) + .attr("y2", function(d) { return x1(d[1]); }); + + center.transition() + .duration(duration) + .style("opacity", 1) + .attr("y1", function(d) { return x1(d[0]); }) + .attr("y2", function(d) { return x1(d[1]); }); + + center.exit().transition() + .duration(duration) + .style("opacity", 1e-6) + .attr("y1", function(d) { return x1(d[0]); }) + .attr("y2", function(d) { return x1(d[1]); }) + .remove(); + + // Update innerquartile box. + var box = g.selectAll("rect.box") + .data([quartileData]); + + box.enter().append("rect") + .attr("class", "box") + .style("fill", function(d) { + var nbm = data.config[2], + pop = data.config[1], + mrkr = data.config[0]; + var color = color_palette[0][pop][1] + (mrkr + 1 )/ nbm + ')'; + return color }) + .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) + .attr("x", 0) + .attr("y", function(d) { return x0(d[2]); }) + .attr("width", width) + .attr("height", function(d) { return x0(d[0]) - x0(d[2]); }) + .transition() + .duration(duration) + .attr("y", function(d) { return x1(d[2]); }) + .attr("height", function(d) { return x1(d[0]) - x1(d[2]); }); + + box.transition() + .duration(duration) + .attr("y", function(d) { return x1(d[2]); }) + .attr("height", function(d) { return x1(d[0]) - x1(d[2]); }); + + // Update median line. + var medianLine = g.selectAll("line.median") + .data([quartileData[1]]); + + medianLine.enter().append("line") + .attr("class", "median") + .attr("x1", 0) + .attr("y1", x0) + .attr("x2", width) + .attr("y2", x0) + .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) + .transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1); + + medianLine.transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1); + + // Update MFI line. + var MFILine = g.selectAll("line.mfi") + .data([mfiData]); + if (showMFI == true) { + MFILine.enter().append("line") + .attr("class", "mfi") + .style("stroke", function(d){ return color_palette[0][data.config[1]][2]; }) + .attr("x1", 0) + .attr("y1", x0) + .attr("x2", width) + .attr("y2", x0) + .transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1); + + MFILine.transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1); + } + + // Update whiskers. + var whisker = g.selectAll("line.whisker") + .data(whiskerData || []); + + whisker.enter().insert("line", "circle, text") + .attr("class", "whisker") + .attr("x1", 0) + .attr("y1", x0) + .attr("x2", 0 + width) + .attr("y2", x0) + .style("opacity", 1e-6) + .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) + .transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1) + .style("opacity", 1); + + whisker.transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1) + .style("opacity", 1); + + whisker.exit().transition() + .duration(duration) + .attr("y1", x1) + .attr("y2", x1) + .style("opacity", 1e-6) + .remove(); + + // Update outliers. + var outlier = g.selectAll("circle.outlier") + .data(outlierIndices, Number); + + outlier.enter().insert("circle", "text") + .attr("class", "outlier") + .attr("r", 3) + .attr("cx", function(d){ + return Math.floor(Math.random() * width); + }) + .attr("cy", function(i) { return x0(d[i]); }) + .style("opacity", 1e-6) + .style("fill", function(d) { + var nbm = data.config[2], + pop = data.config[1], + mrkr = data.config[0]; + var color = color_palette[0][pop][1] + (mrkr + 1 )/ nbm + ')'; + return color; }) + .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) + .transition() + .duration(duration) + .attr("cy", function(i) { return x1(d[i]); }) + .style("opacity", 1); + + outlier.transition() + .duration(duration) + .attr("cy", function(i) { return x1(d[i]); }) + .style("opacity", 1); + + outlier.exit().transition() + .duration(duration) + .attr("cy", function(i) { return x1(d[i]); }) + .style("opacity", 1e-6) + .remove(); + + // Compute the tick format. + var format = tickFormat || x1.tickFormat(8); + // Update box ticks. + var boxTick = g.selectAll("text.box") + .data(quartileData); + + if(showLabels == true) { + boxTick.enter().append("text") + .attr("class", "box") + .attr("dy", ".3em") + .attr("dx", function(d, i) { return i & 1 ? 6 : -6 }) + .attr("x", function(d, i) { return i & 1 ? + width : 0 }) + .attr("y", x0) + .attr("text-anchor", function(d, i) { return i & 1 ? "start" : "end"; }) + .text(format) + .transition() + .duration(duration) + .attr("y", x1); + } + + boxTick.transition() + .duration(duration) + .text(format) + .attr("y", x1); + + // Update whisker ticks. These are handled separately from the box + // ticks because they may or may not exist, and we want don't want + // to join box ticks pre-transition with whisker ticks post-. + var whiskerTick = g.selectAll("text.whisker") + .data(whiskerData || []); + if(showLabels == true) { + whiskerTick.enter().append("text") + .attr("class", "whisker") + .attr("dy", ".3em") + .attr("dx", 6) + .attr("x", width) + .attr("y", x0) + .text(format) + .style("opacity", 1e-6) + .style("stroke", function(d) { return color_palette[0][data.config[1]][3]; }) + .transition() + .duration(duration) + .attr("y", x1) + .style("opacity", 1); + } + whiskerTick.transition() + .duration(duration) + .text(format) + .attr("y", x1) + .style("opacity", 1); + + whiskerTick.exit().transition() + .duration(duration) + .attr("y", x1) + .style("opacity", 1e-6) + .remove(); + }); + d3.timer.flush(); + } + + box.width = function(x) { + if (!arguments.length) return width; + width = x; + return box; + }; + box.height = function(x) { + if (!arguments.length) return height; + height = x; + return box; + }; + box.tickFormat = function(x) { + if (!arguments.length) return tickFormat; + tickFormat = x; + return box; + }; + box.duration = function(x) { + if (!arguments.length) return duration; + duration = x; + return box; + }; + box.domain = function(x) { + if (!arguments.length) return domain; + domain = x == null ? x : d3.functor(x); + return box; + }; + box.value = function(x) { + if (!arguments.length) return value; + value = x; + return box; + }; + box.showLabels = function(x) { + if (!arguments.length) return showLabels; + showLabels = x; + return box; + }; + box.showMFI = function(x) { + if (!arguments.length) return showMFI; + showMFI = x; + return box; + }; + return box; + }; +})();