protvista-uniprot 4.3.8 → 4.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/protvista-uniprot.mjs +14424 -14393
- package/dist/protvista-uniprot.mjs.map +1 -1
- package/dist/types/protvista-uniprot-structure.d.ts +7 -3
- package/package.json +2 -2
- package/src/config.ts +0 -61
- package/src/protvista-uniprot-structure.ts +173 -34
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { LitElement, TemplateResult } from 'lit';
|
|
2
2
|
type ProcessedStructureData = {
|
|
3
3
|
id: string;
|
|
4
|
-
source:
|
|
5
|
-
method
|
|
4
|
+
source: string;
|
|
5
|
+
method?: string;
|
|
6
6
|
resolution?: string;
|
|
7
7
|
chain?: string;
|
|
8
8
|
positions?: string;
|
|
9
9
|
downloadLink?: string;
|
|
10
|
+
sourceDBLink?: string;
|
|
10
11
|
protvistaFeatureId: string;
|
|
11
12
|
};
|
|
12
13
|
declare class ProtvistaUniprotStructure extends LitElement {
|
|
@@ -17,6 +18,7 @@ declare class ProtvistaUniprotStructure extends LitElement {
|
|
|
17
18
|
colorTheme?: string;
|
|
18
19
|
private loading?;
|
|
19
20
|
private alphamissenseAvailable?;
|
|
21
|
+
private modelUrl;
|
|
20
22
|
constructor();
|
|
21
23
|
static get properties(): {
|
|
22
24
|
accession: {
|
|
@@ -43,8 +45,10 @@ declare class ProtvistaUniprotStructure extends LitElement {
|
|
|
43
45
|
updated(): void;
|
|
44
46
|
addStyles(): void;
|
|
45
47
|
removeStyles(): void;
|
|
46
|
-
onTableRowClick({ id }: {
|
|
48
|
+
onTableRowClick({ id, source, downloadLink, }: {
|
|
47
49
|
id: string;
|
|
50
|
+
source?: string;
|
|
51
|
+
downloadLink?: string;
|
|
48
52
|
}): void;
|
|
49
53
|
get cssStyle(): import('lit').CSSResult;
|
|
50
54
|
/**
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "protvista-uniprot",
|
|
3
3
|
"description": "ProtVista tool for the UniProt website",
|
|
4
|
-
"version": "4.
|
|
4
|
+
"version": "4.4.1",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"src"
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"@nightingale-elements/nightingale-navigation": "5.6.0",
|
|
38
38
|
"@nightingale-elements/nightingale-sequence": "5.6.0",
|
|
39
39
|
"@nightingale-elements/nightingale-sequence-heatmap": "5.6.2",
|
|
40
|
-
"@nightingale-elements/nightingale-structure": "5.
|
|
40
|
+
"@nightingale-elements/nightingale-structure": "5.7.0",
|
|
41
41
|
"@nightingale-elements/nightingale-track-canvas": "5.6.0",
|
|
42
42
|
"@nightingale-elements/nightingale-variation": "5.6.0",
|
|
43
43
|
"color-hash": "2.0.2",
|
package/src/config.ts
CHANGED
|
@@ -851,67 +851,6 @@ const config: ProtvistaConfig = {
|
|
|
851
851
|
},
|
|
852
852
|
],
|
|
853
853
|
},
|
|
854
|
-
{
|
|
855
|
-
name: 'STRUCTURAL',
|
|
856
|
-
label: 'Structural features',
|
|
857
|
-
trackType: 'nightingale-track-canvas',
|
|
858
|
-
tracks: [
|
|
859
|
-
{
|
|
860
|
-
name: 'helix',
|
|
861
|
-
label: 'Helix',
|
|
862
|
-
filter: 'HELIX',
|
|
863
|
-
trackType: 'nightingale-track-canvas',
|
|
864
|
-
data: [
|
|
865
|
-
{
|
|
866
|
-
adapter: 'feature-adapter',
|
|
867
|
-
url: `${proteinsApiServices.features}{accession}`,
|
|
868
|
-
},
|
|
869
|
-
],
|
|
870
|
-
tooltip: 'The positions of experimentally determined helical regions',
|
|
871
|
-
},
|
|
872
|
-
{
|
|
873
|
-
name: 'strand',
|
|
874
|
-
label: 'Beta strand',
|
|
875
|
-
filter: 'STRAND',
|
|
876
|
-
trackType: 'nightingale-track-canvas',
|
|
877
|
-
data: [
|
|
878
|
-
{
|
|
879
|
-
adapter: 'feature-adapter',
|
|
880
|
-
url: `${proteinsApiServices.features}{accession}`,
|
|
881
|
-
},
|
|
882
|
-
],
|
|
883
|
-
tooltip: 'The positions of experimentally determined beta strands',
|
|
884
|
-
},
|
|
885
|
-
{
|
|
886
|
-
name: 'turn',
|
|
887
|
-
label: 'Turn',
|
|
888
|
-
filter: 'TURN',
|
|
889
|
-
trackType: 'nightingale-track-canvas',
|
|
890
|
-
data: [
|
|
891
|
-
{
|
|
892
|
-
adapter: 'feature-adapter',
|
|
893
|
-
url: `${proteinsApiServices.features}{accession}`,
|
|
894
|
-
},
|
|
895
|
-
],
|
|
896
|
-
tooltip:
|
|
897
|
-
'The positions of experimentally determined hydrogen-bonded turns',
|
|
898
|
-
},
|
|
899
|
-
{
|
|
900
|
-
name: 'coiled',
|
|
901
|
-
label: 'Coiled coil',
|
|
902
|
-
filter: 'COILED',
|
|
903
|
-
trackType: 'nightingale-track-canvas',
|
|
904
|
-
data: [
|
|
905
|
-
{
|
|
906
|
-
adapter: 'feature-adapter',
|
|
907
|
-
url: `${proteinsApiServices.features}{accession}`,
|
|
908
|
-
},
|
|
909
|
-
],
|
|
910
|
-
tooltip:
|
|
911
|
-
'Coiled coils are built by two or more alpha-helices that wind around each other to form a supercoil',
|
|
912
|
-
},
|
|
913
|
-
],
|
|
914
|
-
},
|
|
915
854
|
],
|
|
916
855
|
};
|
|
917
856
|
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { LitElement, html, svg, TemplateResult, css, nothing } from 'lit';
|
|
2
|
-
import { customElement } from 'lit/decorators.js';
|
|
2
|
+
import { customElement, state } from 'lit/decorators.js';
|
|
3
3
|
import { unsafeHTML } from 'lit/directives/unsafe-html.js';
|
|
4
4
|
import NightingaleStructure, {
|
|
5
5
|
PredictionData,
|
|
6
|
-
StructureData,
|
|
7
6
|
} from '@nightingale-elements/nightingale-structure';
|
|
8
7
|
import ProtvistaDatatable from 'protvista-datatable';
|
|
9
8
|
import { fetchAll, loadComponent } from './utils';
|
|
@@ -21,26 +20,111 @@ const PDBLinks = [
|
|
|
21
20
|
const alphaFoldLink = 'https://alphafold.ebi.ac.uk/entry/';
|
|
22
21
|
const foldseekLink = `https://search.foldseek.com/search`;
|
|
23
22
|
|
|
23
|
+
// Excluded sources from 3d-beacons are PDBe and AlphaFold models as we fetch them separately from their respective API's
|
|
24
|
+
const providersFrom3DBeacons = [
|
|
25
|
+
'SWISS-MODEL',
|
|
26
|
+
'ModelArchive',
|
|
27
|
+
'PED',
|
|
28
|
+
'SASBDB',
|
|
29
|
+
'isoform.io',
|
|
30
|
+
'AlphaFill',
|
|
31
|
+
'HEGELAB',
|
|
32
|
+
'levylab',
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
type UniProtKBData = {
|
|
36
|
+
uniProtKBCrossReferences: UniProtKBCrossReference[];
|
|
37
|
+
sequence: Sequence;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
type UniProtKBCrossReference = {
|
|
41
|
+
database: string;
|
|
42
|
+
id: string;
|
|
43
|
+
properties: Record<string, string>[];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
type Sequence = {
|
|
47
|
+
value: string;
|
|
48
|
+
length: number;
|
|
49
|
+
molWeight: number;
|
|
50
|
+
crc64: string;
|
|
51
|
+
md5: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
type BeaconsData = {
|
|
55
|
+
uniprot_entry: {
|
|
56
|
+
ac: string;
|
|
57
|
+
id: string;
|
|
58
|
+
uniprot_checksum: string;
|
|
59
|
+
sequence_length: number;
|
|
60
|
+
segment_start: number;
|
|
61
|
+
segment_end: number;
|
|
62
|
+
};
|
|
63
|
+
structures: {
|
|
64
|
+
summary: {
|
|
65
|
+
model_identifier: string;
|
|
66
|
+
model_category: string;
|
|
67
|
+
model_url: string;
|
|
68
|
+
model_format: string;
|
|
69
|
+
model_type: string | null;
|
|
70
|
+
model_page_url: string;
|
|
71
|
+
provider: string;
|
|
72
|
+
number_of_conformers: number | null;
|
|
73
|
+
ensemble_sample_url: string | null;
|
|
74
|
+
ensemble_sample_format: string | null;
|
|
75
|
+
created: string;
|
|
76
|
+
sequence_identity: number;
|
|
77
|
+
uniprot_start: number;
|
|
78
|
+
uniprot_end: number;
|
|
79
|
+
coverage: number;
|
|
80
|
+
experimental_method: string | null;
|
|
81
|
+
resolution: number | null;
|
|
82
|
+
confidence_type: string;
|
|
83
|
+
confidence_version: string | null;
|
|
84
|
+
confidence_avg_local_score: number;
|
|
85
|
+
oligomeric_state: string | null;
|
|
86
|
+
preferred_assembly_id: string | null;
|
|
87
|
+
entities: {
|
|
88
|
+
entity_type: string;
|
|
89
|
+
entity_poly_type: string;
|
|
90
|
+
identifier: string;
|
|
91
|
+
identifier_category: string;
|
|
92
|
+
description: string;
|
|
93
|
+
chain_ids: string[];
|
|
94
|
+
}[];
|
|
95
|
+
};
|
|
96
|
+
}[];
|
|
97
|
+
};
|
|
98
|
+
|
|
24
99
|
type ProcessedStructureData = {
|
|
25
100
|
id: string;
|
|
26
|
-
source:
|
|
27
|
-
method
|
|
101
|
+
source: string;
|
|
102
|
+
method?: string;
|
|
28
103
|
resolution?: string;
|
|
29
104
|
chain?: string;
|
|
30
105
|
positions?: string;
|
|
31
106
|
downloadLink?: string;
|
|
107
|
+
sourceDBLink?: string;
|
|
32
108
|
protvistaFeatureId: string;
|
|
33
109
|
};
|
|
34
110
|
|
|
35
|
-
const processPDBData = (data:
|
|
36
|
-
data.
|
|
37
|
-
.filter((xref) => xref.
|
|
111
|
+
const processPDBData = (data: UniProtKBData): ProcessedStructureData[] =>
|
|
112
|
+
data.uniProtKBCrossReferences
|
|
113
|
+
.filter((xref) => xref.database === 'PDB')
|
|
38
114
|
.sort((refA, refB) => refA.id.localeCompare(refB.id))
|
|
39
115
|
.map(({ id, properties }) => {
|
|
40
116
|
if (!properties) {
|
|
41
117
|
return;
|
|
42
118
|
}
|
|
43
|
-
|
|
119
|
+
|
|
120
|
+
const propertyMap = properties.reduce((acc, item) => {
|
|
121
|
+
acc[item.key] = item.value;
|
|
122
|
+
return acc;
|
|
123
|
+
}, {} as Record<string, string>);
|
|
124
|
+
|
|
125
|
+
const method = propertyMap['Method'];
|
|
126
|
+
const resolution = propertyMap['Resolution'];
|
|
127
|
+
const chains = propertyMap['Chains'];
|
|
44
128
|
|
|
45
129
|
let chain;
|
|
46
130
|
let positions;
|
|
@@ -79,6 +163,20 @@ const processAFData = (data: PredictionData[]): ProcessedStructureData[] =>
|
|
|
79
163
|
downloadLink: d.pdbUrl,
|
|
80
164
|
}));
|
|
81
165
|
|
|
166
|
+
const process3DBeaconsData = (data: BeaconsData): ProcessedStructureData[] => {
|
|
167
|
+
const otherStructures = data.structures.filter(({ summary }) =>
|
|
168
|
+
providersFrom3DBeacons.includes(summary.provider)
|
|
169
|
+
);
|
|
170
|
+
return otherStructures.map(({ summary }) => ({
|
|
171
|
+
id: summary['model_identifier'],
|
|
172
|
+
source: summary.provider,
|
|
173
|
+
positions: `${summary['uniprot_start']}-${summary['uniprot_end']}`,
|
|
174
|
+
protvistaFeatureId: summary['model_identifier'],
|
|
175
|
+
downloadLink: summary['model_url'],
|
|
176
|
+
sourceDBLink: summary['model_page_url'],
|
|
177
|
+
}));
|
|
178
|
+
};
|
|
179
|
+
|
|
82
180
|
const AFMetaInfo = html`
|
|
83
181
|
<strong>Model Confidence:</strong>
|
|
84
182
|
<ul class="no-bullet">
|
|
@@ -151,6 +249,9 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
151
249
|
private loading?: boolean;
|
|
152
250
|
private alphamissenseAvailable?: boolean;
|
|
153
251
|
|
|
252
|
+
@state()
|
|
253
|
+
private modelUrl = '';
|
|
254
|
+
|
|
154
255
|
constructor() {
|
|
155
256
|
super();
|
|
156
257
|
loadComponent('nightingale-structure', NightingaleStructure);
|
|
@@ -176,22 +277,34 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
176
277
|
async connectedCallback() {
|
|
177
278
|
super.connectedCallback();
|
|
178
279
|
if (!this.accession) return;
|
|
179
|
-
// https://www.ebi.ac.uk/pdbe/api/mappings/best_structures/${this.accession}
|
|
180
|
-
const pdbUrl = `https://www.ebi.ac.uk/proteins/api/proteins/${this.accession}`;
|
|
181
|
-
const alphaFoldURl = `https://alphafold.ebi.ac.uk/api/prediction/${this.accession}`;
|
|
182
280
|
|
|
183
|
-
|
|
281
|
+
// We are showing PDBe models returned by UniProt's API as there is inconsistency between UniProt's recognised ones and 3d-beacons.
|
|
282
|
+
const pdbUrl = `https://rest.uniprot.org/uniprotkb/${this.accession}`;
|
|
283
|
+
const alphaFoldUrl = `https://alphafold.ebi.ac.uk/api/prediction/${this.accession}`;
|
|
284
|
+
// exclude_provider accepts only value hence 'pdbe' as majority of the models are from there.
|
|
285
|
+
const beaconsUrl = `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${this.accession}.json?exclude_provider=pdbe`;
|
|
184
286
|
|
|
287
|
+
const rawData = await fetchAll([pdbUrl, alphaFoldUrl, beaconsUrl]);
|
|
185
288
|
this.loading = false;
|
|
289
|
+
|
|
290
|
+
const pdbData = processPDBData(rawData[pdbUrl] || []);
|
|
291
|
+
let afData = [];
|
|
292
|
+
// Check if AF sequence matches UniProt sequence
|
|
293
|
+
if (
|
|
294
|
+
rawData[pdbUrl].sequence?.value === rawData[alphaFoldUrl][0]?.sequence
|
|
295
|
+
) {
|
|
296
|
+
afData = processAFData(rawData[alphaFoldUrl] || []);
|
|
297
|
+
}
|
|
298
|
+
const beaconsData = process3DBeaconsData(rawData[beaconsUrl] || []);
|
|
299
|
+
|
|
186
300
|
// TODO: return if no data at all
|
|
187
301
|
// if (!payload) return;
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
const data = [...pdbData, ...afData];
|
|
302
|
+
|
|
303
|
+
const data = [...pdbData, ...afData, ...beaconsData];
|
|
191
304
|
if (!data || !data.length) return;
|
|
192
305
|
|
|
193
306
|
this.data = data;
|
|
194
|
-
this.alphamissenseAvailable = rawData[
|
|
307
|
+
this.alphamissenseAvailable = rawData[alphaFoldUrl].some(
|
|
195
308
|
(data) => data.amAnnotationsUrl
|
|
196
309
|
);
|
|
197
310
|
}
|
|
@@ -233,12 +346,25 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
233
346
|
}
|
|
234
347
|
}
|
|
235
348
|
|
|
236
|
-
onTableRowClick({
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
349
|
+
onTableRowClick({
|
|
350
|
+
id,
|
|
351
|
+
source,
|
|
352
|
+
downloadLink,
|
|
353
|
+
}: {
|
|
354
|
+
id: string;
|
|
355
|
+
source?: string;
|
|
356
|
+
downloadLink?: string;
|
|
357
|
+
}) {
|
|
358
|
+
if (providersFrom3DBeacons.includes(source)) {
|
|
359
|
+
this.modelUrl = downloadLink;
|
|
360
|
+
this.structureId = undefined;
|
|
240
361
|
} else {
|
|
241
|
-
this.
|
|
362
|
+
this.structureId = id;
|
|
363
|
+
if (this.structureId.startsWith('AF-')) {
|
|
364
|
+
this.metaInfo = AFMetaInfo;
|
|
365
|
+
} else {
|
|
366
|
+
this.metaInfo = undefined;
|
|
367
|
+
}
|
|
242
368
|
}
|
|
243
369
|
}
|
|
244
370
|
|
|
@@ -358,7 +484,10 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
358
484
|
protein-accession=${this.accession}
|
|
359
485
|
color-theme=${this.colorTheme}
|
|
360
486
|
></nightingale-structure>`
|
|
361
|
-
: html
|
|
487
|
+
: html`<nightingale-structure
|
|
488
|
+
model-url=${this.modelUrl}
|
|
489
|
+
color-theme=${this.colorTheme}
|
|
490
|
+
></nightingale-structure>`}
|
|
362
491
|
</div>
|
|
363
492
|
<div class="protvista-uniprot-structure__table">
|
|
364
493
|
${this.data && this.data.length
|
|
@@ -386,9 +515,11 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
386
515
|
chain,
|
|
387
516
|
positions,
|
|
388
517
|
downloadLink,
|
|
518
|
+
sourceDBLink,
|
|
389
519
|
}) => html`<tr
|
|
390
520
|
data-id="${id}"
|
|
391
|
-
@click="${() =>
|
|
521
|
+
@click="${() =>
|
|
522
|
+
this.onTableRowClick({ id, source, downloadLink })}"
|
|
392
523
|
>
|
|
393
524
|
<td data-filter="source" data-filter-value="${source}">
|
|
394
525
|
<strong>${source}</strong>
|
|
@@ -415,23 +546,31 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
415
546
|
(prev, curr) => html` ${prev} · ${curr} `
|
|
416
547
|
)}
|
|
417
548
|
`
|
|
418
|
-
:
|
|
549
|
+
: ``}
|
|
550
|
+
${source === 'AlphaFold'
|
|
551
|
+
? html`<a href="${alphaFoldLink}${this.accession}"
|
|
419
552
|
>AlphaFold</a
|
|
420
|
-
>`
|
|
553
|
+
>`
|
|
554
|
+
: ``}
|
|
555
|
+
${sourceDBLink
|
|
556
|
+
? html`<a href="${sourceDBLink}">${source}</a>`
|
|
557
|
+
: ``}
|
|
421
558
|
</td>
|
|
422
559
|
<td>
|
|
423
560
|
${downloadLink
|
|
424
561
|
? html`<a
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
·
|
|
430
|
-
${foldseekURL(
|
|
431
|
-
source === 'PDB' ? id : this.accession,
|
|
432
|
-
source === 'PDB' ? 'PDB' : 'AlphaFoldDB'
|
|
433
|
-
)}`
|
|
562
|
+
href="${downloadLink}"
|
|
563
|
+
class="download-link"
|
|
564
|
+
>${svg`${unsafeHTML(downloadIcon)}`}</a
|
|
565
|
+
> `
|
|
434
566
|
: ''}
|
|
567
|
+
${source === 'PDB' || source === 'AlphaFold'
|
|
568
|
+
? html`·
|
|
569
|
+
${foldseekURL(
|
|
570
|
+
source === 'PDB' ? id : this.accession,
|
|
571
|
+
source === 'PDB' ? 'PDB' : 'AlphaFoldDB'
|
|
572
|
+
)}`
|
|
573
|
+
: ``}
|
|
435
574
|
</td>
|
|
436
575
|
</tr>`
|
|
437
576
|
)}
|