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]
+            + '">&nbsp;&nbsp;&nbsp;</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");
+  });
+}