protvista-uniprot 4.6.2 → 4.6.4

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.
@@ -9,7 +9,15 @@ type ProcessedStructureData = {
9
9
  downloadLink?: string;
10
10
  sourceDBLink?: string;
11
11
  protvistaFeatureId: string;
12
+ amAnnotationsUrl?: string;
13
+ isoform?: TemplateResult;
12
14
  };
15
+ type IsoformIdSequence = [
16
+ {
17
+ isoformId: string;
18
+ sequence: string;
19
+ }
20
+ ];
13
21
  declare class ProtvistaUniprotStructure extends LitElement {
14
22
  accession?: string;
15
23
  sequence?: string;
@@ -18,6 +26,7 @@ declare class ProtvistaUniprotStructure extends LitElement {
18
26
  structureId?: string;
19
27
  metaInfo?: TemplateResult;
20
28
  colorTheme?: string;
29
+ isoforms?: IsoformIdSequence;
21
30
  private loading?;
22
31
  private alphamissenseAvailable?;
23
32
  private modelUrl;
@@ -47,16 +56,21 @@ declare class ProtvistaUniprotStructure extends LitElement {
47
56
  alphamissenseAvailable: {
48
57
  type: BooleanConstructor;
49
58
  };
59
+ isoforms: {
60
+ type: ObjectConstructor;
61
+ attribute: boolean;
62
+ };
50
63
  };
51
64
  connectedCallback(): Promise<void>;
52
65
  disconnectedCallback(): void;
53
66
  updated(): void;
54
67
  addStyles(): void;
55
68
  removeStyles(): void;
56
- onTableRowClick({ id, source, downloadLink, }: {
69
+ onTableRowClick({ id, source, downloadLink, amAnnotationsUrl, }: {
57
70
  id: string;
58
71
  source?: string;
59
72
  downloadLink?: string;
73
+ amAnnotationsUrl?: string;
60
74
  }): void;
61
75
  get cssStyle(): import('lit').CSSResult;
62
76
  /**
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.6.2",
4
+ "version": "4.6.4",
5
5
  "files": [
6
6
  "dist",
7
7
  "src"
@@ -19,6 +19,7 @@ const PDBLinks = [
19
19
  ];
20
20
  const alphaFoldLink = 'https://alphafold.ebi.ac.uk/entry/';
21
21
  const foldseekLink = `https://search.foldseek.com/search`;
22
+ const uniprotKBLink = 'https://www.uniprot.org/uniprotkb/';
22
23
 
23
24
  // Excluded sources from 3d-beacons are PDBe and AlphaFold models as we fetch them separately from their respective API's
24
25
  const providersFrom3DBeacons = [
@@ -123,6 +124,20 @@ type ProcessedStructureData = {
123
124
  downloadLink?: string;
124
125
  sourceDBLink?: string;
125
126
  protvistaFeatureId: string;
127
+ amAnnotationsUrl?: string;
128
+ isoform?: TemplateResult;
129
+ };
130
+
131
+ type IsoformIdSequence = [
132
+ {
133
+ isoformId: string;
134
+ sequence: string;
135
+ }
136
+ ];
137
+
138
+ const getIsoformNum = (s) => {
139
+ const match = s.match(/-(\d+)-F1$/);
140
+ return match ? Number(match[1]) : 0;
126
141
  };
127
142
 
128
143
  const processPDBData = (data: UniProtKBData): ProcessedStructureData[] =>
@@ -173,15 +188,41 @@ const processPDBData = (data: UniProtKBData): ProcessedStructureData[] =>
173
188
  )
174
189
  : [];
175
190
 
176
- const processAFData = (data: AlphaFoldPayload): ProcessedStructureData[] =>
177
- data.map((d) => ({
178
- id: d.modelEntityId,
179
- source: 'AlphaFold',
180
- method: 'Predicted',
181
- positions: `${d.sequenceStart}-${d.sequenceEnd}`,
182
- protvistaFeatureId: d.modelEntityId,
183
- downloadLink: d.pdbUrl,
184
- }));
191
+ const processAFData = (
192
+ data: AlphaFoldPayload,
193
+ accession?: string,
194
+ isoforms?: IsoformIdSequence,
195
+ canonicalSequence?: string,
196
+ ): ProcessedStructureData[] =>
197
+ data
198
+ .map((d) => {
199
+ const isoformMatch = isoforms?.find(
200
+ ({ sequence }) => d.sequence === sequence
201
+ );
202
+
203
+ const isoformElement = isoformMatch
204
+ ? html`<a
205
+ href="${uniprotKBLink}${accession}/entry#${isoformMatch.isoformId}"
206
+ >${isoformMatch.isoformId}
207
+ ${isoformMatch.sequence === canonicalSequence
208
+ ? '(Canonical)'
209
+ : ''}</a
210
+ >`
211
+ : null;
212
+ return {
213
+ id: d.modelEntityId,
214
+ source: 'AlphaFold',
215
+ method: 'Predicted',
216
+ positions: `${d.sequenceStart}-${d.sequenceEnd}`,
217
+ protvistaFeatureId: d.modelEntityId,
218
+ downloadLink: d.pdbUrl,
219
+ amAnnotationsUrl: d.amAnnotationsUrl,
220
+ isoform: isoformElement,
221
+ };
222
+ })
223
+ .sort((a, b) => {
224
+ return getIsoformNum(a.id) - getIsoformNum(b.id);
225
+ });
185
226
 
186
227
  const process3DBeaconsData = (
187
228
  data: BeaconsData,
@@ -307,6 +348,7 @@ class ProtvistaUniprotStructure extends LitElement {
307
348
  structureId?: string;
308
349
  metaInfo?: TemplateResult;
309
350
  colorTheme?: string;
351
+ isoforms?: IsoformIdSequence;
310
352
  private loading?: boolean;
311
353
  private alphamissenseAvailable?: boolean;
312
354
 
@@ -334,6 +376,7 @@ class ProtvistaUniprotStructure extends LitElement {
334
376
  loading: { type: Boolean },
335
377
  colorTheme: { type: String },
336
378
  alphamissenseAvailable: { type: Boolean },
379
+ isoforms: { type: Object, attribute: false },
337
380
  };
338
381
  }
339
382
 
@@ -362,17 +405,35 @@ class ProtvistaUniprotStructure extends LitElement {
362
405
 
363
406
  const pdbData = processPDBData(rawData[pdbUrl] || []);
364
407
  let afData = [];
365
- // Check if AF sequence matches UniProt sequence
366
- const alphaFoldSequenceMatch = rawData[alphaFoldUrl]?.filter(
367
- ({ sequence: afSequence }) =>
368
- rawData[pdbUrl]?.sequence?.value === afSequence ||
369
- this.sequence === afSequence
370
- );
371
- if (alphaFoldSequenceMatch?.length) {
372
- afData = processAFData(alphaFoldSequenceMatch);
373
- this.alphamissenseAvailable = alphaFoldSequenceMatch.some(
374
- (data) => data.amAnnotationsUrl
408
+
409
+ if (this.isoforms && rawData[alphaFoldUrl]?.length) {
410
+ // Include isoforms that are provided in the UniProt isoforms mapping and ignore the rest from AF payload that are out of sync with UniProt
411
+ const alphaFoldSequenceMatches = rawData[alphaFoldUrl]?.filter(
412
+ ({ sequence: afSequence }) =>
413
+ this.isoforms?.some(({ sequence }) => afSequence === sequence)
414
+ );
415
+
416
+ afData = processAFData(
417
+ alphaFoldSequenceMatches,
418
+ this.accession,
419
+ this.isoforms,
420
+ rawData[pdbUrl]?.sequence?.value
375
421
  );
422
+
423
+ this.alphamissenseAvailable = !!afData?.[0].amAnnotationsUrl;
424
+ } else {
425
+ // Check if AF sequence matches UniProt sequence
426
+ const alphaFoldSequenceMatch = rawData[alphaFoldUrl]?.filter(
427
+ ({ sequence: afSequence }) =>
428
+ rawData[pdbUrl]?.sequence?.value === afSequence ||
429
+ this.sequence === afSequence
430
+ );
431
+ if (alphaFoldSequenceMatch?.length) {
432
+ afData = processAFData(alphaFoldSequenceMatch);
433
+ this.alphamissenseAvailable = alphaFoldSequenceMatch.some(
434
+ (data) => data.amAnnotationsUrl
435
+ );
436
+ }
376
437
  }
377
438
 
378
439
  const beaconsData = process3DBeaconsData(
@@ -435,10 +496,12 @@ class ProtvistaUniprotStructure extends LitElement {
435
496
  id,
436
497
  source,
437
498
  downloadLink,
499
+ amAnnotationsUrl,
438
500
  }: {
439
501
  id: string;
440
502
  source?: string;
441
503
  downloadLink?: string;
504
+ amAnnotationsUrl?: string;
442
505
  }) {
443
506
  if (this.checksum || providersFrom3DBeacons.includes(source)) {
444
507
  this.modelUrl = downloadLink;
@@ -454,6 +517,7 @@ class ProtvistaUniprotStructure extends LitElement {
454
517
  this.modelUrl = undefined;
455
518
  if (this.structureId.startsWith('AF-')) {
456
519
  this.metaInfo = AFMetaInfo;
520
+ this.alphamissenseAvailable = !!amAnnotationsUrl;
457
521
  } else {
458
522
  this.metaInfo = undefined;
459
523
  }
@@ -591,6 +655,7 @@ class ProtvistaUniprotStructure extends LitElement {
591
655
  <tr>
592
656
  <th data-filter="source">Source</th>
593
657
  <th>Identifier</th>
658
+ ${this.isoforms ? html`<th>Isoform</th>` : ''}
594
659
  <th data-filter="method">Method</th>
595
660
  <th>Resolution</th>
596
661
  <th>Chain</th>
@@ -610,15 +675,23 @@ class ProtvistaUniprotStructure extends LitElement {
610
675
  positions,
611
676
  downloadLink,
612
677
  sourceDBLink,
678
+ isoform,
679
+ amAnnotationsUrl,
613
680
  }) => html`<tr
614
681
  data-id="${id}"
615
682
  @click="${() =>
616
- this.onTableRowClick({ id, source, downloadLink })}"
683
+ this.onTableRowClick({
684
+ id,
685
+ source,
686
+ downloadLink,
687
+ amAnnotationsUrl,
688
+ })}"
617
689
  >
618
690
  <td data-filter="source" data-filter-value="${source}">
619
691
  <strong>${source}</strong>
620
692
  </td>
621
693
  <td>${id}</td>
694
+ ${this.isoforms ? html`<td>${isoform}</td>` : ''}
622
695
  <td data-filter="method" data-filter-value="${method}">
623
696
  ${method}
624
697
  </td>