Mercurial > repos > immport-devteam > flow_overview
diff js/parallelCoordinates.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/parallelCoordinates.js Wed Jul 29 17:03:53 2020 -0400 @@ -0,0 +1,455 @@ +// Copyright (c) 2016 Northrop Grumman. +// All rights reserved. +/* + * Initialize variables for parallelCoordinates display +*/ +var pCoordApp = pCoordApp || {}; +pCoordApp.allPopulations = []; +pCoordApp.selectedPopulations = []; +pCoordApp.origData; +pCoordApp.flowData; +pCoordApp.headers = []; +pCoordApp.foreground; +pCoordApp.background; +pCoordApp.populations = []; +pCoordApp.allLines; +pCoordApp.lines = []; +pCoordApp.selectedLines = []; + +var displayAll = function() { + displayParallelPlot(); +} +/* + * Display the Population Legend +*/ +var displayPopTable = function() { + $('#popTable tbody').empty(); + pCoordApp.origData.map(function(d,index) { + $('#popTable tbody') + .append('<tr><td align="center"><input type="checkbox" ' + + 'id="pop' + d.Population + '" ' + + 'checked class="popSelect" value=' + index + '/></td>' + + '<td title="' + newNames[d.Population] + '">' + + newNames[d.Population] + + '</td><td><span style="background-color:' + + color_palette[0][index + 1][0] + + '"> </span></td>' + + '<td>' + d.Percentage + '</td></tr>'); + }); + + $('#popSelectAll').click(function() { + var checkAll = $("#popSelectAll").prop('checked'); + if (checkAll) { + $(".popSelect").prop("checked", true); + for (var i = 0; i < pCoordApp.allLines; i ++){ + pCoordApp.selectedLines.push(i); + pCoordApp.lines.push(i); + } + } else { + $(".popSelect").prop("checked", false); + pCoordApp.selectedLines = []; + pCoordApp.lines = []; + } + + pCoordApp.selectedPopulations = []; + $('.popSelect').each(function() { + if (this.checked) { + pCoordApp.selectedPopulations.push(parseInt(this.value)); + } + }); + displayTableGrid(); + if (checkAll) { + displayParallelPlot(); + } else { + updateParallelForeground(); + } + }); + + $('.popSelect').click(function() { + if ($('.popSelect').length == $(".popSelect:checked").length) { + $('#popSelectAll').prop("checked",true); + } else { + $('#popSelectAll').prop("checked",false); + } + + pCoordApp.selectedPopulations = []; + $('.popSelect').each(function() { + if (this.checked) { + pCoordApp.selectedPopulations.push(parseInt(this.value)); + } + }); + + pCoordApp.selectedLines = []; + pCoordApp.lines = []; + + pCoordApp.origData.forEach(function(d,idx){ + if ($.inArray(pCoordApp.populations.indexOf(d.Population), pCoordApp.selectedPopulations) > -1) { + pCoordApp.selectedLines.push(idx); + pCoordApp.lines.push(idx); + } + }); + + displayTableGrid(); + updateParallelForeground(); + }); + updatePopTable(); +}; + +var updatePopTable = function() { + $('.popSelect').each(function() { + var pop = parseInt(this.value), + selectedPops = pCoordApp.origData.map(function(d){ + if ($.inArray(d.idx, pCoordApp.selectedLines) > -1){ + return pCoordApp.populations.indexOf(d.Population); + } + }); + if ($.inArray(pop,selectedPops) > -1) { + this.checked = true; + } else { + this.checked = false; + } + }); +}; + +/* + * Display the table under the graph +*/ +var displayTableGrid = function() { + var updatedData = [], + displayData = [], + colNames = [], + pctargets = [], + colTable = [], + tableHTML = [], + textCol = [], + colOrder = [], + targetCol = 0; + + $("#tableDiv").empty(); + updatedData = $.extend(true, [], tableContent); + updatedData.forEach(function(d, idx){d.idx = idx}); + displayData = updatedData.filter(function(d, index) { + if ($.inArray(index,pCoordApp.selectedLines) > -1) { + return d; + } + }); + + targetCol = pCoordApp.headers.length - 2; + pCoordApp.headers.forEach(function(d,i){ + colTable.push("<th>" + d + "</th>"); + colNames.push({"data":d}); + if (i < targetCol){ + pctargets.push(i); + } + }); + textCol = [targetCol, targetCol + 1]; + colOrder = textCol.concat(pctargets); + tableHTML = [ + '<table id="pcTable" class="pctable display compact" cellspacing="0" width="100%">', + '<thead>', + '<tr>', + colTable.join("\n"), + '</tr>', + '</thead>', + '</table>', + ]; + + $('#tableDiv').html(tableHTML.join("\n")); + var pcTable = $('#pcTable').DataTable({ + columns: colNames, + data: displayData, + order: [[ targetCol, "asc" ]], + pageLength: 10, + //paging: false, + scrollY: 250, + scrollCollapse: true, + scrollX: true, + dom: '<"top"B>t<"bottom"lip><"clear">', + columnDefs: [{ + targets: pctargets, + className: "dt-body-right", + }, { + targets: [targetCol, targetCol+1], + className: "dt-body-center" + }], + buttons: [ + 'copy', 'pdfHtml5','csvHtml5', 'colvis' + ], + colReorder: { + order:colOrder + }, + select: true + }); + + $('#pcTable').on('mouseover', 'tr', function() { + var data = pcTable.row(this).data(); + if (data != undefined) { + var line = data.idx; + pCoordApp.selectedLines = [ line ]; + updateParallelForeground(); + } + }); + $('#pcTable').on('mouseleave', 'tr', function() { + pCoordApp.selectedLines = []; + for (var i = 0, j = pCoordApp.lines.length; i < j; i++) { + pCoordApp.selectedLines.push(pCoordApp.lines[i]); + } + updateParallelForeground(); + }); +}; + +/* + * Display The Main Plot +*/ +var displayParallelPlot = function() { + var margin = {top: 30, right: 10, bottom: 10, left: 10}, + h = $("#chartDiv").height()/1.5, + w = $("#plotDiv").width(), + width = w - margin.left - margin.right, + height = h - margin.top - margin.bottom, + dragging = {}, + y = {}; + + $("#plotDiv").empty(); + $("#plotDiv").height(h); + var svg = d3.select("#plotDiv").append("svg") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + // Y axis label + svg.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"); + + var x = d3.scale.ordinal().rangePoints([0, width], 1); + + // Use this to scale line width to percentage population + var pd = d3.extent(pCoordApp.origData, function(p) { + return +p['Percentage']; + }); + var popScale = d3.scale.linear().range([1,5]).domain(pd); + + var line = d3.svg.line(); + var axis = d3.svg.axis().orient("left").ticks(8); + + var dimensions = d3.keys(pCoordApp.flowData[0]).filter(function(d) { + return (y[d] = d3.scale.linear() + .domain(d3.extent(pCoordApp.flowData,function(p) { return +p[d]; })) + .range([height, 0])); + }); + x.domain(dimensions); + + function path(d) { + return line(dimensions.map(function(p) { + return [x(p), y[p](d[p])]; + })); + } + function position(d) { + var v = dragging[d]; + return v == null ? x(d) : v; + } + function transition(g) { + return g.transition().duration(500); + } + function brush() { + var actives = dimensions.filter(function(p) { + return !y[p].brush.empty(); + }); + var extents = actives.map(function(p) { + return y[p].brush.extent(); + }); + var indices = pCoordApp.origData.filter(function(d) { + var line = d.idx; + var tf = actives.every(function(p,i) { + return extents[i][0] <= pCoordApp.flowData[line][p] && + pCoordApp.flowData[line][p] <= extents[i][1]; + }); + if (tf) { + return line.toString(); + } + }); + pCoordApp.selectedLines = indices.map(function(d) { + return d.idx; + }); + pCoordApp.lines = indices.map(function(d) { + return d.idx; + }); + + updateParallelForeground(); + updatePopTable(); + displayTableGrid(); + }; + + // Display paths in light gray color, to use as reference + pCoordApp.background = svg.append("g") + .attr("class", "background") + .selectAll("path") + .data(pCoordApp.flowData) + .enter().append("path") + .attr("d", path); + + // Add foreground lines for focus, color by population. + pCoordApp.foreground = svg.append("g") + .attr("class", "foreground") + .selectAll("path") + .data(pCoordApp.origData) + .enter().append("path") + .attr("d", path) + .attr("stroke",function(d){ + var pop = pCoordApp.populations.indexOf(d.Population) + 1; + return color_palette[0][pop][0]; + }) + //.attr("stroke-width", 2); + // Use this if you want to scale the lines based on + // population percentage + .attr("stroke-width", function(d) { + var pop = pCoordApp.populations.indexOf(d.Population); + var w = popScale(pCoordApp.origData[pop]['Percentage']); + w = parseInt(w); + return w; + }); + + // Add a group element for each dimension. + var g = svg.selectAll(".dimension") + .data(dimensions) + .enter().append("g") + .attr("class", "dimension") + .attr("transform", function(d) { return "translate(" + x(d) + ")"; }) + .call(d3.behavior.drag() + .origin(function(d) { return {x: x(d)}; }) + .on("dragstart", function(d) { + dragging[d] = x(d); + pCoordApp.background.attr("visibility", "hidden"); + }) + .on("drag", function(d) { + dragging[d] = Math.min(width, Math.max(0, d3.event.x)); + pCoordApp.foreground.attr("d", path); + dimensions.sort(function(a, b) { + return position(a) - position(b); + }); + x.domain(dimensions); + g.attr("transform", function(d) { + return "translate(" + position(d) + ")"; + }); + }) + .on("dragend", function(d) { + delete dragging[d]; + transition(d3.select(this)) + .attr("transform", "translate(" + x(d) + ")"); + transition(pCoordApp.foreground) + .attr("d", path); + pCoordApp.background.attr("d", path) + .transition() + .delay(500) + .duration(0) + .attr("visibility", null); + })); + + // Add an axis and title. + g.append("g") + .attr("class", "axis") + .each(function(d) { + d3.select(this).call(axis.scale(y[d])); + }); + g.append("g") + .attr("class", "xlabel") + .append("text") + .style("text-anchor", "middle") + .attr("y", -9) + .text(function(d) { return d; }); + + // Add and store a brush for each axis. + g.append("g") + .attr("class", "brush") + .each(function(d) { d3.select(this).call(y[d].brush = d3.svg.brush().y(y[d]).on("brush", brush)); }) + .selectAll("rect") + .attr("x", -8) + .attr("width", 16); + + // Control line opacity. + $('#pcline_opacity').on('change', (function() { + var val = $(this).val(); + $('#plotDiv .foreground path').css('stroke-opacity', val.toString()); + $('#pcopacity').html((Math.round(val*10000)/100) + "%"); + })); +}; + +var updateParallelForeground = function() { + pCoordApp.foreground[0].map(function(d) { + var ln = parseInt(d['__data__']['idx']); + if ($.inArray(ln, pCoordApp.selectedLines) < 0){ + d.style.display = "none"; + } else { + d.style.display = null; + } + }); +}; + +/* + * Retrieve the data, then call display functions +*/ +var displayParallelCoordinates = function() { + pCoordApp.origData = $.extend(true,[], tableContent); + pCoordApp.headers = Object.keys(pCoordApp.origData[0]); + pCoordApp.origData.forEach(function(d,idx) { + d.idx = idx; + pCoordApp.selectedLines.push(idx); + pCoordApp.lines.push(idx); + if (!pCoordApp.populations.includes(d.Population)){ + pCoordApp.populations.push(d.Population); + } + }); + /* + * For the plot use only the MFI information + * for each populations. Store in flowData + */ + pCoordApp.flowData = $.extend(true,[],tableContent); + pCoordApp.flowData.forEach(function(d, idx) { + delete d['Population']; + delete d['Count']; + delete d['Percentage']; + delete d.Comment; + pCoordApp.allPopulations.push(idx); + pCoordApp.selectedPopulations.push(idx); + pCoordApp.selectedLines.push(idx); + pCoordApp.lines.push(idx); + }); + + pCoordApp.allLines = pCoordApp.flowData.length; + displayPopTable(); + displayTableGrid(); + displayParallelPlot(); + + $("#resetPCoordDisplay").on("click",function() { + for (var i = 0; i < pCoordApp.allLines; i++) { + pCoordApp.allPopulations.push(i); + pCoordApp.selectedPopulations.push(i); + pCoordApp.selectedLines.push(i); + pCoordApp.lines.push(i); + } + $("#popSelectAll").prop('checked',true); + $(".popSelect").prop("checked",true); + + var opcty = ".8"; + $('#plotDiv .foreground path').css('stroke-opacity', opcty); + $('#pcopacity').html("80%"); + $('#pcline_opacity').val(0.8); + + displayPopTable(); + displayTableGrid(); + displayParallelPlot(); + }); + + $(window).on('resize',function() { + waitForFinalEvent(function() { + displayAll(); + }, 500, "resizeParallelCoordinates"); + }); +}