From d61e38791aedd39c43b0709dea9f12400b7366f6 Mon Sep 17 00:00:00 2001
From: kohleman <kohleman>
Date: Fri, 16 Aug 2013 07:20:53 +0000
Subject: [PATCH] -added FileSaver to save svgs on the fly and make them
 downloadable without any interaction  with the server (HTML5 conform) -added
 overview table plus total lane stats

SVN: 29655
---
 .../as/webapps/laneStatistics/html/index.html | 237 +++++++++++++++---
 1 file changed, 204 insertions(+), 33 deletions(-)

diff --git a/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/laneStatistics/html/index.html b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/laneStatistics/html/index.html
index 86104e8cdab..7a6c2789745 100644
--- a/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/laneStatistics/html/index.html
+++ b/deep_sequencing_unit/source/core-plugins/laneStatistics/1/as/webapps/laneStatistics/html/index.html
@@ -1,13 +1,15 @@
 <!DOCTYPE html>
 <html>
   <head>
-    <title>Title</title>
+    <title>Lane Statistics</title>
     <script type="text/javascript" src="d3.v3.min.js"></script>
     <script type="text/javascript" src="d3.layout.js"></script>
     <script type="text/javascript" src="/openbis/resources/js/jquery.js"></script>
     <script type="text/javascript" src="pie.js"></script>
     <script type="text/javascript" src="/openbis/resources/js/openbis.js"></script>
     <script type="text/javascript" src="openbis-dsu.js"></script>
+    <script type="text/javascript" src="FileSaver.js"></script>
+    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0-rc1/css/bootstrap.min.css">
     <style type="text/css">
 
         .axis path,
@@ -62,15 +64,20 @@
   </head>
   <body>
   <script>
-  
-  statisticsArray = []
  
   dsu = new openbis_dsu('/openbis/openbis', '/datastore_server');
   var webAppContext = new openbisWebAppContext();
   dsu.server.useSession(webAppContext.getSessionId());
+
+  loadData()
+
+function loadData () { 
+  statisticsArray = []
+ 
   var dataSetProperties;
   dsu.retrieveDataSetsForSample(webAppContext.getEntityIdentifier(), getProperties);
- 
+  //console.log (statisticsArray)
+
   function getProperties(dataSetProperties) {
     for (var i = 0; i < dataSetProperties.result.length; i++) {
 
@@ -89,31 +96,96 @@
                             }); 
     }
 
-    //console.log (statisticsArray)
     //console.log (statisticsArray.length)
+    var sums = calculateSum(statisticsArray, true)
+    var sumsWithNOINDEX = calculateSum(statisticsArray, false)
 
     if (! isNaN(statisticsArray[0].percFilteringPass)) {
-      plotTable (statisticsArray)
+      plotLaneTable(sumsWithNOINDEX, false)
+      placeholder();
+      plotLaneTable(sums, true)
+      placeholder();
+      plotTable (statisticsArray);
+      downloadButton ("tableStats");
+      placeholder();
       plotPercFilteringPass (statisticsArray);
-      plotReadsSum (statisticsArray, 'rawReadsSum');
-      plotPercRawClustersPerLane (statisticsArray)
+      downloadButton ("filteredChart");
+      plotReadsSum (statisticsArray, sums);
+      downloadButton ("unfilteredReads");
+      plotPercRawClustersPerLane (statisticsArray);
+      downloadButton ("percRawClusters");
+
+      $("#save_as" + "tableStats").click(function() { submit_download_form("html", "tableStats"); });
+      $("#save_as" + "filteredChart").click(function() { submit_download_form("svg", "filteredChart"); });
+      $("#save_as" + "unfilteredReads").click(function() { submit_download_form("svg", "unfilteredReads"); });
+      $("#save_as" + "percRawClusters").click(function() { submit_download_form("svg", "percRawClusters"); });
+    }
+    else {
+      d3.select("body").append("text").text("No data available!") 
     }
   }
+}
  
 colors = ["#FED976", "#FEB24C", "#FD8D3C", "#FC4E2A", "#E31A1C", "#800026", "#610B5E", "#4C0B5F",
           "#0B0B61", "#0B4C5F", "#0B5F48","#0B5F1E", "#4C5F0B", "#5F480B", "#5F1E0B", "#5F0B22",
            ]
+var formatThousands = d3.format(",");
 
 function isNumber(n) {
   return !isNaN(parseFloat(n)) && isFinite(n);
 }
 
