protvista-uniprot 4.6.1 → 4.6.2
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.
|
@@ -13,6 +13,7 @@ type ProcessedStructureData = {
|
|
|
13
13
|
declare class ProtvistaUniprotStructure extends LitElement {
|
|
14
14
|
accession?: string;
|
|
15
15
|
sequence?: string;
|
|
16
|
+
checksum?: string;
|
|
16
17
|
data?: ProcessedStructureData[];
|
|
17
18
|
structureId?: string;
|
|
18
19
|
metaInfo?: TemplateResult;
|
|
@@ -28,6 +29,9 @@ declare class ProtvistaUniprotStructure extends LitElement {
|
|
|
28
29
|
structureId: {
|
|
29
30
|
type: StringConstructor;
|
|
30
31
|
};
|
|
32
|
+
checksum: {
|
|
33
|
+
type: StringConstructor;
|
|
34
|
+
};
|
|
31
35
|
sequence: {
|
|
32
36
|
type: StringConstructor;
|
|
33
37
|
};
|
package/package.json
CHANGED
|
@@ -33,6 +33,7 @@ const providersFrom3DBeacons = [
|
|
|
33
33
|
];
|
|
34
34
|
|
|
35
35
|
const sourceMethods = new Map([
|
|
36
|
+
['AlphaFold DB', 'Predicted'],
|
|
36
37
|
['SWISS-MODEL', 'Modeling'],
|
|
37
38
|
['ModelArchive', 'Modeling'],
|
|
38
39
|
['PED', 'Modeling'],
|
|
@@ -63,7 +64,7 @@ type Sequence = {
|
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
type BeaconsData = {
|
|
66
|
-
uniprot_entry
|
|
67
|
+
uniprot_entry?: {
|
|
67
68
|
ac: string;
|
|
68
69
|
id: string;
|
|
69
70
|
uniprot_checksum: string;
|
|
@@ -71,6 +72,11 @@ type BeaconsData = {
|
|
|
71
72
|
segment_start: number;
|
|
72
73
|
segment_end: number;
|
|
73
74
|
};
|
|
75
|
+
entry?: {
|
|
76
|
+
sequence: string;
|
|
77
|
+
checksum: string;
|
|
78
|
+
checksum_type: string;
|
|
79
|
+
};
|
|
74
80
|
structures: {
|
|
75
81
|
summary: {
|
|
76
82
|
model_identifier: string;
|
|
@@ -120,49 +126,52 @@ type ProcessedStructureData = {
|
|
|
120
126
|
};
|
|
121
127
|
|
|
122
128
|
const processPDBData = (data: UniProtKBData): ProcessedStructureData[] =>
|
|
123
|
-
data.uniProtKBCrossReferences
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
129
|
+
data.uniProtKBCrossReferences
|
|
130
|
+
? data.uniProtKBCrossReferences
|
|
131
|
+
.filter((xref) => xref.database === 'PDB')
|
|
132
|
+
.sort((refA, refB) => refA.id.localeCompare(refB.id))
|
|
133
|
+
.map(({ id, properties }) => {
|
|
134
|
+
if (!properties) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const propertyMap = properties.reduce((acc, item) => {
|
|
139
|
+
acc[item.key] = item.value;
|
|
140
|
+
return acc;
|
|
141
|
+
}, {} as Record<string, string>);
|
|
142
|
+
|
|
143
|
+
const method = propertyMap['Method'];
|
|
144
|
+
const resolution = propertyMap['Resolution'];
|
|
145
|
+
const chains = propertyMap['Chains'];
|
|
146
|
+
|
|
147
|
+
let chain;
|
|
148
|
+
let positions;
|
|
149
|
+
if (chains) {
|
|
150
|
+
const tokens = chains.split('=');
|
|
151
|
+
if (tokens.length === 2) {
|
|
152
|
+
[chain, positions] = tokens;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const output: ProcessedStructureData = {
|
|
156
|
+
id,
|
|
157
|
+
source: 'PDB',
|
|
158
|
+
method,
|
|
159
|
+
resolution:
|
|
160
|
+
!resolution || resolution === '-' ? undefined : resolution,
|
|
161
|
+
downloadLink: `https://www.ebi.ac.uk/pdbe/entry-files/download/pdb${id.toLowerCase()}.ent`,
|
|
162
|
+
chain,
|
|
163
|
+
positions,
|
|
164
|
+
protvistaFeatureId: id,
|
|
165
|
+
};
|
|
166
|
+
return output;
|
|
167
|
+
})
|
|
168
|
+
.filter(
|
|
169
|
+
(
|
|
170
|
+
transformedItem: ProcessedStructureData | undefined
|
|
171
|
+
): transformedItem is ProcessedStructureData =>
|
|
172
|
+
transformedItem !== undefined
|
|
173
|
+
)
|
|
174
|
+
: [];
|
|
166
175
|
|
|
167
176
|
const processAFData = (data: AlphaFoldPayload): ProcessedStructureData[] =>
|
|
168
177
|
data.map((d) => ({
|
|
@@ -174,23 +183,55 @@ const processAFData = (data: AlphaFoldPayload): ProcessedStructureData[] =>
|
|
|
174
183
|
downloadLink: d.pdbUrl,
|
|
175
184
|
}));
|
|
176
185
|
|
|
177
|
-
const process3DBeaconsData = (
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
186
|
+
const process3DBeaconsData = (
|
|
187
|
+
data: BeaconsData,
|
|
188
|
+
accession: string | undefined,
|
|
189
|
+
checksum: string | undefined
|
|
190
|
+
): ProcessedStructureData[] => {
|
|
191
|
+
// If accession is provided without checksum, filter by whitelisted providers
|
|
192
|
+
const filterByProviders = !!accession && !checksum;
|
|
193
|
+
|
|
194
|
+
let structures = filterByProviders
|
|
195
|
+
? data?.structures?.filter(({ summary }) =>
|
|
196
|
+
providersFrom3DBeacons.includes(summary.provider)
|
|
197
|
+
)
|
|
198
|
+
: data?.structures?.sort(
|
|
199
|
+
(a, b) =>
|
|
200
|
+
b.summary.confidence_avg_local_score -
|
|
201
|
+
a.summary.confidence_avg_local_score
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
if (accession && checksum && structures) {
|
|
205
|
+
const matchIndex = structures.findIndex(({ summary }) =>
|
|
206
|
+
summary.model_identifier.includes(accession)
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
if (matchIndex !== -1) {
|
|
210
|
+
structures = [
|
|
211
|
+
structures[matchIndex],
|
|
212
|
+
...structures.slice(0, matchIndex),
|
|
213
|
+
...structures.slice(matchIndex + 1),
|
|
214
|
+
];
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
181
218
|
return (
|
|
182
|
-
|
|
183
|
-
id: summary
|
|
219
|
+
structures?.map(({ summary }) => ({
|
|
220
|
+
id: summary.model_identifier,
|
|
184
221
|
source: summary.provider,
|
|
185
222
|
method: sourceMethods.get(summary.provider),
|
|
186
|
-
positions: `${summary
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
223
|
+
positions: `${summary.uniprot_start || 1}-${
|
|
224
|
+
summary.uniprot_end || data.entry?.sequence.length
|
|
225
|
+
}`,
|
|
226
|
+
protvistaFeatureId: summary.model_identifier,
|
|
227
|
+
downloadLink: summary.model_url,
|
|
190
228
|
sourceDBLink:
|
|
191
229
|
summary.provider === 'isoform.io'
|
|
192
230
|
? 'https://www.isoform.io/home'
|
|
193
|
-
: summary
|
|
231
|
+
: summary.model_page_url,
|
|
232
|
+
chain:
|
|
233
|
+
summary.entities?.flatMap((entity) => entity.chain_ids).join(', ') ||
|
|
234
|
+
undefined,
|
|
194
235
|
})) || []
|
|
195
236
|
);
|
|
196
237
|
};
|
|
@@ -261,6 +302,7 @@ const styleId = 'protvista-styles';
|
|
|
261
302
|
class ProtvistaUniprotStructure extends LitElement {
|
|
262
303
|
accession?: string;
|
|
263
304
|
sequence?: string;
|
|
305
|
+
checksum?: string;
|
|
264
306
|
data?: ProcessedStructureData[];
|
|
265
307
|
structureId?: string;
|
|
266
308
|
metaInfo?: TemplateResult;
|
|
@@ -286,6 +328,7 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
286
328
|
return {
|
|
287
329
|
accession: { type: String },
|
|
288
330
|
structureId: { type: String },
|
|
331
|
+
checksum: { type: String },
|
|
289
332
|
sequence: { type: String },
|
|
290
333
|
data: { type: Object },
|
|
291
334
|
loading: { type: Boolean },
|
|
@@ -296,13 +339,23 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
296
339
|
|
|
297
340
|
async connectedCallback() {
|
|
298
341
|
super.connectedCallback();
|
|
299
|
-
if (!this.accession) return;
|
|
342
|
+
if (!this.accession && !this.checksum) return;
|
|
300
343
|
|
|
301
344
|
// We are showing PDBe models returned by UniProt's API as there is inconsistency between UniProt's recognised ones and 3d-beacons.
|
|
302
|
-
const pdbUrl =
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
345
|
+
const pdbUrl =
|
|
346
|
+
this.accession && !this.checksum
|
|
347
|
+
? `https://rest.uniprot.org/uniprotkb/${this.accession}`
|
|
348
|
+
: '';
|
|
349
|
+
// AlphaMissense predictions are only available in AF predictions endpoint
|
|
350
|
+
const alphaFoldUrl =
|
|
351
|
+
this.accession && !this.checksum
|
|
352
|
+
? `https://alphafold.ebi.ac.uk/api/prediction/${this.accession}`
|
|
353
|
+
: '';
|
|
354
|
+
// exclude_provider accepts only value hence 'pdbe' as majority of the models are from there if querying by accession
|
|
355
|
+
const beaconsUrl =
|
|
356
|
+
this.accession && !this.checksum
|
|
357
|
+
? `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/uniprot/summary/${this.accession}.json?exclude_provider=pdbe`
|
|
358
|
+
: `https://www.ebi.ac.uk/pdbe/pdbe-kb/3dbeacons/api/v2/sequence/?id=${this.checksum}&type=md5`;
|
|
306
359
|
|
|
307
360
|
const rawData = await fetchAll([pdbUrl, alphaFoldUrl, beaconsUrl]);
|
|
308
361
|
this.loading = false;
|
|
@@ -311,7 +364,9 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
311
364
|
let afData = [];
|
|
312
365
|
// Check if AF sequence matches UniProt sequence
|
|
313
366
|
const alphaFoldSequenceMatch = rawData[alphaFoldUrl]?.filter(
|
|
314
|
-
({ sequence: afSequence }) =>
|
|
367
|
+
({ sequence: afSequence }) =>
|
|
368
|
+
rawData[pdbUrl]?.sequence?.value === afSequence ||
|
|
369
|
+
this.sequence === afSequence
|
|
315
370
|
);
|
|
316
371
|
if (alphaFoldSequenceMatch?.length) {
|
|
317
372
|
afData = processAFData(alphaFoldSequenceMatch);
|
|
@@ -320,7 +375,11 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
320
375
|
);
|
|
321
376
|
}
|
|
322
377
|
|
|
323
|
-
const beaconsData = process3DBeaconsData(
|
|
378
|
+
const beaconsData = process3DBeaconsData(
|
|
379
|
+
rawData[beaconsUrl] || [],
|
|
380
|
+
this.accession,
|
|
381
|
+
this.checksum
|
|
382
|
+
);
|
|
324
383
|
|
|
325
384
|
// TODO: return if no data at all
|
|
326
385
|
// if (!payload) return;
|
|
@@ -341,7 +400,11 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
341
400
|
) as ProtvistaDatatable;
|
|
342
401
|
if (!protvistaDatatableElt?.selectedid && this.data?.[0]) {
|
|
343
402
|
// Select the first element in the table
|
|
344
|
-
this.onTableRowClick({
|
|
403
|
+
this.onTableRowClick({
|
|
404
|
+
id: this.data[0].id,
|
|
405
|
+
source: this.data[0].source,
|
|
406
|
+
downloadLink: this.data[0].downloadLink,
|
|
407
|
+
});
|
|
345
408
|
protvistaDatatableElt.selectedid = this.data[0].id;
|
|
346
409
|
}
|
|
347
410
|
}
|
|
@@ -377,12 +440,15 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
377
440
|
source?: string;
|
|
378
441
|
downloadLink?: string;
|
|
379
442
|
}) {
|
|
380
|
-
if (providersFrom3DBeacons.includes(source)) {
|
|
443
|
+
if (this.checksum || providersFrom3DBeacons.includes(source)) {
|
|
381
444
|
this.modelUrl = downloadLink;
|
|
382
445
|
// Reset the rest
|
|
383
446
|
this.structureId = undefined;
|
|
384
447
|
this.metaInfo = undefined;
|
|
385
448
|
this.colorTheme = 'alphafold';
|
|
449
|
+
if (source === 'AlphaFold DB') {
|
|
450
|
+
this.metaInfo = AFMetaInfo;
|
|
451
|
+
}
|
|
386
452
|
} else {
|
|
387
453
|
this.structureId = id;
|
|
388
454
|
this.modelUrl = undefined;
|
|
@@ -613,7 +679,8 @@ class ProtvistaUniprotStructure extends LitElement {
|
|
|
613
679
|
: html``}
|
|
614
680
|
${!this.data && !this.loading
|
|
615
681
|
? html`<div class="protvista-no-results">
|
|
616
|
-
No structure information available
|
|
682
|
+
No structure information available
|
|
683
|
+
${this.accession ? `for ${this.accession}` : ''}
|
|
617
684
|
</div>`
|
|
618
685
|
: html``}
|
|
619
686
|
</div>
|