Commit ad3013df authored by Wai Yi Leung's avatar Wai Yi Leung

Theme the biopet report with bootstrap, sortable tables.

parent 17ac2dce
......@@ -21,50 +21,61 @@
#if (showPlot)
#{ BammetricsReport.alignmentSummaryPlot(outputDir, "alignmentSummary", summary, !sampleLevel, sampleId = sampleId) }#
<img src="alignmentSummary.png"><br>
<a href="alignmentSummary.tsv">Tsv file</a>
<div class="panel-body">
<img src="alignmentSummary.png" class="img-responsive" />
</div>
<div class="panel-footer">
<i class="glyphicon glyphicon-file"></i> <a href="alignmentSummary.tsv">tsv file</a>
</div>
#end
#if (showTable)
<table>
<thead><tr>
<th>Sample</th>
#if (!sampleLevel) <th>Library</th> #end
<th>Total</th>
<th>Mapped</th>
<th>(%)</th>
<th>Duplicates</th>
<th>(%)</th>
<th>Insert size</th>
</tr></thead>
<tbody>
#for (sample <- samples.toList.sorted)
#{
val libs = (libId, sampleLevel) match {
<div class="panel-body">
<!-- Table -->
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr>
<th>Sample</th>
#if (!sampleLevel) <th>Library</th> #end
<th>Total</th>
<th>Mapped</th>
<th>(%)</th>
<th>Duplicates</th>
<th>(%)</th>
<th>Insert size</th>
</tr></thead>
<tbody>
#for (sample <- samples.toList.sorted)
#{
val libs = (libId, sampleLevel) match {
case (_, true) => List("")
case (Some(libId), _) => List(libId.toString)
case _ => summary.libraries(sample).toList
}
}#
<tr><td rowspan="${libs.size}"><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td>
#for (libId <- libs)
#if (libs.head != libId) <tr> #end
#if (!sampleLevel) <td><a href="${rootPath}Samples/${sample}/Libraries/${libId}/index.html">${libId}</a></td> #end
#{
val prefixPath = List("samples", sample) ::: (if (libId.isEmpty) Nil else List("libraries", libId)) ::: List("bammetrics", "stats")
val total = summary.getValue((prefixPath ::: List("biopet_flagstat", "All")):_*).getOrElse(0L).asInstanceOf[Long]
val mapped = summary.getValue((prefixPath ::: List("biopet_flagstat", "Mapped")):_*).getOrElse(0L).asInstanceOf[Long]
val duplicates = summary.getValue((prefixPath ::: List("biopet_flagstat", "Duplicates")):_*).getOrElse(0L).asInstanceOf[Long]
val insertsizeMean = summary.getValue((prefixPath ::: List("insert_size_metrics", "mean_insert_size")):_*)
}
}#
<td>${total}</td>
<td>${mapped}</td>
<td>${mapped.toDouble / total * 100}%</td>
<td>${duplicates}</td>
<td>${duplicates.toDouble / total * 100}%</td>
<td>${insertsizeMean}</td>
</tr>
<tr><td rowspan="${libs.size}"><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td>
#for (libId <- libs)
#if (libs.head != libId) <tr> #end
#if (!sampleLevel) <td><a href="${rootPath}Samples/${sample}/Libraries/${libId}/index.html">${libId}</a></td> #end
#{
val prefixPath = List("samples", sample) ::: (if (libId.isEmpty) Nil else List("libraries", libId)) ::: List("bammetrics", "stats")
val total = summary.getValue((prefixPath ::: List("biopet_flagstat", "All")):_*).getOrElse(0L).asInstanceOf[Long]
val mapped = summary.getValue((prefixPath ::: List("biopet_flagstat", "Mapped")):_*).getOrElse(0L).asInstanceOf[Long]
val duplicates = summary.getValue((prefixPath ::: List("biopet_flagstat", "Duplicates")):_*).getOrElse(0L).asInstanceOf[Long]
val insertsizeMean = summary.getValue((prefixPath ::: List("insert_size_metrics", "mean_insert_size")):_*)
}#
<td>${total}</td>
<td>${mapped}</td>
<td>${mapped.toDouble / total * 100}%</td>
<td>${duplicates}</td>
<td>${duplicates.toDouble / total * 100}%</td>
<td>${insertsizeMean}</td>
</tr>
#end
#end
#end
</tbody>
</table>
</tbody>
</table>
</div>
#end
\ No newline at end of file
......@@ -11,7 +11,10 @@
#{
def createMenu(page: ReportPage, path: List[String] = Nil): String = {
val buffer: StringBuffer = new StringBuffer()
buffer.append("<ul>")
if (page.subPages.size > 2){
buffer.append("<ul class=\"dropdown-menu\" role=\"menu\">")
}
for (subPage <- page.subPages) {
val href: String = {
......@@ -23,8 +26,9 @@
buffer.append(createMenu(subPage._2, path ::: subPage._1 :: Nil))
buffer.append("</li>")
}
buffer.append("</ul>")
if(page.subPages.size > 2) {
buffer.append("</ul>\n")
}
buffer.toString
}
......@@ -36,42 +40,107 @@
<html>
<head>
<title>${reportName}</title>
<link rel="stylesheet" type="text/css" href="${rootPath}css/biopet.css">
</head>
<body>
<!-- <header><h1>${reportName}</h1></header> -->
<nav id="menu">
<ul>
#for (t <- 0 to path.size)
<li>
#if (t == 0)
<a href="${rootPath}index.html">Home</a>
${unescape(createMenu(indexPage))}
#else
<a href="${rootPath}${path.slice(0, t).mkString("","/","/")}index.html">${path(t - 1)}</a>
${unescape(createMenu(getSubPage(path.slice(0, t)), path.slice(0, t)))}
#end
</li>
#end
</ul>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar"
aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="${rootPath}index.html">Biopet report</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<!-- ${path.size} //-->
<!-- ${path} //-->
#for (t <- 0 to path.size)
#if(t == 0)
<li>
<a href="${rootPath}index.html">Home</a>
</li>
${unescape(createMenu(indexPage))}
#else
<!-- sub from the page, should only fetch last item in list
<a href="${rootPath}${path.slice(0,t).mkString("", "/", "/")}index.html">${path( t - 1 )}</a>
${unescape(createMenu(getSubPage(path.slice(0, t)), path.slice(0, t)))}
//-->
#end
#end
</ul>
</div>
<!--/.nav-collapse -->
</div>
</nav>
<aside id="index">
<ul>
#for ((name, url) <- page.sections)
<li><a href="#${name}">${name}</a></li>
#end
</ul>
</aside>
<aside id="main">
#for ((name, url) <- page.sections)
<section id="${name}">
<h3>${name}</h3>
${unescape(url.render(args))}
</section>
#end
</aside>
<footer>Footer</footer>
<div class="container-fluid">
<div class="row">
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active">
<a href="./index.html">Home</a>
</li>
#for ((name, url) <- page.sections)
<li><a href="#${name}">${name}</a></li>
#end
</ul>
</div>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
#for ((name, url) <- page.sections)
<a id="${name}"></a>
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title" id="panel-title">
${name}
</h3>
</div>
${unescape(url.render(args))}
</div>
<section id="${name}">
</section>
#end
</div>
</div>
</div>
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css">
<!-- Optional theme -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap-theme.min.css">
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="${rootPath}ext/css/bootstrap_dashboard.css">
<link rel="stylesheet" type="text/css" href="${rootPath}ext/css/sortable-theme-bootstrap.css">
<!-- sortable tables //-->
<script src="${rootPath}ext/js/sortable.min.js"></script>
<script language="JavaScript">
<!--
$(document).ready(function() {
Sortable.init()
});
//--></script>
</body>
</html>
\ No newline at end of file
......@@ -2,11 +2,11 @@
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
<%@ var summary: Summary %>
<%@ var rootPath: String %>
<table>
<thead><tr></tr><th>Sample</th></thead></tr>
<tbody>
#for (sample <- summary.samples)
<tr><td><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td></tr>
#end
</tbody>
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr></tr><th>Sample</th></thead></tr>
<tbody>
#for (sample <- summary.samples)
<tr><td><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td></tr>
#end
</tbody>
</table>
\ No newline at end of file
package nl.lumc.sasc.biopet.core.report
import java.io.{ PrintWriter, File }
import java.net.URL
import nl.lumc.sasc.biopet.core.{ BiopetJavaCommandLineFunction, ToolCommand }
import nl.lumc.sasc.biopet.core.summary.Summary
......@@ -72,12 +73,44 @@ trait ReportBuilder extends ToolCommand {
require(cmdArgs.outputDir.isDirectory, "Output dir is not a directory")
logger.info("Write Base files")
// Write css to output dir
val cssDir = new File(cmdArgs.outputDir, "css")
cssDir.mkdirs()
val cssWriter = new PrintWriter(new File(cssDir, "biopet.css"))
Source.fromInputStream(getClass.getResourceAsStream("/nl/lumc/sasc/biopet/core/report/biopet.css")).getLines().foreach(cssWriter.println)
cssWriter.close()
/**
* Copying out the static files from this
* */
val resourcePath: String = "/nl/lumc/sasc/biopet/core/report/ext/"
val externalDir = new File(cmdArgs.outputDir, "ext")
externalDir.mkdirs()
val uri: URL = getClass.getResource(resourcePath)
val dir: File = new File( uri.toURI )
for ( srcFile <- dir.listFiles ) {
logger.info(srcFile.getPath)
if (srcFile.isDirectory) {
var newPath: String = srcFile.getAbsolutePath.split(resourcePath).last
val workDir = new File(externalDir, newPath)
workDir.mkdirs()
logger.info("Writing to " + workDir.getAbsolutePath)
for (f <- srcFile.listFiles()) {
var newFilePath: String = f.getAbsolutePath.split(resourcePath+ newPath).last
val resourceWriter = new PrintWriter( new File(workDir, newFilePath) )
val resourceSrcPath: String = new File( resourcePath, newPath+"/"+newFilePath ).getAbsolutePath
Source.fromInputStream(
getClass.getResourceAsStream(
resourceSrcPath
)
).getLines().foreach(resourceWriter.println)
resourceWriter.close()
}
}
}
logger.info("Parsing summary")
setSummary = new Summary(cmdArgs.summary)
......
......@@ -20,58 +20,72 @@
FlexiprepReport.baseSummaryPlot(outputDir, "QC_Bases_R1","R1", summary, sampleId = sampleId)
FlexiprepReport.baseSummaryPlot(outputDir, "QC_Bases_R2","R2", summary, sampleId = sampleId)
}#
<table>
<tr><th>R1</th><th>R2</th></tr>
<tr>
<td><img src="QC_Bases_R1.png"><br><a href="QC_Bases_R1.tsv">Tsv file</a></td>
<td><img src="QC_Bases_R2.png"><br><a href="QC_Bases_R2.tsv">Tsv file</a></td>
</tr>
</table>
<div class="panel-body">
<div class="row">
<div class="col-sm-6 col-md-6">
<img src="QC_Bases_R1.png" class="img-responsive" />
</div>
<div class="col-sm-6 col-md-6">
<img src="QC_Bases_R2.png" class="img-responsive" />
</div>
</div>
</div>
<div class="panel-footer">
<i class="glyphicon glyphicon-file"></i> <a href="QC_Bases_R1.tsv">R1 reads stats</a> -
<i class="glyphicon glyphicon-file"></i> <a href="QC_Bases_R2.tsv">R2 reads stats</a>
</div>
#end
#if (showTable)
<table>
<thead><tr>
<th>Sample</th>
<th colspan="2">Library</th>
<th>Before QC</th>
<th>Discarded</th>
<th>(%)</th>
<th>After QC</th>
</tr></thead>
<tbody>
#for (sample <- samples.toList.sorted)
#{
val libs = libId match {
case Some(libId) => List(libId.toString)
case _ => summary.libraries(sample).toList
}
<div class="panel-body">
<!-- Table -->
<table class="table sortable-theme-bootstrap" data-sortable>
val sampleRowspan = {
libs.size +
libs.count(summary.getLibraryValue(sample, _, "flexiprep", "settings", "paired").getOrElse(false) == true)
}
}#
<tr><td rowspan="${sampleRowspan}"><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td>
#for (libId <- libs)
#if (libs.head != libId) <tr> #end
#{ val paired = summary.getLibraryValue(sample, libId, "flexiprep", "settings", "paired").getOrElse(false) }#
<td #if (paired == true) rowspan="2" #end><a href="${rootPath}Samples/${sample}/Libraries/${libId}/index.html">${libId}</a></td>
#{ val reads = if (paired == true) List("R1", "R2") else List("R1") }#
#for (read <- reads)
#if (read == "R2") </tr><tr> #end
#{
val beforeTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read, "bases", "num_total").getOrElse(0).asInstanceOf[Long]
val afterTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read + "_after", "bases", "num_total").getOrElse(0).asInstanceOf[Long]
}#
<td>${read}</td>
<td>${beforeTotal}</td>
<td>${beforeTotal - afterTotal}</td>
<td>${(beforeTotal - afterTotal).toDouble / beforeTotal * 100}%</td>
<td>${afterTotal}</td>
<thead><tr>
<th>Sample</th>
<th colspan="2">Library</th>
<th>Before QC</th>
<th>Discarded</th>
<th>(%)</th>
<th>After QC</th>
</tr></thead>
<tbody>
#for (sample <- samples.toList.sorted)
#{
val libs = libId match {
case Some(libId) => List(libId.toString)
case _ => summary.libraries(sample).toList
}
val sampleRowspan = {
libs.size +
libs.count(summary.getLibraryValue(sample, _, "flexiprep", "settings", "paired").getOrElse(false) == true)
}
}#
<tr><td rowspan="${sampleRowspan}"><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td>
#for (libId <- libs)
#if (libs.head != libId) <tr> #end
#{ val paired = summary.getLibraryValue(sample, libId, "flexiprep", "settings", "paired").getOrElse(false) }#
<td #if (paired == true) rowspan="2" #end><a href="${rootPath}Samples/${sample}/Libraries/${libId}/index.html">${libId}</a></td>
#{ val reads = if (paired == true) List("R1", "R2") else List("R1") }#
#for (read <- reads)
#if (read == "R2") </tr><tr> #end
#{
val beforeTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read, "bases", "num_total").getOrElse(0).asInstanceOf[Long]
val afterTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read + "_after", "bases", "num_total").getOrElse(0).asInstanceOf[Long]
}#
<td>${read}</td>
<td>${beforeTotal}</td>
<td>${beforeTotal - afterTotal}</td>
<td>${(beforeTotal - afterTotal).toDouble / beforeTotal * 100}%</td>
<td>${afterTotal}</td>
#end
</tr>
#end
#end
</tr>
#end
#end
</tbody>
</table>
</tbody>
</table>
</div>
#end
\ No newline at end of file
......@@ -21,60 +21,74 @@
FlexiprepReport.readSummaryPlot(outputDir, "QC_Reads_R1","R1", summary, sampleId = sampleId)
FlexiprepReport.readSummaryPlot(outputDir, "QC_Reads_R2","R2", summary, sampleId = sampleId)
}#
<table>
<tr><th>R1</th><th>R2</th></tr>
<tr>
<td><img src="QC_Reads_R1.png"><br><a href="QC_Reads_R1.tsv">Tsv file</a></td>
<td><img src="QC_Reads_R2.png"><br><a href="QC_Reads_R2.tsv">Tsv file</a></td>
</tr>
</table>
<div class="panel-body">
<div class="row">
<div class="col-sm-6 col-md-6">
<img src="QC_Reads_R1.png" class="img-responsive">
</div>
<div class="col-sm-6 col-md-6">
<img src="QC_Reads_R2.png" class="img-responsive">
</div>
</div>
</div>
<div class="panel-footer">
<i class="glyphicon glyphicon-file"></i> <a href="QC_Reads_R1.tsv">R1 reads stats</a> -
<i class="glyphicon glyphicon-file"></i> <a href="QC_Reads_R2.tsv">R2 reads stats</a>
</div>
#end
#if (showTable)
<table>
<thead><tr>
<th>Sample</th>
<th colspan="2">Library</th>
<th>Before QC</th>
<th>Clipping</th>
<th>Trimming</th>
<th>After QC</th>
</tr></thead>
<tbody>
#for (sample <- samples.toList.sorted)
#{
val libs = libId match {
case Some(libId) => List(libId.toString)
case _ => summary.libraries(sample).toList
}
val sampleRowspan = {
libs.size +
libs.count(summary.getLibraryValue(sample, _, "flexiprep", "settings", "paired").getOrElse(false) == true)
}
}#
<tr><td rowspan="${sampleRowspan}"><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td>
#for (libId <- libs)
#if (libs.head != libId) <tr> #end
#{ val paired = summary.getLibraryValue(sample, libId, "flexiprep", "settings", "paired").getOrElse(false) }#
<td #if (paired == true) rowspan="2" #end><a href="${rootPath}Samples/${sample}/Libraries/${libId}/index.html">${libId}</a></td>
#{ val reads = if (paired == true) List("R1", "R2") else List("R1") }#
#for (read <- reads)
#if (read == "R2") </tr><tr> #end
<div class="panel-body">
<!-- Table -->
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr>
<th>Sample</th>
<th colspan="2">Library</th>
<th>Before QC</th>
<th>Clipping</th>
<th>Trimming</th>
<th>After QC</th>
</tr></thead>
<tbody>
#for (sample <- samples.toList.sorted)
#{
val beforeTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read, "reads", "num_total")
val afterTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read + "_after", "reads", "num_total")
val clippingDiscardedToShort = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "clipping_" + read, "num_reads_discarded_too_short").getOrElse(0).asInstanceOf[Long]
val clippingDiscardedToLong = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "clipping_" + read, "num_reads_discarded_too_long").getOrElse(0).asInstanceOf[Long]
val trimmingDiscarded = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "trimming", "num_reads_discarded_" + read).getOrElse(0).asInstanceOf[Long]
val libs = libId match {
case Some(libId) => List(libId.toString)
case _ => summary.libraries(sample).toList
}
val sampleRowspan = {
libs.size +
libs.count(summary.getLibraryValue(sample, _, "flexiprep", "settings", "paired").getOrElse(false) == true)
}
}#
<td>${read}</td>
<td>${beforeTotal}</td>
<td>${clippingDiscardedToShort + clippingDiscardedToLong}</td>
<td>${trimmingDiscarded}</td>
<td>${afterTotal}</td>
<tr><td rowspan="${sampleRowspan}"><a href="${rootPath}Samples/${sample}/index.html">${sample}</a></td>
#for (libId <- libs)
#if (libs.head != libId) <tr> #end
#{ val paired = summary.getLibraryValue(sample, libId, "flexiprep", "settings", "paired").getOrElse(false) }#
<td #if (paired == true) rowspan="2" #end><a href="${rootPath}Samples/${sample}/Libraries/${libId}/index.html">${libId}</a></td>
#{ val reads = if (paired == true) List("R1", "R2") else List("R1") }#
#for (read <- reads)
#if (read == "R2") </tr><tr> #end
#{
val beforeTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read, "reads", "num_total")
val afterTotal = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "seqstat_" + read + "_after", "reads", "num_total")
val clippingDiscardedToShort = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "clipping_" + read, "num_reads_discarded_too_short").getOrElse(0).asInstanceOf[Long]
val clippingDiscardedToLong = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "clipping_" + read, "num_reads_discarded_too_long").getOrElse(0).asInstanceOf[Long]
val trimmingDiscarded = summary.getLibraryValue(sample, libId, "flexiprep", "stats", "trimming", "num_reads_discarded_" + read).getOrElse(0).asInstanceOf[Long]
}#
<td>${read}</td>
<td>${beforeTotal}</td>
<td>${clippingDiscardedToShort + clippingDiscardedToLong}</td>
<td>${trimmingDiscarded}</td>
<td>${afterTotal}</td>
#end
</tr>
#end
#end
</tr>
#end
#end
</tbody>
</table>
</tbody>
</table>
</div>
#end
\ No newline at end of file
......@@ -18,22 +18,31 @@
#if (showPlot)
#{ ShivaReport.variantSummaryPlot(outputDir, "variantSummary", summary, sampleId = sampleId) }#
<img src="variantSummary.png"><br>
<a href="variantSummary.tsv">Tsv file</a>
<div class="panel-body">
<img src="variantSummary.png" class="img-responsive" />
</div>
<div class="panel-footer">
<i class="glyphicon glyphicon-file"></i> <a href="variantSummary.tsv">tsv file</a>
</div>
#end
#if (showTable)
<table>
<thead><tr><th>Sample</th>