sequenceserver 1.1.0.beta6 → 1.1.0.beta7
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.
Potentially problematic release.
This version of sequenceserver might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/sequenceserver/version.rb +1 -1
- data/public/js/circos.js +4 -4
- data/public/js/{errormodal.js → error_modal.js} +0 -0
- data/public/js/{alignmentsoverview.js → hits_overview.js} +2 -2
- data/public/js/kablammo.js +2 -2
- data/public/js/{lengthdistribution.js → length_distribution.js} +1 -1
- data/public/js/report.js +212 -200
- data/public/sequenceserver-report.min.js +17 -16
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 596bc25ee4cb80b8fad1de7a63b7677f291a0743
|
4
|
+
data.tar.gz: bb5bda8278682fb5a79526542023d3addfce8933
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e71d8f58e66599466f5149043f20e1ab5e1490857a557a71005889fdbd70ac46ac3649b18ff5b04037154f9b49ca98a3f37bbccfcef614786c3fc963222424b5
|
7
|
+
data.tar.gz: faaa045609c7009b1dae99175da8da6adbf8bb7a01439a2f2dbbd21d6a64f353ac76a5fe5c276051d96c7dbf9f9041c2ae2f90355ea002d1c37b112bfa8a772e
|
data/public/js/circos.js
CHANGED
@@ -316,10 +316,10 @@ class Graph {
|
|
316
316
|
.attr('transform','translate('+this.svgContainer.width() / 2+','+this.svgContainer.height()/2+')')
|
317
317
|
.append('text')
|
318
318
|
.attr('text-anchor','start')
|
319
|
-
.attr('dy','0.
|
320
|
-
.attr('x', -
|
321
|
-
.
|
322
|
-
.text('
|
319
|
+
.attr('dy','-0.25em')
|
320
|
+
.attr('x', -175)
|
321
|
+
.style("font-size", "14px")
|
322
|
+
.text('Circos looks great with less than 16 queries')
|
323
323
|
}
|
324
324
|
|
325
325
|
layoutReset() {
|
File without changes
|
data/public/js/kablammo.js
CHANGED
@@ -19,11 +19,11 @@ import * as Helpers from './visualisation_helpers';
|
|
19
19
|
|
20
20
|
class Graph {
|
21
21
|
static name() {
|
22
|
-
return '
|
22
|
+
return 'Matching region(s)';
|
23
23
|
}
|
24
24
|
|
25
25
|
static className() {
|
26
|
-
return 'kablammo
|
26
|
+
return 'kablammo';
|
27
27
|
}
|
28
28
|
|
29
29
|
static collapseId(props) {
|
data/public/js/report.js
CHANGED
@@ -1,18 +1,16 @@
|
|
1
|
-
import
|
2
|
-
import showErrorModal from './errormodal';
|
3
|
-
|
4
|
-
import _ from 'underscore';
|
1
|
+
import './sequenceserver' // for custom $.tooltip function
|
5
2
|
import React from 'react';
|
6
|
-
import
|
3
|
+
import _ from 'underscore';
|
7
4
|
|
8
|
-
import * as Helpers from './visualisation_helpers';
|
9
|
-
import GraphicalOverview from './alignmentsoverview';
|
10
|
-
//import Kablammo from './kablammo';
|
11
|
-
import './sequence';
|
12
|
-
import AlignmentExporter from './alignment_exporter';
|
13
|
-
import LengthDistribution from './lengthdistribution';
|
14
5
|
import Circos from './circos';
|
6
|
+
import HitsOverview from './hits_overview';
|
7
|
+
import LengthDistribution from './length_distribution'; // length distribution of hits
|
8
|
+
import HSPOverview from './kablammo';
|
9
|
+
import AlignmentExporter from './alignment_exporter'; // to download textual alignment
|
10
|
+
import './sequence';
|
15
11
|
|
12
|
+
import * as Helpers from './visualisation_helpers'; // for toLetters
|
13
|
+
import showErrorModal from './error_modal';
|
16
14
|
|
17
15
|
/**
|
18
16
|
* Dynamically create form and submit.
|
@@ -514,9 +512,9 @@ var Hit = React.createClass({
|
|
514
512
|
}, this))
|
515
513
|
}
|
516
514
|
</div>
|
517
|
-
{
|
518
|
-
|
519
|
-
|
515
|
+
<HSPOverview key={"kablammo"+this.props.query.id}
|
516
|
+
query={this.props.query} hit={this.props.hit}
|
517
|
+
algorithm={this.props.algorithm}/>
|
520
518
|
<table
|
521
519
|
className="table hsps">
|
522
520
|
<tbody>
|
@@ -678,7 +676,7 @@ var Query = React.createClass({
|
|
678
676
|
{this.numhits() &&
|
679
677
|
(
|
680
678
|
<div className="section-content">
|
681
|
-
<
|
679
|
+
<HitsOverview key={"GO_"+this.props.query.number} query={this.props.query} program={this.props.data.program} collapsed={this.props.data.veryBig}/>
|
682
680
|
<LengthDistribution key={"LD_"+this.props.query.id} query={this.props.query} algorithm={this.props.data.program} collapsed="true"/>
|
683
681
|
<HitsTable key={"HT_"+this.props.query.number} query={this.props.query}/>
|
684
682
|
<div
|
@@ -921,65 +919,12 @@ var SideBar = React.createClass({
|
|
921
919
|
*/
|
922
920
|
var Report = React.createClass({
|
923
921
|
|
924
|
-
//
|
925
|
-
|
926
|
-
/**
|
927
|
-
* Event-handler when hit is selected
|
928
|
-
* Adds glow to hit component.
|
929
|
-
* Updates number of Fasta that can be downloaded
|
930
|
-
*/
|
931
|
-
selectHit: function (id) {
|
932
|
-
|
933
|
-
var checkbox = $("#" + id);
|
934
|
-
var num_checked = $('.hit-links :checkbox:checked').length;
|
935
|
-
|
936
|
-
if (!checkbox || !checkbox.val()) {
|
937
|
-
return;
|
938
|
-
}
|
939
|
-
|
940
|
-
var $hit = $(checkbox.data('target'));
|
941
|
-
|
942
|
-
// Highlight selected hit and sync checkboxes if sequence viewer is open.
|
943
|
-
if (checkbox.is(":checked")) {
|
944
|
-
$hit
|
945
|
-
.addClass('glow')
|
946
|
-
.find(":checkbox").not(checkbox).check();
|
947
|
-
var $a = $('.download-fasta-of-selected');
|
948
|
-
var $b = $('.download-alignment-of-selected');
|
949
|
-
$b.enable()
|
950
|
-
var $n = $a.find('span');
|
951
|
-
$a
|
952
|
-
.enable()
|
953
|
-
}
|
954
|
-
|
955
|
-
else {
|
956
|
-
$hit
|
957
|
-
.removeClass('glow')
|
958
|
-
.find(":checkbox").not(checkbox).uncheck();
|
959
|
-
}
|
960
|
-
|
961
|
-
if (num_checked >= 1)
|
962
|
-
{
|
963
|
-
var $a = $('.download-fasta-of-selected');
|
964
|
-
var $b = $('.download-alignment-of-selected');
|
965
|
-
$a.find('.text-bold').html(num_checked);
|
966
|
-
$b.find('.text-bold').html(num_checked);
|
967
|
-
}
|
968
|
-
|
969
|
-
if (num_checked == 0) {
|
970
|
-
var $a = $('.download-fasta-of-selected');
|
971
|
-
var $b = $('.download-alignment-of-selected');
|
972
|
-
$a.addClass('disabled').find('.text-bold').html('');
|
973
|
-
$b.addClass('disabled').find('.text-bold').html('');
|
974
|
-
}
|
975
|
-
},
|
976
|
-
|
977
|
-
|
978
|
-
// Internal helpers. //
|
979
|
-
|
980
|
-
// Life-cycle methods. //
|
922
|
+
// Model //
|
981
923
|
|
982
924
|
getInitialState: function () {
|
925
|
+
this.fetchResults();
|
926
|
+
this.updateCycle = 0;
|
927
|
+
|
983
928
|
return {
|
984
929
|
search_id: '',
|
985
930
|
program: '',
|
@@ -991,17 +936,77 @@ var Report = React.createClass({
|
|
991
936
|
};
|
992
937
|
},
|
993
938
|
|
994
|
-
|
995
|
-
|
939
|
+
/**
|
940
|
+
* Fetch results.
|
941
|
+
*/
|
942
|
+
fetchResults: function () {
|
943
|
+
var intervals = [200, 400, 800, 1200, 2000, 3000, 5000];
|
944
|
+
|
945
|
+
(function poll (comp) {
|
946
|
+
$.getJSON(location.pathname + '.json')
|
947
|
+
.complete(function (jqXHR) {
|
948
|
+
switch (jqXHR.status) {
|
949
|
+
case 202:
|
950
|
+
var interval;
|
951
|
+
if (intervals.length === 1) {
|
952
|
+
interval = intervals[0];
|
953
|
+
}
|
954
|
+
else {
|
955
|
+
interval = intervals.shift;
|
956
|
+
}
|
957
|
+
setTimeout(poll, interval);
|
958
|
+
break;
|
959
|
+
case 200:
|
960
|
+
comp.updateState(jqXHR.responseJSON);
|
961
|
+
break;
|
962
|
+
case 404:
|
963
|
+
case 400:
|
964
|
+
case 500:
|
965
|
+
showErrorModal(jqXHR.responseJSON);
|
966
|
+
break;
|
967
|
+
}
|
968
|
+
});
|
969
|
+
}(this));
|
996
970
|
},
|
997
971
|
|
998
972
|
/**
|
999
|
-
*
|
1000
|
-
*
|
1001
|
-
* A holding message is shown till results are fetched.
|
973
|
+
* Incrementally update state so that the rendering process is
|
974
|
+
* not overwhelemed when there are too many queries.
|
1002
975
|
*/
|
1003
|
-
|
1004
|
-
|
976
|
+
updateState: function(responseJSON) {
|
977
|
+
var queries = responseJSON.queries;
|
978
|
+
|
979
|
+
// Render results for first 50 queries and set flag if total queries is
|
980
|
+
// more than 250.
|
981
|
+
var numHits = 0;
|
982
|
+
responseJSON.veryBig = queries.length > 250;
|
983
|
+
//responseJSON.veryBig = !_.every(queries, (query) => {
|
984
|
+
//numHits += query.hits.length;
|
985
|
+
//return (numHits <= 500);
|
986
|
+
//});
|
987
|
+
responseJSON.queries = queries.splice(0, 50);
|
988
|
+
this.setState(responseJSON);
|
989
|
+
|
990
|
+
// Render results for remaining queries.
|
991
|
+
var update = function () {
|
992
|
+
if (queries.length > 0) {
|
993
|
+
this.setState({
|
994
|
+
queries: this.state.queries.concat(queries.splice(0, 50))
|
995
|
+
});
|
996
|
+
setTimeout(update.bind(this), 500);
|
997
|
+
}
|
998
|
+
else {
|
999
|
+
this.componentFinishedUpdating();
|
1000
|
+
}
|
1001
|
+
};
|
1002
|
+
setTimeout(update.bind(this), 500);
|
1003
|
+
},
|
1004
|
+
|
1005
|
+
|
1006
|
+
// View //
|
1007
|
+
render: function () {
|
1008
|
+
return this.isResultAvailable() ?
|
1009
|
+
this.resultsJSX() : this.loadingJSX();
|
1005
1010
|
},
|
1006
1011
|
|
1007
1012
|
/**
|
@@ -1049,9 +1054,11 @@ var Report = React.createClass({
|
|
1049
1054
|
}
|
1050
1055
|
<div className={this.shouldShowSidebar() ?
|
1051
1056
|
'col-md-9' : 'col-md-12'}>
|
1052
|
-
{ this.
|
1053
|
-
|
1054
|
-
|
1057
|
+
{ this.overviewJSX() }
|
1058
|
+
{ this.isHitsAvailable()
|
1059
|
+
? <Circos queries={this.state.queries}
|
1060
|
+
program={this.state.program} collapsed="true"/>
|
1061
|
+
: <span></span> }
|
1055
1062
|
{
|
1056
1063
|
_.map(this.state.queries, _.bind(function (query) {
|
1057
1064
|
return (
|
@@ -1065,31 +1072,10 @@ var Report = React.createClass({
|
|
1065
1072
|
);
|
1066
1073
|
},
|
1067
1074
|
|
1068
|
-
/**
|
1069
|
-
* Returns true if sidebar should be shown.
|
1070
|
-
*
|
1071
|
-
* Sidebar is not shown if there is only one query and there are no hits
|
1072
|
-
* corresponding to the query.
|
1073
|
-
*/
|
1074
|
-
shouldShowSidebar: function () {
|
1075
|
-
return !(this.state.queries.length == 1 &&
|
1076
|
-
this.state.queries[0].hits.length == 0);
|
1077
|
-
},
|
1078
|
-
|
1079
|
-
/**
|
1080
|
-
* Returns true if index should be shown in the sidebar.
|
1081
|
-
*
|
1082
|
-
* Index is not shown in the sidebar if there are more than eight queries
|
1083
|
-
* in total.
|
1084
|
-
*/
|
1085
|
-
shouldShowIndex: function () {
|
1086
|
-
return this.state.queries.length <= 8;
|
1087
|
-
},
|
1088
|
-
|
1089
1075
|
/**
|
1090
1076
|
* Renders report overview.
|
1091
1077
|
*/
|
1092
|
-
|
1078
|
+
overviewJSX: function () {
|
1093
1079
|
return (
|
1094
1080
|
<div
|
1095
1081
|
className="overview">
|
@@ -1104,8 +1090,8 @@ var Report = React.createClass({
|
|
1104
1090
|
}).join(", ")
|
1105
1091
|
}
|
1106
1092
|
<br/>
|
1107
|
-
Total: {this.state.stats.nsequences} sequences,
|
1108
|
-
|
1093
|
+
Total: {this.state.stats.nsequences} sequences,
|
1094
|
+
{this.state.stats.ncharacters} characters
|
1109
1095
|
<br/>
|
1110
1096
|
<br/>
|
1111
1097
|
{
|
@@ -1118,106 +1104,86 @@ var Report = React.createClass({
|
|
1118
1104
|
);
|
1119
1105
|
},
|
1120
1106
|
|
1121
|
-
|
1122
|
-
|
1123
|
-
},
|
1107
|
+
|
1108
|
+
// Controller //
|
1124
1109
|
|
1125
1110
|
/**
|
1126
|
-
*
|
1111
|
+
* Returns true if results have been fetched.
|
1112
|
+
*
|
1113
|
+
* A holding message is shown till results are fetched.
|
1127
1114
|
*/
|
1128
|
-
|
1129
|
-
|
1130
|
-
|
1131
|
-
$.getJSON(location.pathname + '.json')
|
1132
|
-
.complete(_.bind(function (jqXHR) {
|
1133
|
-
switch (jqXHR.status) {
|
1134
|
-
case 202:
|
1135
|
-
var interval;
|
1136
|
-
if (intervals.length === 1) {
|
1137
|
-
interval = intervals[0];
|
1138
|
-
}
|
1139
|
-
else {
|
1140
|
-
interval = intervals.shift;
|
1141
|
-
}
|
1142
|
-
setTimeout(this.fetchResults, interval);
|
1143
|
-
break;
|
1144
|
-
case 200:
|
1145
|
-
this.updatePage(jqXHR.responseJSON);
|
1146
|
-
break;
|
1147
|
-
case 404:
|
1148
|
-
case 400:
|
1149
|
-
case 500:
|
1150
|
-
showErrorModal(jqXHR.responseJSON);
|
1151
|
-
break;
|
1152
|
-
}
|
1153
|
-
}, this));
|
1115
|
+
isResultAvailable: function () {
|
1116
|
+
return this.state.queries.length >= 1;
|
1154
1117
|
},
|
1155
1118
|
|
1156
|
-
|
1157
|
-
var
|
1119
|
+
isHitsAvailable: function () {
|
1120
|
+
var cnt = 0;
|
1121
|
+
_.each(this.state.queries, function (query) {
|
1122
|
+
if(query.hits.length == 0) cnt++;
|
1123
|
+
});
|
1124
|
+
return !(cnt == this.state.queries.length);
|
1125
|
+
},
|
1158
1126
|
|
1159
|
-
|
1160
|
-
|
1161
|
-
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
|
1168
|
-
|
1127
|
+
/**
|
1128
|
+
* Returns true if sidebar should be shown.
|
1129
|
+
*
|
1130
|
+
* Sidebar is not shown if there is only one query and there are no hits
|
1131
|
+
* corresponding to the query.
|
1132
|
+
*/
|
1133
|
+
shouldShowSidebar: function () {
|
1134
|
+
return !(this.state.queries.length == 1 &&
|
1135
|
+
this.state.queries[0].hits.length == 0);
|
1136
|
+
},
|
1169
1137
|
|
1170
|
-
|
1171
|
-
|
1172
|
-
|
1173
|
-
|
1174
|
-
|
1175
|
-
|
1176
|
-
|
1177
|
-
|
1178
|
-
else {
|
1179
|
-
this.componentFinishedUpdating();
|
1180
|
-
}
|
1181
|
-
};
|
1182
|
-
setTimeout(update.bind(this), 500);
|
1138
|
+
/**
|
1139
|
+
* Returns true if index should be shown in the sidebar.
|
1140
|
+
*
|
1141
|
+
* Index is not shown in the sidebar if there are more than eight queries
|
1142
|
+
* in total.
|
1143
|
+
*/
|
1144
|
+
shouldShowIndex: function () {
|
1145
|
+
return this.state.queries.length <= 8;
|
1183
1146
|
},
|
1184
1147
|
|
1185
1148
|
/**
|
1186
|
-
*
|
1187
|
-
*
|
1149
|
+
* Called after first call to render. The results may not be available at
|
1150
|
+
* this stage and thus results DOM cannot be scripted here, unless using
|
1151
|
+
* delegated events bound to the window, document, or body.
|
1188
1152
|
*/
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
this.
|
1193
|
-
this.setupDownloadLinks();
|
1153
|
+
componentDidMount: function () {
|
1154
|
+
// This sets up an event handler which enables users to select text
|
1155
|
+
// from hit header without collapsing the hit.
|
1156
|
+
this.preventCollapseOnSelection();
|
1194
1157
|
},
|
1195
1158
|
|
1196
1159
|
/**
|
1197
|
-
*
|
1198
|
-
*
|
1199
|
-
* TODO: can't this be done with CSS?
|
1160
|
+
* Called after each state change. Only a part of results DOM may be
|
1161
|
+
* available after a state change.
|
1200
1162
|
*/
|
1201
|
-
|
1202
|
-
|
1203
|
-
|
1204
|
-
|
1205
|
-
|
1206
|
-
|
1207
|
-
|
1163
|
+
componentDidUpdate: function () {
|
1164
|
+
// We track the number of updates to the component.
|
1165
|
+
this.updateCycle += 1;
|
1166
|
+
|
1167
|
+
// Lock sidebar in its position on first update of
|
1168
|
+
// results DOM.
|
1169
|
+
if (this.updateCycle === 1 ) this.affixSidebar();
|
1208
1170
|
},
|
1209
1171
|
|
1210
1172
|
/**
|
1211
|
-
*
|
1173
|
+
* Prevents folding of hits during text-selection, etc.
|
1212
1174
|
*/
|
1213
|
-
|
1214
|
-
|
1175
|
+
|
1176
|
+
/**
|
1177
|
+
* Called after all results have been rendered.
|
1178
|
+
*/
|
1179
|
+
componentFinishedUpdating: function () {
|
1180
|
+
this.shouldShowIndex() && this.setupScrollSpy();
|
1215
1181
|
},
|
1216
1182
|
|
1217
1183
|
/**
|
1218
1184
|
* Prevents folding of hits during text-selection.
|
1219
1185
|
*/
|
1220
|
-
|
1186
|
+
preventCollapseOnSelection: function () {
|
1221
1187
|
$('body').on('mousedown', ".hit > .section-header > h4", function (event) {
|
1222
1188
|
var $this = $(this);
|
1223
1189
|
$this.on('mouseup mousemove', function handler(event) {
|
@@ -1234,28 +1200,74 @@ var Report = React.createClass({
|
|
1234
1200
|
});
|
1235
1201
|
},
|
1236
1202
|
|
1237
|
-
|
1238
|
-
|
1239
|
-
|
1240
|
-
|
1241
|
-
$(
|
1242
|
-
|
1243
|
-
|
1203
|
+
/**
|
1204
|
+
* Affixes the sidebar.
|
1205
|
+
*/
|
1206
|
+
affixSidebar: function () {
|
1207
|
+
var $sidebar = $('.sidebar');
|
1208
|
+
$sidebar.affix({
|
1209
|
+
offset: {
|
1210
|
+
top: $sidebar.offset().top
|
1211
|
+
}
|
1212
|
+
});
|
1213
|
+
},
|
1244
1214
|
|
1245
|
-
|
1215
|
+
/**
|
1216
|
+
* For the query in viewport, highlights corresponding entry in the index.
|
1217
|
+
*/
|
1218
|
+
setupScrollSpy: function () {
|
1219
|
+
$('body').scrollspy({target: '.sidebar'});
|
1220
|
+
},
|
1246
1221
|
|
1247
|
-
|
1222
|
+
/**
|
1223
|
+
* Event-handler when hit is selected
|
1224
|
+
* Adds glow to hit component.
|
1225
|
+
* Updates number of Fasta that can be downloaded
|
1226
|
+
*/
|
1227
|
+
selectHit: function (id) {
|
1248
1228
|
|
1249
|
-
|
1229
|
+
var checkbox = $("#" + id);
|
1230
|
+
var num_checked = $('.hit-links :checkbox:checked').length;
|
1250
1231
|
|
1251
|
-
|
1252
|
-
|
1253
|
-
|
1254
|
-
|
1255
|
-
|
1256
|
-
|
1257
|
-
|
1258
|
-
|
1232
|
+
if (!checkbox || !checkbox.val()) {
|
1233
|
+
return;
|
1234
|
+
}
|
1235
|
+
|
1236
|
+
var $hit = $(checkbox.data('target'));
|
1237
|
+
|
1238
|
+
// Highlight selected hit and sync checkboxes if sequence viewer is open.
|
1239
|
+
if (checkbox.is(":checked")) {
|
1240
|
+
$hit
|
1241
|
+
.addClass('glow')
|
1242
|
+
.find(":checkbox").not(checkbox).check();
|
1243
|
+
var $a = $('.download-fasta-of-selected');
|
1244
|
+
var $b = $('.download-alignment-of-selected');
|
1245
|
+
$b.enable()
|
1246
|
+
var $n = $a.find('span');
|
1247
|
+
$a
|
1248
|
+
.enable()
|
1249
|
+
}
|
1250
|
+
|
1251
|
+
else {
|
1252
|
+
$hit
|
1253
|
+
.removeClass('glow')
|
1254
|
+
.find(":checkbox").not(checkbox).uncheck();
|
1255
|
+
}
|
1256
|
+
|
1257
|
+
if (num_checked >= 1)
|
1258
|
+
{
|
1259
|
+
var $a = $('.download-fasta-of-selected');
|
1260
|
+
var $b = $('.download-alignment-of-selected');
|
1261
|
+
$a.find('.text-bold').html(num_checked);
|
1262
|
+
$b.find('.text-bold').html(num_checked);
|
1263
|
+
}
|
1264
|
+
|
1265
|
+
if (num_checked == 0) {
|
1266
|
+
var $a = $('.download-fasta-of-selected');
|
1267
|
+
var $b = $('.download-alignment-of-selected');
|
1268
|
+
$a.addClass('disabled').find('.text-bold').html('');
|
1269
|
+
$b.addClass('disabled').find('.text-bold').html('');
|
1270
|
+
}
|
1259
1271
|
},
|
1260
1272
|
});
|
1261
1273
|
|