Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

project GFF3 in-memory #1822

Closed
wants to merge 22 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6bbd62f
parsing forward okay, but is reading lines backwards for some reason
nathandunn Dec 9, 2017
2b7234f
a bit further, when reversing
nathandunn Dec 12, 2017
4eb6e3b
got HTMLFeatures to project correctly
nathandunn Dec 12, 2017
469b478
made some small changes to the tabix code
nathandunn Dec 12, 2017
debcf64
almost isolated a problem
nathandunn Dec 12, 2017
2ffd8d6
added a separate projected HTMLFeatures
nathandunn Dec 14, 2017
491b243
fixed missing include
nathandunn Dec 14, 2017
d68d7de
Merge branch '2.1.0' of https://github.com/GMOD/Apollo into project-gff3
nathandunn Dec 15, 2017
9da0019
added logging and over-rode some subfeature methods
nathandunn Dec 15, 2017
5b76367
canvas is projecting back and forth
nathandunn Dec 15, 2017
bd717dc
fixed bade include
nathandunn Dec 15, 2017
1398932
got subfeatures to show up in some instances , removed logs
nathandunn Dec 16, 2017
64af0da
added logging
nathandunn Dec 16, 2017
2d6b419
added some baseline SVG code
nathandunn Dec 18, 2017
125923d
added some debugging and cleaned up code
nathandunn Dec 19, 2017
14675ef
resolving feature
nathandunn Dec 19, 2017
bd3d784
properly stitching range using HTMLFeatures
nathandunn Dec 21, 2017
d1760cd
fixed subfeature depths
nathandunn Dec 22, 2017
a8ffda6
a very simple stub of a cache
nathandunn Dec 23, 2017
42d3fd0
fixed typo
nathandunn Jan 8, 2018
e0c7379
able to handle gene root types properly when annotating
nathandunn Jan 8, 2018
4413e20
updated track styles to not be so ugly if rendering the gene first
nathandunn Jan 10, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions client/apollo/css/webapollo_track_styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ div.track_localannot {
background-color: #DDDDCC;
}

