Skip to content

Commit

Permalink
#1072 Variant interpretation and notes lost when switching from genco…
Browse files Browse the repository at this point in the history
…de<->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.
  • Loading branch information
tonydisera committed Aug 28, 2024
1 parent 3d85661 commit 1683b78
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 43 deletions.
235 changes: 205 additions & 30 deletions client/app/components/pages/GeneHome.vue
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,8 @@ export default {
'Not significant': 'not-sig',
'Not reviewed': 'not-reviewed'
},
userFlaggedVariantsToApply: null,
//allGenes: allGenesData,
Expand Down Expand Up @@ -2192,13 +2194,19 @@ export default {
window.cacheHelper = self.cacheHelper;
self.cacheHelper.on("geneAnalyzed", function(theGene) {
self.refreshCoverageCounts()
if (self.selectedGene && self.selectedGene.hasOwnProperty("gene_name")
self.promiseRefreshUserFlaggedState(theGene)
.then(function() {
if (self.selectedGene && self.selectedGene.hasOwnProperty("gene_name")
&& theGene.gene_name === self.selectedGene.gene_name) {
self.promiseLoadData()
.catch(function(error) {
self.addAlert("error", error, theGene)
})
}
self.promiseLoadData()
.catch(function(error) {
self.addAlert("error", error, theGene)
})
}
})
.catch(function(error) {
self.addAlert("error", error, theGene)
})
});
self.cacheHelper.on("geneNotAnalyzed", function(geneName) {
console.log("Gene not analyzed " + geneName)
Expand Down Expand Up @@ -2248,9 +2256,23 @@ export default {
this.resume = val;
},
promiseClearCache: function() {
promiseClearCache: function(options) {
let self = this;
if (options && options.saveUserFlaggedState) {
// Keep track of user flagged variants. We will need to
// re-apply the variant interpretation and notes
// after all genes have been re-analyzed.
if (self.cohortModel && self.cohortModel.flaggedVariants) {
self.userFlaggedVariantsToApply = self.cohortModel.flaggedVariants.filter(function(variant) {
return (variant.notes && variant.notes.length > 0) ||
(variant.interpretation && variant.interpretation.length > 0);
})
}
} else {
self.userFlaggedVariantsToApply = null;
}
this.clearFilter();
self.cohortModel.clearFlaggedVariants();
Expand Down Expand Up @@ -2904,26 +2926,29 @@ export default {
.then(function(data) {
if (!data.isValidBuild) {
self.addAlert('error', 'The genome build change to ' + buildName + ' resulted in a problem. ' + data.message)
}
})
self.addAlert('info', 'Genome build <pre>' + buildName + '</pre> selected.');
self.onShowSnackbar({message: 'Genes will be reanalyzed based on genome build '
+ buildName, timeout: 3000});
return;
} else {
self.addAlert('info', 'Genome build <pre>' + buildName + '</pre> selected.');
self.onShowSnackbar({message: 'Genes will be reanalyzed based on genome build '
+ buildName, timeout: 3000});
self.genomeBuildHelper.setCurrentBuild(buildName)
self.setUrlParameters()
self.promiseClearCache()
.then(function() {
return self.promiseResetAllGenes()
})
.then(function() {
self.showLeftPanelForGenes()
self.genomeBuildHelper.setCurrentBuild(buildName)
self.setUrlParameters()
self.promiseClearCache({'saveUserFlaggedState': true})
.then(function() {
return self.promiseResetAllGenes()
})
.then(function() {
self.showLeftPanelForGenes()
if (self.geneModel.geneNames && self.geneModel.geneNames.length > 0) {
self.onAnalyzeAll()
if (self.geneModel.geneNames && self.geneModel.geneNames.length > 0) {
self.onAnalyzeAll()
}
})
}
})
},
onGeneSourceSelected: function(theGeneSource) {
var self = this;
Expand All @@ -2933,7 +2958,7 @@ export default {
self.onShowSnackbar({message: 'Genes will be re-analyzed based on '
+ theGeneSource + ' transcripts', timeout: 3000});
self.promiseClearCache()
self.promiseClearCache({'saveUserFlaggedState': true})
.then(function() {
return self.promiseResetAllGenes()
})
Expand Down Expand Up @@ -2962,7 +2987,7 @@ export default {
self.onShowSnackbar({message: 'Genes will be re-analyzed to only annotate all variants in genes, including intronic regions ', timeout: 3000});
}
self.promiseClearCache()
self.promiseClearCache({'saveUserFlaggedState': true})
.then(function() {
return self.promiseResetAllGenes()
})
Expand Down Expand Up @@ -2992,9 +3017,11 @@ export default {
let self = this;
self.geneModel.geneRegionBuffer = theGeneRegionBuffer;
// We have to clear the cache since the gene regions change
self.promiseClearCache()
self.promiseClearCache({'saveUserFlaggedState': true})
.then(function() {
self.promiseRefreshUserFlaggedState(self.selectedGene)
self.onGeneSelected(self.selectedGene.gene_name);
})
setTimeout(function () {
Expand Down Expand Up @@ -3417,6 +3444,8 @@ export default {
self.geneModel.geneObjects = {};
self.geneModel.geneToLatestTranscript = {};
self.geneModel.clearAllGenes();
self.cohortModel.flaggedVariants = [];
self.cacheHelper.geneToAltTranscript = {};
Expand All @@ -3428,6 +3457,8 @@ export default {
self.applyGenesImpl(genesToReapply.join(","), options,
function() {
console.log("user flagged variants to apply")
console.log(self.userFlaggedVariantsToApply)
resolve();
});
})
Expand Down Expand Up @@ -3870,7 +3901,8 @@ export default {
// If the variant isn't in the filtered variants list,
// mark it as 'user flagged'
if (self.cohortModel.getFlaggedVariant(variant) == null) {
let theFlaggedVariant = self.cohortModel.getFlaggedVariant(variant)
if (theFlaggedVariant == null) {
variant.gene = this.selectedGene;
variant.transcript = this.selectedTranscript;
self.cohortModel.addUserFlaggedVariant(self.selectedGene, self.selectedTranscript, variant);
Expand Down Expand Up @@ -4410,6 +4442,149 @@ export default {
self.onSendFiltersToClin();
}
})
},
promiseRefreshUserFlaggedState: function(geneObject) {
let self = this;
return new Promise(function(resolve, reject) {
let geneName = geneObject.gene_name;
if (self.userFlaggedVariantsToApply == null || self.userFlaggedVariantsToApply.length == 0 ||
self.cohortModel.flaggedVariants == null || self.cohortModel.flaggedVariants.length == 0) {
resolve();
}
// Add any user flagged variants
let userFlaggedVariantsToAdd = self.userFlaggedVariantsToApply.filter(function(source) {
if (source.gene && source.gene.gene_name) {
let matchesGene = source.gene.gene_name == geneName;
let matchingFlaggedVariants = self.cohortModel.flaggedVariants.filter(function(target) {
let foundMatch = (
self.globalApp.utility.stripRefName(source.chrom) == self.globalApp.utility.stripRefName(target.chrom)
&& source.start == target.start
&& source.ref == target.ref
&& source.alt == target.alt);
return foundMatch;
})
return (matchesGene && source.isUserFlagged && matchingFlaggedVariants.length == 0)
} else {
return false;
}
})
// Create the promises to add the user flagged variants
var promises = userFlaggedVariantsToAdd.map(function(source) {
return new Promise(function(resolve1, reject1) {
let theSource = source;
let theGeneObject = geneObject;
let theTranscript = self.geneModel.getCanonicalTranscript(theGeneObject)
self.cohortModel.getProbandModel().promiseGetMatchingVariant(theSource, theGeneObject, theTranscript)
.then(function(matchingVariant) {
if (matchingVariant) {
matchingVariant.isFlagged = true;
matchingVariant.isUserFlagged = true;
matchingVariant.filtersPassed = ['reviewed']
matchingVariant.filtersPassedAll = ['reviewed']
matchingVariant.notes = theSource.notes;
matchingVariant.interpretation = theSource.interpretation;
self.cohortModel.promiseAddUserFlaggedVariant(theGeneObject, theTranscript, matchingVariant)
.then(function() {
resolve1();
})
.catch(function(error) {
reject1('Failed to flag user flagged variant due to error: ' + error)
})
} else {
let theNotes = theSource.notes && theSource.notes.length > 0 ?
theSource.notes.map(function(n){
return n.note
}).join(", ") : "";
self.addAlert('error',
'Failed to flag ' + theGeneObject.gene_name +
' variant ' + theSource.chrom + ":" + theSource.start +
'. Unable to capture interpretation and notes for variant.',
theGeneObject.gene_name,
['interpretation: ' + theSource.interpretation,
'notes: ' + theNotes],
{'showAlertPanel': true})
resolve1();
}
})
})
})
Promise.all(promises)
.then(function() {
// Get the tuples of source variant and target variant
let flaggedVariantsToRefresh = self.userFlaggedVariantsToApply.map(function(source) {
if (source.gene && source.gene.gene_name) {
let matchesGene = source.gene.gene_name == geneName;
let matchingFlaggedVariants = self.cohortModel.flaggedVariants.filter(function(target) {
let foundMatch = (
self.globalApp.utility.stripRefName(source.chrom) == self.globalApp.utility.stripRefName(target.chrom)
&& source.start == target.start
&& source.ref == target.ref
&& source.alt == target.alt);
return foundMatch;
})
return {'source': source,
'matchesGene': matchesGene,
'matchingFlaggedVariants': matchingFlaggedVariants}
} else {
return {'source': source,
'matchesGene': false,
'matchingFlaggedVariants': []}
}
}).filter(function(matchInfo) {
return matchInfo.matchesGene;
})
// Iterate through the tuples of source and target variants and refresh the target
// variant notes and interpretation based on the source. Issue a warning
// if we have a source variant for a gene an no matching flagged variant.
flaggedVariantsToRefresh.forEach(function(matchInfo) {
if (matchInfo.matchingFlaggedVariants && matchInfo.matchingFlaggedVariants.length > 0) {
matchInfo.matchingFlaggedVariants.forEach(function(target) {
console.log("setting user flagged state for variant " + target.start + " for gene " + target.gene.gene_name)
target.interpretation = matchInfo.source.interpretation;
target.notes = matchInfo.source.notes;
var index = self.userFlaggedVariantsToApply.indexOf(matchInfo.source);
if (index !== -1) {
self.userFlaggedVariantsToApply.splice(index, 1);
}
})
} else {
let theNotes = "";
if (matchInfo.source.notes) {
theNotes = matchInfo.source.notes.map(function(n){
return n.note
}).join(", ")
}
self.addAlert('error',
'Cannot refresh the variant interpretation and notes for ' + geneName + ' variant ' +
matchInfo.source.chrom + ':' + matchInfo.source.start + ' ' + matchInfo.source.ref + '>' + matchInfo.source.alt +
' because the variant no longer matches any filter criteria.',
geneName,
['interpretation: ' + matchInfo.source.interpretation,
'notes: ' + theNotes],
{'showAlertPanel': true});
}
})
resolve();
})
.catch(function(error) {
reject(error)
})
})
},
refreshCoverageCounts: function() {
let self = this;
Expand Down Expand Up @@ -4548,7 +4723,7 @@ export default {
this.featureMatrixModel.isBasicMode = false;
this.featureMatrixModel.isSimpleMode = false;
this.filterModel.isBasicMode = false;
this.promiseClearCache()
this.promiseClearCache({'saveUserFlaggedState': true})
.then(function() {
self.calcFeatureMatrixWidthPercent();
self.onFilesLoaded(true, true, function() {
Expand Down Expand Up @@ -4577,7 +4752,7 @@ export default {
this.featureMatrixModel.isBasicMode = false;
this.featureMatrixModel.isSimpleMode = true;
this.filterModel.isBasicMode = false;
this.promiseClearCache()
this.promiseClearCache({'saveUserFlaggedState': true})
.then(function() {
self.calcFeatureMatrixWidthPercent();
self.onFilesLoaded(true, true, function() {
Expand Down
Loading

0 comments on commit 1683b78

Please sign in to comment.