sequenceserver 2.0.0.beta3 → 2.0.0.beta4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.eslintrc.json +36 -0
- data/.rubocop.yml +1 -1
- data/.travis.yml +53 -20
- data/AppImage/recipe.yml +15 -0
- data/AppImage/sequenceserver.desktop +8 -0
- data/AppImage/sequenceserver.png +0 -0
- data/AppImage/sequenceserver.sh +11 -0
- data/README.md +79 -46
- data/bin/sequenceserver +4 -4
- data/lib/sequenceserver/version.rb +1 -1
- data/package.json +2 -0
- data/public/css/grapher.css +3 -0
- data/public/css/sequenceserver.css +17 -6
- data/public/css/sequenceserver.min.css +3 -3
- data/public/js/circos.js +515 -491
- data/public/js/grapher.js +12 -6
- data/public/js/hits_overview.js +321 -308
- data/public/js/hsp.js +12 -7
- data/public/js/length_distribution.js +241 -234
- data/public/js/report.js +196 -174
- data/public/js/search.js +3 -3
- data/public/js/sequenceserver.js +9 -9
- data/public/js/utils.js +17 -10
- data/public/js/visualisation_helpers.js +77 -77
- data/public/sequenceserver-report.min.js +17 -17
- data/public/sequenceserver-search.min.js +1 -1
- data/public/vendor/github/nicgirault/circosJs@1.7.0/dist/circosJS.js +1 -5
- data/sequenceserver.gemspec +1 -2
- data/spec/blast_versions/blast_2.2.30/blast_2.2.30_spec.rb +13 -13
- data/spec/blast_versions/blast_2.2.30/import_spec_capybara_local_2.2.30.rb +555 -25
- data/spec/blast_versions/blast_2.2.31/blast_2.2.31_spec.rb +13 -13
- data/spec/blast_versions/blast_2.2.31/import_spec_capybara_local_2.2.31.rb +558 -24
- data/spec/blast_versions/blast_2.3.0/blast_2.3.0_spec.rb +13 -13
- data/spec/blast_versions/blast_2.3.0/import_spec_capybara_local_2.3.0.rb +561 -26
- data/spec/blast_versions/blast_2.4.0/blast_2.4.0_spec.rb +13 -13
- data/spec/blast_versions/blast_2.4.0/import_spec_capybara_local_2.4.0.rb +561 -25
- data/spec/blast_versions/blast_2.5.0/blast_2.5.0_spec.rb +13 -13
- data/spec/blast_versions/blast_2.5.0/import_spec_capybara_local_2.5.0.rb +558 -24
- data/spec/blast_versions/blast_2.6.0/blast_2.6.0_spec.rb +13 -13
- data/spec/blast_versions/blast_2.6.0/import_spec_capybara_local_2.6.0.rb +559 -24
- data/spec/blast_versions/blast_2.7.1/blast_2.7.1_spec.rb +13 -13
- data/spec/blast_versions/blast_2.7.1/import_spec_capybara_local_2.7.1.rb +559 -28
- data/spec/blast_versions/blast_2.8.1/blast_2.8.1_spec.rb +13 -13
- data/spec/blast_versions/blast_2.8.1/import_spec_capybara_local_2.8.1.rb +559 -27
- data/spec/blast_versions/blast_2.9.0/blast_2.9.0_spec.rb +13 -13
- data/spec/blast_versions/blast_2.9.0/import_spec_capybara_local_2.9.0.rb +557 -25
- data/spec/blast_versions/diamond_0.9.24/diamond_0.9.24_spec.rb +13 -13
- data/spec/blast_versions/diamond_0.9.24/import_spec_capybara_local_0.9.24.rb +219 -21
- data/spec/capybara_spec.rb +25 -28
- data/spec/download_helper.rb +6 -3
- data/spec/sequences/MH011443_1_gi_1486783306_gb_MH011443_1.txt +6 -0
- data/spec/sequences/MH011443_1_gi_1486783307_gb_AYF55702_1.txt +6 -0
- data/spec/sequences/MH011443_1_gi_1528997474_gb_MH447967_1.txt +30 -0
- data/spec/sequences/MH011443_1_sp_P04637_P53_HUMAN.txt +6 -0
- data/spec/sequences/alignment-35_hits_diamond_blastp.txt +210 -0
- data/spec/sequences/alignment-35_hits_diamond_blastx.txt +210 -0
- data/spec/sequences/alignment-3_hits.txt +18 -0
- data/spec/sequences/alignment-40_hits_blastn.txt +246 -0
- data/spec/sequences/alignment-40_hits_blastp.txt +240 -0
- data/spec/sequences/alignment-40_hits_blastp_2.2.30.txt +240 -0
- data/spec/sequences/alignment-40_hits_blastx.txt +240 -0
- data/spec/sequences/alignment-40_hits_tblastn.txt +240 -0
- data/spec/sequences/alignment-40_hits_tblastn_2.2.30.txt +240 -0
- data/spec/sequences/alignment-40_hits_tblastx.txt +2664 -0
- data/spec/sequences/alignment-4_hits.txt +24 -0
- data/spec/sequences/alignment-4_hits_blastn.txt +24 -0
- data/spec/sequences/alignment-4_hits_blastp.txt +24 -0
- data/spec/sequences/alignment-4_hits_blastp_2.2.30.txt +24 -0
- data/spec/sequences/alignment-4_hits_blastx.txt +24 -0
- data/spec/sequences/alignment-4_hits_diamond_blastp.txt +24 -0
- data/spec/sequences/alignment-4_hits_diamond_blastx.txt +24 -0
- data/spec/sequences/alignment-4_hits_tblastn.txt +24 -0
- data/spec/sequences/alignment-4_hits_tblastn_2.2.30.txt +24 -0
- data/spec/sequences/alignment-4_hits_tblastx.txt +318 -0
- data/spec/sequences/sp_P04637_P53_HUMAN_gi_1099170394_ref_XP_018868681_1.txt +6 -0
- data/spec/sequences/sp_P04637_P53_HUMAN_gi_120407068_ref_NP_000537_3.txt +6 -0
- data/spec/sequences/sp_P04637_P53_HUMAN_gi_1484127324_gb_MG595988_1.txt +6 -0
- data/spec/sequences/sp_P04637_P53_HUMAN_gi_395440626_gb_JQ694049_1.txt +6 -0
- data/spec/sequences/sp_P04637_P53_HUMAN_sp_P04637_P53_HUMAN.txt +6 -0
- data/spec/spec_helper.rb +3 -3
- metadata +67 -57
- data/.eslintrc +0 -213
- data/Rakefile +0 -8
- data/spec/dotdir/blast_2.4.0/blastn/TBLASTN_XML_2.4.0.xml +0 -1181
- data/spec/dotdir/blast_2.5.0/blastn/BLASTN_LONG_XML_2.5.0.xml +0 -18813
- data/spec/import_spec_capybara_local.rb +0 -61
data/public/js/grapher.js
CHANGED
|
@@ -3,8 +3,15 @@ import React from 'react';
|
|
|
3
3
|
|
|
4
4
|
import './svgExporter'; // create handlers for SVG and PNG download buttons
|
|
5
5
|
|
|
6
|
+
// Each instance of Grapher is added to this object once the component has been
|
|
7
|
+
// mounted. This is so that grapher can be iterated over and redrawn on window
|
|
8
|
+
// resize event.
|
|
6
9
|
var Graphers = {};
|
|
7
10
|
|
|
11
|
+
// Grapher is a function that takes a Graph class and returns a React component.
|
|
12
|
+
// This React component provides HTML boilerplate to add heading, to make the
|
|
13
|
+
// graphs collapsible, to redraw graphs when window is resized, and SVG and PNG
|
|
14
|
+
// export buttons and functionality.
|
|
8
15
|
export default function Grapher(Graph) {
|
|
9
16
|
|
|
10
17
|
return class extends React.Component {
|
|
@@ -23,7 +30,7 @@ export default function Grapher(Graph) {
|
|
|
23
30
|
<div ref="grapher" className={cssClasses}>
|
|
24
31
|
<div className="grapher-header">
|
|
25
32
|
<h5 className="caption" data-toggle="collapse"
|
|
26
|
-
data-target={
|
|
33
|
+
data-target={'#'+this.collapseId()}>
|
|
27
34
|
{ this.state.collapsed ?
|
|
28
35
|
this.plusIcon() : this.minusIcon() }
|
|
29
36
|
|
|
@@ -66,8 +73,7 @@ export default function Grapher(Graph) {
|
|
|
66
73
|
var cssClasses = Graph.className() + ' svg-container collapse';
|
|
67
74
|
if (!this.state.collapsed) cssClasses += ' in';
|
|
68
75
|
return (
|
|
69
|
-
<div ref="svgContainer" id={this.collapseId()}
|
|
70
|
-
className={cssClasses}>
|
|
76
|
+
<div ref="svgContainer" id={this.collapseId()} className={cssClasses}>
|
|
71
77
|
</div>
|
|
72
78
|
);
|
|
73
79
|
}
|
|
@@ -95,7 +101,7 @@ export default function Grapher(Graph) {
|
|
|
95
101
|
this.graph = null;
|
|
96
102
|
|
|
97
103
|
// Draw if uncollapsed.
|
|
98
|
-
if (this.state.collapsed) { return }
|
|
104
|
+
if (this.state.collapsed) { return; }
|
|
99
105
|
this.graph = new Graph(this.svgContainer(), this.props);
|
|
100
106
|
this.svgContainer().find('svg').attr('data-name', Graph.dataName(this.props));
|
|
101
107
|
}
|
|
@@ -110,13 +116,13 @@ $(window).resize(_.debounce(function () {
|
|
|
110
116
|
}, 125));
|
|
111
117
|
|
|
112
118
|
// Swap-icon and toggle .graph-links on collapse.
|
|
113
|
-
$('body').on('hidden.bs.collapse',
|
|
119
|
+
$('body').on('hidden.bs.collapse', '.collapse', function () {
|
|
114
120
|
var component = Graphers[$(this).attr('id')];
|
|
115
121
|
if (component) {
|
|
116
122
|
component.setState({ collapsed: true });
|
|
117
123
|
}
|
|
118
124
|
});
|
|
119
|
-
$('body').on('shown.bs.collapse',
|
|
125
|
+
$('body').on('shown.bs.collapse', '.collapse', function () {
|
|
120
126
|
var component = Graphers[$(this).attr('id')];
|
|
121
127
|
if (component) {
|
|
122
128
|
component.setState({ collapsed: false });
|
data/public/js/hits_overview.js
CHANGED
|
@@ -2,360 +2,373 @@ import d3 from 'd3';
|
|
|
2
2
|
import _ from 'underscore';
|
|
3
3
|
import Grapher from './grapher';
|
|
4
4
|
import * as Helpers from './visualisation_helpers';
|
|
5
|
+
import Utils from './utils';
|
|
5
6
|
|
|
6
7
|
class Graph {
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
static className() {
|
|
13
|
-
return 'alignment-overview';
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static collapseId(props) {
|
|
17
|
-
return 'alignment_'+props.query.number;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
static dataName(props) {
|
|
21
|
-
return 'Alignment-Overview-'+props.query.id;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
constructor($svgContainer, props) {
|
|
25
|
-
this.svg_container = $svgContainer;
|
|
26
|
-
$queryDiv = $svgContainer.parents('.resultn');
|
|
27
|
-
hits = this.extractData(props.query.hits, props.query.number);
|
|
28
|
-
this.graphIt($queryDiv, $svgContainer, 0, 20, null, hits);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
extractData(query_hits, number) {
|
|
32
|
-
var hits = [];
|
|
33
|
-
query_hits.map(function (hit) {
|
|
34
|
-
var _hsps = [];
|
|
35
|
-
var hsps = hit.hsps;
|
|
36
|
-
_.each(hsps, function (hsp) {
|
|
37
|
-
var _hsp = {};
|
|
38
|
-
_hsp.hspEvalue = hsp.evalue;
|
|
39
|
-
_hsp.hspStart = hsp.qstart;
|
|
40
|
-
_hsp.hspEnd = hsp.qend;
|
|
41
|
-
_hsp.hspFrame = hsp.sframe;
|
|
42
|
-
_hsp.hspId = "Query_"+number+"_hit_"+hit.number+"_hsp_"+hsp.number;
|
|
43
|
-
_hsps.push(_hsp);
|
|
44
|
-
});
|
|
45
|
-
_hsps.hitId = hit.id;
|
|
46
|
-
_hsps.hitDef = "Query_"+number+"_hit_"+hit.number;
|
|
47
|
-
_hsps.hitEvalue = hit.evalue;
|
|
48
|
-
hits.push(_hsps);
|
|
49
|
-
});
|
|
50
|
-
return hits;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
setupTooltip() {
|
|
54
|
-
this.svg_container.find('[data-toggle="tooltip"]').tooltip({
|
|
55
|
-
'placement': 'top', 'container': 'body', 'html': 'true',
|
|
56
|
-
'delay': 0, 'white-space': 'nowrap'
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
setupClick($graphDiv) {
|
|
61
|
-
$('a', $graphDiv).click(function (evt) {
|
|
62
|
-
evt.preventDefault();
|
|
63
|
-
evt.stopPropagation();
|
|
64
|
-
window.location.hash = $(this).attr('href');
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
graphControls($queryDiv, $graphDiv, isInit, opts, hits) {
|
|
69
|
-
var MIN_HITS_TO_SHOW = 20;
|
|
70
|
-
|
|
71
|
-
var totalHits, shownHits, lessButton, moreButton;
|
|
72
|
-
|
|
73
|
-
var countHits = function () {
|
|
74
|
-
totalHits = hits.length;
|
|
75
|
-
shownHits = $queryDiv.find('.ghit > g').length;
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
var setupButtons = function($queryDiv, $graphDiv) {
|
|
79
|
-
$graphDiv
|
|
80
|
-
.append(
|
|
81
|
-
$('<button/>')
|
|
82
|
-
.addClass('btn btn-link more')
|
|
83
|
-
.attr('type', 'button')
|
|
84
|
-
.attr('data-parent-query', $queryDiv.attr('id'))
|
|
85
|
-
.html('View More ')
|
|
86
|
-
.append(
|
|
87
|
-
$('<i/>')
|
|
88
|
-
.html(' ')
|
|
89
|
-
.addClass('fa fa-angle-double-down')
|
|
90
|
-
),
|
|
91
|
-
$('<button/>')
|
|
92
|
-
.addClass('btn btn-link less')
|
|
93
|
-
.attr('type', 'button')
|
|
94
|
-
.attr('data-parent-query', $queryDiv.attr('id'))
|
|
95
|
-
.html('View Less ')
|
|
96
|
-
.append(
|
|
97
|
-
$('<i/>')
|
|
98
|
-
.html(' ')
|
|
99
|
-
.addClass('fa fa-angle-double-up')
|
|
100
|
-
)
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
lessButton = $('.less', $graphDiv);
|
|
104
|
-
moreButton = $('.more', $graphDiv);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
var initButtons = function () {
|
|
108
|
-
countHits();
|
|
109
|
-
if (totalHits === MIN_HITS_TO_SHOW ||
|
|
110
|
-
shownHits < MIN_HITS_TO_SHOW) {
|
|
111
|
-
lessButton.hide();
|
|
112
|
-
moreButton.hide();
|
|
113
|
-
}
|
|
114
|
-
else if (shownHits === totalHits) {
|
|
115
|
-
moreButton.hide();
|
|
116
|
-
lessButton.show();
|
|
117
|
-
}
|
|
118
|
-
else if (shownHits === MIN_HITS_TO_SHOW) {
|
|
119
|
-
lessButton.hide();
|
|
120
|
-
moreButton.show();
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
lessButton.show();
|
|
124
|
-
moreButton.show();
|
|
125
|
-
}
|
|
126
|
-
};
|
|
9
|
+
static name() {
|
|
10
|
+
return 'Graphical overview of hits';
|
|
11
|
+
}
|
|
127
12
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
setupButtons($queryDiv, $graphDiv);
|
|
131
|
-
initButtons();
|
|
13
|
+
static className() {
|
|
14
|
+
return 'alignment-overview';
|
|
132
15
|
}
|
|
133
16
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
initButtons();
|
|
138
|
-
this.setupTooltip();
|
|
139
|
-
e.stopPropagation();
|
|
140
|
-
},this));
|
|
17
|
+
static collapseId(props) {
|
|
18
|
+
return 'alignment_'+props.query.number;
|
|
19
|
+
}
|
|
141
20
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
21
|
+
static dataName(props) {
|
|
22
|
+
return 'Alignment-Overview-'+props.query.id;
|
|
23
|
+
}
|
|
145
24
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
25
|
+
constructor($svgContainer, props) {
|
|
26
|
+
this.svg_container = $svgContainer;
|
|
27
|
+
$queryDiv = $svgContainer.parents('.resultn');
|
|
28
|
+
hits = this.extractData(props.query.hits, props.query.number);
|
|
29
|
+
this.graphIt($queryDiv, $svgContainer, 0, 20, null, hits);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
extractData(query_hits, number) {
|
|
33
|
+
var hits = [];
|
|
34
|
+
query_hits.map(function (hit) {
|
|
35
|
+
var _hsps = [];
|
|
36
|
+
var hsps = hit.hsps;
|
|
37
|
+
_.each(hsps, function (hsp) {
|
|
38
|
+
var _hsp = {};
|
|
39
|
+
_hsp.hspEvalue = hsp.evalue;
|
|
40
|
+
_hsp.hspStart = hsp.qstart;
|
|
41
|
+
_hsp.hspEnd = hsp.qend;
|
|
42
|
+
_hsp.hspFrame = hsp.sframe;
|
|
43
|
+
_hsp.hspId = 'Query_' + number + '_hit_' + hit.number + '_hsp_' + hsp.number;
|
|
44
|
+
_hsp.hspIdentity = hsp.identity;
|
|
45
|
+
_hsp.hspGaps = hsp.gaps;
|
|
46
|
+
_hsp.hspPositives = hsp.positives;
|
|
47
|
+
_hsp.hspLength = hsp.length;
|
|
48
|
+
_hsps.push(_hsp);
|
|
49
|
+
});
|
|
50
|
+
_hsps.hitId = hit.id;
|
|
51
|
+
_hsps.hitDef = 'Query_'+number+'_hit_'+hit.number;
|
|
52
|
+
_hsps.hitEvalue = hit.evalue;
|
|
53
|
+
hits.push(_hsps);
|
|
54
|
+
});
|
|
55
|
+
return hits;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setupTooltip() {
|
|
59
|
+
this.svg_container.find('[data-toggle="tooltip"]').tooltip({
|
|
60
|
+
'placement': 'top', 'container': 'body', 'html': 'true',
|
|
61
|
+
'delay': 0, 'white-space': 'nowrap'
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
setupClick($graphDiv) {
|
|
66
|
+
$('a', $graphDiv).click(function (evt) {
|
|
67
|
+
evt.preventDefault();
|
|
68
|
+
evt.stopPropagation();
|
|
69
|
+
window.location.hash = $(this).attr('href');
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
graphControls($queryDiv, $graphDiv, isInit, opts, hits) {
|
|
74
|
+
var MIN_HITS_TO_SHOW = 20;
|
|
75
|
+
|
|
76
|
+
var totalHits, shownHits, lessButton, moreButton;
|
|
77
|
+
|
|
78
|
+
var countHits = function () {
|
|
79
|
+
totalHits = hits.length;
|
|
80
|
+
shownHits = $queryDiv.find('.ghit > g').length;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
var setupButtons = function($queryDiv, $graphDiv) {
|
|
84
|
+
$graphDiv
|
|
85
|
+
.append(
|
|
86
|
+
$('<button/>')
|
|
87
|
+
.addClass('btn btn-link more')
|
|
88
|
+
.attr('type', 'button')
|
|
89
|
+
.attr('data-parent-query', $queryDiv.attr('id'))
|
|
90
|
+
.html('View More ')
|
|
91
|
+
.append(
|
|
92
|
+
$('<i/>')
|
|
93
|
+
.html(' ')
|
|
94
|
+
.addClass('fa fa-angle-double-down')
|
|
95
|
+
),
|
|
96
|
+
$('<button/>')
|
|
97
|
+
.addClass('btn btn-link less')
|
|
98
|
+
.attr('type', 'button')
|
|
99
|
+
.attr('data-parent-query', $queryDiv.attr('id'))
|
|
100
|
+
.html('View Less ')
|
|
101
|
+
.append(
|
|
102
|
+
$('<i/>')
|
|
103
|
+
.html(' ')
|
|
104
|
+
.addClass('fa fa-angle-double-up')
|
|
105
|
+
)
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
lessButton = $('.less', $graphDiv);
|
|
109
|
+
moreButton = $('.more', $graphDiv);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
var initButtons = function () {
|
|
113
|
+
countHits();
|
|
114
|
+
if (totalHits === MIN_HITS_TO_SHOW ||
|
|
115
|
+
shownHits < MIN_HITS_TO_SHOW) {
|
|
116
|
+
lessButton.hide();
|
|
117
|
+
moreButton.hide();
|
|
118
|
+
}
|
|
119
|
+
else if (shownHits === totalHits) {
|
|
120
|
+
moreButton.hide();
|
|
121
|
+
lessButton.show();
|
|
122
|
+
}
|
|
123
|
+
else if (shownHits === MIN_HITS_TO_SHOW) {
|
|
124
|
+
lessButton.hide();
|
|
125
|
+
moreButton.show();
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
lessButton.show();
|
|
129
|
+
moreButton.show();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
// Setup view buttons' state properly if called for first time.
|
|
134
|
+
if (isInit === true) {
|
|
135
|
+
setupButtons($queryDiv, $graphDiv);
|
|
149
136
|
initButtons();
|
|
150
137
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
138
|
+
|
|
139
|
+
moreButton.on('click', _.bind(function (e) {
|
|
140
|
+
countHits();
|
|
141
|
+
this.graphIt($queryDiv, $graphDiv, shownHits, MIN_HITS_TO_SHOW, opts, hits);
|
|
154
142
|
initButtons();
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
143
|
+
this.setupTooltip();
|
|
144
|
+
e.stopPropagation();
|
|
145
|
+
},this));
|
|
146
|
+
|
|
147
|
+
lessButton.on('click', _.bind(function (e) {
|
|
148
|
+
countHits();
|
|
149
|
+
var diff = shownHits - MIN_HITS_TO_SHOW;
|
|
150
|
+
|
|
151
|
+
// Decrease number of shown hits by defined constant.
|
|
152
|
+
if (diff >= MIN_HITS_TO_SHOW) {
|
|
153
|
+
this.graphIt($queryDiv, $graphDiv, shownHits, -MIN_HITS_TO_SHOW, opts, hits);
|
|
154
|
+
initButtons();
|
|
155
|
+
}
|
|
156
|
+
else if (diff !== 0) {
|
|
157
|
+
// Ensure a certain number of hits always stay in graph.
|
|
158
|
+
this.graphIt($queryDiv, $graphDiv, shownHits, MIN_HITS_TO_SHOW - shownHits, opts, hits);
|
|
159
|
+
initButtons();
|
|
160
|
+
}
|
|
161
|
+
this.setupTooltip();
|
|
162
|
+
e.stopPropagation();
|
|
163
|
+
},this));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
drawLegend(svg, options, width, height, hits) {
|
|
167
|
+
var svg_legend = svg.append('g')
|
|
168
|
+
.attr('transform',
|
|
169
|
+
'translate(0,' + (height - 1.88 * options.margin) + ')');
|
|
170
|
+
|
|
171
|
+
svg_legend.append('rect')
|
|
172
|
+
.attr('x', 7 * (width - 2 * options.margin) / 10)
|
|
173
|
+
.attr('width', 2 * (width - 4 * options.margin) / 10)
|
|
174
|
+
.attr('height', options.legend)
|
|
175
|
+
.attr('fill', 'url(#legend-grad)');
|
|
176
|
+
|
|
177
|
+
svg_legend.append('text')
|
|
178
|
+
.attr('class',' legend-text')
|
|
179
|
+
.attr('transform', 'translate(0, ' +options.legend +')')
|
|
180
|
+
.attr('x', 6 * (width - 2 * options.margin) / 10 - options.margin / 2)
|
|
181
|
+
.text('Weaker hits');
|
|
177
182
|
// .text(function() {
|
|
178
183
|
// return Helpers.prettify_evalue(hits[hits.length-1].hitEvalue);
|
|
179
184
|
// })
|
|
180
185
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
svg_legend.append('text')
|
|
187
|
+
.attr('class',' legend-text')
|
|
188
|
+
.attr('transform', 'translate(0, ' + options.legend + ')')
|
|
189
|
+
.attr('x', 9 * (width - 2 * options.margin) / 10 + options.margin / 2)
|
|
190
|
+
.text('Stronger hits');
|
|
186
191
|
// .text(function () {
|
|
187
192
|
// return Helpers.prettify_evalue(hits[0].hitEvalue);
|
|
188
193
|
// })
|
|
189
194
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
195
|
+
svg.append('linearGradient')
|
|
196
|
+
.attr('id', 'legend-grad')
|
|
197
|
+
.selectAll('stop')
|
|
198
|
+
.data([
|
|
199
|
+
{offset: '0%', color: '#ccc'},
|
|
200
|
+
{offset: '50%', color: '#888'},
|
|
201
|
+
{offset: '100%', color: '#000'}
|
|
202
|
+
])
|
|
203
|
+
.enter()
|
|
204
|
+
.append('stop')
|
|
205
|
+
.attr('offset', function (d) {
|
|
206
|
+
return d.offset;
|
|
207
|
+
})
|
|
208
|
+
.attr('stop-color', function (d) {
|
|
209
|
+
return d.color;
|
|
210
|
+
});
|
|
211
|
+
}
|
|
207
212
|
|
|
208
|
-
|
|
213
|
+
graphIt($queryDiv, $graphDiv, index, howMany, opts, inhits) {
|
|
209
214
|
/* barHeight: Height of each hit track.
|
|
210
215
|
* legend: Height reserved for the overview legend.
|
|
211
216
|
* margin: Margin around the svg element.
|
|
212
217
|
*/
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
218
|
+
var defaults = {
|
|
219
|
+
barHeight: 3,
|
|
220
|
+
legend: inhits.length > 1 ? 3 : 0,
|
|
221
|
+
margin: 20
|
|
222
|
+
},
|
|
223
|
+
options = $.extend(defaults, opts);
|
|
219
224
|
var hits = inhits.slice(0 , index + howMany);
|
|
220
225
|
|
|
221
|
-
|
|
222
|
-
|
|
226
|
+
// Don't draw anything when no hits are obtained.
|
|
227
|
+
if (hits.length < 1) return false;
|
|
223
228
|
|
|
224
|
-
|
|
229
|
+
if (index !== 0) {
|
|
225
230
|
// Currently, we have no good way to extend pre-existing graph
|
|
226
231
|
// and hence, are removing the old one and redrawing.
|
|
227
|
-
|
|
228
|
-
|
|
232
|
+
$graphDiv.find('svg').remove();
|
|
233
|
+
}
|
|
229
234
|
|
|
230
|
-
|
|
231
|
-
|
|
235
|
+
var queryLen = $queryDiv.data().queryLen;
|
|
236
|
+
var q_i = $queryDiv.attr('id');
|
|
232
237
|
|
|
233
|
-
|
|
234
|
-
|
|
238
|
+
var width = $graphDiv.width();
|
|
239
|
+
var height = hits.length * (options.barHeight) +
|
|
235
240
|
2 * options.legend + 5 * options.margin;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
241
|
+
// var height = $graphDiv.height();
|
|
242
|
+
|
|
243
|
+
var SEQ_TYPES = {
|
|
244
|
+
blastn: 'nucleic_acid',
|
|
245
|
+
blastp: 'amino_acid',
|
|
246
|
+
blastx: 'nucleic_acid',
|
|
247
|
+
tblastx: 'nucleic_acid',
|
|
248
|
+
tblastn: 'amino_acid'
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
var svg = d3.select($graphDiv[0])
|
|
252
|
+
.selectAll('svg')
|
|
253
|
+
.data([hits])
|
|
254
|
+
.enter()
|
|
255
|
+
.insert('svg', ':first-child')
|
|
251
256
|
.attr('width', width)
|
|
252
257
|
.attr('height', height)
|
|
253
|
-
|
|
258
|
+
.append('g')
|
|
254
259
|
.attr('transform', 'translate(' + options.margin / 2 + ', ' + (1.5 * options.margin) + ')');
|
|
255
260
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
261
|
+
var x = d3.scale
|
|
262
|
+
.linear()
|
|
263
|
+
.range([0, width - options.margin]);
|
|
259
264
|
|
|
260
|
-
|
|
265
|
+
x.domain([1, queryLen]);
|
|
261
266
|
|
|
262
|
-
|
|
263
|
-
|
|
267
|
+
var algorithm = $queryDiv.data().algorithm;
|
|
268
|
+
var formatter = Helpers.tick_formatter(x, SEQ_TYPES[algorithm]);
|
|
264
269
|
|
|
265
|
-
|
|
266
|
-
|
|
270
|
+
var _tValues = x.ticks(11);
|
|
271
|
+
_tValues.pop();
|
|
267
272
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
273
|
+
var xAxis = d3.svg
|
|
274
|
+
.axis()
|
|
275
|
+
.scale(x)
|
|
276
|
+
.orient('top')
|
|
277
|
+
.tickValues(_tValues.concat([1, queryLen]))
|
|
278
|
+
.tickFormat(formatter);
|
|
274
279
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
280
|
+
// Attach the axis to DOM (<svg> element)
|
|
281
|
+
var container = svg.append('g')
|
|
282
|
+
.attr('transform', 'translate(0, ' + options.margin + ')')
|
|
283
|
+
.append('g')
|
|
279
284
|
.attr('class', 'x axis')
|
|
280
285
|
.call(xAxis);
|
|
281
286
|
|
|
282
|
-
|
|
283
|
-
|
|
287
|
+
// Vertical alignment of ticks
|
|
288
|
+
container.selectAll('text')
|
|
284
289
|
.attr('x','25px')
|
|
285
290
|
.attr('y','2px')
|
|
286
291
|
.attr('transform','rotate(-90)');
|
|
287
292
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
293
|
+
var y = d3.scale
|
|
294
|
+
.ordinal()
|
|
295
|
+
.rangeBands([0, height - 3 * options.margin - 2 * options.legend], 0.3);
|
|
291
296
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
297
|
+
y.domain(hits.map(function (d) {
|
|
298
|
+
return d.hitId;
|
|
299
|
+
}));
|
|
295
300
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
301
|
+
var gradScale = d3.scale
|
|
302
|
+
.log()
|
|
303
|
+
.domain([
|
|
304
|
+
d3.min([1e-5, d3.min(hits.map(function (d) {
|
|
305
|
+
if (parseFloat(d.hitEvalue) === 0.0) return undefined;
|
|
306
|
+
return d.hitEvalue;
|
|
307
|
+
}))
|
|
308
|
+
]),
|
|
309
|
+
d3.max(hits.map(function (d) {
|
|
310
|
+
return d.hitEvalue;
|
|
302
311
|
}))
|
|
303
|
-
])
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
.selectAll('.hits')
|
|
314
|
-
.data(hits)
|
|
315
|
-
.enter()
|
|
316
|
-
.append('g')
|
|
312
|
+
])
|
|
313
|
+
.range([40,150]);
|
|
314
|
+
|
|
315
|
+
svg.append('g')
|
|
316
|
+
.attr('class', 'ghit')
|
|
317
|
+
.attr('transform', 'translate(0, ' + 1.65 * (options.margin - options.legend) + ')')
|
|
318
|
+
.selectAll('.hits')
|
|
319
|
+
.data(hits)
|
|
320
|
+
.enter()
|
|
321
|
+
.append('g')
|
|
317
322
|
.each(function (d,i) {
|
|
318
323
|
// TODO: Avoid too many variables and improve naming.
|
|
319
324
|
|
|
320
325
|
d3.select(this)
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
326
|
+
.selectAll('.hsp')
|
|
327
|
+
.data(d).enter()
|
|
328
|
+
.append('a')
|
|
329
|
+
.each(function (v, j) {
|
|
325
330
|
// Drawing the HSPs connector line using the same
|
|
326
331
|
// color as that of the hit track (using lookahead).
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
332
|
+
var yHspline = y(d.hitId) + options.barHeight / 2;
|
|
333
|
+
var hsplineColor = d3.rgb(gradScale(v.hspEvalue),
|
|
334
|
+
gradScale(v.hspEvalue),
|
|
335
|
+
gradScale(v.hspEvalue));
|
|
336
|
+
|
|
337
|
+
if (j+1 < d.length) {
|
|
338
|
+
if (d[j].hspEnd <= d[j+1].hspStart) {
|
|
339
|
+
d3.select(this.parentNode)
|
|
340
|
+
.append('line')
|
|
341
|
+
.attr('x1', x(d[j].hspEnd))
|
|
342
|
+
.attr('y1', yHspline)
|
|
343
|
+
.attr('x2', x(d[j+1].hspStart))
|
|
344
|
+
.attr('y2', yHspline)
|
|
345
|
+
.attr('stroke', hsplineColor);
|
|
346
|
+
}
|
|
347
|
+
else if (d[j].hspStart > d[j+1].hspEnd) {
|
|
348
|
+
d3.select(this.parentNode)
|
|
349
|
+
.append('line')
|
|
350
|
+
.attr('x1', x(d[j+1].hspEnd))
|
|
351
|
+
.attr('y1', yHspline)
|
|
352
|
+
.attr('x2', x(d[j].hspStart))
|
|
353
|
+
.attr('y2', yHspline)
|
|
354
|
+
.attr('stroke', hsplineColor);
|
|
355
|
+
}
|
|
341
356
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
.attr('y2', yHspline)
|
|
349
|
-
.attr('stroke', hsplineColor);
|
|
357
|
+
|
|
358
|
+
var alt_tooltip = d.hitId + '<br>E value: ' + Helpers.prettify_evalue(v.hspEvalue) +
|
|
359
|
+
`<br>Identities: ${Utils.inPercentage(v.hspIdentity, v.hspLength)}`;
|
|
360
|
+
// if chosen algorithm was blastn, the tooltip won't show the Positives% value in the tooltip
|
|
361
|
+
if (algorithm != 'blastn'){
|
|
362
|
+
alt_tooltip += `<br>Positives: ${Utils.inPercentage(v.hspPositives, v.hspLength)}`;
|
|
350
363
|
}
|
|
351
|
-
|
|
364
|
+
alt_tooltip += `, Gaps: ${Utils.inPercentage(v.hspGaps, v.hspLength)}`;
|
|
352
365
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
366
|
+
// Draw the rectangular hit tracks itself.
|
|
367
|
+
d3.select(this)
|
|
368
|
+
.attr('xlink:href', '#' + q_i + '_hit_' + (i+1))
|
|
369
|
+
.append('rect')
|
|
357
370
|
.attr('data-toggle', 'tooltip')
|
|
358
|
-
.attr('title',
|
|
371
|
+
.attr('title', alt_tooltip)
|
|
359
372
|
.attr('class','bar')
|
|
360
373
|
.attr('x', function (d) {
|
|
361
374
|
return x(d.hspStart);
|
|
@@ -366,24 +379,24 @@ class Graph {
|
|
|
366
379
|
})
|
|
367
380
|
.attr('height', options.barHeight)
|
|
368
381
|
.attr('fill', d3.rgb(hsplineColor));
|
|
369
|
-
|
|
382
|
+
});
|
|
370
383
|
});
|
|
371
384
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
385
|
+
// Draw legend only when more than one hit present
|
|
386
|
+
if (hits.length > 1) {
|
|
387
|
+
this.drawLegend(svg, options, width, height, inhits);
|
|
388
|
+
}
|
|
389
|
+
// Bind listener events once all the graphical elements have
|
|
390
|
+
// been drawn for first time.
|
|
391
|
+
if (index === 0) {
|
|
392
|
+
this.graphControls($queryDiv, $graphDiv, true, opts, inhits);
|
|
393
|
+
}
|
|
394
|
+
// Refresh tooltip each time graph is redrawn.
|
|
395
|
+
this.setupTooltip();
|
|
396
|
+
// Ensure clicking on 'rect' takes user to the relevant hit on all
|
|
397
|
+
// browsers.
|
|
398
|
+
this.setupClick($graphDiv);
|
|
380
399
|
}
|
|
381
|
-
// Refresh tooltip each time graph is redrawn.
|
|
382
|
-
this.setupTooltip();
|
|
383
|
-
// Ensure clicking on 'rect' takes user to the relevant hit on all
|
|
384
|
-
// browsers.
|
|
385
|
-
this.setupClick($graphDiv);
|
|
386
|
-
}
|
|
387
400
|
}
|
|
388
401
|
|
|
389
402
|
var HitsOverview = Grapher(Graph);
|