/*
/*
To support WebApollo with sequence alteration features shown on SequenceTrack,
sequence style MUST NOT have a z-index specified
*/
Expand Down Expand Up @@ -189,12 +189,15 @@ div.annot-sequence {
* (currently only subfeatures like this are exons, which have CDS and UTR child divs)
*/
.container-100pct,
.plus-container-100pct,
.plus-container-100pct,
.plus-mRNA,
.minus-mRNA,
.minus-container-100pct {
height: 100%;
background-color: transparent;
}


.feature-render {
position: absolute;
min-width: 1px;
Expand Down
16 changes: 14 additions & 2 deletions client/apollo/js/JSONUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,18 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
console.log(jfeature);
}

// if specified_type is not 'gene' or 'pseudo-gene' and we find 'gene' or pseudogene, then we need to replace jfeature with the sub-type
if(jfeature.get('type')==='gene' || jfeature.get('type')==='pseudogene'){
var root_sub_features = jfeature.get('subfeatures');
if(root_sub_features.length===1){
jfeature = root_sub_features[0];
}
else{
console.log('Problem creating Apollo, wrong number of subfeatures found');
console.log(root_sub_features);
}
}

var afeature = new Object();
var astrand;
// Apollo feature strand must be an integer
Expand Down Expand Up @@ -312,7 +324,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
// use filteredsubs if present instead of subfeats?
// if (jfeature.filteredsubs) { subfeats = jfeature.filteredsubs; }
// else { subfeats = jfeature.get('subfeatures'); }
subfeats = jfeature.get('subfeatures');
subfeats = jfeature.get('subfeatures');
if( subfeats && subfeats.length ) {
afeature.children = [];
var slength = subfeats.length;
Expand Down Expand Up @@ -387,7 +399,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
foundExons = true;
}
if (converted_subtype) {
afeature.children.push( JSONUtils.createApolloFeature( subfeat, converted_subtype ) );
afeature.children.push( JSONUtils.createApolloFeature( subfeat, converted_subtype ) );
if (diagnose) { console.log(" subfeat original type: " + subtype + ", converted type: " + converted_subtype); }
}
else {
Expand Down
28 changes: 27 additions & 1 deletion client/apollo/js/ProjectionUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,26 @@ define([ 'dojo/_base/declare',
else{
return input ;
}
}
};

ProjectionUtils.flipStrand = function(input){
if(input==='+') return '-';
if(input==='-') return '+';
return input ;
};

ProjectionUtils.unProjectGFF3 = function(refSeqName,line){
var returnArray ;
returnArray = line.split("\t");
var coords = this.unProjectCoordinates(refSeqName,returnArray[3],returnArray[4]);
var sequenceListObject = this.parseSequenceList(refSeqName);
if(sequenceListObject[0].reverse){
returnArray[6] = this.flipStrand(returnArray[6]);
}
returnArray[3] = coords[0];
returnArray[4] = coords[1];
return returnArray.join("\t")
};

/**
* Unproject the given start and end
Expand Down Expand Up @@ -122,8 +141,10 @@ define([ 'dojo/_base/declare',
if(!feature.isProjected) return feature ;
feature.data.start = feature.data._original_start ;
feature.data.end = feature.data._original_end ;
feature.data.strand = feature.data._original_strand;
delete feature.data._original_start;
delete feature.data._original_end ;
delete feature.data._original_strand ;
feature.isProjected = false;
if (feature.data.subfeatures) {
for (var i = 0; i < feature.data.subfeatures.length; i++) {
Expand All @@ -141,14 +162,19 @@ define([ 'dojo/_base/declare',

var start = feature.get("start");
var end = feature.get("end");
var strand = feature.get("strand");
var projectedArray = this.projectCoordinates(refSeqName, start, end);
if (!feature.data) {
feature.data = {};
}
feature.data._original_start = start;
feature.data._original_end = end;
feature.data._original_strand = strand;


feature.data.start = projectedArray[0];
feature.data.end = projectedArray[1];
feature.data.strand = this.projectStrand(refSeqName,feature.data.strand);
feature.isProjected = true;
if (feature.data.subfeatures) {
for (var i = 0; i < feature.data.subfeatures.length; i++) {
Expand Down
9 changes: 7 additions & 2 deletions client/apollo/js/SVGFeatures.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ define( [
'JBrowse/View/Track/_FeatureContextMenusMixin',
'JBrowse/View/Track/_YScaleMixin',
'JBrowse/Model/Location',
'WebApollo/ProjectionUtils',
'JBrowse/Model/SimpleFeature'
],
function(
Expand All @@ -42,6 +43,7 @@ define( [
FeatureContextMenuMixin,
YScaleMixin,
Location,
ProjectionUtils,
SimpleFeature
) {

Expand Down Expand Up @@ -376,7 +378,7 @@ return declare(
return this.svgHeight;
},
guessGlyphType: function(feature) {
return 'JBrowse/View/FeatureGlyph/'+( {'gene': 'Gene', 'mRNA': 'ProcessedTranscript', 'transcript': 'ProcessedTranscript' }[feature.get('type')] || 'Box' );
return 'WebApollo/View/FeatureGlyph/SVG/'+( {'gene': 'Gene', 'mRNA': 'ProcessedTranscript', 'transcript': 'ProcessedTranscript' }[feature.get('type')] || 'Box' );
},

fillBlock: function( args ) {
Expand Down Expand Up @@ -717,8 +719,9 @@ return declare(
// (long labels that extend outside the feature's bounds, for
// example)
var bpExpansion = Math.round( this.config.maxFeatureGlyphExpansion / scale );
var refSeqName = this.refSeq.name ;

var region = { ref: this.refSeq.name,
var region = { ref: refSeqName,
start: Math.max( 0, leftBase - bpExpansion ),
end: rightBase + bpExpansion
};
Expand All @@ -731,6 +734,8 @@ return declare(
featuresInProgress++;
var rectNumber = fRects.length-1;

feature = ProjectionUtils.projectJSONFeature(feature,refSeqName);

// get the appropriate glyph object to render this feature
thisB.getGlyph(
args,
Expand Down
127 changes: 22 additions & 105 deletions client/apollo/js/Store/SeqFeature/GFF3.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ define( [
'WebApollo/ProjectionUtils',
'WebApollo/Store/SeqFeature/GlobalStatsEstimationMixin',
'JBrowse/Store/SeqFeature/GFF3',
'WebApollo/Store/SeqFeature/GFF3/Parser',
'JBrowse/Errors'
'JBrowse/Store/SeqFeature/GFF3/Parser'
],
function(
declare,
Expand All @@ -17,92 +16,16 @@ define( [
ProjectionUtils,
GlobalStatsEstimationMixin,
GFF3,
Parser,
Errors
Parser
) {

return declare([ GFF3 ],
return declare([ GFF3 , GlobalStatsEstimationMixin],

/**
* @lends JBrowse.Store.SeqFeature.GFF3
*/
{

_estimateGlobalStats: function(refseq) {
var deferred = new Deferred();
refseq = refseq || this.refSeq;
var sequenceListObject = ProjectionUtils.parseSequenceList(refseq.name);
var timeout = this.storeTimeout || 3000;
var startTime = new Date();

var statsFromInterval = function( length, callback ) {
var thisB = this;
var sampleCenter;
if (sequenceListObject[0].reverse) {
sampleCenter = refseq.end * 0.75 + refseq.start * 0.25;
}
else {
sampleCenter = refseq.start * 0.75 + refseq.end * 0.25;
}
var start = Math.max( 0, Math.round( sampleCenter - length/2 ) );
var end = Math.min( Math.round( sampleCenter + length/2 ), refseq.end );
var unprojectedArray = ProjectionUtils.unProjectCoordinates(refseq.name, start, end);
var unprojectedStart = unprojectedArray[0];
var unprojectedEnd = unprojectedArray[1];
var features = [];
this._getFeatures({
ref: sequenceListObject[0].name,
start: unprojectedStart,
end: unprojectedEnd
},
function( feature ) {
features.push(feature);
},
function( error ) {
features = array.filter(
features,
function(f) {
return f.get('start') >= unprojectedStart && f.get('end') <= unprojectedEnd;
}
);
callback.call( thisB, length,
{
featureDensity: features.length / length,
_statsSampleFeatures: features.length,
_statsSampleInterval: { ref: refseq.name, start: start, end: end, length: length }
});
},
function( error ) {
callback.call( thisB, length, null, error );
});
};

var maybeRecordStats = function( interval, stats, error ) {
if( error ) {
if( error.isInstanceOf(Errors.DataOverflow) ) {
console.log( 'Store statistics found chunkSizeLimit error, using empty: '+(this.source||this.name) );
deferred.resolve( { featureDensity: 0, error: 'global stats estimation found chunkSizeError' } );
}
else {
deferred.reject( error );
}
} else {
var refLen = refseq.end - refseq.start;
if( stats._statsSampleFeatures >= 300 || interval * 2 > refLen || error ) {
console.log( 'WA Store statistics: '+(this.source||this.name), stats );
deferred.resolve( stats );
} else if( ((new Date()) - startTime) < timeout ) {
statsFromInterval.call( this, interval * 2, maybeRecordStats );
} else {
console.log( 'Store statistics timed out: '+(this.source||this.name) );
deferred.resolve( { featureDensity: 0, error: 'global stats estimation timed out' } );
}
}
};

statsFromInterval.call( this, 100, maybeRecordStats );
return deferred;
},

_loadFeatures: function() {
var thisB = this;
Expand Down Expand Up @@ -142,13 +65,27 @@ return declare([ GFF3 ],

thisB._deferred.features.resolve( features );
console.log('Parse final: ' +features.length);
console.log(features)
}
});
var fail = lang.hitch( this, '_failAllDeferred' );
// parse the whole file and store it
var sequenceListObject = ProjectionUtils.parseSequenceList(thisB.refSeq.name);
var reverse = sequenceListObject[0].reverse ;
var lines = [];
// this.data.reverseFetchLines(
this.data.fetchLines(
function( line ) {
if(reverse && line.length>30) {
// console.log('reversing ->['+line+']');
line = line.split("").reverse().join("").replace(" ", "\t").slice(0, -1).replace('\n', '');
}
if(line.length > 30){
// console.log('unprojecting ->['+line+']');
line = ProjectionUtils.unProjectGFF3(thisB.refSeq.name,line);
// console.log('unprojectED ->['+line+']');
}
// console.log(line) ;
lines.push(line);
try {
parser.addLine(line);
} catch(e) {
Expand All @@ -161,13 +98,6 @@ return declare([ GFF3 ],
);
},

_getFeatures: function( query, featureCallback, finishedCallback, errorCallback ) {
var thisB = this;
thisB._deferred.features.then( function() {
console.log('got features? ' +thisB._deferred.features);
thisB._search( query, featureCallback, finishedCallback, errorCallback );
});
},

_search: function( query, featureCallback, finishCallback, errorCallback ) {
// search in this.features, which are sorted
Expand All @@ -177,20 +107,13 @@ return declare([ GFF3 ],
var converted = this.features;

// parse sequenceList from query.ref
var chrName, min, max ;
var chrName ;
if(ProjectionUtils.isSequenceList(query.ref)){
var sequenceListObject = ProjectionUtils.parseSequenceList(query.ref);
// unproject start and end
var featureLocationArray = ProjectionUtils.unProjectCoordinates(query.ref, query.start, query.end);
// rebuild the query
chrName = sequenceListObject[0].name;
min = featureLocationArray[0];
max = featureLocationArray[1];
}
else{
chrName = query.ref ;
min = query.start ;
max = query.end ;
}

var refName = this.browser.regularizeReferenceName( chrName );
Expand All @@ -202,15 +125,9 @@ return declare([ GFF3 ],
}

var checkEnd = 'start' in query
? function(f) { return f.get('end') >= min; }
? function(f) { return f.get('end') >= query.start; }
: function() { return true; };

// var checkEnd = 'start' in query
// ? function(f) {
// f = ProjectionUtils.projectJSONFeature(f,query.ref);
// return f.get('end') >= min;
// }
// : function() { return true; };

for( ; i<bare.length; i++ ) {
// lazily convert the bare feature data to JBrowse features
Expand All @@ -220,11 +137,11 @@ return declare([ GFF3 ],
return this._formatFeature( b );
}.call( this, bare[i], i )
);
f = ProjectionUtils.unprojectJSONFeature(f,query.ref);
// f = ProjectionUtils.unprojectJSONFeature(f,query.ref);
// features are sorted by ref seq and start coord, so we
// can stop if we are past the ref seq or the end of the
// query region
if( f._reg_seq_id != refName || f.get('start') > max )
if( f._reg_seq_id != refName || f.get('start') > query.end )
break;

if( checkEnd( f ) ) {
Expand Down
Loading