sequenceserver 2.0.0.beta4 → 2.0.0.rc5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.dockerignore +1 -0
- data/.travis.yml +7 -4
- data/AppImage/sequenceserver.sh +5 -0
- data/Dockerfile +14 -12
- data/bin/sequenceserver +37 -28
- data/lib/sequenceserver.rb +35 -7
- data/lib/sequenceserver/blast/job.rb +18 -25
- data/lib/sequenceserver/blast/report.rb +68 -34
- data/lib/sequenceserver/config.rb +1 -1
- data/lib/sequenceserver/database.rb +0 -129
- data/lib/sequenceserver/makeblastdb.rb +243 -0
- data/lib/sequenceserver/routes.rb +28 -2
- data/lib/sequenceserver/version.rb +1 -1
- data/public/SequenceServer_logo.png +0 -0
- data/public/css/grapher.css +8 -15
- data/public/css/sequenceserver.css +119 -55
- data/public/css/sequenceserver.min.css +3 -3
- data/public/js/circos.js +1 -1
- data/public/js/download_fasta.js +17 -0
- data/public/js/grapher.js +7 -9
- data/public/js/hit.js +217 -0
- data/public/js/hits_overview.js +12 -13
- data/public/js/hsp.js +104 -84
- data/public/js/{sequenceserver.js → jquery_world.js} +1 -18
- data/public/js/kablammo.js +337 -334
- data/public/js/length_distribution.js +1 -1
- data/public/js/query.js +147 -0
- data/public/js/report.js +216 -836
- data/public/js/search.js +194 -192
- data/public/js/sequence_modal.js +167 -0
- data/public/js/sidebar.js +210 -0
- data/public/js/utils.js +2 -19
- data/public/js/visualisation_helpers.js +2 -2
- data/public/sequenceserver-report.min.js +19 -19
- data/public/sequenceserver-search.min.js +11 -11
- data/public/vendor/github/twbs/bootstrap@3.3.5/js/bootstrap.js +2 -2
- data/spec/blast_versions/blast_2.2.30/import_spec_capybara_local_2.2.30.rb +15 -15
- data/spec/blast_versions/blast_2.2.31/import_spec_capybara_local_2.2.31.rb +15 -15
- data/spec/blast_versions/blast_2.3.0/import_spec_capybara_local_2.3.0.rb +15 -15
- data/spec/blast_versions/blast_2.4.0/import_spec_capybara_local_2.4.0.rb +15 -15
- data/spec/blast_versions/blast_2.5.0/import_spec_capybara_local_2.5.0.rb +15 -15
- data/spec/blast_versions/blast_2.6.0/import_spec_capybara_local_2.6.0.rb +15 -15
- data/spec/blast_versions/blast_2.7.1/import_spec_capybara_local_2.7.1.rb +15 -15
- data/spec/blast_versions/blast_2.8.1/import_spec_capybara_local_2.8.1.rb +15 -15
- data/spec/blast_versions/blast_2.9.0/import_spec_capybara_local_2.9.0.rb +15 -15
- data/spec/blast_versions/diamond_0.9.24/import_spec_capybara_local_0.9.24.rb +6 -6
- data/spec/capybara_spec.rb +14 -3
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.ndb +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nos +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.not +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.ntf +0 -0
- data/spec/database/sample/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nto +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pdb +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pos +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pot +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.ptf +0 -0
- data/spec/database/sample/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pto +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pdb +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pos +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pot +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.ptf +0 -0
- data/spec/database/sample/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pto +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.ndb +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nos +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.not +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.ntf +0 -0
- data/spec/database/sample/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nto +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhd +8 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhi +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nhr +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nin +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nog +0 -0
- data/spec/database/{sample → v4}/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsd +0 -0
- data/spec/database/{sample → v4}/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsi +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.fasta.nsq +0 -0
- data/spec/database/v4/genome/Solenopsis_invicta/Solenopsis_invicta_gnG_subset.txt +8 -0
- data/spec/database/v4/links.rb +23 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta +6449 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phd +1189 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phi +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.phr +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pin +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.pog +0 -0
- data/spec/database/{sample → v4}/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psd +0 -0
- data/spec/database/{sample → v4}/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psi +0 -0
- data/spec/database/v4/proteins/Solenopsis_invicta/Sinvicta2-2-3.prot.subset.fasta.psq +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phd +9140 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phi +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.phr +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pin +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.pog +0 -0
- data/spec/database/{sample → v4}/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psd +0 -0
- data/spec/database/{sample → v4}/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psi +0 -0
- data/spec/database/v4/proteins/uniprot/2018-04-Swiss-Prot_insecta.fasta.psq +0 -0
- data/spec/database/v4/proteins/uniprot/URL +1 -0
- data/spec/database/v4/si_uniprot_idmap.yml +14180 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta +5486 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhd +473 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhi +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nhr +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nin +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nog +0 -0
- data/spec/database/{sample → v4}/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsd +0 -0
- data/spec/database/{sample → v4}/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsi +0 -0
- data/spec/database/v4/transcripts/Solenopsis_invicta/Sinvicta2-2-3.cdna.subset.fasta.nsq +0 -0
- data/spec/database_spec.rb +0 -76
- data/spec/makeblastdb_spec.rb +121 -0
- data/views/layout.erb +5 -1
- metadata +75 -15
data/public/js/hit.js
ADDED
@@ -0,0 +1,217 @@
|
|
1
|
+
import React from 'react';
|
2
|
+
import _ from 'underscore';
|
3
|
+
|
4
|
+
import HSPOverview from './kablammo';
|
5
|
+
import downloadFASTA from './download_fasta';
|
6
|
+
import AlignmentExporter from './alignment_exporter'; // to download textual alignment
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Component for each hit. Receives props from Report. Has no state.
|
10
|
+
*/
|
11
|
+
export default React.createClass({
|
12
|
+
/**
|
13
|
+
* Returns accession number of the hit sequence.
|
14
|
+
*/
|
15
|
+
accession: function () {
|
16
|
+
return this.props.hit.accession;
|
17
|
+
},
|
18
|
+
|
19
|
+
/**
|
20
|
+
* Returns length of the hit sequence.
|
21
|
+
*/
|
22
|
+
hitLength: function () {
|
23
|
+
return this.props.hit.length;
|
24
|
+
},
|
25
|
+
|
26
|
+
// Internal helpers. //
|
27
|
+
|
28
|
+
/**
|
29
|
+
* Returns id that will be used for the DOM node corresponding to the hit.
|
30
|
+
*/
|
31
|
+
domID: function () {
|
32
|
+
return 'Query_' + this.props.query.number + '_hit_' + this.props.hit.number;
|
33
|
+
},
|
34
|
+
|
35
|
+
databaseIDs: function () {
|
36
|
+
return _.map(this.props.querydb, _.iteratee('id'));
|
37
|
+
},
|
38
|
+
|
39
|
+
showSequenceViewer: function () {
|
40
|
+
this.props.showSequenceModal(this.viewSequenceLink());
|
41
|
+
},
|
42
|
+
|
43
|
+
viewSequenceLink: function () {
|
44
|
+
return encodeURI(`get_sequence/?sequence_ids=${this.accession()}&database_ids=${this.databaseIDs()}`);
|
45
|
+
},
|
46
|
+
|
47
|
+
downloadFASTA: function (event) {
|
48
|
+
var accessions = [this.accession()];
|
49
|
+
downloadFASTA(accessions, this.databaseIDs());
|
50
|
+
},
|
51
|
+
|
52
|
+
// Event-handler for exporting alignments.
|
53
|
+
// Calls relevant method on AlignmentExporter defined in alignment_exporter.js.
|
54
|
+
downloadAlignment: function (event) {
|
55
|
+
var hsps = _.map(this.props.hit.hsps, _.bind(function (hsp) {
|
56
|
+
hsp.query_id = this.props.query.id;
|
57
|
+
hsp.hit_id = this.props.hit.id;
|
58
|
+
return hsp;
|
59
|
+
}, this));
|
60
|
+
|
61
|
+
var aln_exporter = new AlignmentExporter();
|
62
|
+
aln_exporter.export_alignments(hsps, this.props.query.id+'_'+this.props.hit.id);
|
63
|
+
},
|
64
|
+
|
65
|
+
|
66
|
+
// Life cycle methods //
|
67
|
+
|
68
|
+
render: function () {
|
69
|
+
return (
|
70
|
+
<div className="hit" id={this.domID()} data-hit-def={this.props.hit.id}
|
71
|
+
data-hit-len={this.props.hit.length} data-hit-evalue={this.props.hit.evalue}>
|
72
|
+
{ this.headerJSX() } { this.contentJSX() }
|
73
|
+
</div>
|
74
|
+
);
|
75
|
+
},
|
76
|
+
|
77
|
+
// See Query.shouldComponentUpdate. The same applies for hits.
|
78
|
+
shouldComponentUpdate: function () {
|
79
|
+
return !this.props.hit;
|
80
|
+
},
|
81
|
+
|
82
|
+
headerJSX: function () {
|
83
|
+
var meta = `length: ${this.hitLength().toLocaleString()}`;
|
84
|
+
|
85
|
+
if (this.props.showQueryCrumbs && this.props.showHitCrumbs) {
|
86
|
+
// Multiper queries, multiple hits
|
87
|
+
meta = `hit ${this.props.hit.number} of query ${this.props.query.number}, ` + meta;
|
88
|
+
}
|
89
|
+
else if (this.props.showQueryCrumbs && !this.props.showHitCrumbs) {
|
90
|
+
// Multiple queries, single hit
|
91
|
+
meta = `the only hit of query ${this.props.query.number}, ` + meta;
|
92
|
+
}
|
93
|
+
else if (!this.props.showQueryCrumbs && this.props.showHitCrumbs) {
|
94
|
+
// Single query, multiple hits
|
95
|
+
meta = `hit ${this.props.hit.number}, ` + meta;
|
96
|
+
}
|
97
|
+
|
98
|
+
return <div className="section-header">
|
99
|
+
<h4>
|
100
|
+
<i className="fa fa-minus-square-o"></i>
|
101
|
+
<strong>{this.props.hit.id}</strong>
|
102
|
+
{this.props.hit.title}
|
103
|
+
</h4>
|
104
|
+
<span className="label label-reset pos-label">{meta}</span>
|
105
|
+
</div>;
|
106
|
+
},
|
107
|
+
|
108
|
+
contentJSX: function () {
|
109
|
+
return <div className="section-content" data-parent-hit={this.domID()}>
|
110
|
+
{ this.hitLinks() }
|
111
|
+
<HSPOverview key={'kablammo' + this.props.query.id} query={this.props.query}
|
112
|
+
hit={this.props.hit} algorithm={this.props.algorithm}
|
113
|
+
showHSPCrumbs={this.props.hit.hsps.length > 1}
|
114
|
+
collapsed={this.props.veryBig} />
|
115
|
+
</div>;
|
116
|
+
},
|
117
|
+
|
118
|
+
hitLinks: function () {
|
119
|
+
var btns = [];
|
120
|
+
if (!this.props.imported_xml) {
|
121
|
+
btns = btns.concat([
|
122
|
+
this.viewSequenceButton(),
|
123
|
+
this.downloadFASTAButton()
|
124
|
+
]);
|
125
|
+
}
|
126
|
+
btns.push(this.downloadAlignmentButton());
|
127
|
+
|
128
|
+
return (
|
129
|
+
<div className="hit-links">
|
130
|
+
<label>
|
131
|
+
<input type="checkbox" id={this.domID() + '_checkbox'}
|
132
|
+
value={this.accession()} onChange={function () {
|
133
|
+
this.props.selectHit(this.domID() + '_checkbox');
|
134
|
+
}.bind(this)} data-target={'#' + this.domID()}
|
135
|
+
/> Select
|
136
|
+
</label>
|
137
|
+
{
|
138
|
+
btns.map((btn) => {
|
139
|
+
return [<span className="line">|</span>, this.button(btn)];
|
140
|
+
})
|
141
|
+
}
|
142
|
+
{
|
143
|
+
this.props.hit.links.map((link) => {
|
144
|
+
return [<span className="line">|</span>, this.a(link)];
|
145
|
+
})
|
146
|
+
}
|
147
|
+
</div>
|
148
|
+
);
|
149
|
+
},
|
150
|
+
|
151
|
+
// Return JSX for view sequence button.
|
152
|
+
viewSequenceButton: function () {
|
153
|
+
if (this.hitLength() > 10000) {
|
154
|
+
return {
|
155
|
+
text: 'Sequence',
|
156
|
+
icon: 'fa-eye',
|
157
|
+
className: 'view-sequence',
|
158
|
+
title: 'Sequence too long',
|
159
|
+
};
|
160
|
+
}
|
161
|
+
else {
|
162
|
+
return {
|
163
|
+
text: 'Sequence',
|
164
|
+
icon: 'fa-eye',
|
165
|
+
className: 'view-sequence',
|
166
|
+
onClick: () => this.showSequenceViewer()
|
167
|
+
};
|
168
|
+
|
169
|
+
}
|
170
|
+
},
|
171
|
+
|
172
|
+
downloadFASTAButton: function () {
|
173
|
+
return {
|
174
|
+
text: 'FASTA',
|
175
|
+
icon: 'fa-download',
|
176
|
+
className: 'download-fa',
|
177
|
+
onClick: () => this.downloadFASTA()
|
178
|
+
};
|
179
|
+
},
|
180
|
+
|
181
|
+
downloadAlignmentButton: function () {
|
182
|
+
return {
|
183
|
+
text: 'Alignment',
|
184
|
+
icon: 'fa-download',
|
185
|
+
className: 'download-aln',
|
186
|
+
onClick: () => this.downloadAlignment()
|
187
|
+
};
|
188
|
+
},
|
189
|
+
|
190
|
+
button: function ({text, icon, title, className, onClick}) {
|
191
|
+
if (onClick) {
|
192
|
+
return <button className={`btn-link ${className}`}
|
193
|
+
title={title} onClick={onClick}><i className={`fa ${icon}`}></i> {text}
|
194
|
+
</button>;
|
195
|
+
}
|
196
|
+
else {
|
197
|
+
return <button className="btn-link view-sequence disabled"
|
198
|
+
title={title} disabled="true">
|
199
|
+
<i className={`fa ${icon}`}></i> {text}
|
200
|
+
</button>;
|
201
|
+
}
|
202
|
+
},
|
203
|
+
|
204
|
+
/**
|
205
|
+
* Render URL for sequence-viewer.
|
206
|
+
*/
|
207
|
+
a: function (link) {
|
208
|
+
if (!link.title || !link.url) return;
|
209
|
+
|
210
|
+
let className = 'btn btn-link';
|
211
|
+
if (link.class) className = `${className} ${link.class}`;
|
212
|
+
return <a href={link.url} className={className} target='_blank'>
|
213
|
+
{link.icon && <i className={'fa ' + link.icon}></i>}
|
214
|
+
{' ' + link.title + ' '}
|
215
|
+
</a>;
|
216
|
+
}
|
217
|
+
});
|
data/public/js/hits_overview.js
CHANGED
@@ -166,10 +166,10 @@ class Graph {
|
|
166
166
|
drawLegend(svg, options, width, height, hits) {
|
167
167
|
var svg_legend = svg.append('g')
|
168
168
|
.attr('transform',
|
169
|
-
'translate(0,' + (height - 1.
|
169
|
+
'translate(0,' + (height - 1.75 * options.margin) + ')');
|
170
170
|
|
171
171
|
svg_legend.append('rect')
|
172
|
-
.attr('x', 7 * (width - 2 * options.margin) / 10)
|
172
|
+
.attr('x', 7.5 * (width - 2 * options.margin) / 10)
|
173
173
|
.attr('width', 2 * (width - 4 * options.margin) / 10)
|
174
174
|
.attr('height', options.legend)
|
175
175
|
.attr('fill', 'url(#legend-grad)');
|
@@ -177,7 +177,7 @@ class Graph {
|
|
177
177
|
svg_legend.append('text')
|
178
178
|
.attr('class',' legend-text')
|
179
179
|
.attr('transform', 'translate(0, ' +options.legend +')')
|
180
|
-
.attr('x',
|
180
|
+
.attr('x', 9.5 * (width - 2 * options.margin) / 10 + options.margin / 2)
|
181
181
|
.text('Weaker hits');
|
182
182
|
// .text(function() {
|
183
183
|
// return Helpers.prettify_evalue(hits[hits.length-1].hitEvalue);
|
@@ -186,7 +186,7 @@ class Graph {
|
|
186
186
|
svg_legend.append('text')
|
187
187
|
.attr('class',' legend-text')
|
188
188
|
.attr('transform', 'translate(0, ' + options.legend + ')')
|
189
|
-
.attr('x',
|
189
|
+
.attr('x', 6.7 * (width - 2 * options.margin) / 10 - options.margin / 2)
|
190
190
|
.text('Stronger hits');
|
191
191
|
// .text(function () {
|
192
192
|
// return Helpers.prettify_evalue(hits[0].hitEvalue);
|
@@ -196,9 +196,9 @@ class Graph {
|
|
196
196
|
.attr('id', 'legend-grad')
|
197
197
|
.selectAll('stop')
|
198
198
|
.data([
|
199
|
-
{offset: '0%', color: '#
|
200
|
-
{offset: '
|
201
|
-
{offset: '100%', color: '#
|
199
|
+
{offset: '0%', color: '#000'},
|
200
|
+
{offset: '45%', color: '#c74f14'},
|
201
|
+
{offset: '100%', color: '#f6bea2'}
|
202
202
|
])
|
203
203
|
.enter()
|
204
204
|
.append('stop')
|
@@ -216,7 +216,7 @@ class Graph {
|
|
216
216
|
* margin: Margin around the svg element.
|
217
217
|
*/
|
218
218
|
var defaults = {
|
219
|
-
barHeight:
|
219
|
+
barHeight: 4,
|
220
220
|
legend: inhits.length > 1 ? 3 : 0,
|
221
221
|
margin: 20
|
222
222
|
},
|
@@ -237,7 +237,8 @@ class Graph {
|
|
237
237
|
|
238
238
|
var width = $graphDiv.width();
|
239
239
|
var height = hits.length * (options.barHeight) +
|
240
|
-
|
240
|
+
2 * options.legend + 4 * options.margin;
|
241
|
+
|
241
242
|
// var height = $graphDiv.height();
|
242
243
|
|
243
244
|
var SEQ_TYPES = {
|
@@ -310,7 +311,7 @@ class Graph {
|
|
310
311
|
return d.hitEvalue;
|
311
312
|
}))
|
312
313
|
])
|
313
|
-
.range([
|
314
|
+
.range([0,0.8]);
|
314
315
|
|
315
316
|
svg.append('g')
|
316
317
|
.attr('class', 'ghit')
|
@@ -330,9 +331,7 @@ class Graph {
|
|
330
331
|
// Drawing the HSPs connector line using the same
|
331
332
|
// color as that of the hit track (using lookahead).
|
332
333
|
var yHspline = y(d.hitId) + options.barHeight / 2;
|
333
|
-
var hsplineColor = d3.
|
334
|
-
gradScale(v.hspEvalue),
|
335
|
-
gradScale(v.hspEvalue));
|
334
|
+
var hsplineColor = d3.hsl(20, 0.82, gradScale(v.hspEvalue));
|
336
335
|
|
337
336
|
if (j+1 < d.length) {
|
338
337
|
if (d[j].hspEnd <= d[j+1].hspStart) {
|
data/public/js/hsp.js
CHANGED
@@ -17,16 +17,22 @@ export default class HSP extends React.Component {
|
|
17
17
|
}
|
18
18
|
|
19
19
|
domID() {
|
20
|
-
return
|
21
|
-
this.props.
|
20
|
+
return 'Query_' + this.props.query.number + '_hit_' +
|
21
|
+
this.props.hit.number + '_' + this.props.hsp.number;
|
22
|
+
}
|
23
|
+
|
24
|
+
hitDOM_ID() {
|
25
|
+
return 'Query_' + this.props.query.number + '_hit_' + this.props.hit.number;
|
22
26
|
}
|
23
27
|
|
24
28
|
// Renders pretty formatted alignment.
|
25
29
|
render () {
|
26
30
|
return (
|
27
|
-
<div className="hsp" id={this.domID()} ref="hsp"
|
31
|
+
<div className="hsp" id={this.domID()} ref="hsp"
|
32
|
+
data-parent-hit={this.hitDOM_ID()}>
|
28
33
|
<pre className="pre-reset hsp-stats">
|
29
|
-
{Helpers.toLetters(this.hsp.number)
|
34
|
+
{this.props.showHSPNumbers && `${Helpers.toLetters(this.hsp.number)}. `}
|
35
|
+
{this.hspStats().map((s, i) => <span key={i}>{s}</span>)}
|
30
36
|
</pre>
|
31
37
|
{this.hspLines()}
|
32
38
|
</div>
|
@@ -39,11 +45,17 @@ export default class HSP extends React.Component {
|
|
39
45
|
}
|
40
46
|
|
41
47
|
draw () {
|
42
|
-
var
|
43
|
-
|
48
|
+
var charWidth = this.props.getCharacterWidth();
|
49
|
+
var containerWidth = $(React.findDOMNode(this.refs.hsp)).width();
|
50
|
+
this.chars = Math.floor((containerWidth - 4) / charWidth);
|
44
51
|
this.forceUpdate();
|
45
52
|
}
|
46
53
|
|
54
|
+
// See Query.shouldComponentUpdate. The same applies for hsp.
|
55
|
+
shouldComponentUpdate () {
|
56
|
+
return !this.props.hsp;
|
57
|
+
}
|
58
|
+
|
47
59
|
/**
|
48
60
|
* Returns an array of span elements or plain strings (React automatically
|
49
61
|
* adds span tag around strings). This array is passed as it is to JSX to be
|
@@ -60,17 +72,17 @@ export default class HSP extends React.Component {
|
|
60
72
|
line.push(`Score: ${Utils.inTwoDecimal(this.hsp.bit_score)} (${this.hsp.score}), `);
|
61
73
|
|
62
74
|
// E value
|
63
|
-
line.push(
|
75
|
+
line.push('E value: '); line.push(Utils.inExponential(this.hsp.evalue)); line.push(', ');
|
64
76
|
|
65
77
|
// Identity
|
66
|
-
line.push([`
|
78
|
+
line.push([`Identity: ${Utils.inFraction(this.hsp.identity, this.hsp.length)} (${Utils.inPercentage(this.hsp.identity, this.hsp.length)}), `]);
|
67
79
|
|
68
80
|
// Positives (for protein alignment).
|
69
81
|
if (this.props.algorithm === 'blastp' ||
|
70
82
|
this.props.algorithm === 'blastx' ||
|
71
83
|
this.props.algorithm === 'tblastn' ||
|
72
84
|
this.props.algorithm === 'tblastx') {
|
73
|
-
line.push(`Positives: ${Utils.inFraction(this.hsp.positives, this.hsp.length)} (${Utils.inPercentage(this.hsp.positives, this.hsp.length)}), `)
|
85
|
+
line.push(`Positives: ${Utils.inFraction(this.hsp.positives, this.hsp.length)} (${Utils.inPercentage(this.hsp.positives, this.hsp.length)}), `);
|
74
86
|
}
|
75
87
|
|
76
88
|
// Gaps
|
@@ -80,23 +92,27 @@ export default class HSP extends React.Component {
|
|
80
92
|
//line.push(`Query coverage: ${this.hsp.qcovhsp}%, `)
|
81
93
|
|
82
94
|
switch (this.props.algorithm) {
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
+
case 'tblastx':
|
96
|
+
line.push(`, Frame: ${Utils.inFraction(this.hsp.qframe, this.hsp.sframe)}`);
|
97
|
+
break;
|
98
|
+
case 'blastn':
|
99
|
+
line.push(`, Strand: ${(this.hsp.qframe > 0 ? '+' : '-')} / ${(this.hsp.sframe > 0 ? '+' : '-')}`);
|
100
|
+
break;
|
101
|
+
case 'blastx':
|
102
|
+
line.push(`, Query Frame: ${this.hsp.qframe}`);
|
103
|
+
break;
|
104
|
+
case 'tblastn':
|
105
|
+
line.push(`, Hit Frame: ${this.hsp.sframe}`);
|
106
|
+
break;
|
95
107
|
}
|
96
108
|
|
97
109
|
return line;
|
98
110
|
}
|
99
111
|
|
112
|
+
/**
|
113
|
+
* Returns array of pre tags containing the three query, middle, and subject
|
114
|
+
* lines that together comprise one 'rendered line' of HSP.
|
115
|
+
*/
|
100
116
|
hspLines () {
|
101
117
|
// Space reserved for showing coordinates
|
102
118
|
var width = this.width();
|
@@ -115,7 +131,6 @@ export default class HSP extends React.Component {
|
|
115
131
|
var nqseq = this.nqseq();
|
116
132
|
var nsseq = this.nsseq();
|
117
133
|
for (let i = 1; i <= lines; i++) {
|
118
|
-
let line = [];
|
119
134
|
let seq_start_index = chars * (i - 1);
|
120
135
|
let seq_stop_index = seq_start_index + chars;
|
121
136
|
|
@@ -133,32 +148,37 @@ export default class HSP extends React.Component {
|
|
133
148
|
this.sframe_unit() * this.sframe_sign();
|
134
149
|
nsseq = lsend + this.sframe_unit() * this.sframe_sign();
|
135
150
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
151
|
+
pp.push(
|
152
|
+
<pre key={this.hsp.number + ',' + i} className="pre-reset hsp-lines">
|
153
|
+
<span className="hsp-coords">
|
154
|
+
{`Query ${this.formatCoords(lqstart, width)} `}
|
155
|
+
</span>
|
156
|
+
<span>{lqseq}</span>
|
157
|
+
<span className="hsp-coords">{` ${lqend}`}</span>
|
158
|
+
<br/>
|
159
|
+
<span className="hsp-coords">
|
160
|
+
{`${this.formatCoords('', width + 8)} `}
|
161
|
+
</span>
|
162
|
+
<span>{lmseq}</span>
|
163
|
+
<br/>
|
164
|
+
<span className="hsp-coords">
|
165
|
+
{`Subject ${this.formatCoords(lsstart, width)} `}
|
166
|
+
</span>
|
167
|
+
<span>{lsseq}</span>
|
168
|
+
<span className="hsp-coords">{` ${lsend}`}</span>
|
169
|
+
<br/>
|
170
|
+
</pre>);
|
152
171
|
}
|
153
172
|
|
154
173
|
return pp;
|
155
174
|
}
|
156
175
|
|
157
|
-
// Width of
|
158
|
-
|
176
|
+
// Width of the coordinate part of hsp lines. Essentially the length of
|
177
|
+
// the largest coordinate.
|
178
|
+
width () {
|
159
179
|
return _.max(_.map([this.hsp.qstart, this.hsp.qend,
|
160
|
-
|
161
|
-
|
180
|
+
this.hsp.sstart, this.hsp.send],
|
181
|
+
(n) => { return n.toString().length; }));
|
162
182
|
}
|
163
183
|
|
164
184
|
// Alignment start coordinate for query sequence.
|
@@ -167,16 +187,16 @@ export default class HSP extends React.Component {
|
|
167
187
|
// (translated) query sequence aligned.
|
168
188
|
nqseq () {
|
169
189
|
switch (this.props.algorithm) {
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
190
|
+
case 'blastp':
|
191
|
+
case 'blastx':
|
192
|
+
case 'tblastn':
|
193
|
+
case 'tblastx':
|
194
|
+
return this.hsp.qframe >= 0 ? this.hsp.qstart : this.hsp.qend;
|
195
|
+
case 'blastn':
|
196
|
+
// BLASTN is a bit weird in that, no matter which direction the query
|
197
|
+
// sequence aligned in, qstart is taken as alignment start coordinate
|
198
|
+
// for query.
|
199
|
+
return this.hsp.qstart;
|
180
200
|
}
|
181
201
|
}
|
182
202
|
|
@@ -186,16 +206,16 @@ export default class HSP extends React.Component {
|
|
186
206
|
// (translated) subject sequence aligned.
|
187
207
|
nsseq () {
|
188
208
|
switch (this.props.algorithm) {
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
209
|
+
case 'blastp':
|
210
|
+
case 'blastx':
|
211
|
+
case 'tblastn':
|
212
|
+
case 'tblastx':
|
213
|
+
return this.hsp.sframe >= 0 ? this.hsp.sstart : this.hsp.send;
|
214
|
+
case 'blastn':
|
215
|
+
// BLASTN is a bit weird in that, no matter which direction the
|
216
|
+
// subject sequence aligned in, sstart is taken as alignment
|
217
|
+
// start coordinate for subject.
|
218
|
+
return this.hsp.sstart;
|
199
219
|
}
|
200
220
|
}
|
201
221
|
|
@@ -209,16 +229,16 @@ export default class HSP extends React.Component {
|
|
209
229
|
// translated or not.
|
210
230
|
qframe_unit () {
|
211
231
|
switch (this.props.algorithm) {
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
232
|
+
case 'blastp':
|
233
|
+
case 'blastn':
|
234
|
+
case 'tblastn':
|
235
|
+
return 1;
|
236
|
+
case 'blastx':
|
237
|
+
// _Translated_ nucleotide query against protein database.
|
238
|
+
case 'tblastx':
|
239
|
+
// _Translated_ nucleotide query against translated
|
240
|
+
// nucleotide database.
|
241
|
+
return 3;
|
222
242
|
}
|
223
243
|
}
|
224
244
|
|
@@ -232,17 +252,17 @@ export default class HSP extends React.Component {
|
|
232
252
|
// translated or not.
|
233
253
|
sframe_unit () {
|
234
254
|
switch (this.props.algorithm) {
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
255
|
+
case 'blastp':
|
256
|
+
case 'blastx':
|
257
|
+
case 'blastn':
|
258
|
+
return 1;
|
259
|
+
case 'tblastn':
|
260
|
+
// Protein query against _translated_ nucleotide database.
|
261
|
+
return 3;
|
262
|
+
case 'tblastx':
|
263
|
+
// Translated nucleotide query against _translated_
|
264
|
+
// nucleotide database.
|
265
|
+
return 3;
|
246
266
|
}
|
247
267
|
}
|
248
268
|
|
@@ -283,7 +303,7 @@ export default class HSP extends React.Component {
|
|
283
303
|
}
|
284
304
|
|
285
305
|
spanCoords (text) {
|
286
|
-
return <span className="hsp-coords">{text}</span
|
306
|
+
return <span className="hsp-coords">{text}</span>;
|
287
307
|
}
|
288
308
|
}
|
289
309
|
|