From 00df6091355947944f2435af064a4e3e9f6ed93d Mon Sep 17 00:00:00 2001
From: kohleman <kohleman>
Date: Thu, 29 Aug 2013 14:05:14 +0000
Subject: [PATCH] initial commit for complete Flow Cell statistics

SVN: 29692
---
 .../as/webapps/cellStatistics/html/index.html | 248 ++++++++++++++++++
 .../as/webapps/cellStatistics/html/style.css  |  47 ++++
 .../webapps/cellStatistics/plugin.properties  |   6 +
 3 files changed, 301 insertions(+)
 create mode 100644 deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/index.html
 create mode 100644 deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/style.css
 create mode 100644 deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/plugin.properties

diff --git a/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/index.html b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/index.html
new file mode 100644
index 00000000000..06d40af202c
--- /dev/null
+++ b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/index.html
@@ -0,0 +1,248 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Flowcell Statistics</title>
+    <script type="text/javascript" src="/openbis/resources/js/d3.v3.min.js"></script>
+    <script type="text/javascript" src="/openbis/resources/js/d3.layout.js"></script>
+    <script type="text/javascript" src="/openbis/resources/js/jquery.js"></script>
+    <script type="text/javascript" src="/openbis/resources/js/openbis.js"></script>
+    <script type="text/javascript" src="/openbis/resources/js/openbis-dsu.js"></script>
+    <script type="text/javascript" src="/openbis/resources/js/openbis-action-deferrer.js"></script>
+    <script type="text/javascript" src="/openbis/resources/js/FileSaver.js"></script>
+    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/css/bootstrap.min.css">
+    <link rel="stylesheet" type="text/css" href="style.css" />
+  </head>
+  <body>
+  <script>
+
+  var formatThousands = d3.format(",");
+  dsu = new openbis_dsu('/openbis/openbis', '/datastore_server');
+  var webAppContext = new openbisWebAppContext();
+  dsu.server.useSession(webAppContext.getSessionId());
+
+  var prop;
+  var flowcellProperties = [];
+  var myArray = [];
+  var sumArray = [];
+  var sumsArray = [] 
+  
+  loadData()
+
+  /* ------- General functions -------------------------------------------*/
+
+  // used for sorting by lane of the final array of objects
+  function compare(a,b) {
+    if (a.lane < b.lane)
+       return -1;
+    if (a.lane > b.lane)
+      return 1;
+    return 0;
+  }
+
+  function isNumber(n) {
+    return !isNaN(parseFloat(n)) && isFinite(n);
+  }
+
+  function roundFloat(myFloat) {
+    return Number(myFloat).toFixed(2); 
+  }
+
+
+  /* -------------------------------------------------------------------*/
+
+function loadData () { 
+  var dataSetProperties;
+  var prop;
+
+  dsu.retrieveSample(webAppContext.getEntityIdentifier(), function(response) {
+
+    flowcellProperties = response.result[0].properties;
+    numberOfLanes = (flowcellProperties.LANECOUNT);
+
+    var sampleCodes = [];
+    for (i = 1; i <= numberOfLanes; i++) {
+      sampleCodes.push(webAppContext.entityIdentifier + ":" + i);
+    }
+
+    var deferrer = new openbisActionDeferrer(function(){
+      sumArray.sort(compare);
+      plotLaneTable (sumArray, true);
+      downloadButton ("tableStats");
+      $("#save_as" + "tableStats").click(function() { submit_download_form("html", "tableStats"); });
+    }, sampleCodes);
+
+    sampleCodes.forEach(function(sampleCode){
+      dsu.retrieveDataSetsForSample(sampleCode, function(response){
+        getProperties(response);
+        //console.log("got response " + sampleCode);
+        var sums = calculateSum(myArray, sampleCode, true);
+        //console.log(sums[0])
+        sumArray.push(sums[0]);
+        myArray = [];
+        deferrer.dependencyCompleted(sampleCode);  
+      });
+    });
+
+    function getProperties(dataSetProperties) {
+      for (var i = 0; i < dataSetProperties.result.length; i++) {
+        myArray.push({
+                            'externalSampleName' : dataSetProperties.result[i].properties.EXTERNAL_SAMPLE_NAME,
+                            'index1': dataSetProperties.result[i].properties.BARCODE,
+                            'index2': dataSetProperties.result[i].properties.INDEX2,
+                            'percFilteringPass' : parseFloat(dataSetProperties.result[i].properties.PERCENTAGE_PASSED_FILTERING),
+                            'rawReadsSum' : dataSetProperties.result[i].properties.RAW_READS_SUM,
+                            'pfReadsSum' : dataSetProperties.result[i].properties.PF_READS_SUM,
+                            'rawYieldMbases' : dataSetProperties.result[i].properties.RAW_YIELD_MBASES,
+                            'yieldMbases' : dataSetProperties.result[i].properties.YIELD_MBASES,
+                            'percRawClustersPerLane': parseFloat(dataSetProperties.result[i].properties.PERCENTAGE_RAW_CLUSTERS_PER_LANE),
+                            'pfMeanQualityScore' : parseFloat(dataSetProperties.result[i].properties.PFMEANQUALITYSCORE),
+                            'pfYieldq30Percentage' : parseFloat(dataSetProperties.result[i].properties.PFYIELDQ30PERCENTAGE)
+                            }); 
+      };
+    };
+  });
+};
+ 
+function plotLaneTable (sumArray, withNOINDEX) {
+
+  var laneTableStats = d3.select("body")
+    .append("table")
+    .attr("id", "tableStats")
+    .attr("class", "tableStats")
+    ;
+  header = {"Lane":1, "# of Samples":1, "Average Passed Filtering (PF)":1, "Sum Raw Reads":1, "Sum PF Reads":1, "Sum Raw Bases":1,
+            "Sum PF Bases":1, "Average Raw Clusters in % per Index":1, "Average PF Phred Score":1, "Average > 30 Phred Score":1 }
+
+  // create the table header
+  var thead = laneTableStats.selectAll("th")
+              .data(d3.keys(header))
+              .enter().append("th")
+              .text(function(d){return d})
+              ;
+
+  // create rows
+  var tr = laneTableStats.selectAll("tr")
+           .data(sumArray).enter().append("tr")
+  // cells
+  var td = tr.selectAll("td")
+    .data(function(d){return d3.values(d)})
+    .enter().append("td")
+    .text(function(d) {if (isNumber(d)) {return formatThousands(d)}; return d;})
+    .style("text-align", function(d){if (isNumber(d)) {return "right"} return "left"})
+    ;
+}
+
+function placeholder() {
+
+var space = d3.select("body")
+              .append("svg")
+              .attr("id", "placeholder")
+              .attr("width", 1500)
+              .attr("height", 50)
+              ;
+}
+
+function calculateSum(statisticsArray, sampleCode, withNOINDEX) {
+
+  var sums = []
+  var averagePercFilteringPass = 0;
+  var sumRawReads = 0;
+  var sumPfReads = 0;
+  var sumRawYieldMbases = 0;
+  var sumYieldMbases = 0;
+  var averagePercRawClustersPerLane = 0;
+  var averagePfMeanQualityScore = 0;
+  var averagePfYieldq30Percentage = 0;
+  
+  for (var i = 0; i < statisticsArray.length; i++) {
+    // do not calculate with the NOINDEX reads
+    if ((typeof (statisticsArray[i].externalSampleName) == 'undefined') && withNOINDEX) {
+       continue;
+    }  else {
+
+      averagePercFilteringPass = averagePercFilteringPass + parseFloat(statisticsArray[i].percFilteringPass);
+      sumRawReads = sumRawReads + parseInt(statisticsArray[i].rawReadsSum);
+      sumPfReads = sumPfReads + parseInt(statisticsArray[i].pfReadsSum);
+      sumRawYieldMbases = sumRawYieldMbases + parseInt(statisticsArray[i].rawYieldMbases);
+      sumYieldMbases = sumYieldMbases + parseInt(statisticsArray[i].yieldMbases);
+      averagePercRawClustersPerLane = averagePercRawClustersPerLane + parseInt(statisticsArray[i].percRawClustersPerLane);
+      averagePfMeanQualityScore = averagePfMeanQualityScore + parseInt(statisticsArray[i].pfMeanQualityScore);
+      averagePfYieldq30Percentage = averagePfYieldq30Percentage + parseInt(statisticsArray[i].pfYieldq30Percentage);
+    }
+  }
+  if (withNOINDEX) {penalty = -1} else {penalty = 0} 
+ 
+  // added the Math.max function to make sure that there is no division by zero,
+  // can happen when a single sample is on a lane (no multiplexing) 
+  averagePercFilteringPass = roundFloat(averagePercFilteringPass / Math.max((statisticsArray.length + penalty),1));
+  averagePercRawClustersPerLane = roundFloat(averagePercRawClustersPerLane / Math.max((statisticsArray.length + penalty),1));
+  averagePfMeanQualityScore = roundFloat(averagePfMeanQualityScore / Math.max((statisticsArray.length + penalty),1));
+  averagePfYieldq30Percentage = roundFloat(averagePfYieldq30Percentage / Math.max((statisticsArray.length + penalty),1));
+
+  sums.push({
+                            'lane' : sampleCode.split("/")[2].split(":")[1],
+                            'numberOfSamples' : statisticsArray.length,
+                            'averagePercFilteringPass' : averagePercFilteringPass,
+                            'rawReadsSum' : sumRawReads,
+                            'pfReadsSum' : sumPfReads,
+                            'rawYieldMbases' : sumRawYieldMbases,
+                            'yieldMbases' : sumYieldMbases,
+                            'percRawClustersPerLane': averagePercRawClustersPerLane,
+                            'pfMeanQualityScore' : averagePfMeanQualityScore,
+                            'pfYieldq30Percentage' : averagePfYieldq30Percentage
+                            });
+  return sums;
+}
+
+
+  function downloadButton (buttonName) {
+
+    var div = d3.select("body").append("button")
+      .attr("class", "btn-xs")
+      .attr("type", "submit")
+      .attr("id", "save_as" + buttonName)
+      .attr("value", "")
+      .text("Save")
+      ;
+  }
+
+  function submit_download_form(output_format, svgName)
+  {
+    var rawSampleName = webAppContext.entityIdentifier
+    var split = rawSampleName.split(":")
+    var fc = split[0].split("/")[2]
+    var lane = split[1]
+
+    // Get the d3js SVG element
+    var tmp = document.getElementById(svgName);
+
+    if (output_format == "svg") {
+
+      // Extract the data as SVG text string
+      var svg_xml = "<svg  xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">" + (new XMLSerializer).serializeToString(tmp) + "</svg>";
+
+      var blob = new Blob([svg_xml], {type: "image/svg+xml;charset=utf-8"});
+    }
+    if (output_format == "html") {
+      var html = "<html> <head> <title></title> <style type=\"text/css\">" + 
+        "table.tableStats { font-family: sans-serif; font-size: 14px; border-collapse:collapse; }" +
+        ".tableStats th { padding:6px 10px; color:#444; font-weight:bold; text-shadow:1px 1px 1px #fff; border-bottom:2px solid #444; }" +
+        ".tableStats tr:nth-child(even) { background: WhiteSmoke; }" +
+        ".tableStats td { padding:0px 10px 10px 10px; }" +
+        "</style> </head> <body>" +
+        (new XMLSerializer).serializeToString(tmp) +
+        "</body> </html>"
+      var blob = new Blob([html], {type: "image/html;charset=utf-8"});
+    }
+   if (output_format == "png") {
+       console.log("png")
+   }
+
+    saveAs(blob, fc + "_" + svgName + "." + output_format);
+
+  }
+
+  </script>
+  </body>
+</html>
+
diff --git a/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/style.css b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/style.css
new file mode 100644
index 00000000000..985d8ac6db0
--- /dev/null
+++ b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/html/style.css
@@ -0,0 +1,47 @@
+        .axis path,
+        .axis line {
+          fill: none;
+          stroke: #000;
+          shape-rendering: crispEdges;
+        }
+
+        .axis text {
+          font-family: sans-serif;
+          font-size: 10px;
+        }
+
+        table.tableStats {
+          font-family: sans-serif;
+          font-size: 14px;
+          border-collapse:collapse;
+        }
+
+        .tableStats th {
+          padding:6px 10px;
+          color:#444;
+          font-weight:bold;
+          text-shadow:1px 1px 1px #fff;
+          border-bottom:2px solid #444;
+        }
+
+        .tableStats tr:nth-child(even) {
+          background: WhiteSmoke;
+        }
+        .tableStats td {
+
+          padding:0px 10px 10px 10px;
+
+       }
+
+        div.tooltip {
+          position: absolute;
+          text-align: center;
+          width: 100px;
+          height: 42px;
+          padding: 2px;
+          font: 12px sans-serif;
+          background: LightSalmon;
+          border: 0px;
+          border-radius: 8px;
+          pointer-events: none;
+        }
diff --git a/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/plugin.properties b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/plugin.properties
new file mode 100644
index 00000000000..19629033996
--- /dev/null
+++ b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/cellStatistics/plugin.properties
@@ -0,0 +1,6 @@
+# The properties file for an example webapps plugin
+# This file has no properties defined because none need to be defined.
+webapp-folder = html
+openbisui-contexts = sample-details-view
+sample-entity-types = ILLUMINA_FLOW_CELL
+label = Flow Cell Statistics
-- 
GitLab