p2s_mapper 1.4.0 → 2.1.0
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/README.md +220 -39
- package/dist/alignmentQuality.d.ts +5 -5
- package/dist/alphaFoldModels.d.ts +4 -4
- package/dist/alphaFoldModels.js +4 -4
- package/dist/chooseMappedEntity.d.ts +11 -13
- package/dist/chooseMappedEntity.js +9 -12
- package/dist/chooseMappedEntity.js.map +1 -1
- package/dist/coordinates.d.ts +19 -19
- package/dist/coordinates.js.map +1 -1
- package/dist/dbIds.d.ts +1 -2
- package/dist/extractPerResidueConfidence.d.ts +1 -2
- package/dist/extractStructureSequences.d.ts +26 -34
- package/dist/extractStructureSequences.js +2 -2
- package/dist/extractStructureSequences.js.map +1 -1
- package/dist/fetchUtils.d.ts +7 -7
- package/dist/fetchUtils.js +26 -8
- package/dist/fetchUtils.js.map +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +2 -4
- package/dist/index.js.map +1 -1
- package/dist/isoformRanking.d.ts +4 -1
- package/dist/mappings.d.ts +9 -12
- package/dist/mappings.js +4 -5
- package/dist/mappings.js.map +1 -1
- package/dist/pairwiseAlignment.d.ts +5 -4
- package/dist/pairwiseAlignment.js +9 -7
- package/dist/pairwiseAlignment.js.map +1 -1
- package/dist/pdbEntry.d.ts +32 -0
- package/dist/pdbEntry.js +182 -0
- package/dist/pdbEntry.js.map +1 -0
- package/dist/pdbUniProtMapping.d.ts +14 -39
- package/dist/pdbUniProtMapping.js +22 -140
- package/dist/pdbUniProtMapping.js.map +1 -1
- package/dist/structureFormat.d.ts +11 -18
- package/dist/structureFormat.js +4 -6
- package/dist/structureFormat.js.map +1 -1
- package/dist/structureSources.d.ts +37 -13
- package/dist/structureSources.js +144 -57
- package/dist/structureSources.js.map +1 -1
- package/dist/structureUrls.d.ts +13 -16
- package/dist/structureUrls.js +25 -23
- package/dist/structureUrls.js.map +1 -1
- package/dist/types.d.ts +2 -5
- package/dist/types.js +2 -5
- package/dist/types.js.map +1 -1
- package/dist/uniProtSearch.js +3 -8
- package/dist/uniProtSearch.js.map +1 -1
- package/esm/alignmentQuality.d.ts +5 -5
- package/esm/alphaFoldModels.d.ts +4 -4
- package/esm/alphaFoldModels.js +4 -4
- package/esm/chooseMappedEntity.d.ts +11 -13
- package/esm/chooseMappedEntity.js +9 -12
- package/esm/chooseMappedEntity.js.map +1 -1
- package/esm/coordinates.d.ts +19 -19
- package/esm/coordinates.js.map +1 -1
- package/esm/dbIds.d.ts +1 -2
- package/esm/extractPerResidueConfidence.d.ts +1 -2
- package/esm/extractStructureSequences.d.ts +26 -34
- package/esm/extractStructureSequences.js +2 -2
- package/esm/extractStructureSequences.js.map +1 -1
- package/esm/fetchUtils.d.ts +7 -7
- package/esm/fetchUtils.js +26 -8
- package/esm/fetchUtils.js.map +1 -1
- package/esm/index.d.ts +1 -3
- package/esm/index.js +2 -4
- package/esm/index.js.map +1 -1
- package/esm/isoformRanking.d.ts +4 -1
- package/esm/mappings.d.ts +9 -12
- package/esm/mappings.js +4 -5
- package/esm/mappings.js.map +1 -1
- package/esm/pairwiseAlignment.d.ts +5 -4
- package/esm/pairwiseAlignment.js +7 -5
- package/esm/pairwiseAlignment.js.map +1 -1
- package/esm/pdbEntry.d.ts +32 -0
- package/esm/pdbEntry.js +174 -0
- package/esm/pdbEntry.js.map +1 -0
- package/esm/pdbUniProtMapping.d.ts +14 -39
- package/esm/pdbUniProtMapping.js +22 -137
- package/esm/pdbUniProtMapping.js.map +1 -1
- package/esm/structureFormat.d.ts +11 -18
- package/esm/structureFormat.js +4 -6
- package/esm/structureFormat.js.map +1 -1
- package/esm/structureSources.d.ts +37 -13
- package/esm/structureSources.js +139 -55
- package/esm/structureSources.js.map +1 -1
- package/esm/structureUrls.d.ts +13 -16
- package/esm/structureUrls.js +23 -23
- package/esm/structureUrls.js.map +1 -1
- package/esm/types.d.ts +2 -5
- package/esm/types.js +2 -5
- package/esm/types.js.map +1 -1
- package/esm/uniProtSearch.js +3 -8
- package/esm/uniProtSearch.js.map +1 -1
- package/package.json +3 -2
- package/src/alignmentQuality.ts +5 -5
- package/src/alphaFoldModels.ts +4 -4
- package/src/chooseMappedEntity.ts +12 -15
- package/src/coordinates.ts +14 -17
- package/src/dbIds.ts +1 -1
- package/src/extractPerResidueConfidence.ts +1 -1
- package/src/extractStructureSequences.ts +26 -33
- package/src/fetchUtils.ts +30 -8
- package/src/index.ts +2 -4
- package/src/isoformRanking.ts +4 -4
- package/src/mappings.ts +9 -12
- package/src/pairwiseAlignment.ts +12 -9
- package/src/pdbEntry.ts +240 -0
- package/src/pdbUniProtMapping.ts +25 -164
- package/src/structureFormat.ts +11 -18
- package/src/structureSources.ts +194 -70
- package/src/structureUrls.ts +25 -23
- package/src/types.ts +2 -5
- package/src/uniProtSearch.ts +3 -8
- package/dist/pdbeBestStructures.d.ts +0 -23
- package/dist/pdbeBestStructures.js +0 -79
- package/dist/pdbeBestStructures.js.map +0 -1
- package/dist/pdbeEntryMolecules.d.ts +0 -7
- package/dist/pdbeEntryMolecules.js +0 -39
- package/dist/pdbeEntryMolecules.js.map +0 -1
- package/dist/siftsNumbering.d.ts +0 -23
- package/dist/siftsNumbering.js +0 -44
- package/dist/siftsNumbering.js.map +0 -1
- package/esm/pdbeBestStructures.d.ts +0 -23
- package/esm/pdbeBestStructures.js +0 -73
- package/esm/pdbeBestStructures.js.map +0 -1
- package/esm/pdbeEntryMolecules.d.ts +0 -7
- package/esm/pdbeEntryMolecules.js +0 -35
- package/esm/pdbeEntryMolecules.js.map +0 -1
- package/esm/siftsNumbering.d.ts +0 -23
- package/esm/siftsNumbering.js +0 -40
- package/esm/siftsNumbering.js.map +0 -1
- package/src/pdbeBestStructures.ts +0 -94
- package/src/pdbeEntryMolecules.ts +0 -37
- package/src/siftsNumbering.ts +0 -61
package/esm/pdbUniProtMapping.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// UniProt <-> PDB residue mapping.
|
|
2
2
|
//
|
|
3
3
|
// UniProt feature coordinates are positions in the UniProt canonical sequence.
|
|
4
4
|
// For an AlphaFold model that *is* the structure's own sequence, so a feature at
|
|
@@ -6,134 +6,19 @@
|
|
|
6
6
|
// entry it is not: the deposited construct is usually a fragment, often with
|
|
7
7
|
// tags or engineered residues, so the two numberings differ by a per-segment
|
|
8
8
|
// offset (1TUP's p53 chain starts at UniProt 94; 6VXX's spike SEQRES 33 is
|
|
9
|
-
// UniProt 14).
|
|
10
|
-
//
|
|
9
|
+
// UniProt 14). The entry's own UniProt alignment, which `fetchPdbEntry` reads
|
|
10
|
+
// from RCSB, is the authority on that correspondence.
|
|
11
11
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// position + 1 (see applyLociInteractivity.ts for the other place that boundary
|
|
15
|
-
// is crossed).
|
|
16
|
-
import { isDefinitiveFailure, jsonfetch, timeout } from "./fetchUtils.js";
|
|
17
|
-
export function pdbeSiftsUrl(pdbId) {
|
|
18
|
-
return `https://www.ebi.ac.uk/pdbe/api/mappings/uniprot/${pdbId.toLowerCase()}`;
|
|
19
|
-
}
|
|
20
|
-
const SIFTS_RETRY_DELAYS_MS = [1000, 3000];
|
|
21
|
-
// bounded, since a view reports itself loading until SIFTS answers
|
|
22
|
-
const SIFTS_TIMEOUT_MS = 20_000;
|
|
23
|
-
/**
|
|
24
|
-
* SIFTS for an entry, retried twice: one failed request would otherwise leave a
|
|
25
|
-
* fusion construct mapped onto its partner for the whole session.
|
|
26
|
-
*
|
|
27
|
-
* A 4xx is not retried. PDBe answers 404 for an entry it has no UniProt
|
|
28
|
-
* mapping for at all — a DNA-only or obsolete entry — and that answer cannot
|
|
29
|
-
* change, so the retries only postponed it: measured 2026-09-16, `1hhb` and
|
|
30
|
-
* `1bna` each took three requests and ~4.8s to say so, which a caller shows as
|
|
31
|
-
* four and a half seconds of "resolving" for a structure that will never
|
|
32
|
-
* resolve.
|
|
33
|
-
*/
|
|
34
|
-
export async function fetchUniProtStructureMappings(pdbId, opts) {
|
|
35
|
-
const { signal: caller, ...rest } = opts ?? {};
|
|
36
|
-
const signal = caller ?? undefined;
|
|
37
|
-
const deadline = () => signal
|
|
38
|
-
? AbortSignal.any([signal, AbortSignal.timeout(SIFTS_TIMEOUT_MS)])
|
|
39
|
-
: AbortSignal.timeout(SIFTS_TIMEOUT_MS);
|
|
40
|
-
for (let attempt = 0;; attempt++) {
|
|
41
|
-
try {
|
|
42
|
-
return parseUniProtStructureMappings(await jsonfetch(pdbeSiftsUrl(pdbId), { ...rest, signal: deadline() }));
|
|
43
|
-
}
|
|
44
|
-
catch (e) {
|
|
45
|
-
const delay = SIFTS_RETRY_DELAYS_MS[attempt];
|
|
46
|
-
// the caller's own abort is not a failure to retry either
|
|
47
|
-
if (delay === undefined || isDefinitiveFailure(e) || signal?.aborted) {
|
|
48
|
-
throw e;
|
|
49
|
-
}
|
|
50
|
-
await timeout(delay, signal);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function isRecord(value) {
|
|
55
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
56
|
-
}
|
|
57
|
-
function finiteNumber(value) {
|
|
58
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
59
|
-
}
|
|
60
|
-
function residueNumber(endpoint) {
|
|
61
|
-
return isRecord(endpoint) ? finiteNumber(endpoint.residue_number) : undefined;
|
|
62
|
-
}
|
|
63
|
-
function authorResidueNumber(endpoint) {
|
|
64
|
-
return isRecord(endpoint)
|
|
65
|
-
? finiteNumber(endpoint.author_residue_number)
|
|
66
|
-
: undefined;
|
|
67
|
-
}
|
|
68
|
-
function parseSegment(mapping) {
|
|
69
|
-
if (!isRecord(mapping)) {
|
|
70
|
-
return undefined;
|
|
71
|
-
}
|
|
72
|
-
const entityId = finiteNumber(mapping.entity_id);
|
|
73
|
-
const unpStart = finiteNumber(mapping.unp_start);
|
|
74
|
-
const unpEnd = finiteNumber(mapping.unp_end);
|
|
75
|
-
const structStart = residueNumber(mapping.start);
|
|
76
|
-
const structEnd = residueNumber(mapping.end);
|
|
77
|
-
const authorStart = authorResidueNumber(mapping.start);
|
|
78
|
-
const authorEnd = authorResidueNumber(mapping.end);
|
|
79
|
-
return entityId === undefined ||
|
|
80
|
-
unpStart === undefined ||
|
|
81
|
-
unpEnd === undefined ||
|
|
82
|
-
structStart === undefined ||
|
|
83
|
-
structEnd === undefined
|
|
84
|
-
? undefined
|
|
85
|
-
: {
|
|
86
|
-
entityId: String(entityId),
|
|
87
|
-
...(typeof mapping.chain_id === 'string'
|
|
88
|
-
? { chainId: mapping.chain_id }
|
|
89
|
-
: {}),
|
|
90
|
-
unpStart,
|
|
91
|
-
unpEnd,
|
|
92
|
-
// SEQRES/label_seq_id is 1-based, structure positions are 0-based
|
|
93
|
-
structStart: structStart - 1,
|
|
94
|
-
structEnd: structEnd - 1,
|
|
95
|
-
...(authorStart === undefined ? {} : { authorStart }),
|
|
96
|
-
...(authorEnd === undefined ? {} : { authorEnd }),
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Parses a PDBe `mappings/uniprot/{pdbId}` response into one entry per UniProt
|
|
101
|
-
* accession. Unparseable segments are skipped rather than failing the whole
|
|
102
|
-
* response — a chimera with one malformed segment still maps its other chains.
|
|
103
|
-
* The response is keyed by pdb id, so the single entry is taken whatever its key.
|
|
104
|
-
*/
|
|
105
|
-
export function parseUniProtStructureMappings(json) {
|
|
106
|
-
const entry = isRecord(json) ? Object.values(json)[0] : undefined;
|
|
107
|
-
const uniprot = isRecord(entry) ? entry.UniProt : undefined;
|
|
108
|
-
if (!isRecord(uniprot)) {
|
|
109
|
-
return [];
|
|
110
|
-
}
|
|
111
|
-
const result = [];
|
|
112
|
-
for (const [accession, value] of Object.entries(uniprot)) {
|
|
113
|
-
const mappings = isRecord(value) ? value.mappings : undefined;
|
|
114
|
-
const segments = Array.isArray(mappings)
|
|
115
|
-
? mappings.map(parseSegment).filter(s => s !== undefined)
|
|
116
|
-
: [];
|
|
117
|
-
if (segments.length > 0) {
|
|
118
|
-
result.push({
|
|
119
|
-
accession,
|
|
120
|
-
name: isRecord(value) && typeof value.name === 'string'
|
|
121
|
-
? value.name
|
|
122
|
-
: undefined,
|
|
123
|
-
segments,
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
12
|
+
// Structure positions here index the entity's SEQRES from 0, i.e.
|
|
13
|
+
// label_seq_id - 1, which is this package's structure-sequence position.
|
|
129
14
|
function coveredResidues(segments) {
|
|
130
15
|
return segments.reduce((a, s) => a + (s.structEnd - s.structStart + 1), 0);
|
|
131
16
|
}
|
|
132
17
|
/**
|
|
133
|
-
* The segments of one accession that describe this entity.
|
|
134
|
-
* entities as the mmCIF does, and a PDB-format file loaded through
|
|
135
|
-
* them per chain (1H26.pdb's chain C is entity 2, which in
|
|
136
|
-
* so a segment naming its chain is matched by chain.
|
|
18
|
+
* The segments of one accession that describe this entity. The mapping
|
|
19
|
+
* numbers entities as the mmCIF does, and a PDB-format file loaded through
|
|
20
|
+
* Mol* numbers them per chain (1H26.pdb's chain C is entity 2, which in the
|
|
21
|
+
* mmCIF is cyclin A), so a segment naming its chain is matched by chain.
|
|
137
22
|
*/
|
|
138
23
|
function segmentsForEntity(mapping, entity) {
|
|
139
24
|
return dedupeSegments(mapping.segments.filter(s => s.chainId === undefined
|
|
@@ -141,12 +26,11 @@ function segmentsForEntity(mapping, entity) {
|
|
|
141
26
|
: entity.chains.includes(s.chainId)));
|
|
142
27
|
}
|
|
143
28
|
/**
|
|
144
|
-
* Picks the UniProt entry
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
* contributing the most residues wins.
|
|
29
|
+
* Picks the UniProt entry for a given entity, with its segments narrowed to
|
|
30
|
+
* that entity. Pass the entity mapped to the transcript: a heteromer's chains
|
|
31
|
+
* align to different accessions, and the wrong one would annotate the wrong
|
|
32
|
+
* protein. When several accessions cover one entity (a chimeric construct), the
|
|
33
|
+
* one covering the most residues wins.
|
|
150
34
|
*/
|
|
151
35
|
export function chooseUniProtMappingForEntity(mappings, entity) {
|
|
152
36
|
if (entity === undefined) {
|
|
@@ -165,10 +49,11 @@ export function chooseUniProtMappingForEntity(mappings, entity) {
|
|
|
165
49
|
const OWN_PSEUDOCOUNT = 5;
|
|
166
50
|
const MIN_OWN_IDENTITY = 0.5;
|
|
167
51
|
/**
|
|
168
|
-
* Mapped structure positions
|
|
169
|
-
* transcript's, on a chain that fuses two. Local
|
|
170
|
-
* boundary, and on every GPCR fusion construct
|
|
171
|
-
* residues onto the partner, 33 of them onto T4
|
|
52
|
+
* Mapped structure positions the entry's UniProt alignment assigns to a
|
|
53
|
+
* protein other than the transcript's, on a chain that fuses two. Local
|
|
54
|
+
* alignment bridges a fusion boundary, and on every GPCR fusion construct
|
|
55
|
+
* checked it scattered receptor residues onto the partner, 33 of them onto T4
|
|
56
|
+
* lysozyme in 2RH1.
|
|
172
57
|
*
|
|
173
58
|
* `mapped` is each mapped structure position and whether its pair is
|
|
174
59
|
* identical. The transcript's own accession is the one whose covered positions
|
|
@@ -177,7 +62,7 @@ const MIN_OWN_IDENTITY = 0.5;
|
|
|
177
62
|
* fused to CDK2 covers 11 positions against 224 chance hits on the kinase, and
|
|
178
63
|
* counting unmapped the peptide. Unless that accession reaches half identity
|
|
179
64
|
* the transcript is taken to be neither protein, and nothing is unmapped.
|
|
180
|
-
* Residues
|
|
65
|
+
* Residues assigned to no accession, such as tags, stay mapped.
|
|
181
66
|
*/
|
|
182
67
|
export function fusionPartnerPositions(mappings, entity, mapped) {
|
|
183
68
|
const partners = new Set();
|
|
@@ -214,8 +99,8 @@ export function fusionPartnerPositions(mappings, entity, mapped) {
|
|
|
214
99
|
}
|
|
215
100
|
return partners;
|
|
216
101
|
}
|
|
217
|
-
//
|
|
218
|
-
// repeat the same entity-level correspondence. They collapse to one
|
|
102
|
+
// The mapping lists one segment per *chain*, so the several chains of a
|
|
103
|
+
// homodimer repeat the same entity-level correspondence. They collapse to one.
|
|
219
104
|
function dedupeSegments(segments) {
|
|
220
105
|
const seen = new Set();
|
|
221
106
|
return segments.filter(s => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdbUniProtMapping.js","sourceRoot":"","sources":["../src/pdbUniProtMapping.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"pdbUniProtMapping.js","sourceRoot":"","sources":["../src/pdbUniProtMapping.ts"],"names":[],"mappings":"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"}
|
package/esm/structureFormat.d.ts
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Which molstar trajectory parser a structure needs.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* error.
|
|
4
|
+
* A wrong choice fails either way. Parsing a PDB file as mmCIF throws
|
|
5
|
+
* ("Unexpected token. Expected data_, loop_, or data name"). Parsing an mmCIF
|
|
6
|
+
* as PDB succeeds and yields a model with zero polymer entities and thousands of
|
|
7
|
+
* misread atoms, so the structure loads with no sequence, no alignment and no
|
|
8
|
+
* genome mapping, and with no error.
|
|
10
9
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* The two names are the subset of molstar's `BuiltInTrajectoryFormat` a
|
|
15
|
-
* structure loaded from a file or a url can be, spelled out rather than
|
|
16
|
-
* imported so nothing here depends on molstar.
|
|
10
|
+
* The two names are the subset of molstar's `BuiltInTrajectoryFormat` that a
|
|
11
|
+
* structure file or URL can be, written out so nothing here imports molstar.
|
|
17
12
|
*/
|
|
18
13
|
export type StructureFormat = 'pdb' | 'mmcif';
|
|
19
14
|
/** Trailing extension of a filename or URL, lowercased, ignoring any query or
|
|
@@ -21,18 +16,16 @@ export type StructureFormat = 'pdb' | 'mmcif';
|
|
|
21
16
|
export declare function structureFileExtension(nameOrUrl: string): string;
|
|
22
17
|
/**
|
|
23
18
|
* Format for a filename or URL. Unknown extensions fall back to mmCIF, which is
|
|
24
|
-
* what
|
|
25
|
-
* hand out `.cif`).
|
|
19
|
+
* what AlphaFold and RCSB serve (`.cif`).
|
|
26
20
|
*/
|
|
27
21
|
export declare function structureFormatFromName(nameOrUrl: string): StructureFormat;
|
|
28
22
|
/** Whether a URL points at a binary-encoded structure, which molstar must be
|
|
29
23
|
* told to download as bytes rather than text. */
|
|
30
24
|
export declare function isBinaryStructureUrl(url: string): boolean;
|
|
31
25
|
/**
|
|
32
|
-
* Format for structure text
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* and is the only signal available here.
|
|
26
|
+
* Format for structure text with no filename, such as inline data, a pasted
|
|
27
|
+
* file, or a PDB built by `caCoordsToPdb`. The content is more reliable than a
|
|
28
|
+
* name, and here it is the only signal.
|
|
36
29
|
*
|
|
37
30
|
* mmCIF is line-oriented and its first meaningful line is a `data_` block
|
|
38
31
|
* header (comments and blank lines may precede it); PDB has none.
|
package/esm/structureFormat.js
CHANGED
|
@@ -14,8 +14,7 @@ export function structureFileExtension(nameOrUrl) {
|
|
|
14
14
|
}
|
|
15
15
|
/**
|
|
16
16
|
* Format for a filename or URL. Unknown extensions fall back to mmCIF, which is
|
|
17
|
-
* what
|
|
18
|
-
* hand out `.cif`).
|
|
17
|
+
* what AlphaFold and RCSB serve (`.cif`).
|
|
19
18
|
*/
|
|
20
19
|
export function structureFormatFromName(nameOrUrl) {
|
|
21
20
|
return PDB_EXTENSIONS.has(structureFileExtension(nameOrUrl)) ? 'pdb' : 'mmcif';
|
|
@@ -26,10 +25,9 @@ export function isBinaryStructureUrl(url) {
|
|
|
26
25
|
return structureFileExtension(url) === 'bcif';
|
|
27
26
|
}
|
|
28
27
|
/**
|
|
29
|
-
* Format for structure text
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* and is the only signal available here.
|
|
28
|
+
* Format for structure text with no filename, such as inline data, a pasted
|
|
29
|
+
* file, or a PDB built by `caCoordsToPdb`. The content is more reliable than a
|
|
30
|
+
* name, and here it is the only signal.
|
|
33
31
|
*
|
|
34
32
|
* mmCIF is line-oriented and its first meaningful line is a `data_` block
|
|
35
33
|
* header (comments and blank lines may precede it); PDB has none.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structureFormat.js","sourceRoot":"","sources":["../src/structureFormat.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"structureFormat.js","sourceRoot":"","sources":["../src/structureFormat.ts"],"names":[],"mappings":"AAcA,gFAAgF;AAChF,wEAAwE;AACxE,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;AAEtE;mEACmE;AACnE,MAAM,UAAU,sBAAsB,CAAC,SAAiB;IACtD,MAAM,IAAI,GAAG,SAAS,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAA;IACxC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC3C,IAAI,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1B,KAAK,CAAC,GAAG,EAAE,CAAA;IACb,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,OAAO,cAAc,CAAC,GAAG,CAAC,sBAAsB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAA;AAChF,CAAC;AAED;iDACiD;AACjD,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,OAAO,sBAAsB,CAAC,GAAG,CAAC,KAAK,MAAM,CAAA;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,0BAA0B,CAAC,IAAY;IACrD,2EAA2E;IAC3E,wBAAwB;IACxB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC3B,IAAI,OAAO,KAAK,EAAE,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/C,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAA;QACpE,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC"}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { FetchOptions } from './fetchUtils.ts';
|
|
2
|
+
export declare const RCSB_SEQUENCE_COORDINATES_URL = "https://sequence-coordinates.rcsb.org/graphql";
|
|
2
3
|
export interface ExperimentalStructure {
|
|
3
4
|
pdbId: string;
|
|
5
|
+
/** RCSB's name for it: 'X-ray', 'EM', 'NMR', ... */
|
|
4
6
|
method: string;
|
|
5
7
|
/** Å; absent for NMR and some EM entries */
|
|
6
8
|
resolution?: number;
|
|
@@ -9,20 +11,42 @@ export interface ExperimentalStructure {
|
|
|
9
11
|
end: number;
|
|
10
12
|
/** fraction of the UniProt sequence the entry covers, 0..1 */
|
|
11
13
|
coverage: number;
|
|
14
|
+
/** author chain ids of the protein */
|
|
15
|
+
chains: string[];
|
|
12
16
|
}
|
|
13
|
-
|
|
17
|
+
/** One polymer entity aligned to the accession. */
|
|
18
|
+
export interface EntityAlignment {
|
|
19
|
+
/** RCSB's id, "1TUP_3" */
|
|
20
|
+
entityId: string;
|
|
21
|
+
pdbId: string;
|
|
22
|
+
start: number;
|
|
23
|
+
end: number;
|
|
24
|
+
coverage: number;
|
|
25
|
+
}
|
|
26
|
+
export interface EntityDetails {
|
|
27
|
+
method: string;
|
|
28
|
+
resolution?: number;
|
|
29
|
+
chains: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare function entityAlignmentsQuery(uniprotId: string): string;
|
|
32
|
+
export declare const ENTITY_DETAILS_QUERY = "query($ids: [String!]!) { polymer_entities(entity_ids: $ids) {\n rcsb_id\n rcsb_polymer_entity_container_identifiers { auth_asym_ids }\n entry { rcsb_entry_info { experimental_method resolution_combined } }\n} }";
|
|
33
|
+
/**
|
|
34
|
+
* PDB entities only: the same list carries RCSB's computed models
|
|
35
|
+
* (`AF_AFP04637F1_1`), which a residue mapping does not exist for. The range
|
|
36
|
+
* spans every aligned region, as 3D-Beacons reported it.
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseEntityAlignments(data: unknown): EntityAlignment[];
|
|
39
|
+
export declare function parseEntityDetails(data: unknown): Map<string, EntityDetails>;
|
|
40
|
+
/**
|
|
41
|
+
* One row per entry, best coverage first and sharpest within a tie. An entry
|
|
42
|
+
* with several entities of the protein (a construct crystallised beside a
|
|
43
|
+
* different fragment of itself) takes the best-covering entity's range and
|
|
44
|
+
* every entity's chains.
|
|
45
|
+
*/
|
|
46
|
+
export declare function experimentalStructures(alignments: EntityAlignment[], details: ReadonlyMap<string, EntityDetails>): ExperimentalStructure[];
|
|
14
47
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* prediction comes from AlphaFold's own API, which answers per model. And
|
|
19
|
-
* 3D-Beacons files SASBDB's small-angle-scattering fits under "experimentally
|
|
20
|
-
* determined" too, with numeric ids and near-full coverage — dystrophin's best
|
|
21
|
-
* "structure" by coverage was SASBDB 436 — which are not entries a residue
|
|
22
|
-
* mapping exists for. Hence the `provider === 'PDBe'` gate rather than the
|
|
23
|
-
* category alone.
|
|
48
|
+
* Every PDB entry aligned to the accession. An accession with none, or one
|
|
49
|
+
* RCSB does not know, is `[]`; an isoform accession is asked as its entry,
|
|
50
|
+
* which is what the alignment is numbered on.
|
|
24
51
|
*/
|
|
25
|
-
export declare function parseExperimentalStructures(json: unknown): ExperimentalStructure[];
|
|
26
|
-
/** Best-effort: an unreachable API reads as "no entries", which costs a
|
|
27
|
-
* structure suggestion and nothing else. */
|
|
28
52
|
export declare function fetchExperimentalStructures(uniprotId: string, opts?: FetchOptions): Promise<ExperimentalStructure[]>;
|
package/esm/structureSources.js
CHANGED
|
@@ -1,82 +1,166 @@
|
|
|
1
|
-
// The experimental structures
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// crystal structure beside a prediction without a PDB search of
|
|
5
|
-
// the entry id from here and ask `
|
|
1
|
+
// The experimental structures RCSB aligns to a UniProt entry: every PDB entity
|
|
2
|
+
// carrying the accession, with the UniProt range it covers, then each entry's
|
|
3
|
+
// method, resolution and chains. Two CORS-enabled calls, which is what lets a
|
|
4
|
+
// page offer a crystal structure beside a prediction without a PDB search of
|
|
5
|
+
// its own; take the entry id from here and ask `fetchPdbEntry` for its
|
|
6
6
|
// residue mapping.
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import { RCSB_DATA_GRAPHQL_URL, graphqlFetch } from "./pdbEntry.js";
|
|
8
|
+
import { isPdbId } from "./structureUrls.js";
|
|
9
|
+
export const RCSB_SEQUENCE_COORDINATES_URL = 'https://sequence-coordinates.rcsb.org/graphql';
|
|
10
|
+
export function entityAlignmentsQuery(uniprotId) {
|
|
11
|
+
return `{ alignments(from: UNIPROT, to: PDB_ENTITY, queryId: "${uniprotId}") {
|
|
12
|
+
target_alignments {
|
|
13
|
+
target_id
|
|
14
|
+
coverage { query_coverage }
|
|
15
|
+
aligned_regions { query_begin query_end }
|
|
16
|
+
}
|
|
17
|
+
} }`;
|
|
13
18
|
}
|
|
19
|
+
export const ENTITY_DETAILS_QUERY = `query($ids: [String!]!) { polymer_entities(entity_ids: $ids) {
|
|
20
|
+
rcsb_id
|
|
21
|
+
rcsb_polymer_entity_container_identifiers { auth_asym_ids }
|
|
22
|
+
entry { rcsb_entry_info { experimental_method resolution_combined } }
|
|
23
|
+
} }`;
|
|
24
|
+
// RCSB's cap on ids per batch request
|
|
25
|
+
const DETAILS_BATCH = 1000;
|
|
14
26
|
function isRecord(value) {
|
|
15
27
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
16
28
|
}
|
|
17
29
|
function finiteNumber(value) {
|
|
18
30
|
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
19
31
|
}
|
|
32
|
+
function strings(value) {
|
|
33
|
+
return Array.isArray(value)
|
|
34
|
+
? value.filter((v) => typeof v === 'string')
|
|
35
|
+
: [];
|
|
36
|
+
}
|
|
20
37
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* prediction comes from AlphaFold's own API, which answers per model. And
|
|
25
|
-
* 3D-Beacons files SASBDB's small-angle-scattering fits under "experimentally
|
|
26
|
-
* determined" too, with numeric ids and near-full coverage — dystrophin's best
|
|
27
|
-
* "structure" by coverage was SASBDB 436 — which are not entries a residue
|
|
28
|
-
* mapping exists for. Hence the `provider === 'PDBe'` gate rather than the
|
|
29
|
-
* category alone.
|
|
38
|
+
* PDB entities only: the same list carries RCSB's computed models
|
|
39
|
+
* (`AF_AFP04637F1_1`), which a residue mapping does not exist for. The range
|
|
40
|
+
* spans every aligned region, as 3D-Beacons reported it.
|
|
30
41
|
*/
|
|
31
|
-
export function
|
|
32
|
-
const
|
|
33
|
-
|
|
42
|
+
export function parseEntityAlignments(data) {
|
|
43
|
+
const alignments = isRecord(data) ? data.alignments : undefined;
|
|
44
|
+
const targets = isRecord(alignments)
|
|
45
|
+
? alignments.target_alignments
|
|
46
|
+
: undefined;
|
|
47
|
+
if (!Array.isArray(targets)) {
|
|
34
48
|
return [];
|
|
35
49
|
}
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
const s = isRecord(entry) ? entry.summary : undefined;
|
|
39
|
-
if (!isRecord(s)) {
|
|
50
|
+
return targets.flatMap(target => {
|
|
51
|
+
if (!isRecord(target) || typeof target.target_id !== 'string') {
|
|
40
52
|
return [];
|
|
41
53
|
}
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
54
|
+
const [pdbId] = target.target_id.split('_');
|
|
55
|
+
const coverage = isRecord(target.coverage)
|
|
56
|
+
? finiteNumber(target.coverage.query_coverage)
|
|
57
|
+
: undefined;
|
|
58
|
+
const regions = Array.isArray(target.aligned_regions)
|
|
59
|
+
? target.aligned_regions.filter(isRecord)
|
|
60
|
+
: [];
|
|
61
|
+
const begins = regions.map(r => finiteNumber(r.query_begin));
|
|
62
|
+
const ends = regions.map(r => finiteNumber(r.query_end));
|
|
63
|
+
return pdbId !== undefined &&
|
|
64
|
+
isPdbId(pdbId) &&
|
|
65
|
+
coverage !== undefined &&
|
|
66
|
+
begins.length > 0 &&
|
|
67
|
+
begins.every(b => b !== undefined) &&
|
|
68
|
+
ends.every(e => e !== undefined)
|
|
51
69
|
? [
|
|
52
70
|
{
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
resolution: finiteNumber(s.resolution),
|
|
58
|
-
start,
|
|
59
|
-
end,
|
|
71
|
+
entityId: target.target_id,
|
|
72
|
+
pdbId: pdbId.toLowerCase(),
|
|
73
|
+
start: Math.min(...begins),
|
|
74
|
+
end: Math.max(...ends),
|
|
60
75
|
coverage,
|
|
61
76
|
},
|
|
62
77
|
]
|
|
63
78
|
: [];
|
|
64
|
-
})
|
|
65
|
-
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
export function parseEntityDetails(data) {
|
|
82
|
+
const entities = isRecord(data) ? data.polymer_entities : undefined;
|
|
83
|
+
const details = new Map();
|
|
84
|
+
for (const entity of Array.isArray(entities) ? entities : []) {
|
|
85
|
+
if (!isRecord(entity) || typeof entity.rcsb_id !== 'string') {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const ids = entity.rcsb_polymer_entity_container_identifiers;
|
|
89
|
+
const info = isRecord(entity.entry)
|
|
90
|
+
? entity.entry.rcsb_entry_info
|
|
91
|
+
: undefined;
|
|
92
|
+
const resolutions = isRecord(info) ? info.resolution_combined : undefined;
|
|
93
|
+
const resolution = Array.isArray(resolutions)
|
|
94
|
+
? finiteNumber(resolutions[0])
|
|
95
|
+
: undefined;
|
|
96
|
+
details.set(entity.rcsb_id, {
|
|
97
|
+
method: isRecord(info) && typeof info.experimental_method === 'string'
|
|
98
|
+
? info.experimental_method
|
|
99
|
+
: 'experimental',
|
|
100
|
+
...(resolution === undefined ? {} : { resolution }),
|
|
101
|
+
chains: strings(isRecord(ids) ? ids.auth_asym_ids : undefined),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return details;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* One row per entry, best coverage first and sharpest within a tie. An entry
|
|
108
|
+
* with several entities of the protein (a construct crystallised beside a
|
|
109
|
+
* different fragment of itself) takes the best-covering entity's range and
|
|
110
|
+
* every entity's chains.
|
|
111
|
+
*/
|
|
112
|
+
export function experimentalStructures(alignments, details) {
|
|
113
|
+
const byEntry = new Map();
|
|
114
|
+
for (const a of alignments) {
|
|
115
|
+
const d = details.get(a.entityId);
|
|
116
|
+
if (!d) {
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const existing = byEntry.get(a.pdbId);
|
|
120
|
+
if (!existing) {
|
|
121
|
+
byEntry.set(a.pdbId, {
|
|
122
|
+
pdbId: a.pdbId,
|
|
123
|
+
method: d.method,
|
|
124
|
+
...(d.resolution === undefined ? {} : { resolution: d.resolution }),
|
|
125
|
+
start: a.start,
|
|
126
|
+
end: a.end,
|
|
127
|
+
coverage: a.coverage,
|
|
128
|
+
chains: [...d.chains],
|
|
129
|
+
});
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
for (const chain of d.chains) {
|
|
133
|
+
if (!existing.chains.includes(chain)) {
|
|
134
|
+
existing.chains.push(chain);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (a.coverage > existing.coverage) {
|
|
138
|
+
Object.assign(existing, {
|
|
139
|
+
start: a.start,
|
|
140
|
+
end: a.end,
|
|
141
|
+
coverage: a.coverage,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return [...byEntry.values()].sort((a, b) => b.coverage - a.coverage ||
|
|
66
146
|
(a.resolution ?? Infinity) - (b.resolution ?? Infinity));
|
|
67
147
|
}
|
|
68
|
-
|
|
69
|
-
|
|
148
|
+
const ISOFORM_SUFFIX = /-\d+$/;
|
|
149
|
+
/**
|
|
150
|
+
* Every PDB entry aligned to the accession. An accession with none, or one
|
|
151
|
+
* RCSB does not know, is `[]`; an isoform accession is asked as its entry,
|
|
152
|
+
* which is what the alignment is numbered on.
|
|
153
|
+
*/
|
|
70
154
|
export async function fetchExperimentalStructures(uniprotId, opts) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
155
|
+
const alignments = parseEntityAlignments(await graphqlFetch(RCSB_SEQUENCE_COORDINATES_URL, entityAlignmentsQuery(uniprotId.replace(ISOFORM_SUFFIX, '')), undefined, opts));
|
|
156
|
+
const ids = alignments.map(a => a.entityId);
|
|
157
|
+
const details = new Map();
|
|
158
|
+
for (let i = 0; i < ids.length; i += DETAILS_BATCH) {
|
|
159
|
+
const batch = parseEntityDetails(await graphqlFetch(RCSB_DATA_GRAPHQL_URL, ENTITY_DETAILS_QUERY, { ids: ids.slice(i, i + DETAILS_BATCH) }, opts));
|
|
160
|
+
for (const [id, d] of batch) {
|
|
161
|
+
details.set(id, d);
|
|
78
162
|
}
|
|
79
163
|
}
|
|
80
|
-
return
|
|
164
|
+
return experimentalStructures(alignments, details);
|
|
81
165
|
}
|
|
82
166
|
//# sourceMappingURL=structureSources.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,
|
|
1
|
+
{"version":3,"file":"structureSources.js","sourceRoot":"","sources":["../src/structureSources.ts"],"names":[],"mappings":"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"}
|