protvista-uniprot 4.6.2 → 4.6.3

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.3",
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,39 @@ 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 isCanonical = isoformMatch.sequence === canonicalSequence;
204
+ const isoformElement = isoformMatch
205
+ ? html`<a
206
+ href="${uniprotKBLink}${accession}/entry#${isoformMatch.isoformId}"
207
+ >${isoformMatch.isoformId} ${isCanonical ? '(Canonical)' : ''}</a
208
+ >`
209
+ : null;
210
+ return {
211
+ id: d.modelEntityId,
212
+ source: 'AlphaFold',
213
+ method: 'Predicted',
214
+ positions: `${d.sequenceStart}-${d.sequenceEnd}`,
215
+ protvistaFeatureId: d.modelEntityId,
216
+ downloadLink: d.pdbUrl,
217
+ amAnnotationsUrl: d.amAnnotationsUrl,
218
+ isoform: isoformElement,
219
+ };
220
+ })
221
+ .sort((a, b) => {
222
+ return getIsoformNum(a.id) - getIsoformNum(b.id);
223
+ });
185
224
 
186
225
  const process3DBeaconsData = (
187
226
  data: BeaconsData,
@@ -307,6 +346,7 @@ class ProtvistaUniprotStructure extends LitElement {
307
346
  structureId?: string;
308
347
  metaInfo?: TemplateResult;
309
348
  colorTheme?: string;
349
+ isoforms?: IsoformIdSequence;
310
350
  private loading?: boolean;
311
351
  private alphamissenseAvailable?: boolean;
312
352
 
@@ -334,6 +374,7 @@ class ProtvistaUniprotStructure extends LitElement {
334
374
  loading: { type: Boolean },
335
375
  colorTheme: { type: String },
336
376
  alphamissenseAvailable: { type: Boolean },
377
+ isoforms: { type: Object, attribute: false },
337
378
  };
338
379
  }
339
380
 
@@ -362,17 +403,35 @@ class ProtvistaUniprotStructure extends LitElement {
362
403
 
363
404
  const pdbData = processPDBData(rawData[pdbUrl] || []);
364
405
  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
406
+
407
+ if (this.isoforms && rawData[alphaFoldUrl]?.length) {
408
+ // Include isoforms that are provided in the UniProt isoforms mapping and ignore the rest from AF payload that are out of sync with UniProt
409
+ const alphaFoldSequenceMatches = rawData[alphaFoldUrl]?.filter(
410
+ ({ sequence: afSequence }) =>
411
+ this.isoforms?.some(({ sequence }) => afSequence === sequence)
412
+ );
413
+
414
+ afData = processAFData(
415
+ alphaFoldSequenceMatches,
416
+ this.accession,
417
+ this.isoforms,
418
+ rawData[pdbUrl]?.sequence?.value
375
419
  );
420
+
421
+ this.alphamissenseAvailable = !!afData?.[0].amAnnotationsUrl;
422
+ } else {
423
+ // Check if AF sequence matches UniProt sequence
424
+ const alphaFoldSequenceMatch = rawData[alphaFoldUrl]?.filter(
425
+ ({ sequence: afSequence }) =>
426
+ rawData[pdbUrl]?.sequence?.value === afSequence ||
427
+ this.sequence === afSequence
428
+ );
429
+ if (alphaFoldSequenceMatch?.length) {
430
+ afData = processAFData(alphaFoldSequenceMatch);
431
+ this.alphamissenseAvailable = alphaFoldSequenceMatch.some(
432
+ (data) => data.amAnnotationsUrl
433
+ );
434
+ }
376
435
  }
377
436
 
378
437
  const beaconsData = process3DBeaconsData(
@@ -435,10 +494,12 @@ class ProtvistaUniprotStructure extends LitElement {
435
494
  id,
436
495
  source,
437
496
  downloadLink,
497
+ amAnnotationsUrl,
438
498
  }: {
439
499
  id: string;
440
500
  source?: string;
441
501
  downloadLink?: string;
502
+ amAnnotationsUrl?: string;
442
503
  }) {
443
504
  if (this.checksum || providersFrom3DBeacons.includes(source)) {
444
505
  this.modelUrl = downloadLink;
@@ -454,6 +515,7 @@ class ProtvistaUniprotStructure extends LitElement {
454
515
  this.modelUrl = undefined;
455
516
  if (this.structureId.startsWith('AF-')) {
456
517
  this.metaInfo = AFMetaInfo;
518
+ this.alphamissenseAvailable = !!amAnnotationsUrl;
457
519
  } else {
458
520
  this.metaInfo = undefined;
459
521
  }
@@ -591,6 +653,7 @@ class ProtvistaUniprotStructure extends LitElement {
591
653
  <tr>
592
654
  <th data-filter="source">Source</th>
593
655
  <th>Identifier</th>
656
+ ${this.isoforms ? html`<th>Isoform</th>` : ''}
594
657
  <th data-filter="method">Method</th>
595
658
  <th>Resolution</th>
596
659
  <th>Chain</th>
@@ -610,15 +673,23 @@ class ProtvistaUniprotStructure extends LitElement {
610
673
  positions,
611
674
  downloadLink,
612
675
  sourceDBLink,
676
+ isoform,
677
+ amAnnotationsUrl,
613
678
  }) => html`<tr
614
679
  data-id="${id}"
615
680
  @click="${() =>
616
- this.onTableRowClick({ id, source, downloadLink })}"
681
+ this.onTableRowClick({
682
+ id,
683
+ source,
684
+ downloadLink,
685
+ amAnnotationsUrl,
686
+ })}"
617
687
  >
618
688
  <td data-filter="source" data-filter-value="${source}">
619
689
  <strong>${source}</strong>
620
690
  </td>
621
691
  <td>${id}</td>
692
+ ${this.isoforms ? html`<td>${isoform}</td>` : ''}
622
693
  <td data-filter="method" data-filter-value="${method}">
623
694
  ${method}
624
695
  </td>