Skip to content

Commit

Permalink
Merge pull request #295 from eweitz/cache-find-interactions
Browse files Browse the repository at this point in the history
Instantly find interacting genes
  • Loading branch information
eweitz authored Mar 6, 2022
2 parents 7bb37cf + 8d561f5 commit 8586f29
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 24 deletions.
2 changes: 1 addition & 1 deletion dist/js/ideogram.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/js/ideogram.min.js.map

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion src/js/annotations/labels.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ function addAnnotLabel(annotName, backgroundColor, borderColor) {
renderLabel(annot, style, ideo);
}

export function applyRankCutoff(annots, cutoff, ideo) {
export function sortAnnotsByRank(annots, ideo) {
if ('geneCache' in ideo === false) return annots;

const ranks = ideo.geneCache.interestingNames;
Expand All @@ -201,6 +201,12 @@ export function applyRankCutoff(annots, cutoff, ideo) {
return a.rank - b.rank;
});

return rankedAnnots;
}

export function applyRankCutoff(annots, cutoff, ideo) {
const rankedAnnots = sortAnnotsByRank(annots, ideo);

// Take the top N ranked genes, where N is `cutoff`
annots = rankedAnnots.slice(0, cutoff);

Expand Down
73 changes: 56 additions & 17 deletions src/js/kit/related-genes.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@
* https://eweitz.github.io/ideogram/related-genes
*/

import {decompressSync, strFromU8} from 'fflate';

import {
initAnalyzeRelatedGenes, analyzePlotTimes, analyzeRelatedGenes, timeDiff,
getRelatedGenesByType, getRelatedGenesTooltipAnalytics
} from './analyze-related-genes';

import {writeLegend} from '../annotations/legend';
import {getAnnotDomId} from '../annotations/process';
import {applyRankCutoff} from '../annotations/labels';
import {applyRankCutoff, sortAnnotsByRank} from '../annotations/labels';
import {getDir} from '../lib';
import initGeneCache from '../gene-cache';
import {fetchGpmls, summarizeInteractions} from './wikipathways';
Expand Down Expand Up @@ -128,14 +130,28 @@ async function fetchInteractions(gene, ideo) {
const ixns = {};
const seenNameIds = {};
const orgNameSimple = ideo.config.organism.replace(/-/g, ' ');
const queryString = `?query=${gene.name}&format=json`;
const url =
`https://webservice.wikipathways.org/findInteractions${queryString}`;
const upperGene = gene.name.toUpperCase();
// const queryString = `?query=${gene.name}&format=json`;
// const url =
// `https://webservice.wikipathways.org/findInteractions${queryString}`;
// const url = `http://localhost:8080/dist/data/cache/${gene.name}.json.gz`;
const url = `https://cdn.jsdelivr.net/npm/ixn2/${upperGene}.json.gz`;

// await sleep(3000);

const response = await fetch(url);
const data = await response.json();
// const data = await response.json();

let data = {result: []};

if (response.ok) {
const blob = await response.blob();
const uint8Array = new Uint8Array(await blob.arrayBuffer());
data = JSON.parse(strFromU8(decompressSync(uint8Array)));
}

// console.log('data')
// console.log(data)

// For each interaction, get nodes immediately upstream and downstream.
// Filter out pathway nodes that are definitely not gene symbols, then
Expand All @@ -155,23 +171,36 @@ async function fetchInteractions(gene, ideo) {
const name = interaction.name;
const id = interaction.id;

rawIxns.forEach(rawIxn => {
// rawIxns can contain multiple genes, e.g. when
// a group (i.e. a complex or a set of paralogs)
// interacts with the searched gene
const wrappedRawIxns = rawIxns.map(rawIxn => {
return {name: rawIxn, color: ''};
});
const sortedRawIxns =
sortAnnotsByRank(wrappedRawIxns, ideo).map(i => i.name);

sortedRawIxns.forEach(rawIxn => {

const normRawIxn = rawIxn.toLowerCase();

// Prevent overwriting searched gene. Occurs with e.g. human CD4
if (rawIxn.includes(gene.name)) return;
if (normRawIxn.includes(gene.name.toLowerCase())) return;

// if (rawIxn === '') return; // Avoid oddly blank placeholders

const nameId = name + id;

const isRelevant =
isInteractionRelevant(rawIxn, gene, nameId, seenNameIds, ideo);
isInteractionRelevant(normRawIxn, gene, nameId, seenNameIds, ideo);

if (isRelevant) {
seenNameIds[nameId] = 1;
const ixn = {name, pathwayId: id};
if (rawIxn in ixns) {
ixns[rawIxn].push(ixn);
if (normRawIxn in ixns) {
ixns[normRawIxn].push(ixn);
} else {
ixns[rawIxn] = [ixn];
ixns[normRawIxn] = [ixn];
}
}
});
Expand Down Expand Up @@ -373,7 +402,7 @@ async function fetchInteractionAnnots(interactions, searchedGene, ideo) {
const annot = parseAnnotFromMgiGene(gene, ideo, 'purple');
annots.push(annot);

const ixns = interactions[gene.symbol];
const ixns = interactions[gene.symbol.toLowerCase()];

const descriptionObj = describeInteractions(gene, ixns, searchedGene);

Expand Down Expand Up @@ -534,6 +563,19 @@ function processParalogs(annot, ideo) {
});
}

/**
* Sorts gene names consistently.
*
* Might also loosely rank by first-discovered or most prominent
*/
function sortGeneNames(aName, bName) {
// Rank shorter names above longer names
if (bName.length !== aName.length) return bName.length - aName.length;

// Rank names of equal length alphabetically
return [aName, bName].sort().indexOf(aName) === 0 ? 1 : -1;
}

/** Sorts by relevance of related status */
function sortAnnotsByRelatedStatus(a, b) {
var aName, bName, aColor, bColor;
Expand All @@ -557,16 +599,13 @@ function sortAnnotsByRelatedStatus(a, b) {
if (aColor === 'purple' && bColor === 'pink') return -1;
if (bColor === 'purple' && aColor === 'pink') return 1;

// Rank shorter names above longer names
if (bName.length !== aName.length) return bName.length - aName.length;

// Rank names of equal length alphabetically
return [aName, bName].sort().indexOf(aName) === 0 ? 1 : -1;
return sortGeneNames(aName, bName);
}

function mergeDescriptions(annot, desc, ideo) {
let mergedDesc;
const descriptions = ideo.annotDescriptions.annots;

if (annot.name in descriptions) {
const otherDesc = descriptions[annot.name];
mergedDesc = desc;
Expand Down
2 changes: 1 addition & 1 deletion src/js/kit/wikipathways.js
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ export function fetchGpmls(ideo) {
gpmlsByInteractingGene[ixnGene] = {};
pathwayIds.map(async pathwayId => {
const pathwayFile = `${pathwayId}.xml.gz`;
const gpmlUrl = `https://cdn.jsdelivr.net/npm/ixn/${pathwayFile}`;
const gpmlUrl = `https://cdn.jsdelivr.net/npm/ixn2/${pathwayFile}`;
const response = await fetch(gpmlUrl);
const blob = await response.blob();
const uint8Array = new Uint8Array(await blob.arrayBuffer());
Expand Down
6 changes: 3 additions & 3 deletions test/online/related-genes.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ describe('Ideogram related genes kit', function() {
ideogram.plotRelatedGenes('BRCA1');
setTimeout(function() {
const bard1Label =
document.querySelector('#ideogramLabel__c1_a0');
document.querySelector('#chr2-9606 .annot path');
bard1Label.dispatchEvent(new Event('mouseover'));

setTimeout(function() {
Expand All @@ -102,11 +102,11 @@ describe('Ideogram related genes kit', function() {
assert.include(tooltip.textContent, 'Interacts with BRCA1 in');

done();
}, 2000);
}, 1000);

}, 1000);
}, 1000);
}, 2000);
}, 1000);
}, 2000);


Expand Down

0 comments on commit 8586f29

Please sign in to comment.