Skip to content

Commit eb3b94a

Browse files
authored
Merge pull request #1152 from jvwong/iss1132_EntitySummaryUpdates
Iss1132 entity summary updates
2 parents b266776 + b7c7ea0 commit eb3b94a

File tree

12 files changed

+262
-189
lines changed

12 files changed

+262
-189
lines changed

src/client/features/search/entity-summary-box.js

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,23 @@ const _ = require('lodash');
66
const classNames = require('classnames');
77

88
const { fetch } = require('../../../util');
9-
const config = require('../../../config');
10-
let { DATASOURCES } = require('../../../models/entity/summary');
9+
const { MAX_SIF_NODES, NS_HGNC_SYMBOL, NS_GENECARDS, NS_NCBI_GENE, NS_UNIPROT } = require('../../../config');
1110

1211
const ENTITY_OTHER_NAMES_LIMIT = 4;
1312
const ENTITY_SUMMARY_DISPLAY_LIMIT = 6;
1413

15-
//Temporary - to be dealt with in #1116 (https://github.com/PathwayCommons/app-ui/issues/1116)
16-
const DATASOURCE_NAMES = {
17-
[DATASOURCES.NCBIGENE]: {
18-
displayName: 'NCBI Gene',
19-
linkUrl: DATASOURCES.NCBIGENE
20-
},
21-
[DATASOURCES.HGNC]: {
22-
displayName: 'HGNC',
23-
linkUrl: 'http://identifiers.org/hgnc.symbol/'
24-
},
25-
[DATASOURCES.UNIPROT]: {
26-
displayName: 'UniProt',
27-
linkUrl: DATASOURCES.UNIPROT
28-
},
29-
[DATASOURCES.GENECARDS]: {
30-
displayName: 'GeneCards',
31-
linkUrl: 'https://www.genecards.org/cgi-bin/carddisp.pl?gene='
32-
},
14+
const SUPPORTED_COLLECTIONS = new Map([
15+
[NS_GENECARDS, 'GeneCards'],
16+
[NS_HGNC_SYMBOL, 'HGNC'],
17+
[NS_NCBI_GENE, 'NCBI Gene'],
18+
[NS_UNIPROT, 'UniProt']
19+
]);
20+
21+
const getHgncFromXref = xrefLinks => {
22+
let symbol;
23+
const hgncXrefLink = _.find( xrefLinks, link => link.namespace === NS_HGNC_SYMBOL );
24+
if( hgncXrefLink ) symbol = _.last( _.compact( hgncXrefLink.uri.split('/') ) );
25+
return symbol;
3326
};
3427

3528
class EntitySummaryBox extends React.Component {
@@ -43,12 +36,11 @@ class EntitySummaryBox extends React.Component {
4336
}
4437
render(){
4538
let { summary } = this.props;
46-
let { dataSource, displayName, localID, description, aliasIds, xref } = summary;
47-
// Retrieve the HGNC symbol (http://www.pathwaycommons.org/sifgraph/swagger-ui.html)
48-
let hgncSymbol = summary.xref[ DATASOURCES.HGNC ] || localID; // Prefix is hgnc
49-
let sortedLinks = _.toPairs( xref ).concat([[ dataSource, localID ]])
50-
.sort( (p1, p2) => p1[0] > p2[0] ? 1: -1 )
51-
.map( pair => h('a.plain-link', { href: (DATASOURCE_NAMES[pair[0]]).linkUrl + pair[1], target:'_blank' }, (DATASOURCE_NAMES[pair[0]]).displayName));
39+
let { displayName, description, aliasIds, xrefLinks } = summary;
40+
const hgncSymbol = getHgncFromXref( xrefLinks );
41+
42+
let sortedLinks = xrefLinks.sort( (p1, p2) => p1.namespace > p2.namespace ? 1: -1 )
43+
.map( link => h( 'a.plain-link', { href: link.uri, target:'_blank' }, SUPPORTED_COLLECTIONS.get( link.namespace ) ) );
5244

5345
let moreInfo = h('div.entity-more-info',[
5446
h('div.entity-names', [
@@ -109,9 +101,7 @@ class EntitySummaryBoxList extends React.Component {
109101

110102
componentDidMount(){
111103
let { entitySummaryResults } = this.props;
112-
let hgncSymbols = _.values( entitySummaryResults )
113-
.map( summary => summary.xref[ DATASOURCES.HGNC ] || summary.xref[ 'localID' ] ); // Prefix is hgnc
114-
104+
let hgncSymbols = entitySummaryResults.map( summaryResult => getHgncFromXref( _.get( summaryResult, ['summary', 'xrefLinks'] ) ) );
115105

116106
fetch('/api/interactions/image?' + queryString.stringify({ sources: hgncSymbols })).then( r => r.json() ).then( res => {
117107
let { img } = res;
@@ -121,21 +111,15 @@ class EntitySummaryBoxList extends React.Component {
121111

122112
render(){
123113
let { entitySummaryResults } = this.props;
124-
const entitySummaryKeys = _.keys( entitySummaryResults );
125-
126-
// Retrieve the HGNC symbol (http://www.pathwaycommons.org/sifgraph/swagger-ui.html)
127-
let sources = _.values( entitySummaryResults )
128-
.map( summary => summary.xref[ DATASOURCES.HGNC ] || summary.xref[ 'localID' ] ); // Prefix is hgnc
129-
130-
let singleSrcLabel = `View interactions between ${sources[0]} and top ${config.MAX_SIF_NODES} genes`;
114+
let sources = entitySummaryResults.map( summaryResult => getHgncFromXref( _.get( summaryResult, ['summary', 'xrefLinks'] ) ) );
115+
let singleSrcLabel = `View interactions between ${sources[0]} and top ${MAX_SIF_NODES} genes`;
131116
let multiSrcLabel = `View iteractions between ${sources.slice(0, sources.length - 1).join(', ')} and ${sources.slice(-1)}`;
132-
133117
let interactionsLinkLabel = sources.length === 1 ? singleSrcLabel : multiSrcLabel;
134118

135-
let entitySummaryBoxes = entitySummaryKeys
119+
let entitySummaryBoxes = entitySummaryResults
136120
.slice( 0, ENTITY_SUMMARY_DISPLAY_LIMIT )
137-
.map( key => {
138-
const summary = _.get( entitySummaryResults, key );
121+
.map( summaryResult => {
122+
const summary = _.get( summaryResult, 'summary' );
139123
let props = { summary };
140124
return h(EntitySummaryBox, props);
141125
});

src/models/entity/summary.js

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
// Entity summary
22
const _ = require('lodash');
33

4-
//To be moved and integrated with all the other 'datasource'
5-
const DATASOURCES = {
6-
NCBIGENE: 'http://identifiers.org/ncbigene/',
7-
HGNC: 'http://identifiers.org/hgnc/',
8-
UNIPROT: 'http://identifiers.org/uniprot/',
9-
GENECARDS: 'http://identifiers.org/genecards/'
10-
};
11-
124
const DEFAULTS = {
13-
dataSource: '',
5+
namespace: '',
146
displayName: '',
15-
localID: '',
7+
localId: '',
168
description: '',
179
aliases: [],
1810
aliasIds: [],
19-
xref: {}
11+
xrefLinks: []
2012
};
2113

2214
class EntitySummary {
@@ -25,4 +17,4 @@ class EntitySummary {
2517
}
2618
}
2719

28-
module.exports = { EntitySummary, DATASOURCES };
20+
module.exports = { EntitySummary };

src/server/external-services/hgnc.js

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const { fetch } = require('../../util');
22
const _ = require('lodash');
3-
const { HGNC_BASE_URL } = require('../../config');
4-
const { EntitySummary, DATASOURCES } = require('../../models/entity/summary');
3+
const { HGNC_BASE_URL, NS_GENECARDS, NS_HGNC_SYMBOL, NS_NCBI_GENE, NS_UNIPROT, IDENTIFIERS_URL } = require('../../config');
4+
const { EntitySummary } = require('../../models/entity/summary');
55
const logger = require('../logger');
66

77
//Could cache somewhere here.
@@ -20,9 +20,11 @@ const fetchBySymbol = symbol => {
2020

2121
const fetchBySymbols = symbols => Promise.all( symbols.map(fetchBySymbol) );
2222

23+
const createUri = ( namespace, localId ) => IDENTIFIERS_URL + '/' + namespace + '/' + localId;
24+
2325
const getEntitySummary = async symbols => {
2426

25-
const summary = {};
27+
const summary = [];
2628
if ( _.isEmpty( symbols ) ) return summary;
2729

2830
const results = await fetchBySymbols( symbols );
@@ -31,26 +33,40 @@ const getEntitySummary = async symbols => {
3133
docList.forEach( doc => {
3234

3335
const symbol = _.get( doc, 'symbol', '');
34-
const xref = {
35-
[DATASOURCES.GENECARDS] : symbol
36-
};
36+
3737
// Add database links
38+
const xrefLinks = [{
39+
"namespace": NS_GENECARDS,
40+
"uri": createUri( NS_GENECARDS, symbol )
41+
}, {
42+
"namespace": NS_HGNC_SYMBOL,
43+
"uri": createUri( NS_HGNC_SYMBOL, symbol )
44+
}];
45+
3846
if ( _.has( doc, 'entrez_id') ){
39-
xref[DATASOURCES.NCBIGENE] = _.get( doc, 'entrez_id');
47+
xrefLinks.push({
48+
"namespace": NS_NCBI_GENE,
49+
"uri": createUri( NS_NCBI_GENE, _.get( doc, 'entrez_id') )
50+
});
4051
}
52+
4153
if ( _.has( doc, 'uniprot_ids') ){
42-
xref[DATASOURCES.UNIPROT] = _.get( doc, 'uniprot_ids[0]', '');
54+
xrefLinks.push({
55+
"namespace": NS_UNIPROT,
56+
"uri": createUri( NS_UNIPROT, _.get( doc, 'uniprot_ids') )
57+
});
4358
}
59+
4460
const eSummary = new EntitySummary({
45-
dataSource: DATASOURCES.HGNC,
61+
namespace: NS_HGNC_SYMBOL,
4662
displayName: _.get( doc, 'name', ''),
47-
localID: symbol,
63+
localId: symbol,
4864
aliases: _.get( doc, 'alias_name', []),
4965
aliasIds:_.get( doc, 'alias_symbol', []),
50-
xref: xref
66+
xrefLinks: xrefLinks
5167
});
5268

53-
return summary[ symbol ] = eSummary;
69+
summary.push(eSummary);
5470
});
5571

5672
return summary;

src/server/external-services/ncbi.js

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
const { fetch } = require('../../util');
2-
const { NCBI_EUTILS_BASE_URL, PUB_CACHE_MAX_SIZE } = require('../../config');
2+
const { NCBI_EUTILS_BASE_URL, PUB_CACHE_MAX_SIZE, NS_GENECARDS, NS_HGNC_SYMBOL, NS_NCBI_GENE, IDENTIFIERS_URL } = require('../../config');
33
const { URLSearchParams } = require('url');
44
const QuickLRU = require('quick-lru');
55
const _ = require('lodash');
6-
const { EntitySummary, DATASOURCES } = require('../../models/entity/summary');
6+
const { EntitySummary } = require('../../models/entity/summary');
77
const logger = require('../logger');
88

99
const pubCache = new QuickLRU({ maxSize: PUB_CACHE_MAX_SIZE });
@@ -79,9 +79,11 @@ const fetchByGeneIds = ( geneIds ) => {
7979
});
8080
};
8181

82+
const createUri = ( namespace, localId ) => IDENTIFIERS_URL + '/' + namespace + '/' + localId;
83+
8284
const getEntitySummary = async ( uids ) => {
8385

84-
const summary = {};
86+
const summary = [];
8587
if ( _.isEmpty( uids ) ) return summary;
8688

8789
const results = await fetchByGeneIds( uids );
@@ -90,25 +92,35 @@ const getEntitySummary = async ( uids ) => {
9092
result.uids.forEach( uid => {
9193
if( _.has( result, uid['error'] ) ) return;
9294
const doc = result[ uid ];
93-
const xref = {};
95+
const xrefLinks = [];
9496

9597
// Fetch external database links first
96-
if ( _.has( doc, 'name' ) ){
97-
xref[DATASOURCES.HGNC] = _.get( doc, 'name' ,'');
98-
xref[DATASOURCES.GENECARDS] = _.get( doc, 'name', '');
98+
const localId = _.get( doc, 'name');
99+
if( localId ){
100+
[ NS_HGNC_SYMBOL, NS_GENECARDS ].forEach( namespace => {
101+
xrefLinks.push({
102+
"namespace": namespace,
103+
"uri": createUri( namespace, localId )
104+
});
105+
});
99106
}
107+
// push in NCBI xrefLink too
108+
xrefLinks.push({
109+
"namespace": NS_NCBI_GENE,
110+
"uri": createUri( NS_NCBI_GENE, uid )
111+
});
100112

101113
const eSummary = new EntitySummary({
102-
dataSource: DATASOURCES.NCBIGENE,
114+
namespace: NS_NCBI_GENE,
103115
displayName: _.get( doc, 'description', ''),
104-
localID: _.get( doc, 'uid', ''),
116+
localId: uid,
105117
description: _.get( doc, 'summary', ''),
106118
aliases: _.get( doc, 'otherdesignations', '').split('|'),
107119
aliasIds: _.get( doc, 'otheraliases', '').split(',').map( a => a.trim() ),
108-
xref: xref
120+
xrefLinks: xrefLinks
109121
});
110122

111-
return summary[ uid ] = eSummary;
123+
summary.push(eSummary);
112124
});
113125

114126
return summary;

src/server/external-services/uniprot.js

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const { fetch } = require('../../util');
2-
const { UNIPROT_API_BASE_URL } = require('../../config');
2+
const { UNIPROT_API_BASE_URL, NS_GENECARDS, NS_HGNC_SYMBOL, NS_NCBI_GENE, NS_UNIPROT, IDENTIFIERS_URL } = require('../../config');
33
const _ = require('lodash');
4-
const { EntitySummary, DATASOURCES } = require('../../models/entity/summary');
4+
const { EntitySummary } = require('../../models/entity/summary');
55
const logger = require('../logger');
66

77
//Could cache somewhere here.
@@ -18,39 +18,56 @@ const fetchByAccessions = ( accessions ) => {
1818
});
1919
};
2020

21+
const createUri = ( namespace, localId ) => IDENTIFIERS_URL + '/' + namespace + '/' + localId;
22+
2123
const getEntitySummary = async ( accessions ) => {
2224

23-
const summary = {};
25+
const summary = [];
2426
if ( _.isEmpty( accessions ) ) return summary;
2527

2628
const results = await fetchByAccessions( accessions );
2729
if ( _.has( results, 'errorMessage') ) return summary;
2830

2931
results.forEach( doc => {
3032

31-
// Fetch external database links first
32-
const xref = {};
33+
const accession = _.get( doc, 'accession', '');
34+
35+
// Create external database links first
36+
const xrefLinks = [{
37+
"namespace": NS_UNIPROT,
38+
"uri": createUri( NS_UNIPROT, accession )
39+
}];
3340
doc.dbReferences.forEach( xrf => {
34-
if ( xrf.type === 'GeneID' ) {
35-
xref[DATASOURCES.NCBIGENE] = _.get( xrf, 'id', '');
36-
}
37-
if ( xrf.type === 'HGNC' ) {
38-
xref[DATASOURCES.HGNC] = _.get( xrf, "properties['gene designation']");
39-
xref[DATASOURCES.GENECARDS] = _.get( xrf, "properties['gene designation']");
41+
switch ( xrf.type ){
42+
case 'HGNC':
43+
xrefLinks.push({
44+
"namespace": NS_GENECARDS,
45+
"uri": createUri( NS_GENECARDS, _.get( xrf, "properties['gene designation']" ) )
46+
});
47+
xrefLinks.push({
48+
"namespace": NS_HGNC_SYMBOL,
49+
"uri": createUri( NS_HGNC_SYMBOL, _.get( xrf, "properties['gene designation']" ) )
50+
});
51+
break;
52+
case 'GeneID':
53+
xrefLinks.push({
54+
"namespace": NS_NCBI_GENE,
55+
"uri": createUri( NS_NCBI_GENE, _.get( xrf, 'id', '') )
56+
});
57+
break;
4058
}
4159
});
42-
const accession = _.get( doc, 'accession', '');
4360
const eSummary = new EntitySummary({
44-
dataSource: DATASOURCES.UNIPROT,
61+
namespace: NS_UNIPROT,
4562
displayName: _.get( doc, 'protein.recommendedName.fullName.value', ''),
46-
localID: accession,
63+
localId: accession,
4764
description: _.get( doc, 'comments[0].text[0].value', ''),
4865
aliases: _.get( doc, 'protein.alternativeName', []).map( elt => _.get( elt, 'fullName.value') ),
4966
aliasIds: _.get( doc, 'protein.recommendedName.shortName', []).map( elt => _.get( elt, 'value') ),
50-
xref: xref
67+
xrefLinks: xrefLinks
5168
});
5269

53-
return summary[ accession ] = eSummary;
70+
summary.push(eSummary);
5471
});
5572

5673
return summary;

0 commit comments

Comments
 (0)