Commit 5ef02db9 authored by Wai Yi Leung's avatar Wai Yi Leung
Browse files

Merge branch 'feature-report' into 'develop'

Feature report

See also issue #102

Things to do:
- [x] implement template library
- [ ] General features
 - [x] Versions template
 - [x] Intro text sections
 - [x] Intro text pages
 - [x] Fix menu
 - [x] fix sidebar, should highlight current section
 - [x] Fix sortable tables, @wyleung
 - [x] Auto scala width on number of samples
- [ ] Report for Flexiprep
 - [x] Files template
- [ ] Report for bammetrics, #127 required
 - [x] Fix insertsize
- [ ] Report for Mapping
 - [x] Files template
- [ ] Report for Shiva
 - [x] Files template
 - [x] Show tables on click
- [ ] Report for Carp
- [ ] Setup a generic layout

See merge request !149
parents 7d5425d9 6142593f
......@@ -22,6 +22,12 @@ trait GatkGeneral extends CommandLineGATK with BiopetJavaCommandLineFunction wit
if (config.contains("gatk_key")) gatk_key = config("gatk_key")
if (config.contains("pedigree")) pedigree = config("pedigree")
override val versionRegex = """(.*)""".r
override val versionExitcode = List(0, 1)
override def versionCommand = executable + " -jar " + jarFile + " -version"
override def getVersion = super.getVersion.collect { case version => "Gatk " + version }
override def beforeGraph: Unit = {
super.beforeGraph
if (reference_sequence == null) reference_sequence = referenceFasta()
......
......@@ -57,7 +57,7 @@
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_2.11</artifactId>
<artifactId>scalatest_2.10</artifactId>
<version>2.2.1</version>
<scope>test</scope>
</dependency>
......
......@@ -47,7 +47,7 @@
</dependency>
<dependency>
<groupId>org.scalatest</groupId>
<artifactId>scalatest_2.11</artifactId>
<artifactId>scalatest_2.10</artifactId>
<version>2.2.1</version>
<scope>test</scope>
</dependency>
......
#import(nl.lumc.sasc.biopet.core.summary.Summary)
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
#import(nl.lumc.sasc.biopet.pipelines.bammetrics.BammetricsReport)
#import(java.io.File)
<%@ var summary: Summary %>
<%@ var sampleId: Option[String] = None %>
<%@ var libId: Option[String] = None %>
<%@ var sampleLevel: Boolean = false %>
<%@ var rootPath: String %>
<%@ var outputDir: File %>
<%@ var showPlot: Boolean = false %>
<%@ var showTable: Boolean = true %>
<%@ var showIntro: Boolean = true%>
#{
val samples = sampleId match {
case Some(sample) => {
List(sample.toString)
}
case _ => summary.samples.toList
}
}#
#if (showIntro)
<br/>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-6">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc risus est, volutpat quis enim sit amet, lacinia posuere ante. Mauris eget massa efficitur, luctus nisl ut, placerat nibh. Pellentesque id nulla maximus, rutrum dui nec, lobortis odio. Fusce eu enim ac sem auctor congue. Ut ac ullamcorper quam, eget sollicitudin felis. Maecenas posuere sagittis blandit. Proin mollis magna lectus, id gravida est consectetur vitae. Nulla id risus at tellus laoreet finibus in id lacus. Duis lobortis commodo nisl viverra tempor. Curabitur sit amet pretium dui, sit amet tincidunt mauris. Duis volutpat eu purus ut molestie.
</p>
</div>
</div>
#end
#if (showPlot)
#{ BammetricsReport.alignmentSummaryPlot(outputDir, "alignmentSummary", summary, !sampleLevel, sampleId = sampleId) }#
<div class="panel-body">
<img src="alignmentSummary.png" class="img-responsive" />
</div>
<div class="panel-footer">
#if (showTable)
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#alignmentSummaryTable">Hide table</button>
#else
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#alignmentSummaryTable">Show table</button>
#end
<i class="glyphicon glyphicon-file"></i> <a href="alignmentSummary.tsv">tsv file</a>
</div>
#end
<div class="panel-body collapse #if (showTable)in#end" id="alignmentSummaryTable">
<!-- Table -->
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr>
<th data-sorted="true" data-sorted-direction="ascending">Sample</th>
#if (!sampleLevel) <th>Library</th> #end
<th>Total</th>
<th>Mapped</th>
<th>(%)</th>
<th>Duplicates</th>
<th>(%)</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]
}#
<td>${total}</td>
<td>${mapped}</td>
<td>${mapped.toDouble / total * 100}%</td>
<td>${duplicates}</td>
<td>${duplicates.toDouble / total * 100}%</td>
</tr>
#end
#end
</tbody>
</table>
</div>
\ No newline at end of file
#import(nl.lumc.sasc.biopet.core.summary.Summary)
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
<%@ var summary: Summary %>
<%@ var sampleId: Option[String] %>
<%@ var libId: Option[String] = None %>
<%@ var rootPath: String %>
<%@ var metricsTag: String = "bammetrics" %>
<%@ var fields: List[String] = List("All", "Mapped", "Duplicates", "MAPQ>30", "MateUnmapped", "Mate on other chr")%>
<table>
<tbody>
#for (field <- fields)
<tr><th>${field}</th><td>
#if (libId.isDefined)
${summary.getLibraryValue(sampleId.get, libId.get, metricsTag, "stats", "biopet_flagstat", field)}
#else
${summary.getSampleValue(sampleId.get, metricsTag, "stats", "biopet_flagstat", field)}
#end
</td></tr>
#end
</tbody>
</table>
#import(nl.lumc.sasc.biopet.utils.IoUtils)
#import(nl.lumc.sasc.biopet.core.summary.Summary)
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
#import(org.apache.commons.io.FileUtils)
#import(java.io.File)
<%@ var summary: Summary %>
<%@ var sampleId: Option[String] = None %>
<%@ var libId: Option[String] = None %>
<%@ var sampleLevel: Boolean = true %>
<%@ var rootPath: String %>
<%@ var outputDir: File %>
<%@ var metricsTag: String = "bammetrics" %>
<%@ var target: String %>
#{
val samples = sampleId match {
case Some(sample) => List(sample.toString)
case _ => summary.samples.toList
}
}#
<table class="table">
<thead><tr>
<th>sample</th>
<th>mean</th>
<th>median</th>
<th>max</th>
<th>horizontal</th>
<th>frac min 10x</th>
<th>frac min 20x</th>
<th>frac min 30x</th>
<th>frac min 40x</th>
<th>frac min 50x</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(metricsTag, "stats", target + "_cov_stats", "coverage", "_all")
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]
}#
<td>${summary.getValue((prefixPath ::: "mean" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "median" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "max" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "horizontal" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "frac_min_10x" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "frac_min_20x" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "frac_min_30x" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "frac_min_40x" :: Nil):_*)}</td>
<td>${summary.getValue((prefixPath ::: "frac_min_50x" :: Nil):_*)}</td>
</tr>
#end
#end
</tbody>
</table>
#import(nl.lumc.sasc.biopet.utils.IoUtils)
#import(nl.lumc.sasc.biopet.core.summary.Summary)
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
#import(org.apache.commons.io.FileUtils)
#import(java.io.File)
<%@ var summary: Summary %>
<%@ var sampleId: Option[String] %>
<%@ var libId: Option[String] = None %>
<%@ var outputDir: File %>
<%@ var metricsTag: String = "bammetrics" %>
<%@ var target: String %>
#{
val originalPlot = new File(summary.getLibraryValue(sampleId, libId, metricsTag, "files", target + "_cov_stats", "plot", "path")
.getOrElse(throw new IllegalArgumentException("No plot found in summary")).toString)
val plot = new File(outputDir, target + "_cov_stats.png")
val values = summary.getLibraryValue(sampleId, libId, metricsTag, "stats", target + "_cov_stats", "coverage", "_all")
.getOrElse(throw new IllegalArgumentException("No plot found in summary")).asInstanceOf[Map[String, Any]]
if (originalPlot.exists()) IoUtils.copyFile(originalPlot, plot)
}#
<img src="${plot}">
<table class="table">
<thead><tr>
<th>mean</th>
<th>median</th>
<th>max</th>
<th>horizontal</th>
<th>frac min 10x</th>
<th>frac min 20x</th>
<th>frac min 30x</th>
<th>frac min 40x</th>
<th>frac min 50x</th>
</tr></thead>
<tbody>
<tr>
<td>${values.get("mean")}</td>
<td>${values.get("median")}</td>
<td>${values.get("max")}</td>
<td>${values.get("horizontal")}</td>
<td>${values.get("frac_min_10x")}</td>
<td>${values.get("frac_min_20x")}</td>
<td>${values.get("frac_min_30x")}</td>
<td>${values.get("frac_min_40x")}</td>
<td>${values.get("frac_min_50x")}</td>
</tr>
</tbody>
</table>
#import(nl.lumc.sasc.biopet.core.summary.Summary)
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
#import(nl.lumc.sasc.biopet.pipelines.bammetrics.BammetricsReport)
#import(java.io.File)
#import(org.apache.commons.io.FileUtils)
<%@ var summary: Summary %>
<%@ var sampleId: Option[String] = None %>
<%@ var libId: Option[String] = None %>
<%@ var rootPath: String %>
<%@ var metricsTag: String = "bammetrics" %>
<%@ var sampleLevel: Boolean = false %>
<%@ var outputDir: File %>
<%@ var fields: List[String] = List("mean_insert_size", "standard_deviation", "median_insert_size")%>
<%@ var showPlot: Boolean = false %>
<%@ var showTable: Boolean = true %>
<%@ var showIntro: Boolean = true%>
#{
val samples = sampleId match {
case Some(sample) => {
List(sample.toString)
}
case _ => summary.samples.toList
}
}#
#if (showIntro)
<br/>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-6">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc risus est, volutpat quis enim sit amet, lacinia posuere ante. Mauris eget massa efficitur, luctus nisl ut, placerat nibh. Pellentesque id nulla maximus, rutrum dui nec, lobortis odio. Fusce eu enim ac sem auctor congue. Ut ac ullamcorper quam, eget sollicitudin felis. Maecenas posuere sagittis blandit. Proin mollis magna lectus, id gravida est consectetur vitae. Nulla id risus at tellus laoreet finibus in id lacus. Duis lobortis commodo nisl viverra tempor. Curabitur sit amet pretium dui, sit amet tincidunt mauris. Duis volutpat eu purus ut molestie.
</p>
</div>
</div>
#end
#if (showPlot)
#{ BammetricsReport.insertSizePlot(outputDir, "insertsize", summary, !sampleLevel, sampleId = sampleId) }#
<div class="panel-body">
<img src="insertsize.png" class="img-responsive" />
</div>
<div class="panel-footer">
#if (showTable)
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#insertsizeTable">Hide table</button>
#else
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#insertsizeTable">Show table</button>
#end
<i class="glyphicon glyphicon-file"></i> <a href="insertsize.tsv">tsv file</a>
</div>
#end
<div class="panel-body collapse #if (showTable)in#end" id="insertsizeTable">
<!-- Table -->
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr>
<th data-sorted="true" data-sorted-direction="ascending">Sample</th>
#if (!sampleLevel) <th>Library</th> #end
#for (field <- fields)
<th>${field.replaceAll("_", " ")}</th>
#end
</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 fieldValues = for (field <- fields) yield {
summary.getValue((prefixPath ::: List("CollectInsertSizeMetrics", "metrics", field.toUpperCase)):_*).getOrElse(prefixPath ::: metricsTag :: Nil)
}
}#
#for (value <- fieldValues)
<td>${value}</td>
#end
</tr>
#end
#end
</tbody>
</table>
</div>
#{ //TODO: Need content }#
Todo
\ No newline at end of file
#import(nl.lumc.sasc.biopet.core.summary.Summary)
#import(nl.lumc.sasc.biopet.core.report.ReportPage)
#import(nl.lumc.sasc.biopet.pipelines.bammetrics.BammetricsReport)
#import(java.io.File)
#import(org.apache.commons.io.FileUtils)
<%@ var summary: Summary %>
<%@ var sampleId: Option[String] = None %>
<%@ var libId: Option[String] = None %>
<%@ var rootPath: String %>
<%@ var metricsTag: String = "bammetrics" %>
<%@ var sampleLevel: Boolean = false %>
<%@ var outputDir: File %>
<%@ var fields: List[String] = List("mean_coverage", "pct_5x", "pct_10x", "pct_15x", "pct_20x", "pct_25x", "pct_30x", "pct_40x", "pct_50x", "pct_60x", "pct_70x", "pct_80x", "pct_90x", "pct_100x")%>
<%@ var showPlot: Boolean = false %>
<%@ var showTable: Boolean = true %>
<%@ var showIntro: Boolean = true%>
#{
val samples = sampleId match {
case Some(sample) => {
List(sample.toString)
}
case _ => summary.samples.toList
}
}#
#if (showIntro)
<br/>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-6">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc risus est, volutpat quis enim sit amet, lacinia posuere ante. Mauris eget massa efficitur, luctus nisl ut, placerat nibh. Pellentesque id nulla maximus, rutrum dui nec, lobortis odio. Fusce eu enim ac sem auctor congue. Ut ac ullamcorper quam, eget sollicitudin felis. Maecenas posuere sagittis blandit. Proin mollis magna lectus, id gravida est consectetur vitae. Nulla id risus at tellus laoreet finibus in id lacus. Duis lobortis commodo nisl viverra tempor. Curabitur sit amet pretium dui, sit amet tincidunt mauris. Duis volutpat eu purus ut molestie.
</p>
</div>
</div>
#end
#if (showPlot)
#{ BammetricsReport.wgsHistogramPlot(outputDir, "wgs", summary, !sampleLevel, sampleId = sampleId) }#
<div class="panel-body">
<img src="wgs.png" class="img-responsive" />
</div>
<div class="panel-footer">
#if (showTable)
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#wgsTable">Hide table</button>
#else
<button type="button" class="btn btn-info" data-toggle="collapse" data-target="#wgsTable">Show table</button>
#end
<i class="glyphicon glyphicon-file"></i> <a href="wgs.tsv">tsv file</a>
</div>
#end
<div class="panel-body collapse #if (showTable)in#end" id="wgsTable">
<!-- Table -->
<table class="table sortable-theme-bootstrap" data-sortable>
<thead><tr>
<th data-sorted="true" data-sorted-direction="ascending">Sample</th>
#if (!sampleLevel) <th>Library</th> #end
#for (field <- fields)
<th>${field.replaceAll("_", " ")}</th>
#end
</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 fieldValues = for (field <- fields) yield {
summary.getValue((prefixPath ::: List("wgs", "metrics", field.toUpperCase)):_*).getOrElse(prefixPath ::: metricsTag :: Nil)
}
}#
#for (value <- fieldValues)
<td>${value}</td>
#end
</tr>
#end
#end
</tbody>
</table>
</div>
......@@ -156,8 +156,10 @@ class BamMetrics(val root: Configurable) extends QScript with SummaryQScript wit
//FIXME:should use piping
add(BedtoolsCoverage(this, inputBam, intervals.bed, coverageFile, depth = true), true)
val covStats = CoverageStats(this, coverageFile, targetDir)
covStats.title = Some("Coverage for " + targetName)
covStats.subTitle = Some(".")
add(covStats)
addSummarizable(covStats, "cov_stats")
addSummarizable(covStats, targetName + "_cov_stats")
}
addSummaryJobs
......
package nl.lumc.sasc.biopet.pipelines.bammetrics
import java.io.{ PrintWriter, File }
import nl.lumc.sasc.biopet.core.report.{ ReportBuilder, ReportPage, ReportSection }
import nl.lumc.sasc.biopet.core.summary.{ SummaryValue, Summary }
import nl.lumc.sasc.biopet.extensions.rscript.{ XYPlot, StackedBarPlot }
/**
* Created by pjvan_thof on 3/30/15.
*/
object BammetricsReport extends ReportBuilder {
// FIXME: Not yet finished
val reportName = "Bam Metrics"
def indexPage = ReportPage(List(), List(), Map())
def bamMetricsPage(summary: Summary, sampleId: Option[String], libId: Option[String]) = {
val targets = (
summary.getLibraryValue(sampleId, libId, "bammetrics", "settings", "amplicon_name"),
summary.getLibraryValue(sampleId, libId, "bammetrics", "settings", "roi_name")
) match {
case (Some(amplicon: String), Some(roi: List[_])) => amplicon :: roi.map(_.toString)
case (_, Some(roi: List[_])) => roi.map(_.toString)
case _ => Nil
}
ReportPage(
(if (targets.isEmpty) List() else List("Targets" -> ReportPage(
List(),
targets.map(t => (t -> ReportSection("/nl/lumc/sasc/biopet/pipelines/bammetrics/covstatsPlot.ssp", Map("target" -> t)))),
Map()))),
List(
"Summary" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/bammetrics/alignmentSummary.ssp"),
"Insert Size" -> ReportSection("/nl/lumc/sasc/biopet/pipelines/bammetrics/insertSize.ssp", Map("showPlot" -> true))
),
Map()
)
}
def alignmentSummaryPlot(outputDir: File,
prefix: String,
summary: Summary,
libraryLevel: Boolean = false,
sampleId: Option[String] = None): Unit = {
val tsvFile = new File(outputDir, prefix + ".tsv")
val pngFile = new File(outputDir, prefix + ".png")
val tsvWriter = new PrintWriter(tsvFile)
if (libraryLevel) tsvWriter.print("Library") else tsvWriter.print("Sample")
tsvWriter.println("\tMapped\tDuplicates\tUnmapped\tSecondary")
def getLine(summary: Summary, sample: String, lib: Option[String] = None): String = {
val mapped = new SummaryValue(List("bammetrics", "stats", "biopet_flagstat", "Mapped"),
summary, Some(sample), lib).value.getOrElse(0).toString.toLong
val duplicates = new SummaryValue(List("bammetrics", "stats", "biopet_flagstat", "Duplicates"),
summary, Some(sample), lib).value.getOrElse(0).toString.toLong
val total = new SummaryValue(List("bammetrics", "stats", "biopet_flagstat", "All"),
summary, Some(sample), lib).value.getOrElse(0).toString.toLong
val secondary = new SummaryValue(List("bammetrics", "stats", "biopet_flagstat", "NotPrimaryAlignment"),
summary, Some(sample), lib).value.getOrElse(0).toString.toLong
val sb = new StringBuffer()
if (lib.isDefined) sb.append(sample + "-" + lib.get + "\t") else sb.append(sample + "\t")
sb.append((mapped - duplicates) + "\t")
sb.append(duplicates + "\t")
sb.append((total - mapped - secondary) + "\t")
sb.append(secondary)
sb.toString
}
if (libraryLevel) {
for (
sample <- summary.samples if (sampleId.isEmpty || sample == sampleId.get);
lib <- summary.libraries(sample)
) {
tsvWriter.println(getLine(summary, sample, Some(lib)))
}
} else {
for (sample <- summary.samples if (sampleId.isEmpty || sample == sampleId.get)) {
tsvWriter.println(getLine(summary, sample))
}
}
tsvWriter.close()
val plot =