Skip to content

Commit

Permalink
Merge pull request #108 from veg/develop
Browse files Browse the repository at this point in the history
hiv-trace fixes
  • Loading branch information
stevenweaver authored Feb 9, 2018
2 parents 43d7335 + a93680f commit d7e30ce
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 22 deletions.
13 changes: 12 additions & 1 deletion app/models/hivtrace.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ var HivTrace = new Schema({
validate: [notEmptyValidator, "Ambiguity Handling field is empty"]
},
sequence_length: Number,
job_started : { type: Boolean, default:false },
status_stack: Array,
status: {
type: String
Expand Down Expand Up @@ -274,6 +275,7 @@ HivTrace.virtual("url").get(function() {
});

HivTrace.methods.saveAttributes = function(cb) {

var self = this;

// Once annotations are configured, save the mapped attributes so that we
Expand All @@ -288,16 +290,19 @@ HivTrace.methods.saveAttributes = function(cb) {
});

var patient_attributes = _.map(headers, function(d) {

var attrs = d.split(delimiter);
var key_val = _.object(annotations, attrs);
key_val["header"] = d;
return key_val;

});

// save attributes for each patient
self.patient_attributes = patient_attributes;

cb(null, self);

};

HivTrace.methods.addAttributesToResults = function(cb) {
Expand All @@ -306,6 +311,12 @@ HivTrace.methods.addAttributesToResults = function(cb) {
var attributes = self.patient_attributes;
var attr_keys = _.keys(attributes[0]);

var category_map = {
"categorical" : "String",
"individual" : "String",
"temporal" : "Date"
};

// transform attributes to be a dictionary
var attrs_by_id = _.object(
_.map(attributes, function(item) {
Expand All @@ -319,7 +330,7 @@ HivTrace.methods.addAttributesToResults = function(cb) {
return d.annotation;
}),
_.map(self.attributes, function(val, key) {
new_dict = { type: val.category, label: val.annotation };
new_dict = { type: category_map[val.category], label: val.annotation };
return new_dict;
})
);
Expand Down
12 changes: 10 additions & 2 deletions app/routes/hivtrace.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ exports.jobPage = function(req, res) {
if (err || !hivtrace) {
res.json(500, error.errorResponse("hivtrace : " + id + " : missing id"));
} else {
if (hivtrace.status === undefined) {

if (!hivtrace.job_started) {

var callback = function(err) {
if (err) {
logger.error(err);
Expand All @@ -237,7 +239,12 @@ exports.jobPage = function(req, res) {
}
};

HivTrace.submitJob(hivtrace, callback);
hivtrace.job_started=true;

hivtrace.save((err, hivtrace) => {
HivTrace.submitJob(hivtrace, callback);
});

}

res.format({
Expand Down Expand Up @@ -442,6 +449,7 @@ exports.mapAttributes = function(req, res) {
};

exports.saveAttributes = function(req, res) {

var id = req.params.id;
var postdata = req.body;

Expand Down
2 changes: 1 addition & 1 deletion app/templates/hivtrace/jobpage.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@


<div class="container">
<h1 class="page-header">HIV TRACE</h1>
<h1 class="page-header">HIV-TRACE</h1>
<div id="hiv-cluster-report" data-hivtraceid="<%= hivtrace._id %>">

<% if (hivtrace.status == 'aborted') { %>
Expand Down
53 changes: 35 additions & 18 deletions app/templates/hivtrace/results.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@
<i class = "fa fa-search" ></i>
</span>
<input type="text" class="form-control" placeholder="Text in attributes" id='network_ui_bar_filter' />
<span class="input-group-addon">
Hide others <input type = 'checkbox' id = 'network_ui_bar_hide_filter'> </input>
</span>
<span class="input-group-addon">
Show small clusters <input type = 'checkbox' id = 'network_ui_bar_show_small_clusters'> </input>
</span>
<span class="input-group-addon">
<i class = "fa fa-question" id = "network_ui_search_help"></i>
</span>
Expand All @@ -68,9 +74,8 @@
</div>

<!-- Legend SVG -->
<div class = "row" id= "network_ui_bar_legend" style = "margin-top : 0.25em">
<div class="alert alert-info alert-dismissible" role="alert"">
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<div class = "row collapse" id= "network_ui_bar_legend" style = "margin-top : 0.1em">
<div class="well">
<span class="label label-primary">Clusters</span> are shown as circles with thick rims
<svg width = "20" height = "20" style = "vertical-align: bottom; display: inline">
<circle cx = "10" cy = "10" r = "7" class = 'cluster'> </circle>
Expand All @@ -81,29 +86,42 @@
rendering options), with thin rims <svg width = "20" height = "20" style = "vertical-align: bottom; display: inline">
<circle cx = "10" cy = "10" r = "7" class = 'node'> </circle>
</svg>, and <em>area</em> scaling with the number of links.
<p/>
Type in text to search for clusters and nodes whose <em>attributes contain the term</em>. <br/>
For example, typing in <code>MSM</code> will highlight nodes and/or clusters that
have 'MSM' in any of the data fields. <br/>
Type in space separated terms (<code>MSM IDU</code>) to search for <b>either</b> term. <br/>
Type in terms in quotes (<code>\"male\"</code>) will search for this <b>exact</b> term. <br/>
Type in <code>&lt;0.01</code> to search for nodes that have edges which are 0.01 (1%) or shorter. Any positive threshold works <br/>
<p/>
Matching node <svg width = '20' height = '20' style = 'vertical-align: bottom; display: inline'><circle cx = '10' cy = '10' r = '7' class = 'node selected_object'> </circle></svg><br/>
Cluster where 25% of nodes match the term <svg width = '28' height = '28' style = 'vertical-align: bottom; display: inline'><circle cx = '14' cy = '14' r = '8' class = 'cluster'> </circle>
<path d = 'M 2 14 A 12 12 0 0 1 14 2'/ style = 'fill: none; stroke: #337AB7; stroke-width: 3px;'>
</svg><br/>
Cluster where 75% of nodes match the term <svg width = '28' height = '28' style = 'vertical-align: bottom; display: inline'><circle cx = '14' cy = '14' r = '8' class = 'cluster'> </circle>
<path d = 'M 2 14 A 12 12 0 1 1 14 26'/ style = 'fill: none; stroke: #337AB7; stroke-width: 3px;'>
</svg>
<p/>

Use the <code>Hide others</code> checkbox to automatically hide all clusters/nodes that do not match the search terms
<br/>
Use the <code>Show small clusters</code> checkbox to display small clusters that may have been hidden for clarity

</div>
</div>

<!-- Main SVG -->
<div id='network_tag'>
<div class="my_progress">
<div class="progress-bar progress-bar-striped disabled" role="progressbar" aria-valuenow="100"
aria-valuemin="0" aria-valuemax="100" style="width: 100%">
aria-valuemin="0" aria-valuemax="100" style="width: 100%; height: 50px">
Loading the network
</div>
</div>

</div>
</div>
</div>
<div class="row">
<div class='col-lg-9'>
<p id='network_status_string' class='text-info'></p>
</div>
</div>
</div>


Expand All @@ -123,10 +141,6 @@
<div class='col-lg-6'>
<p class="lead"> Misc. </p>
<div id='fasta-export' class='row hivtrace-download-button'>
<a download target="_blank" href='<%= hivtrace._id %>/aligned.fasta' class='btn btn-default btn-sm'><span class="fa fa-download"></span> HXB2 Alignment</a>
<a download target="_blank" href='<%= hivtrace._id %>/tn93.csv' class='btn btn-default btn-sm'><span class="fa fa-download"></span> TN93 Distance File</a>
<a download target="_blank" href='<%= hivtrace._id %>/export_network' class='btn btn-default btn-sm'><span class="fa fa-download"></span> Network SVG</a>
<a download target="_blank" href='/images/legends/legend_sex_trans_vl.pdf' class='btn btn-default btn-sm'><span class="fa fa-download"></span> Legend Trans Mode/Viral Load</a>
</div>
</div>

Expand Down Expand Up @@ -212,7 +226,6 @@
</div>

<span class="pull-right" id="cluster-table-export"> </span>
<p class="lead"> Clusters </p>
<table class="table table-striped table-condensed table-hover" id="cluster_table"></table>
</div>
</div>
Expand Down Expand Up @@ -261,6 +274,10 @@
<script src="/assets/js/hivtrace/results.js"></script>
<script>
//render_attribute_modal();
$(document).ready(function() {
render_attribute_modal();
$('.dropdown-toggle').dropdown();
});
</script>
3 changes: 3 additions & 0 deletions public/assets/css/datamonkey.css
Original file line number Diff line number Diff line change
Expand Up @@ -669,3 +669,6 @@ a.hyphy-anchor {
display:none;
}

#cluster_table td:first-child {
min-width:200px;
}
2 changes: 2 additions & 0 deletions src/entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ var branch_selection = require('jsx/branch-selection.jsx');
var stats = require('jsx/stats.jsx');
var analysis_tree = require('jsx/analysis_tree.jsx');
var jobqueue = require('jsx/jobqueue.jsx');
var render_attribute_modal = require('jsx/attribute_table.jsx');

window.gard_form = gard_form;
window.slac_form = slac_form;
Expand All @@ -34,3 +35,4 @@ window.hyphyVision = hyphyVision;
window.datamonkey_stats = stats;
window.datamonkey_analysis_tree = analysis_tree;
window.datamonkey_jobqueue = jobqueue;
window.render_attribute_modal = render_attribute_modal;
106 changes: 106 additions & 0 deletions src/jsx/attribute_table.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
var React = require("react"),
ReactDOM = require("react-dom");

/*
Displays a modal on the HIV-TRACE results page when the user clicks "View" under the Attributes column
The modal displays a table of attributes associated with the node
In order to update the modal, a custom event, "view-attributes", needs to be triggered on the shiv-attribute-modal div.
The object associated with it will be a dictionary with keys and its respective values.
*/
var AttributeModal = React.createClass({

getInitialState: function() {
return { attr : {} };
},

displayModal : function(attributes) {
this.setState( { attr : attributes } );
$('#shiv-attribute-modal').modal();
},

componentDidMount: function() {

var self = this;

// append to passed container
$( "#shiv-attribute-modal" ).on( "view-attributes", function( event, attributes ) {
self.displayModal(attributes);
});

},

attributeRow : function(val) {
return (
<tr>
<td>{val[0]}</td>
<td>{val[1]}</td>
</tr>
);
},

attributeTable : function() {

var self = this;

// filter out _id from attributes
var attr = _.omit(self.state.attr, '_id');

// transform to tuples and sort by key
var attr_tuple = _.sortBy(_.map(attr, function(v,k) { return [k,v]}), function(d) { return d[0] });

var attributeRows = _.map(attr_tuple, self.attributeRow);

return (
<table className="table table-hover table-condensed">
<thead>
<th>Name</th>
<th>Value</th>
</thead>
{attributeRows}
</table>
)

},

render : function() {

var self = this;
var attributeTable = self.attributeTable();

return (

<div role="dialog" id="shiv-attribute-modal" className="modal ng-scope">
<div className="modal-dialog"><div className="modal-content">
<div className="modal-header dialog-header-attribute">
<button data-dismiss="modal" className="close" type="button">×</button>
<h4 className="modal-title">Patient Attributes</h4>
</div>

<div id="modal-attribute-msg" className="modal-body">
{attributeTable}
</div>

<div className="modal-footer">
<button data-dismiss="modal" className="btn btn-warning" type="button">Close</button>
</div>
</div>
</div>
</div>

)

}

});

function render_attribute_modal() {
ReactDOM.render(
<AttributeModal />, document.getElementById("shiv-node-tab-attribute-modal")
);
}


module.exports = render_attribute_modal;

0 comments on commit d7e30ce

Please sign in to comment.