4.5.6. VSReports Templates¶
Note
This section is specific to customizing the Report Templates that power the Reports view (VSReports). This functionality is deprecated and will be replaced by the evolving report customization available in VSClinical. See Customizing VSClinical Reports for more details.
Reports are fully customizable and Golden Helix is happy to offer customization services. For more information contact your account manager.
Users with JavaScript development experience can extensively modify templates. To access the development console click the Gear menu and select Developer JavaScript Console. This will bring up a WebKit-like dev console. Click on the icon in the lower left corner to open the JavaScript console. Note that after making any changes to JavaScript files you will need to select Reload Report Template from the Gear menu to update the current namespace with those changes.
Templates consist of three main parts:
Layout Object: In the report.js file a variable layout is defined. This is a object which defines the form that is laid out in the report tab.
Template: Each template contains a template file which defines the layout of the rendered report. Handlebars is used as the templating language.
Render Function: The render function in
report.js
combines the information from the form and sources in VarSeq to create a context to pass to the compiled Handlebars template for rendering.
VarSeq provides four main objects to the JavaScript namespace which can be
accessed via functions on the form
object.
form.getProjectData()
: Returns an object which corresponds to data in the project. The samples property contains the meta-data associated with the samples in the project. The sources property contains meta-data about the sources used during annotation. The variants property contains the annotated variants in the selected set of variants.form.getInputData()
: Returns an object containing the user input from the form in the report tab.form.getParamsData()
Returns an object containing the user input from the template configuration dialog.form.templateText()
: Returns a string containing the handlebars template. You must compile this string into a template prior to passing the context to render report.
When the form is created in the report tab, each of the items in the
layout
object tries to call it’s autofill function. If the form
item supports the choices property, and the choices are specified as a
function, this function will be called as well. The choices function
is called before the autofill function so that the autofill function
may make use of the newly set choices. Each autofill function is
passed the project, input, and variants objects as described
above. Additionally record set forms are passed a fourth argument
containing the variant used to construct the form. Finally the last
argument passed to the autofill and choices function is the thisFrom
object. The this form object contains the state of all of the form
objects in the current form. The thisForm object allows form items to
change based on updates to other items in the same form. The function
should return the autofill value to populate the associated widget
with.
Whenever the Create Report icon is pressed the render function is called. It is passed all four of the previously described variable as arguments. The render function should return the fully rendered output string (i.e. valid HTML).
Additional JavaScript helper functions have been included in
scripts/templateUtils.js
. The lodash and
string.js libraries are included by default
as well. You can include any other client-side libraries that do not
require a DOM by importing them at the top of report.js
. Note,
that this import is not a true ES6 style import; it instead prepends
the library code prior to evaluation.
Bootstrap is included as a CSS framework.
The Layout¶
There is a defined list of widgets that VarSeq includes that can be used to construct the report form. All of the available widgets can be found in the following image and are described in detail below.