-function plotTable (statisticsArray) {
+function plotLaneTable (sums, withNOINDEX) {
 
-  var formatThousands = d3.format(",");
+  d3.select("body").append("text")
+    .text("Lane Based Summary Table") 
+    .attr("class", "h4");
+  
+  d3.select("body").append("text")
+    .text(function (){if (withNOINDEX) {return " without NOINDEX";} return " with NOINDEX";}) 
+    .attr("class", "h6");
+
+
+  var laneTableStats = d3.select("body")
+    .append("table")
+    .attr("id", "tableLaneStats")
+    .attr("class", "tableStats")
+    ;
+
+  header = {"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})
+              ;
+
+  // fill the table
+  // create rows
+  var tr = laneTableStats.selectAll("tr")
+           .data(sums).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 plotTable (statisticsArray) {
+  
+  /*
+  d3.select("body").append("text")
+    .text("Index Based Summary Table") 
+    .attr("class", "h4");
+  */
 
   var tableStats = d3.select("body")
     .append("table")
+    .attr("id", "tableStats")
     .attr("class", "tableStats")
     ;
 
@@ -121,7 +193,7 @@ function plotTable (statisticsArray) {
               "PF Bases":1,"Raw Clusters in %":1, "Mean Phred Score":1, "> 30 Phred Score in %":1}
 
   // create the table header
-  var thead = d3.select("table").selectAll("th")
+  var thead = tableStats.selectAll("th")
               //.data(d3.keys(statisticsArray[0])) // got replaced with more readable names
               .data(d3.keys(header))
               .enter().append("th")
@@ -130,7 +202,7 @@ function plotTable (statisticsArray) {
 
   // fill the table
   // create rows
-  var tr = d3.select("table").selectAll("tr")
+  var tr = tableStats.selectAll("tr")
            .data(statisticsArray).enter().append("tr")
 
   // cells
@@ -142,21 +214,26 @@ function plotTable (statisticsArray) {
     //.on("mouseout", function(){d3.select(this).style("background-color", "white")})
     .style("text-align", function(d){if (isNumber(d)) {return "right"} return "left"})
     ;
+}
+
+function placeholder() {
 
 var space = d3.select("body")
               .append("svg")
-              .attr("width", 1800)
+              .attr("id", "placeholder")
+              .attr("width", 1500)
               .attr("height", 50)
               ;
 }
 
+
 function plotPercFilteringPass (statisticsArray) {
 
   if (statisticsArray.length > 60) {var svgWidth = 7000;}
   else if (statisticsArray.length > 10) {var svgWidth = 4000;}
   else {var svgWidth = 3000;}
 
-  svgWidth = statisticsArray.length * 120
+  svgWidth = statisticsArray.length * 100
   if (svgWidth < 200) {svgWidth = 300;}
 
 
@@ -170,8 +247,12 @@ function plotPercFilteringPass (statisticsArray) {
     svgWidth = svgWidth - margin.left - margin.right,
     svgHeight = 250 - margin.top - margin.bottom;
 
+
+//d3.select("#ex1").append("svg")
+
   var svgFilteredChartAgenda = d3.select("body")
                            .append("svg")
+                           .attr("id", "chartAgenda")
                            .attr("width", agendaWidth )
                            .attr("height", svgHeight + margin.top + margin.bottom)
                            ;  
@@ -202,6 +283,7 @@ function plotPercFilteringPass (statisticsArray) {
   
   var svgFilteredChart = d3.select("body")
                            .append("svg")
+                           .attr("id", "filteredChart")
 			   .attr("width", svgWidth + margin.left + margin.right)
     	    		   .attr("height", svgHeight + margin.top + margin.bottom)
                            .append("g")
@@ -286,9 +368,9 @@ function plotPercFilteringPass (statisticsArray) {
 }
 
 
-function plotReadsSum (statisticsArray, field){
+function plotReadsSum (statisticsArray, sums){
 
-  svgWidth = statisticsArray.length * 120
+  svgWidth = statisticsArray.length * 100
   if (svgWidth < 200) {svgWidth = 300;}
 
   var formatThousands = d3.format(",");
@@ -306,16 +388,18 @@ function plotReadsSum (statisticsArray, field){
 
   var svgReadsSum = d3.select("body")
                            .append("svg")
+                           .attr("id", "unfilteredReads")
                            .attr("width", svgWidth + margin.left + margin.right)
                            .attr("height", svgHeight + margin.top + margin.bottom)
                            .append("g")
                            .attr("transform", "translate(" + margin.left + "," + margin.top + ")")
                            ;
 
-  var rawReadsSum = calculateSum(statisticsArray, field)
+  var rawReadsSum = 0;
+  rawReadsSum = sums[0].rawReadsSum
 
   svgReadsSum.append('text')
-                  .text("Number of unfiltered Reads " +  formatThousands(rawReadsSum))
+                  .text("Number of raw Reads: " +  formatThousands(rawReadsSum))
                   .attr("transform", "translate(" + (svgWidth/2) + "," + (svgHeight - 200) + ")")
                   .attr("font-family", "sans-serif")
                   .attr("font-size", "14px")
@@ -369,7 +453,8 @@ function plotReadsSum (statisticsArray, field){
      .enter()
      .append("text")
      .text(function(d) { return formatThousands(d.rawReadsSum); })
-     .attr("x", function(d, i) { return i * 1/(1+valuePadding)*(svgWidth / statisticsArray.length) + ((svgWidth /statisticsArray.length ) /2) - 20; })
+     //.attr("x", function(d, i) { return i * 1/(1+valuePadding)*(svgWidth / statisticsArray.length) + ((svgWidth /statisticsArray.length ) /2) -10; })
+     .attr ("x", function (d) {return x(d.externalSampleName+d.index1) + 20;})
      .attr("y", function(d) {
                    return (svgHeight - margin.top - margin.bottom + 20) ;
                   })
@@ -382,23 +467,61 @@ function plotReadsSum (statisticsArray, field){
 
 }
 
-function calculateSum(statisticsArray, field) {
-  /*console.log(field)
-  var obj = JSON.parse(field);
-  console.log(obj);
-*/
-  var sum = 0;
-  for (var i = 0; i < statisticsArray.length; i++) {
-    sum = sum + parseInt(statisticsArray[i].rawReadsSum);
-  }
-  //console.log(sum);
-  return sum;
-
+function roundFloat(myFloat) {
+  return Number(myFloat).toFixed(2); 
 }
 
 
+function calculateSum(statisticsArray, 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} 
+  
+  averagePercFilteringPass = roundFloat(averagePercFilteringPass / (statisticsArray.length + penalty));
+  averagePercRawClustersPerLane = roundFloat(averagePercRawClustersPerLane / (statisticsArray.length + penalty));
+  averagePfMeanQualityScore = roundFloat(averagePfMeanQualityScore / (statisticsArray.length + penalty));
+  averagePfYieldq30Percentage = roundFloat(averagePfYieldq30Percentage / (statisticsArray.length + penalty));
+
+  sums.push({
+                            'averagePercFilteringPass' : averagePercFilteringPass,
+                            'rawReadsSum' : sumRawReads,
+                            'pfReadsSum' : sumPfReads,
+                            'rawYieldMbases' : sumRawYieldMbases,
+                            'yieldMbases' : sumYieldMbases,
+                            'percRawClustersPerLane': averagePercRawClustersPerLane,
+                            'pfMeanQualityScore' : averagePfMeanQualityScore,
+                            'pfYieldq30Percentage' : averagePfYieldq30Percentage 
+                            });
+
+  //console.log(sums);
+  return sums;
 
+}
 
 
 function plotPercRawClustersPerLane (percRawClustersPerLaneArray) {
@@ -425,6 +548,7 @@ function plotPercRawClustersPerLane (percRawClustersPerLaneArray) {
       .value(function(d) { return d.percRawClustersPerLane; });
 
   var svgPercRawClustersPerLaneChart = d3.select("body").append("svg")
+      .attr("id", "percRawClusters")
       .attr("width", width)
       .attr("height", height)
       .append("g")
@@ -454,8 +578,6 @@ function plotPercRawClustersPerLane (percRawClustersPerLaneArray) {
        var perc = d.data.percRawClustersPerLane + " %";
        if (d.data.externalSampleName == undefined || d.data.externalSampleName.length > 10) {return d.data.index1 + "  " + perc}
                return d.data.externalSampleName + "  " + perc })
-      //.on("mouseover", function(){d3.select(this).attr("font-size", "20px")})
-      //.on("mouseout", function(){d3.select(this).style("", "white")})
       .on("mouseover", function(d) {      
             div.transition()        
                 .duration(200)      
@@ -483,6 +605,55 @@ function plotPercRawClustersPerLane (percRawClustersPerLaneArray) {
 
 }
 
+
+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 + "_Lane_" + lane + "_" + svgName + "." + output_format);
+
+  }
+
   </script>
   </body>
 </html>
-- 
GitLab