Skip to content

Commit 1683b78

Browse files
committed
#1072 Variant interpretation and notes lost when switching from gencode<->refseq. To fix this, before the cache is cleared and flagged variants are removed, keep track of flagged variants with interpretation and/or notes. Then after gene is analyzed, set the interpretation and notes on the matching variants. We will keep track of the user flagged state when the genome build changes, the gene source changes. Switching from advanced to basic/simple mode is more complicated as this reloads the entire app in the browser, so a separate issue (#1100) was created to address this problem.
1 parent 3d85661 commit 1683b78

File tree

4 files changed

+296
-43
lines changed

4 files changed

+296
-43
lines changed

client/app/components/pages/GeneHome.vue

Lines changed: 205 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -934,6 +934,8 @@ export default {
934934
'Not significant': 'not-sig',
935935
'Not reviewed': 'not-reviewed'
936936
},
937+
938+
userFlaggedVariantsToApply: null,
937939
938940
939941
//allGenes: allGenesData,
@@ -2192,13 +2194,19 @@ export default {
21922194
window.cacheHelper = self.cacheHelper;
21932195
self.cacheHelper.on("geneAnalyzed", function(theGene) {
21942196
self.refreshCoverageCounts()
2195-
if (self.selectedGene && self.selectedGene.hasOwnProperty("gene_name")
2197+
self.promiseRefreshUserFlaggedState(theGene)
2198+
.then(function() {
2199+
if (self.selectedGene && self.selectedGene.hasOwnProperty("gene_name")
21962200
&& theGene.gene_name === self.selectedGene.gene_name) {
2197-
self.promiseLoadData()
2198-
.catch(function(error) {
2199-
self.addAlert("error", error, theGene)
2200-
})
2201-
}
2201+
self.promiseLoadData()
2202+
.catch(function(error) {
2203+
self.addAlert("error", error, theGene)
2204+
})
2205+
}
2206+
})
2207+
.catch(function(error) {
2208+
self.addAlert("error", error, theGene)
2209+
})
22022210
});
22032211
self.cacheHelper.on("geneNotAnalyzed", function(geneName) {
22042212
console.log("Gene not analyzed " + geneName)
@@ -2248,9 +2256,23 @@ export default {
22482256
this.resume = val;
22492257
},
22502258
2251-
promiseClearCache: function() {
2259+
promiseClearCache: function(options) {
22522260
let self = this;
2253-
2261+
2262+
if (options && options.saveUserFlaggedState) {
2263+
// Keep track of user flagged variants. We will need to
2264+
// re-apply the variant interpretation and notes
2265+
// after all genes have been re-analyzed.
2266+
if (self.cohortModel && self.cohortModel.flaggedVariants) {
2267+
self.userFlaggedVariantsToApply = self.cohortModel.flaggedVariants.filter(function(variant) {
2268+
return (variant.notes && variant.notes.length > 0) ||
2269+
(variant.interpretation && variant.interpretation.length > 0);
2270+
})
2271+
}
2272+
} else {
2273+
self.userFlaggedVariantsToApply = null;
2274+
}
2275+
22542276
this.clearFilter();
22552277
self.cohortModel.clearFlaggedVariants();
22562278
@@ -2904,26 +2926,29 @@ export default {
29042926
.then(function(data) {
29052927
if (!data.isValidBuild) {
29062928
self.addAlert('error', 'The genome build change to ' + buildName + ' resulted in a problem. ' + data.message)
2907-
}
2908-
})
2909-
2910-
self.addAlert('info', 'Genome build <pre>' + buildName + '</pre> selected.');
2911-
self.onShowSnackbar({message: 'Genes will be reanalyzed based on genome build '
2912-
+ buildName, timeout: 3000});
2929+
return;
2930+
} else {
2931+
self.addAlert('info', 'Genome build <pre>' + buildName + '</pre> selected.');
2932+
self.onShowSnackbar({message: 'Genes will be reanalyzed based on genome build '
2933+
+ buildName, timeout: 3000});
29132934
2914-
self.genomeBuildHelper.setCurrentBuild(buildName)
2915-
self.setUrlParameters()
2916-
self.promiseClearCache()
2917-
.then(function() {
2918-
return self.promiseResetAllGenes()
2919-
})
2920-
.then(function() {
2921-
self.showLeftPanelForGenes()
2935+
self.genomeBuildHelper.setCurrentBuild(buildName)
2936+
self.setUrlParameters()
2937+
self.promiseClearCache({'saveUserFlaggedState': true})
2938+
.then(function() {
2939+
return self.promiseResetAllGenes()
2940+
})
2941+
.then(function() {
2942+
self.showLeftPanelForGenes()
29222943
2923-
if (self.geneModel.geneNames && self.geneModel.geneNames.length > 0) {
2924-
self.onAnalyzeAll()
2944+
if (self.geneModel.geneNames && self.geneModel.geneNames.length > 0) {
2945+
self.onAnalyzeAll()
2946+
}
2947+
})
2948+
29252949
}
29262950
})
2951+
29272952
},
29282953
onGeneSourceSelected: function(theGeneSource) {
29292954
var self = this;
@@ -2933,7 +2958,7 @@ export default {
29332958
self.onShowSnackbar({message: 'Genes will be re-analyzed based on '
29342959
+ theGeneSource + ' transcripts', timeout: 3000});
29352960
2936-
self.promiseClearCache()
2961+
self.promiseClearCache({'saveUserFlaggedState': true})
29372962
.then(function() {
29382963
return self.promiseResetAllGenes()
29392964
})
@@ -2962,7 +2987,7 @@ export default {
29622987
self.onShowSnackbar({message: 'Genes will be re-analyzed to only annotate all variants in genes, including intronic regions ', timeout: 3000});
29632988
}
29642989
2965-
self.promiseClearCache()
2990+
self.promiseClearCache({'saveUserFlaggedState': true})
29662991
.then(function() {
29672992
return self.promiseResetAllGenes()
29682993
})
@@ -2992,9 +3017,11 @@ export default {
29923017
let self = this;
29933018
self.geneModel.geneRegionBuffer = theGeneRegionBuffer;
29943019
// We have to clear the cache since the gene regions change
2995-
self.promiseClearCache()
3020+
self.promiseClearCache({'saveUserFlaggedState': true})
29963021
.then(function() {
3022+
self.promiseRefreshUserFlaggedState(self.selectedGene)
29973023
self.onGeneSelected(self.selectedGene.gene_name);
3024+
29983025
})
29993026
30003027
setTimeout(function () {
@@ -3417,6 +3444,8 @@ export default {
34173444
self.geneModel.geneObjects = {};
34183445
self.geneModel.geneToLatestTranscript = {};
34193446
self.geneModel.clearAllGenes();
3447+
3448+
34203449
self.cohortModel.flaggedVariants = [];
34213450
34223451
self.cacheHelper.geneToAltTranscript = {};
@@ -3428,6 +3457,8 @@ export default {
34283457
34293458
self.applyGenesImpl(genesToReapply.join(","), options,
34303459
function() {
3460+
console.log("user flagged variants to apply")
3461+
console.log(self.userFlaggedVariantsToApply)
34313462
resolve();
34323463
});
34333464
})
@@ -3870,7 +3901,8 @@ export default {
38703901
38713902
// If the variant isn't in the filtered variants list,
38723903
// mark it as 'user flagged'
3873-
if (self.cohortModel.getFlaggedVariant(variant) == null) {
3904+
let theFlaggedVariant = self.cohortModel.getFlaggedVariant(variant)
3905+
if (theFlaggedVariant == null) {
38743906
variant.gene = this.selectedGene;
38753907
variant.transcript = this.selectedTranscript;
38763908
self.cohortModel.addUserFlaggedVariant(self.selectedGene, self.selectedTranscript, variant);
@@ -4410,6 +4442,149 @@ export default {
44104442
self.onSendFiltersToClin();
44114443
}
44124444
})
4445+
},
4446+
promiseRefreshUserFlaggedState: function(geneObject) {
4447+
let self = this;
4448+
4449+
return new Promise(function(resolve, reject) {
4450+
4451+
let geneName = geneObject.gene_name;
4452+
4453+
if (self.userFlaggedVariantsToApply == null || self.userFlaggedVariantsToApply.length == 0 ||
4454+
self.cohortModel.flaggedVariants == null || self.cohortModel.flaggedVariants.length == 0) {
4455+
resolve();
4456+
}
4457+
4458+
// Add any user flagged variants
4459+
let userFlaggedVariantsToAdd = self.userFlaggedVariantsToApply.filter(function(source) {
4460+
if (source.gene && source.gene.gene_name) {
4461+
let matchesGene = source.gene.gene_name == geneName;
4462+
let matchingFlaggedVariants = self.cohortModel.flaggedVariants.filter(function(target) {
4463+
let foundMatch = (
4464+
self.globalApp.utility.stripRefName(source.chrom) == self.globalApp.utility.stripRefName(target.chrom)
4465+
&& source.start == target.start
4466+
&& source.ref == target.ref
4467+
&& source.alt == target.alt);
4468+
return foundMatch;
4469+
})
4470+
return (matchesGene && source.isUserFlagged && matchingFlaggedVariants.length == 0)
4471+
} else {
4472+
return false;
4473+
}
4474+
})
4475+
4476+
// Create the promises to add the user flagged variants
4477+
var promises = userFlaggedVariantsToAdd.map(function(source) {
4478+
return new Promise(function(resolve1, reject1) {
4479+
let theSource = source;
4480+
let theGeneObject = geneObject;
4481+
let theTranscript = self.geneModel.getCanonicalTranscript(theGeneObject)
4482+
self.cohortModel.getProbandModel().promiseGetMatchingVariant(theSource, theGeneObject, theTranscript)
4483+
.then(function(matchingVariant) {
4484+
if (matchingVariant) {
4485+
matchingVariant.isFlagged = true;
4486+
matchingVariant.isUserFlagged = true;
4487+
matchingVariant.filtersPassed = ['reviewed']
4488+
matchingVariant.filtersPassedAll = ['reviewed']
4489+
matchingVariant.notes = theSource.notes;
4490+
matchingVariant.interpretation = theSource.interpretation;
4491+
self.cohortModel.promiseAddUserFlaggedVariant(theGeneObject, theTranscript, matchingVariant)
4492+
.then(function() {
4493+
resolve1();
4494+
})
4495+
.catch(function(error) {
4496+
reject1('Failed to flag user flagged variant due to error: ' + error)
4497+
})
4498+
} else {
4499+
let theNotes = theSource.notes && theSource.notes.length > 0 ?
4500+
theSource.notes.map(function(n){
4501+
return n.note
4502+
}).join(", ") : "";
4503+
self.addAlert('error',
4504+
'Failed to flag ' + theGeneObject.gene_name +
4505+
' variant ' + theSource.chrom + ":" + theSource.start +
4506+
'. Unable to capture interpretation and notes for variant.',
4507+
theGeneObject.gene_name,
4508+
['interpretation: ' + theSource.interpretation,
4509+
'notes: ' + theNotes],
4510+
{'showAlertPanel': true})
4511+
resolve1();
4512+
}
4513+
})
4514+
})
4515+
})
4516+
4517+
Promise.all(promises)
4518+
.then(function() {
4519+
// Get the tuples of source variant and target variant
4520+
let flaggedVariantsToRefresh = self.userFlaggedVariantsToApply.map(function(source) {
4521+
if (source.gene && source.gene.gene_name) {
4522+
let matchesGene = source.gene.gene_name == geneName;
4523+
let matchingFlaggedVariants = self.cohortModel.flaggedVariants.filter(function(target) {
4524+
let foundMatch = (
4525+
self.globalApp.utility.stripRefName(source.chrom) == self.globalApp.utility.stripRefName(target.chrom)
4526+
&& source.start == target.start
4527+
&& source.ref == target.ref
4528+
&& source.alt == target.alt);
4529+
return foundMatch;
4530+
})
4531+
return {'source': source,
4532+
'matchesGene': matchesGene,
4533+
'matchingFlaggedVariants': matchingFlaggedVariants}
4534+
} else {
4535+
return {'source': source,
4536+
'matchesGene': false,
4537+
'matchingFlaggedVariants': []}
4538+
}
4539+
}).filter(function(matchInfo) {
4540+
return matchInfo.matchesGene;
4541+
})
4542+
4543+
// Iterate through the tuples of source and target variants and refresh the target
4544+
// variant notes and interpretation based on the source. Issue a warning
4545+
// if we have a source variant for a gene an no matching flagged variant.
4546+
flaggedVariantsToRefresh.forEach(function(matchInfo) {
4547+
if (matchInfo.matchingFlaggedVariants && matchInfo.matchingFlaggedVariants.length > 0) {
4548+
matchInfo.matchingFlaggedVariants.forEach(function(target) {
4549+
console.log("setting user flagged state for variant " + target.start + " for gene " + target.gene.gene_name)
4550+
target.interpretation = matchInfo.source.interpretation;
4551+
target.notes = matchInfo.source.notes;
4552+
var index = self.userFlaggedVariantsToApply.indexOf(matchInfo.source);
4553+
if (index !== -1) {
4554+
self.userFlaggedVariantsToApply.splice(index, 1);
4555+
}
4556+
})
4557+
} else {
4558+
let theNotes = "";
4559+
if (matchInfo.source.notes) {
4560+
theNotes = matchInfo.source.notes.map(function(n){
4561+
return n.note
4562+
}).join(", ")
4563+
}
4564+
self.addAlert('error',
4565+
'Cannot refresh the variant interpretation and notes for ' + geneName + ' variant ' +
4566+
matchInfo.source.chrom + ':' + matchInfo.source.start + ' ' + matchInfo.source.ref + '>' + matchInfo.source.alt +
4567+
' because the variant no longer matches any filter criteria.',
4568+
geneName,
4569+
['interpretation: ' + matchInfo.source.interpretation,
4570+
'notes: ' + theNotes],
4571+
{'showAlertPanel': true});
4572+
}
4573+
})
4574+
4575+
resolve();
4576+
4577+
})
4578+
.catch(function(error) {
4579+
reject(error)
4580+
})
4581+
4582+
4583+
4584+
4585+
})
4586+
4587+
44134588
},
44144589
refreshCoverageCounts: function() {
44154590
let self = this;
@@ -4548,7 +4723,7 @@ export default {
45484723
this.featureMatrixModel.isBasicMode = false;
45494724
this.featureMatrixModel.isSimpleMode = false;
45504725
this.filterModel.isBasicMode = false;
4551-
this.promiseClearCache()
4726+
this.promiseClearCache({'saveUserFlaggedState': true})
45524727
.then(function() {
45534728
self.calcFeatureMatrixWidthPercent();
45544729
self.onFilesLoaded(true, true, function() {
@@ -4577,7 +4752,7 @@ export default {
45774752
this.featureMatrixModel.isBasicMode = false;
45784753
this.featureMatrixModel.isSimpleMode = true;
45794754
this.filterModel.isBasicMode = false;
4580-
this.promiseClearCache()
4755+
this.promiseClearCache({'saveUserFlaggedState': true})
45814756
.then(function() {
45824757
self.calcFeatureMatrixWidthPercent();
45834758
self.onFilesLoaded(true, true, function() {

0 commit comments

Comments
 (0)