To add a widget to the form, add the corresponding javascript object to the layout section of the report.js file.
Each of the form widget is divded into sections which are objects with the following properties:
id
- used to access the objectlabel
- the label for the input field in the form in VarSeqcontext
- specifies if the input is either at the sample, variant, or other record level. It will commonly be one of the following values:sample
- These widgets provide report fields for the current sample.variant
- These widgets are associated with a variant record set. At the top of the section will be a widget to select the “Variant Set” that defines variants for this section. Each selected variant will have all the contained widgets instantiated for it. Widgets in these sections will have an extravariant
value passed to itsautoFill
function.cnv
- Similar tovariant
but contains selected records from a CNV table.coverageregion
- Similar tovariant
but contains selected records from a Coverage Region table.loh
- Similar tovariant
but contains selected records from a Loss of Heterozygoisty table.
Each item corresponds to a widget which will be created in the form. These widget have share the following common properties:
id
- used to retrieve datalabel
- provides a label in the input formdoc
- help string displayed on hover of i icon in input formrequired
- boolean denoting if widget must be filled out by end usertype
- defines the type of widget to be displayed using the following strings:autoFill
- function which returns a value to dynamically fill the widget’s input. Form has different parameters passed to it based on the context of the container for the widget.sample context arguments include
project
,input
andthisForm
variant or other non-sample context arguments include
project
,input
,variant
andthisForm
default
- static default value for a widget (should not be used with autoFill)
Additionally each widget has some unique values. These parameters allow you to customize the widgit behavior.
Short Text Edit¶
The short text edit widget provides a sigle line for text entry. The specification of completion values allow for quick editing when the value is one of several common values.
Properties:
value - text in line edit
placeholder - text in line edit when empty
completions - if specified this must be a list of values, or a function which return a list of value. The list of values are then used to populate the autocompleter. If a function is specified it will be called each time that the value of the widget changes. The arguments passed to the function are the same as the arguments that are passed to the autofill function with the addition of the current widget value, which is passes as the last argument.
Example in report layout:
{
id: 'shortTextId',
label: 'Short Text Label',
type: 'shortText',
placeholder: "place holder text",
completions: ['one', 'two', 'three']
}
Multi Line Edit¶
Provides free form text edit widget with an adjustable size.
Properties:
value - test in line edit
heightInLines - (integer) How many lines to provide for text input
{
id:'longTextId',
label: 'Long Text',
type: 'longText',
heightInLines: 5
}
Rich Text Edit¶
Provides the same features as the Multi Line Edit widget, with the addition of rich text formating.
Properties:
value - text in line edit
heightInLines - (integer) how many lines to provide for input
{
id: 'richText',
label: 'Rich Text',
type:'richTextEdit',
heightInLines: 6
}
Choice¶
Creates a widget with a dropdown menu with multiple choices. An unset value may also be specified to leave the entry as missing.
Properties:
value - enum
unsetName - When set this provides an option for an ‘unsetName’ for Missing.
choices - String list of the posible choices, or a function which returns a string list of choices. This function will be passed the same values that are passed to autofill function.
symbols - [optional] choices are used for display only and these strings will be used to represent them. The length of this string must match the number of values in th choices list.
{
id: 'choiceId',
label: 'Choice',
type: 'choice',
unsetName: 'Missing Choice',
choices: [ 'choice 1' , 'choice 2','choice 3'],
}
ChoiceText¶
Creates a widget with a text input and predefined choices available from a dropdown menu. An unset value may also be specified to leave the entry as missing.
This differs from the Choices
widget by allowing free form text
input as well as choices that are defined by autofill-like function.
Properties:
value - enum
unsetName - When set this provides an option for an ‘unsetName’ for Missing.
choices - String list of the posible choices, or a function which returns a string list of choices. This function will be passed the same values that are passed to autofill function.
{
id: 'transcriptName',
label: 'Reported Transcript',
type: 'choiceText',
unsetName: 'Not Reported',
choices: function(project, input, variant, thisForm) {
return _.chain(variant).get('transcript_2').pluck('TranscriptName').value();
},
autoFill: function(project, input, variant) {
var clinicallyRelevant = _.chain(variant)
.get('transcript')
.get('TranscriptNameClinicallyRelevant')
.value();
return clinicallyRelevant.length > 0 ? clinicallyRelevant[0] : '';
}
}
Integer Edit¶
This widget allows for free form entry of integers within a specified minimum and max value.
Properties:
value : integer
placeholder : text placed in the line edit when empty
min - minimum value allowed
max - maximum value allowed
step - (int) change made to the value with the up and down arrow keys
completions - if specified this must be a list of values, or a function which return a list of value. The list of values are then used to populate the autocompleter. If a function is specified it will be called each time that the value of the widget changes. The arguments passed to the function are the same as the arguments that are passed to the autofill function with the addition of the current widget value, which is passes as the last argument.
{
id: 'intId',
label: 'Input an Integer',
type: 'int',
placeholder: 'enter and int value',
min: 0,
max: 10,
step: 2
}
Real Edit¶
This widget allows for free form entry of real values within a specified minimum and max value.
Properties:
value : double
placeholder : text placed in the line edit when empty
min - minimum value allowed
max - maximum value allowed
step - (double) change made to the value with the up and down arrow keys
completions - if specified this must be a list of values, or a function which return a list of value. The list of values are then used to populate the autocompleter. If a function is specified it will be called each time that the value of the widget changes. The arguments passed to the function are the same as the arguments that are passed to the autofill function with the addition of the current widget value, which is passes as the last argument.
{
id: 'realId',
label: 'Insert a Real Value',
type: 'real',
placeholder: 'enter a real value',
min: 0,
max: 10,
step: 0.5
}
Static Text¶
This provides a text value which can be specified with the ‘default’ parameter, or read in dynamically with the autofill parameter.
Properties:
value : string value
staticValue: string in the label for the value
{
id: 'staticTextId',
label: 'Static Text',
type: 'staticText',
default: 'Static text value'
}
File Select¶
This widget allows you to select an image to include in the report.
Properties:
value : byte array
width : target width in pixels
height : target height in pixels
{
id: 'fileSelectId',
label: 'File Select',
type:'filePath',
width: 300,
height: 400
}
Date Time Edit¶
The date time widget can be used to specify when an event occurred. The format for the value in this field can be specified with the following symbols.
Format:
d |
the numeric day |
dd |
the numeric day with a leading zero |
ddd |
the abbreviated day name |
dddd |
the full day name |
M |
the numeric month |
MM |
the numeric month with a leading zero |
MMM |
the abbreviated month name |
MMMM |
the full month name |
yy |
the last two digits of the year |
yyyy |
the full numeric year |
Properties:
value: (int) unix epoch time in ms
format: datetime format string
{
id: 'dateTimeEditId',
label: 'Date Time',
type: 'dateTimeEdit',
format: 'YYYYMMDD',
showPopup: true
}
Note the autoFill function for this widget expects the returned date to be in the msec since Unix epoch format in local time zone. It is suggested to simply return the toTime() value from a JavaScript “Date” object. For example:
{
id: 'dob',
label: 'Date of Birth',
doc: 'Enter patient birthday',
type: 'dateTimeEdit',
autoFill: function(project, input, thisForm) {
// Assuming DOB field as added to the sample on import in form YYYY-MM-DD
var date = project.samples.Current.entity.DOB;
var b = date.split(/\D/);
return (new Date(b[0], b[1]-1, b[2])).getTime();
}
}
Sign Off¶
The signoff provides the first and last name of the user who clicks the signoff button in VarSeq. If the report is not signed off the value returned by this widget will be an empty list.
Properties:
value : list of values if singed off [ first name, last name, signoff date (unix epoch time in ms)
{ id: 'signOffId', type: 'signOff', label: 'Sign Off' }
The Render Function¶
The render function of VarSeq is given the current project data, input context, report parameters, and the template text and is expected to return the rendered report as the returned string value.
var render = function(templateText, // form.templateText()
params, // form.getParamsData()
project, // form.getProjectData()
input // form.getInputData()
) {
// take the values from the layout widgets and map them
// back to the layout widgets
var labeledInput = templateUtils.labelInput(layout, input);
// combine the labeled inputs with the values loaded from
// the report's param file
var ctx = _.extend(labeledInput, params);
// Join the project state data with the layout widget data
ctx = preprocessContext(ctx, project);
// Process the form data with the project data to set the values
// used in the report template
var records = _.get(input,
'variants.records',
[]).concat(_.get(input, 'incidental.records'));
var variantList = _.get(ctx, 'variants', []);
ctx.references = templateUtils.getReferences(records, project.variants);
ctx.variantsByGene = groupVariantsByGene(variantList);
ctx.geneSummary = createGeneSummary(params, project, input);
ctx.reportName = project.samples.Current.entity.Name + " Report";
// Load the template into handlebars
var template = Handlebars.compile(templateText, {noEscape: true});
// render the report, and return the completed html
return template(ctx);
};
The render function is located in the report.js
file. It can be
replaced with a custom render function or adjusted to meet the required
output.
Example: Adding a Data Field to a Report¶
To illustrate how templates are organized, let’s walk through a complete example where a field is added to the report input form and the data is used in the final report.
First, we need to add a widget to the input form. We can do this by modifying
the layout
variable in report.js
.
Let’s make a widget for an alphanumeric lab id. We’ll assume that this
id will be defined in a TSV file used during the import process. We’ll
place this widget in a lab reference section. To accomplish this we’ll
insert following object in the layout
array. Its position in the
array defines its position in the VarSeq form.
{
id: 'labRef',
label: 'Laboratory Reference Information',
context: 'sample',
items: [
{
id: 'labId',
type: 'shortText',
label: 'Identification Number',
doc: 'Internal Reference Number',
required: true,
autoFill: function(project, input) { return _.get(project,
'samples.Current.importedId', '');
}
}
]
}
One thing to note is how the autoFill function is written. In order to
be robust to different project setups, it is good practice to use
lodash’s get
function which tolerates null references and return a
default value rather than throwing a runtime error. In this case, our
default value is simply the empty string.
When developing more complex autoFill
functions it can be useful to
execute them from the developer console. To do so enter layout
into the console and you’ll see the layout object that you defined in
your report.js
file. Find the autoFill
property on the layout
item of interest and call it with the correct arguments. In our
example I can call:
layout[3].items[0].autoFill(form.getProjectData(), form.getInputData());
The function will return whatever the function will fill into the input text box.
After adding this to our layout array, we now need to reload the report form by clicking on the Gear icon and selecting Reload Report Template. You should now see a new widget in your layout. Type something in the box and open a developer console via the Gear Menu. Expand the console by clicking on the button on the lower left. In the console type:
> form.getInputData().labRef.labId
You should see the text you just typed into the box in VarSeq. In fact all the
input values are returned by the getInputData()
function on the
form
object. Try typing:
> form.getInputData()
In the console you’ll see an navigable object containing your input
values. Similarly, you can inspect the values in the template
configuration dialog with the function getParamsData()
and project
specific data including annotations on the current variants with
getProjectData()
.
So the next task is to get our labId
into our template. To pass
this value to the template, we bind it to the context which in turn is
passed to the compiled template. For more information on how this
process works refer to the Handlebars documentation.
To bind the value to the context, navigate to the render
function. After the line:
var ctx = _.extend(labeledInput, params);
Add:
ctx.labId = _.get(input, 'labRef.labId', '');
This line assigns the output of lodash’s get
function to the
property labId
on the ctx
object. For more information on this
function see the lodash documentation.
Now when the ctx
object is passed as an argument to the compiled
template in the line:
return template(ctx);
the labId
property can be used in the template.
Finally, we need to edit the actual template file to use this new
property. Open the template.tpl
file that exists next to
report.js
. You’ll notice this file contains what looks like HTML
with a lot of curly braces. These curly braces allow us to access the
properties on the ctx
object passed to the template.
Let’s add the lab id to the existing references information. Navigate to the section that looks like:
Modify it so it looks like:
Now save the file, return to VarSeq, reload the template via the Gear Menu. Make sure to enter some text in the “Identification Number:” form widget and press the Play button to generate the template. You should see the text that you entered in the form as the last item in the Reference Information section in the generate report.
You may have noticed that many of the items in the template take the
form of {{foo.bar.data}}
and {{foo.bar.label}}
. This format
comes from the automatic labeling that we do in the render
function when we call templateUtils.labelInput
. What this utility
function does is use the labels we created in the layout
variable
for the data in input
. This provides for consistent labeling
between our form and template. It is entirely optional, but it is good
to note that we could have used the line:
and generated the same output. This especially useful when we have
many items in a section and want to add them to the template without
writing all the HTML by hand. We could use the eachInMap
custom
Handlebars helper that is in the report.js
function. Using this
syntax we can write:
This snippet will iterate over all the values in the labRef object
that was bound to the context. For each property in the the object, the
eachInMap
helper will place the property name in the dt
tag
and value for the property in the dd
tag. This is purely for
convenience and is not necessary for simple template modification.
You have now seen how data flows through the report template
system. This template system is pure JavaScript and users
can access and modify data anyway prior to sending it off
to the template. We encourage users to get familiar with the objects
passed to the render function (templateText
, params
, project
, and
input
). These variables can be accessed in the developer console by
using the functions templateText
, getParamsData
,
getProjectData
, and getInputData
on the form object. Accessing
the data contained in these objects is at the core of the report
building process. After you find the information you need, just build
up a context with that data and pass it to your template.
Example: Selecting a Variant Transcript¶
To illustrate how the choices
and autoFill
functions work lets
create an example which allows users to select from the list of
transcripts for a selected variant.
To make the transcripts available for the variants in the project we
will make RefSeq Genes
a required annotation. To do this add
transcript to the requiredSources
variable in the report.
var requiredSources = ["transcript"];
This will prompt the user with a red warning triangle if they add the report to a project that hasn’t already been annotated with the gene transcript algorithm.
Once the variants have been annotated with the gene transcripts the variants as they are passed into the form will have properties for each of the three field groups that are added when the gene annotation is performed:
transcript
- RefSeq Genes 105 Interim v1, NCBItranscript_2
- Transcript Interactions RefSeq Genes 105 Interim v1, NCBItranscript_3
- Aux Fields RefSeq Genes 105 Interim v1, NCBI
We can examine one of these the value of one of the variants by adding
a variant to the report record set, and opening the “Developer
JavaScript Console” for the report. Next get the project variants by
calling the form.getProjectData()
function. This will output an
object which when expanded will look like the following:

As you can see, in this project there are two variants in the
projectData. The variant with the key of 4
is expanded. In this
variant object’s attributes we can see there is a property for each of
the fields added by the gene annotation (transcript
, transcript_2
,
transcript_3
). By expanding these properties we can see the values
of the fields in each of these source groups.
Here we can see that variant 4
has four different transcripts
represented by the four objects in the transcript_2
list. The first
transcript in this example is shown expaned above with a HGVS.c
notation of NM_001281493.1:c.2532+14A>T.
In this example we are going to use the HGVSc
field values to
identify the different transcripts. The user will select the
transcript from from a choice widget. We will then update other
widgets in the form based on the users selection.
The first step will be to create the choice widget which allows
the user to select the transcript. We add this to the variant
section of the layout
to create a transcript selector for each of
the variants that is added to the report, and add a choices
function to populate the widget with the HGVS.c values for the current
variant.
{
id: 'variants',
label: 'Genetic Variants',
context: 'variant',
items: [
{
id: 'transcript_choice',
label: 'HGVS.c',
type: 'choice',
choices: function(project, input, variant){
return _.chain(variant).get('transcript_2').pluck('HGVSc').value();
},
required: true,
doc: "The HGVS.c notation of the selected transcript"
},
Next we will create the several label widgets to display information about the users transcript selection.
{
id: 'dist_of_tx',
label: 'Dist of Tx',
type: 'label',
autoFill: function(project, input, variant, formState) {
// lookup the current selection of the 'transcript_choice' widget
var hgvsc = formState['transcript_choice'];
// using the selected hgvs.c notionation find the transcript object
// that was selected in this form's variant
var transcript_2 = _.chain(variant).get('transcript_2');
var selected_tx = transcript_2.find({'HGVSc' : hgvsc}).value();
//return the DistofTx of selected value for the current selected value
return selected_tx['DistofTx'];
}
},
{
id: 'ontology',
label: 'Ontology',
type: 'label',
autoFill: function(project, input, variant, formState) {
var hgvsc = formState['transcript_choice'];
var transcript_2 = _.chain(variant).get('transcript_2');
var selected_tx = transcript_2.find({'HGVSc' : hgvsc}).value();
return selected_tx['SequenceOntology'];
}
},
In each of the above widgets the autofill function is used to set the
state of the label widget based on state of the
transcript_choice
widget. The HGVS.c notation selected in the
HGVS.c choices widget is stored in the formState
. Each widget
following the HGVS.c choices widget can look up the current
selected value and use it to set it’s state in it’s autofill
function.

This will create a form with three widgets for each of the variants selected. Each form will have three widgets an HGVS.c widget, a Dist of Tx, and an Ontology widget, which are updated depending on the selected transcript.