Skip to content

Commit

Permalink
Merge 4cb5be8 into d36d5be
Browse files Browse the repository at this point in the history
  • Loading branch information
nathandunn committed Feb 9, 2019
2 parents d36d5be + 4cb5be8 commit bf01d07
Showing 1 changed file with 116 additions and 36 deletions.
152 changes: 116 additions & 36 deletions client/apollo/js/JSONUtils.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
define([ 'dojo/_base/declare',
'dojo/_base/array',
'JBrowse/Util',
'JBrowse/Model/SimpleFeature',
'JBrowse/Model/SimpleFeature',
'WebApollo/SequenceOntologyUtils'
],
function( declare, array, Util, SimpleFeature, SeqOnto ) {
Expand Down Expand Up @@ -38,7 +38,7 @@ var JAFeature = declare( SimpleFeature, {
constructor: function( afeature, parent ) {
this.afeature = afeature;
if (parent) { this._parent = parent; }

// get the main data
var loc = afeature.location;
var pfeat = this;
Expand All @@ -49,21 +49,21 @@ var JAFeature = declare( SimpleFeature, {
name: afeature.name,
parent_id: afeature.parent_id,
parent_type: afeature.parent_type ? afeature.parent_type.name : undefined,
type: afeature.type.name,
type: afeature.type.name,
properties: afeature.properties
};

if (this.data.type === "CDS") {
this.data.type = "wholeCDS";
if (this.data.type === "CDS") {
this.data.type = "wholeCDS";
}
else if (this.data.type === "stop_codon_read_through") {
parent.data.readThroughStopCodon = true;
}

this._uniqueID = afeature.uniquename;

// this doesn't work, since can be multiple properties with same CV term (comments, for example)
// could create arrray for each flattened cv-name for multiple values, but not sure what the point would be over
// could create arrray for each flattened cv-name for multiple values, but not sure what the point would be over
// just making sure can access via get('properties') via above assignment into data object
// parse the props
/* var props = afeature.properties;
Expand Down Expand Up @@ -95,7 +95,7 @@ var JAFeature = declare( SimpleFeature, {
}
}
}

if (!parent) {
if (afeature.children) {
var descendants = [];
Expand All @@ -116,16 +116,16 @@ var JAFeature = declare( SimpleFeature, {
afeature.children = [ child ];
}
}

// moved subfeature assignment to bottom of feature construction, since subfeatures may need to call method on their parent
// only thing subfeature constructor won't have access to is parent.data.subfeatures
// get the subfeatures
// get the subfeatures
this.data.subfeatures = array.map( afeature.children, function(s) {
return new JAFeature( s, pfeat);
} );

},

getUniqueName: function() {
if (this.parent() && this.parent().get("cloned_subfeatures")) {
return this.parent().id();
Expand All @@ -152,18 +152,18 @@ JSONUtils.flattenFeature = function(feature, descendants) {


/**
* takes any JBrowse feature, returns a SimpleFeature "copy",
* takes any JBrowse feature, returns a SimpleFeature "copy",
* for which all properties returned by tags() are mutable (has set() method)
* needed since JBrowse features no longer necessarily mutable
* feature requirements:
* functions: id, parent, tags, get
* if subfeatures, then returned as array by feature.get('subfeatures')
*
*
*/
JSONUtils.makeSimpleFeature = function(feature, parent) {
var result = new SimpleFeature({id: feature.id(), parent: (parent ? parent : feature.parent()) });
var ftags = feature.tags();
for (var tindex = 0; tindex < ftags.length; tindex++) {
for (var tindex = 0; tindex < ftags.length; tindex++) {
var tag = ftags[tindex];
// forcing lower case, since still having case issues with NCList features
result.set(tag.toLowerCase(), feature.get(tag.toLowerCase()));
Expand All @@ -187,7 +187,7 @@ JSONUtils.makeSimpleFeature = function(feature, parent) {
* afeature: sequence alteration in ApolloEditorService JSON format,
*/
JSONUtils.createJBrowseSequenceAlteration = function( afeature ) {
var loc = afeature.location;
var loc = afeature.location;
var uid = afeature.uniquename;
var justification;
for (var i = 0; i < afeature.properties.length; i++) {
Expand All @@ -211,42 +211,122 @@ JSONUtils.createJBrowseSequenceAlteration = function( afeature ) {
});
};

JSONUtils.isAlignment = function(feature){
return feature.data.cigar !== undefined ;
};

JSONUtils.parseCigar = function( cigar ) {
return array.map( cigar.toUpperCase().match(/\d+\D/g), function( op ) {
return [ op.match(/\D/)[0], parseInt( op ) ];
});
};

/**
* Generate exon subfeatures only from M vs N.
* @param feature
*/
JSONUtils.generateFeaturesFromCigar = function(feature){
var cigarData = feature.data.cigar ;
// var baseObject = {};


// 12M3N5M9N4M
// split <Number>Cigar
var ops = this.parseCigar(cigarData);
var currOffset = 0;
// var mismatches = [];
// {"track":"ctgA","features":[{"location":{"fmin":17399,"fmax":23000,"strand":1},"type":{"cv":{"name":"sequence"},"name":"mRNA"},"name":"Apple3","children":[{"location":{"fmin":17999,"fmax":21200,"strand":1},"type":{"cv":{"name":"sequence"},"name":"CDS"}},{"location":{"fmin":20999,"fmax":21200,"strand":1},"type":{"cv":{"name":"sequence"},"name":"exon"}},{"location":{"fmin":18999,"fmax":19500,"strand":1},"type":{"cv":{"name":"sequence"},"name":"exon"}},{"location":{"fmin":17999,"fmax":18800,"strand":1},"type":{"cv":{"name":"sequence"},"name":"exon"}}]}],"operation":"add_transcript","clientToken":"85401581821119996091324637603"}
console.log('ffeature',feature);
// feature.children = feature.children ? feature.children : [];
// console.log('childrens: '+feature.children);
// console.log('subfeatures: ' + feature.subfeature)
// feature.children = feature.children ? feature.children : [];
feature.children = [];
// baseObject.children= [];
var start = feature.data.start ;
array.forEach( ops, function( oprec ) {
var op = oprec[0];
var len = oprec[1];
if( op === 'M' || op === '=' || op === 'E' ) {
// TODO: create an exon subfeature for each
// add subfeature

var exon = new SimpleFeature({parent: feature});
exon.set('start', currOffset+start);
exon.set('end', currOffset + len+start);
exon.set('strand', feature.strand);
exon.set('type', 'exon');
// feature.children().push(JSONUtils.createApolloFeature(exon, "exon"));
feature.children.push(JSONUtils.createApolloFeature(exon, "exon"));
// baseObject.children.push(JSONUtils.createApolloFeature(exon, "exon"));

}
// if( op == 'I' )
// // GAH: shouldn't length of insertion really by 0, since JBrowse internally uses zero-interbase coordinates?
// mismatches.push( { start: currOffset, type: 'insertion', base: ''+len, length: 1 });
// else if( op == 'D' )
// mismatches.push( { start: currOffset, type: 'deletion', base: '*', length: len });
// else if( op == 'N' )
// mismatches.push( { start: currOffset, type: 'skip', base: 'N', length: len });
// else if( op == 'X' )
// mismatches.push( { start: currOffset, type: 'mismatch', base: 'X', length: len });
// else if( op == 'H' )
// mismatches.push( { start: currOffset, type: 'hardclip', base: 'H'+len, length: 1 });
// else if( op == 'S' )
// mismatches.push( { start: currOffset, type: 'softclip', base: 'S'+len, cliplen: len, length: 1 });
// if( op != 'I' && op != 'S' && op != 'H' )
currOffset += len;
});
feature.data.children = feature.children;
console.log('output',feature)
return feature ;
};

/**
/**
* creates a feature in ApolloEditorService JSON format
* takes as argument:
* jfeature: a feature in JBrowse JSON format,
* jfeature: a feature in JBrowse JSON format,
* fields: array specifying order of fields in jfeature
* subfields: array specifying order of fields in subfeatures of jfeature
* specified_type (optional): type passed in that overrides type info for jfeature
* ApolloEditorService format:
* {
* "location" : { "fmin": fmin, "fmax": fmax, "strand": strand },
* {
* "location" : { "fmin": fmin, "fmax": fmax, "strand": strand },
* "type": { "cv": { "name":, cv }, // typical cv name: "SO" (Sequence Ontology)
* "name": cvterm }, // typical name: "transcript"
* "children": { __recursive ApolloEditorService feature__ }
* }
*
* For ApolloEditorService "add_feature" call to work, need to have "gene" as toplevel feature,
*
* For ApolloEditorService "add_feature" call to work, need to have "gene" as toplevel feature,
* then "transcript", then ???
*
*
* JBrowse JSON fields example: ["start", "end", "strand", "id", "subfeatures"]
*
* type handling
* if specified_type arg present, it determines type name
* else if fields has a "type" field, use that to determine type name
* else don't include type
* else don't include type
*
* ignoring JBrowse ID / name fields for now
* currently, for features with lazy-loaded children, ignores children
* currently, for features with lazy-loaded children, ignores children
*/
JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, specified_subtype ) {
console.log('creating apollo feature')
var diagnose = (JSONUtils.verbose_conversion && jfeature.children() && jfeature.children().length > 0);
if (diagnose) {
console.log("converting JBrowse feature to Apollo feture, specified type: " + specified_type);
if (diagnose) {
console.log("converting JBrowse feature to Apollo feture, specified type: " + specified_type);
console.log(jfeature);
}

if(this.isAlignment(jfeature)){
console.log('is an alignment')
jfeature = this.generateFeaturesFromCigar(jfeature)
}
else{
console.log('just regular input')
}


var afeature = new Object();
var astrand;
// Apollo feature strand must be an integer
Expand All @@ -261,7 +341,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
default:
astrand = 0; // either not stranded or strand is uknown
}

afeature.location = {
"fmin": jfeature.get('start'),
"fmax": jfeature.get('end'),
Expand Down Expand Up @@ -295,7 +375,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
// using 'id' attribute in the absence of 'name' attribute
name !== undefined ? afeature.name = name : afeature.name = id;
}

/*
afeature.properties = [];
var property = { value : "source_id=" + jfeature.get('id'),
Expand All @@ -314,14 +394,14 @@ 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;
var cds;
var cdsFeatures = [];
var foundExons = false;

var updateCds = function(subfeat) {
if (!cds) {
cds = new SimpleFeature({id: "cds", parent: jfeature});
Expand All @@ -339,14 +419,14 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
}
}
};

for (var i=0; i<slength; i++) {
var subfeat = subfeats[i];
var subtype = subfeat.get('type');
var converted_subtype = specified_subtype || subtype;
if (!specified_subtype) {
if (SeqOnto.exonTerms[subtype]) {
// definitely an exon, leave exact subtype as is
// definitely an exon, leave exact subtype as is
// converted_subtype = "exon"
}
else if (subtype === "wholeCDS" || subtype === "polypeptide") {
Expand All @@ -361,7 +441,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
converted_subtype = null;
cdsFeatures.push(subfeat);
}
else if (SeqOnto.spliceTerms[subtype]) {
else if (SeqOnto.spliceTerms[subtype]) {
// splice sites -- filter out? leave unchanged?
// 12/16/2012 filtering out for now, causes errors in AnnotTrack duplication operation
converted_subtype = null; // filter out
Expand All @@ -379,7 +459,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
// filter out UTR
converted_subtype = null;
}
else {
else {
// convert everything else to exon???
// need to do this since server only creates exons for "exon" and descendant terms
converted_subtype = "exon";
Expand All @@ -406,7 +486,7 @@ JSONUtils.createApolloFeature = function( jfeature, specified_type, useName, spe
}
}
else if ( specified_type === 'transcript' ) {
// special casing for Apollo "transcript" features being created from
// special casing for Apollo "transcript" features being created from
// JBrowse top-level features that have no children
// need to create an artificial exon child the same size as the transcript
var fake_exon = new SimpleFeature({id: jfeature.id()+"_dummy_exon", parent: jfeature});
Expand Down Expand Up @@ -595,5 +675,5 @@ JSONUtils.classifyVariant = function( refAllele, altAlleles, fmin, fmax ) {
window.JSONUtils = JSONUtils;

return JSONUtils;

});

0 comments on commit bf01d07

Please sign in to comment.