Commit 513f967a authored by jhoogenboom's avatar jhoogenboom
Browse files

Added Profilevis to the Vis tool and added various enhancements.

* Added options for the graph width and filtering on marker name to
  Samplevis and Profilevis.
* The text fields in the HTML versions of Samplevs and Profilevis
  now update the graph OnChange instead of OnKeyUp. This is done
  because rendering the graph takes a while with large data files.
* Fixed glitch in Profilevis that caused useless horizontal axis
  labels when the logarithmic scale is used.
* Fixed glitch in Profilevis that caused Vega to render the graph
  even before data was loaded.
* Changed -R option of SeqConvert to -r to avoid a potential
  collision with the -R/--report option if SeqConvert ever gets
  report output support in the future.
parent b7d64a4f
......@@ -116,7 +116,7 @@ def add_arguments(parser):
type=argparse.FileType('r'),
help="second library file to use for output; if specified, allele "
"names can be conveniently updated to fit this new library file")
parser.add_argument('-R', '--reverse-complement', metavar="MARKER",
parser.add_argument('-r', '--reverse-complement', metavar="MARKER",
nargs="+", default=[],
help="to be used togethwer with -L/--library2; specify the markers "
"for which the sequences are reverse-complemented in the new "
......
......@@ -56,6 +56,14 @@ _DEF_BAR_WIDTH = 15
# This value can be overridden by the -p command line option.
_DEF_SUBGRAPH_PADDING = 70
# Default graph width in pixels.
# This value can be overridden by the -w command line option.
_DEF_WIDTH = 600
# Default marker name matching regular expression.
# This value can be overridden by the -M command line option.
_DEF_MARKER_REGEX = ".*"
# Default data file that Vega will read when -V/--vega is specified
# without providing data to embed in the file.
# It is currently impossible to override this value.
......@@ -91,7 +99,7 @@ def set_data_formula_transform_value(spec, dataname, fieldname, value):
def create_visualisation(vistype, infile, outfile, vega, online, tidy,
min_abs, min_pct, bar_width, padding):
min_abs, min_pct, bar_width, padding, marker, width):
# Get graph spec.
spec = json.load(resource_stream(
"fdstools", "vis/%svis/%svis.json" % (vistype, vistype)))
......@@ -104,15 +112,19 @@ def create_visualisation(vistype, infile, outfile, vega, online, tidy,
spec["data"][0]["url"] = _DEF_DATA_FILENAME
# Apply settings.
spec["width"] = width
set_data_formula_transform_value(spec, "yscale", "barwidth", bar_width)
set_data_formula_transform_value(spec, "yscale", "subgraphoffset", padding)
set_data_formula_transform_value(
spec, "table", "filter_marker", "'" + marker + "'")
if vistype == "sample":
set_data_formula_transform_value(
spec, "yscale", "barwidth", bar_width)
set_data_formula_transform_value(
spec, "yscale", "subgraphoffset", padding)
set_data_formula_transform_value(
spec, "table", "amplitude_threshold", min_abs)
set_data_formula_transform_value(
spec, "table", "amplitude_pct_threshold", min_pct)
elif vistype == "profile":
set_data_formula_transform_value(
spec, "table", "filter_threshold", min_pct)
# Stringify spec.
if tidy:
......@@ -156,8 +168,11 @@ def create_visualisation(vistype, infile, outfile, vega, online, tidy,
def add_arguments(parser):
parser.add_argument('type', metavar="TYPE", choices=("sample",),
help="the type of data to visualise: one of %(choices)s")
parser.add_argument('type', metavar="TYPE", choices=("sample", "profile"),
help="the type of data to visualise; use 'sample' to visualise "
"sample data files and BGCorrect output; use 'profile' to "
"visualise background noise profiles obtained with BGEstimate, "
"BGHomStats, and BGPredict")
parser.add_argument('infile', metavar="IN", nargs="?",
help="file containing the data to embed in the visualisation file; if "
"not specified, HTML visualisation files will contain a file "
......@@ -180,24 +195,36 @@ def add_arguments(parser):
parser.add_argument('-t', '--tidy', action="store_true",
help="tidily indent the generated JSON")
samplevis = parser.add_argument_group("sample visualisation options",
description="used when TYPE=sample")
samplevis.add_argument('-n', '--min-abs', metavar="N", type=pos_int_arg,
visgroup = parser.add_argument_group("visualisation options",
description="words in [brackets] indicate applicable visualisation "
"types")
visgroup.add_argument('-n', '--min-abs', metavar="N", type=pos_int_arg,
default=_DEF_THRESHOLD_ABS,
help="only show alleles with this minimum number of reads (default: "
"%(default)s)")
samplevis.add_argument('-m', '--min-pct', metavar="PCT", type=float,
help="[sample] only show sequences with this minimum number of reads "
"(default: %(default)s)")
visgroup.add_argument('-m', '--min-pct', metavar="PCT", type=float,
default=_DEF_THRESHOLD_PCT,
help="only show alleles with at least this percentage of the number "
"of reads of the highest allele of a marker (default: "
"%(default)s)")
samplevis.add_argument('-b', '--bar-width', metavar="N", type=pos_int_arg,
help="[sample, profile] for sample: only show sequences with at least "
"this percentage of the number of reads of the highest allele of "
"a marker; for profile: at least this percentage of the true "
"allele (default: %(default)s)")
visgroup.add_argument('-M', '--marker', metavar="REGEX",
default=_DEF_MARKER_REGEX,
help="[sample, profile] only show graphs for the markers that match "
"the given regular expression; the default value '%(default)s' "
"matches any marker name")
visgroup.add_argument('-b', '--bar-width', metavar="N", type=pos_int_arg,
default=_DEF_BAR_WIDTH,
help="width of the bars in pixels (default: %(default)s)")
samplevis.add_argument('-p', '--padding', metavar="N", type=pos_int_arg,
help="[sample, profile] width of the bars in pixels (default: "
"%(default)s)")
visgroup.add_argument('-p', '--padding', metavar="N", type=pos_int_arg,
default=_DEF_SUBGRAPH_PADDING,
help="amount of padding (in pixels) between graphs of different "
"markers (default: %(default)s)")
help="[sample, profile] amount of padding (in pixels) between graphs "
"of different markers (default: %(default)s)")
visgroup.add_argument('-w', '--width', metavar="N", type=pos_int_arg,
default=_DEF_WIDTH,
help="[sample, profile] width of the graph area in pixels (default: "
"%(default)s)")
#add_arguments
......@@ -222,7 +249,7 @@ def run(args):
create_visualisation(args.type, args.infile, args.outfile, args.vega,
args.online, args.tidy, args.min_abs, args.min_pct,
args.bar_width, args.padding)
args.bar_width, args.padding, args.marker, args.width)
#run
......
......@@ -47,8 +47,10 @@
<!--
Select marker: <select id="markers"></select><br>
Select allele: <select id="alleles"></select><br> -->
Display options: bar width <input type="text" value="15" id="barwidth" size="2">px; subgraph spacing <input type="text" value="70" id="subgraphoffset" size="3">px<br>
Filtering: minimum noise ratio <input type="text" value="0.5" id="minP" size="3">%<br>
Display options: graph width <input type="text" value="600" id="graphwidth" size="3">px;
bar width <input type="text" value="15" id="barwidth" size="2">px;
subgraph spacing <input type="text" value="70" id="subgraphoffset" size="3">px<br>
Filtering: minimum noise ratio <input type="text" value="0.5" id="minP" size="3">%; marker <input type="text" id="markerFilter" size="10" title="Supports regular expression syntax: e.g., use '.*' to match anything."><br>
Axis scale: <input type="radio" name="scale" value="linear" id="scaleLinear" checked> Linear
<input type="radio" name="scale" value="log" id="scaleLog"> Logarithmic<br>
Render as: <input type="radio" name="renderer" value="canvas" id="renderCanvas"> Canvas
......@@ -84,7 +86,9 @@
if(graph_spec["marks"][i]["scales"][j]["name"] == "x")
graph_spec["marks"][i]["scales"][j]["type"] = value;
setDataFormulaTransformValue("table", "low", value == "log"? "0.001" : "0");
parse();
if(graph)
parse();
}
function setDataFormulaTransformValue(dataname, fieldname, value){
......@@ -186,27 +190,39 @@
document.getElementById("scaleLog").addEventListener('change', function(){
setScale(this.value);
}, false);
document.getElementById("barwidth").addEventListener('keyup', function(){
document.getElementById("graphwidth").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
graph_spec["width"] = value;
if(graph)
parse();
}, false);
document.getElementById("barwidth").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("yscale", "barwidth", value) && graph)
parse();
}, false);
document.getElementById("subgraphoffset").addEventListener('keyup', function(){
document.getElementById("subgraphoffset").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("yscale", "subgraphoffset", value) && graph)
parse();
}, false);
document.getElementById("minP").addEventListener('keyup', function(){
document.getElementById("minP").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("table", "filter_threshold", value) && graph)
parse();
}, false);
document.getElementById("markerFilter").addEventListener('change', function(){
if(setDataFormulaTransformValue("table", "filter_marker", "'" + this.value + "'") && graph)
parse();
}, false);
//Toggle options visibility.
document.getElementById("optionsheader").addEventListener('click', function(){
......@@ -222,6 +238,8 @@
setScale(document.getElementById("scaleLinear").value);
else
setScale(document.getElementById("scaleLog").value);
document.getElementById("markerFilter").value = getDataFormulaTransformValue("table", "filter_marker").replace(/^(['"]?)(.*(?=\1$))\1$/, '$2');
document.getElementById("graphwidth").value = graph_spec["width"];
document.getElementById("barwidth").value = getDataFormulaTransformValue("yscale", "barwidth");
document.getElementById("subgraphoffset").value = getDataFormulaTransformValue("yscale", "subgraphoffset");
document.getElementById("minP").value = getDataFormulaTransformValue("table", "filter_threshold");
......
......@@ -26,6 +26,15 @@
"type": "filter",
"test": "datum.fmean+datum.rmean < 200 && max(datum.fmean, datum.rmean) > datum.filter_threshold"
},
{
"type": "formula",
"field": "filter_marker",
"expr": "'.*'"
},
{
"type": "filter",
"test": "test('^' + datum.filter_marker + '$', datum.marker)"
},
{
"type": "formula",
"field": "low",
......@@ -236,7 +245,7 @@
{
"type": "x",
"scale": "x",
"format": "s",
"format": ".1r",
"grid": true,
"layer": "back",
"title": "Noise ratio (%)",
......
......@@ -44,8 +44,11 @@
<span id="fileselectspan" style="display: none">
Open sample data file (or drag a file onto this page): <input id="fileselect" type="file"><br>
</span>
Display options: bar width <input type="text" value="15" id="barwidth" size="2">px; marker spacing <input type="text" value="70" id="subgraphoffset" size="3">px<br>
Display options: graph width <input type="text" value="600" id="graphwidth" size="3">px;
bar width <input type="text" value="15" id="barwidth" size="2">px;
marker spacing <input type="text" value="70" id="subgraphoffset" size="3">px<br>
Filtering: require at least <input type="text" value="15" id="minN" size="3"> reads and at least <input type="text" value="0.5" id="minP" size="3">% of highest allele per marker<br>
Filtering: marker <input type="text" id="markerFilter" size="10" title="Supports regular expression syntax: e.g., use '.*' to match anything."><br>
Axis scale: <input type="radio" name="scale" value="linear" id="scaleLinear" checked> Linear
<input type="radio" name="scale" value="sqrt" id="scaleLog"> Square root<br>
Render as: <input type="radio" name="renderer" value="canvas" id="renderCanvas"> Canvas
......@@ -183,34 +186,46 @@
document.getElementById("scaleLog").addEventListener('change', function(){
setScale(this.value);
}, false);
document.getElementById("barwidth").addEventListener('keyup', function(){
document.getElementById("graphwidth").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
graph_spec["width"] = value;
if(graph)
parse();
}, false);
document.getElementById("barwidth").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("yscale", "barwidth", value) && graph)
parse();
}, false);
document.getElementById("subgraphoffset").addEventListener('keyup', function(){
document.getElementById("subgraphoffset").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("yscale", "subgraphoffset", value) && graph)
parse();
}, false);
document.getElementById("minN").addEventListener('keyup', function(){
document.getElementById("minN").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("table", "amplitude_threshold", value) && graph)
parse();
}, false);
document.getElementById("minP").addEventListener('keyup', function(){
document.getElementById("minP").addEventListener('change', function(){
var value = parseFloat(this.value);
if(isNaN(value))
return;
if(setDataFormulaTransformValue("table", "amplitude_pct_threshold", value) && graph)
parse();
}, false);
document.getElementById("markerFilter").addEventListener('change', function(){
if(setDataFormulaTransformValue("table", "filter_marker", "'" + this.value + "'") && graph)
parse();
}, false);
//Toggle options visibility.
document.getElementById("optionsheader").addEventListener('click', function(){
......@@ -226,6 +241,8 @@
setScale(document.getElementById("scaleLinear").value);
else
setScale(document.getElementById("scaleLog").value);
document.getElementById("markerFilter").value = getDataFormulaTransformValue("table", "filter_marker").replace(/^(['"]?)(.*(?=\1$))\1$/, '$2');
document.getElementById("graphwidth").value = graph_spec["width"];
document.getElementById("barwidth").value = getDataFormulaTransformValue("yscale", "barwidth");
document.getElementById("subgraphoffset").value = getDataFormulaTransformValue("yscale", "subgraphoffset");
document.getElementById("minN").value = getDataFormulaTransformValue("table", "amplitude_threshold");
......
......@@ -74,6 +74,15 @@
"type": "filter",
"test": "datum.amplitude > datum.amplitude_threshold && datum.amplitude_pct > datum.amplitude_pct_threshold"
},
{
"type": "formula",
"field": "filter_marker",
"expr": "'.*'"
},
{
"type": "filter",
"test": "test('^' + datum.filter_marker + '$', datum.name)"
},
{
"type": "formula",
"field": "shared",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment