p2s_mapper 1.0.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/LICENSE +21 -0
- package/README.md +148 -0
- package/dist/alignmentQuality.d.ts +58 -0
- package/dist/alignmentQuality.js +108 -0
- package/dist/alignmentQuality.js.map +1 -0
- package/dist/alphaFoldModels.d.ts +29 -0
- package/dist/alphaFoldModels.js +60 -0
- package/dist/alphaFoldModels.js.map +1 -0
- package/dist/caCoordsToPdb.d.ts +18 -0
- package/dist/caCoordsToPdb.js +95 -0
- package/dist/caCoordsToPdb.js.map +1 -0
- package/dist/chooseMappedEntity.d.ts +55 -0
- package/dist/chooseMappedEntity.js +140 -0
- package/dist/chooseMappedEntity.js.map +1 -0
- package/dist/coordinates.d.ts +66 -0
- package/dist/coordinates.js +66 -0
- package/dist/coordinates.js.map +1 -0
- package/dist/dbIds.d.ts +16 -0
- package/dist/dbIds.js +42 -0
- package/dist/dbIds.js.map +1 -0
- package/dist/extractPerResidueConfidence.d.ts +49 -0
- package/dist/extractPerResidueConfidence.js +42 -0
- package/dist/extractPerResidueConfidence.js.map +1 -0
- package/dist/extractStructureSequences.d.ts +142 -0
- package/dist/extractStructureSequences.js +217 -0
- package/dist/extractStructureSequences.js.map +1 -0
- package/dist/fetchUtils.d.ts +34 -0
- package/dist/fetchUtils.js +91 -0
- package/dist/fetchUtils.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/invertMap.d.ts +2 -0
- package/dist/invertMap.js +8 -0
- package/dist/invertMap.js.map +1 -0
- package/dist/isoformRanking.d.ts +47 -0
- package/dist/isoformRanking.js +91 -0
- package/dist/isoformRanking.js.map +1 -0
- package/dist/mappings.d.ts +58 -0
- package/dist/mappings.js +193 -0
- package/dist/mappings.js.map +1 -0
- package/dist/package.json +1 -0
- package/dist/pairwiseAlignment.d.ts +35 -0
- package/dist/pairwiseAlignment.js +337 -0
- package/dist/pairwiseAlignment.js.map +1 -0
- package/dist/pdbUniProtMapping.d.ts +75 -0
- package/dist/pdbUniProtMapping.js +241 -0
- package/dist/pdbUniProtMapping.js.map +1 -0
- package/dist/pdbeBestStructures.d.ts +23 -0
- package/dist/pdbeBestStructures.js +79 -0
- package/dist/pdbeBestStructures.js.map +1 -0
- package/dist/pdbeEntryMolecules.d.ts +7 -0
- package/dist/pdbeEntryMolecules.js +39 -0
- package/dist/pdbeEntryMolecules.js.map +1 -0
- package/dist/siftsNumbering.d.ts +23 -0
- package/dist/siftsNumbering.js +44 -0
- package/dist/siftsNumbering.js.map +1 -0
- package/dist/stripStopCodon.d.ts +15 -0
- package/dist/stripStopCodon.js +24 -0
- package/dist/stripStopCodon.js.map +1 -0
- package/dist/structureFormat.d.ts +40 -0
- package/dist/structureFormat.js +54 -0
- package/dist/structureFormat.js.map +1 -0
- package/dist/structureSources.d.ts +28 -0
- package/dist/structureSources.js +76 -0
- package/dist/structureSources.js.map +1 -0
- package/dist/structureUrls.d.ts +54 -0
- package/dist/structureUrls.js +147 -0
- package/dist/structureUrls.js.map +1 -0
- package/dist/types.d.ts +14 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/dist/uniProtSearch.d.ts +32 -0
- package/dist/uniProtSearch.js +114 -0
- package/dist/uniProtSearch.js.map +1 -0
- package/esm/alignmentQuality.d.ts +58 -0
- package/esm/alignmentQuality.js +100 -0
- package/esm/alignmentQuality.js.map +1 -0
- package/esm/alphaFoldModels.d.ts +29 -0
- package/esm/alphaFoldModels.js +55 -0
- package/esm/alphaFoldModels.js.map +1 -0
- package/esm/caCoordsToPdb.d.ts +18 -0
- package/esm/caCoordsToPdb.js +91 -0
- package/esm/caCoordsToPdb.js.map +1 -0
- package/esm/chooseMappedEntity.d.ts +55 -0
- package/esm/chooseMappedEntity.js +134 -0
- package/esm/chooseMappedEntity.js.map +1 -0
- package/esm/coordinates.d.ts +66 -0
- package/esm/coordinates.js +58 -0
- package/esm/coordinates.js.map +1 -0
- package/esm/dbIds.d.ts +16 -0
- package/esm/dbIds.js +35 -0
- package/esm/dbIds.js.map +1 -0
- package/esm/extractPerResidueConfidence.d.ts +49 -0
- package/esm/extractPerResidueConfidence.js +38 -0
- package/esm/extractPerResidueConfidence.js.map +1 -0
- package/esm/extractStructureSequences.d.ts +142 -0
- package/esm/extractStructureSequences.js +205 -0
- package/esm/extractStructureSequences.js.map +1 -0
- package/esm/fetchUtils.d.ts +34 -0
- package/esm/fetchUtils.js +82 -0
- package/esm/fetchUtils.js.map +1 -0
- package/esm/index.d.ts +23 -0
- package/esm/index.js +30 -0
- package/esm/index.js.map +1 -0
- package/esm/invertMap.d.ts +2 -0
- package/esm/invertMap.js +5 -0
- package/esm/invertMap.js.map +1 -0
- package/esm/isoformRanking.d.ts +47 -0
- package/esm/isoformRanking.js +86 -0
- package/esm/isoformRanking.js.map +1 -0
- package/esm/mappings.d.ts +58 -0
- package/esm/mappings.js +179 -0
- package/esm/mappings.js.map +1 -0
- package/esm/pairwiseAlignment.d.ts +35 -0
- package/esm/pairwiseAlignment.js +328 -0
- package/esm/pairwiseAlignment.js.map +1 -0
- package/esm/pdbUniProtMapping.d.ts +75 -0
- package/esm/pdbUniProtMapping.js +231 -0
- package/esm/pdbUniProtMapping.js.map +1 -0
- package/esm/pdbeBestStructures.d.ts +23 -0
- package/esm/pdbeBestStructures.js +73 -0
- package/esm/pdbeBestStructures.js.map +1 -0
- package/esm/pdbeEntryMolecules.d.ts +7 -0
- package/esm/pdbeEntryMolecules.js +35 -0
- package/esm/pdbeEntryMolecules.js.map +1 -0
- package/esm/siftsNumbering.d.ts +23 -0
- package/esm/siftsNumbering.js +40 -0
- package/esm/siftsNumbering.js.map +1 -0
- package/esm/stripStopCodon.d.ts +15 -0
- package/esm/stripStopCodon.js +20 -0
- package/esm/stripStopCodon.js.map +1 -0
- package/esm/structureFormat.d.ts +40 -0
- package/esm/structureFormat.js +48 -0
- package/esm/structureFormat.js.map +1 -0
- package/esm/structureSources.d.ts +28 -0
- package/esm/structureSources.js +71 -0
- package/esm/structureSources.js.map +1 -0
- package/esm/structureUrls.d.ts +54 -0
- package/esm/structureUrls.js +134 -0
- package/esm/structureUrls.js.map +1 -0
- package/esm/types.d.ts +14 -0
- package/esm/types.js +23 -0
- package/esm/types.js.map +1 -0
- package/esm/uniProtSearch.d.ts +32 -0
- package/esm/uniProtSearch.js +110 -0
- package/esm/uniProtSearch.js.map +1 -0
- package/package.json +63 -0
- package/src/alignmentQuality.ts +132 -0
- package/src/alphaFoldModels.ts +91 -0
- package/src/caCoordsToPdb.ts +111 -0
- package/src/chooseMappedEntity.ts +198 -0
- package/src/coordinates.ts +119 -0
- package/src/dbIds.ts +46 -0
- package/src/extractPerResidueConfidence.ts +88 -0
- package/src/extractStructureSequences.ts +342 -0
- package/src/fetchUtils.ts +110 -0
- package/src/index.ts +34 -0
- package/src/invertMap.ts +4 -0
- package/src/isoformRanking.ts +139 -0
- package/src/mappings.ts +230 -0
- package/src/pairwiseAlignment.ts +423 -0
- package/src/pdbUniProtMapping.ts +320 -0
- package/src/pdbeBestStructures.ts +94 -0
- package/src/pdbeEntryMolecules.ts +37 -0
- package/src/siftsNumbering.ts +61 -0
- package/src/stripStopCodon.ts +20 -0
- package/src/structureFormat.ts +70 -0
- package/src/structureSources.ts +101 -0
- package/src/structureUrls.ts +171 -0
- package/src/types.ts +30 -0
- package/src/uniProtSearch.ts +212 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uniProtSearch.js","sourceRoot":"","sources":["../src/uniProtSearch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { PairwiseAlignment } from './mappings.ts';
|
|
2
|
+
export interface AlignmentQuality {
|
|
3
|
+
/** columns carrying a residue on both rows, i.e. mapped positions */
|
|
4
|
+
aligned: number;
|
|
5
|
+
identical: number;
|
|
6
|
+
transcriptLength: number;
|
|
7
|
+
structureLength: number;
|
|
8
|
+
/** identical over aligned; 0 when nothing aligned */
|
|
9
|
+
identity: number;
|
|
10
|
+
/** identical over the shorter of the two sequences: the statistic that
|
|
11
|
+
* separates a real match from a chance local alignment, see below */
|
|
12
|
+
identityOverShorter: number;
|
|
13
|
+
/** aligned over the structure's length */
|
|
14
|
+
structureCoverage: number;
|
|
15
|
+
/** first and last transcript residue the alignment covers, 1-based
|
|
16
|
+
* inclusive; 0 when nothing aligned. A structure is usually a fragment, and
|
|
17
|
+
* which part of the protein it holds is the reader's first question. */
|
|
18
|
+
transcriptStart: number;
|
|
19
|
+
transcriptEnd: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Below either floor the mapped positions are as likely to be chance as
|
|
23
|
+
* homology. Local alignment picks the best-scoring stretch of two sequences,
|
|
24
|
+
* so identity over the aligned columns is inflated whatever the inputs:
|
|
25
|
+
* measured 2026-09-11 on random sequences, Smith-Waterman with BLOSUM62 gave
|
|
26
|
+
* 37% identity over 27 columns at 300 × 300 and 30% over 100 columns at
|
|
27
|
+
* 500 × 150, two thirds of the shorter chain, and p53 against a ribosomal
|
|
28
|
+
* protein (7K00 RPS11) gives 31 identities at a third identity. Neither local
|
|
29
|
+
* identity nor coverage alone separates those from a real match. Identical
|
|
30
|
+
* residues over the shorter sequence does: 0.03, 0.20 and 0.24 for the chance
|
|
31
|
+
* cases against 0.9 or better for any structure of the transcript's protein
|
|
32
|
+
* and about 0.6 for an ortholog.
|
|
33
|
+
*
|
|
34
|
+
* A short alignment has to be nearly perfect instead: a 10-residue decoy with
|
|
35
|
+
* 3 identities sits at the ratio floor, while a real bound peptide (1YCR's 15
|
|
36
|
+
* p53 residues, 4ZZJ's 7) is identical or one off. So under
|
|
37
|
+
* SHORT_ALIGNMENT_RESIDUES identical residues the ratio floor rises to
|
|
38
|
+
* SHORT_ALIGNMENT_IDENTITY, and under MIN_IDENTICAL_RESIDUES nothing passes,
|
|
39
|
+
* since a tetrapeptide is never the gene's product.
|
|
40
|
+
*/
|
|
41
|
+
export declare const LOW_IDENTITY_OVER_SHORTER = 0.3;
|
|
42
|
+
export declare const SHORT_ALIGNMENT_RESIDUES = 20;
|
|
43
|
+
export declare const SHORT_ALIGNMENT_IDENTITY = 0.8;
|
|
44
|
+
export declare const MIN_IDENTICAL_RESIDUES = 5;
|
|
45
|
+
export declare function alignmentQuality(pa: PairwiseAlignment): AlignmentQuality;
|
|
46
|
+
export declare function isLowSimilarity(q: AlignmentQuality): boolean;
|
|
47
|
+
/** One line for the alignment header: "87% identity over 219 of 393
|
|
48
|
+
* structure residues". */
|
|
49
|
+
export declare function describeAlignmentQuality(q: AlignmentQuality): string;
|
|
50
|
+
/**
|
|
51
|
+
* The same counted from the transcript's side, for the always-visible header:
|
|
52
|
+
* how much of the gene's protein this structure speaks for is what decides
|
|
53
|
+
* whether a codon has a residue at all.
|
|
54
|
+
*/
|
|
55
|
+
export declare function describeTranscriptCoverage(q: AlignmentQuality): string;
|
|
56
|
+
/** Which residues of the transcript a fragment holds, or undefined when it
|
|
57
|
+
* covers the whole translation. */
|
|
58
|
+
export declare function describeCoveredRange(q: AlignmentQuality): string | undefined;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { alignmentLength, structureAlignedSeq, transcriptAlignedSeq, } from "./mappings.js";
|
|
2
|
+
/**
|
|
3
|
+
* Below either floor the mapped positions are as likely to be chance as
|
|
4
|
+
* homology. Local alignment picks the best-scoring stretch of two sequences,
|
|
5
|
+
* so identity over the aligned columns is inflated whatever the inputs:
|
|
6
|
+
* measured 2026-09-11 on random sequences, Smith-Waterman with BLOSUM62 gave
|
|
7
|
+
* 37% identity over 27 columns at 300 × 300 and 30% over 100 columns at
|
|
8
|
+
* 500 × 150, two thirds of the shorter chain, and p53 against a ribosomal
|
|
9
|
+
* protein (7K00 RPS11) gives 31 identities at a third identity. Neither local
|
|
10
|
+
* identity nor coverage alone separates those from a real match. Identical
|
|
11
|
+
* residues over the shorter sequence does: 0.03, 0.20 and 0.24 for the chance
|
|
12
|
+
* cases against 0.9 or better for any structure of the transcript's protein
|
|
13
|
+
* and about 0.6 for an ortholog.
|
|
14
|
+
*
|
|
15
|
+
* A short alignment has to be nearly perfect instead: a 10-residue decoy with
|
|
16
|
+
* 3 identities sits at the ratio floor, while a real bound peptide (1YCR's 15
|
|
17
|
+
* p53 residues, 4ZZJ's 7) is identical or one off. So under
|
|
18
|
+
* SHORT_ALIGNMENT_RESIDUES identical residues the ratio floor rises to
|
|
19
|
+
* SHORT_ALIGNMENT_IDENTITY, and under MIN_IDENTICAL_RESIDUES nothing passes,
|
|
20
|
+
* since a tetrapeptide is never the gene's product.
|
|
21
|
+
*/
|
|
22
|
+
export const LOW_IDENTITY_OVER_SHORTER = 0.3;
|
|
23
|
+
export const SHORT_ALIGNMENT_RESIDUES = 20;
|
|
24
|
+
export const SHORT_ALIGNMENT_IDENTITY = 0.8;
|
|
25
|
+
export const MIN_IDENTICAL_RESIDUES = 5;
|
|
26
|
+
export function alignmentQuality(pa) {
|
|
27
|
+
const t = transcriptAlignedSeq(pa);
|
|
28
|
+
const s = structureAlignedSeq(pa);
|
|
29
|
+
let aligned = 0;
|
|
30
|
+
let identical = 0;
|
|
31
|
+
let transcriptLength = 0;
|
|
32
|
+
let structureLength = 0;
|
|
33
|
+
let transcriptStart = 0;
|
|
34
|
+
let transcriptEnd = 0;
|
|
35
|
+
for (let i = 0; i < alignmentLength(pa); i++) {
|
|
36
|
+
const a = t[i];
|
|
37
|
+
const b = s[i];
|
|
38
|
+
const ta = a !== '-';
|
|
39
|
+
const sb = b !== '-';
|
|
40
|
+
if (ta) {
|
|
41
|
+
transcriptLength++;
|
|
42
|
+
}
|
|
43
|
+
if (sb) {
|
|
44
|
+
structureLength++;
|
|
45
|
+
}
|
|
46
|
+
if (ta && sb) {
|
|
47
|
+
aligned++;
|
|
48
|
+
transcriptStart = transcriptStart || transcriptLength;
|
|
49
|
+
transcriptEnd = transcriptLength;
|
|
50
|
+
if (a.toUpperCase() === b.toUpperCase()) {
|
|
51
|
+
identical++;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const shorter = Math.min(transcriptLength, structureLength);
|
|
56
|
+
return {
|
|
57
|
+
aligned,
|
|
58
|
+
identical,
|
|
59
|
+
transcriptLength,
|
|
60
|
+
structureLength,
|
|
61
|
+
identity: aligned ? identical / aligned : 0,
|
|
62
|
+
identityOverShorter: shorter ? identical / shorter : 0,
|
|
63
|
+
structureCoverage: structureLength ? aligned / structureLength : 0,
|
|
64
|
+
transcriptStart,
|
|
65
|
+
transcriptEnd,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
export function isLowSimilarity(q) {
|
|
69
|
+
const floor = q.identical < SHORT_ALIGNMENT_RESIDUES
|
|
70
|
+
? SHORT_ALIGNMENT_IDENTITY
|
|
71
|
+
: LOW_IDENTITY_OVER_SHORTER;
|
|
72
|
+
return q.identical < MIN_IDENTICAL_RESIDUES || q.identityOverShorter < floor;
|
|
73
|
+
}
|
|
74
|
+
/** One line for the alignment header: "87% identity over 219 of 393
|
|
75
|
+
* structure residues". */
|
|
76
|
+
export function describeAlignmentQuality(q) {
|
|
77
|
+
if (q.aligned === 0) {
|
|
78
|
+
return 'no residues aligned';
|
|
79
|
+
}
|
|
80
|
+
return `${Math.round(q.identity * 100)}% identity over ${q.aligned} of ${q.structureLength} structure residues`;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The same counted from the transcript's side, for the always-visible header:
|
|
84
|
+
* how much of the gene's protein this structure speaks for is what decides
|
|
85
|
+
* whether a codon has a residue at all.
|
|
86
|
+
*/
|
|
87
|
+
export function describeTranscriptCoverage(q) {
|
|
88
|
+
if (q.aligned === 0) {
|
|
89
|
+
return 'no residues aligned';
|
|
90
|
+
}
|
|
91
|
+
return `${Math.round(q.identity * 100)}% identity, ${q.aligned} of ${q.transcriptLength} transcript residues covered`;
|
|
92
|
+
}
|
|
93
|
+
/** Which residues of the transcript a fragment holds, or undefined when it
|
|
94
|
+
* covers the whole translation. */
|
|
95
|
+
export function describeCoveredRange(q) {
|
|
96
|
+
return q.aligned === 0 || q.aligned === q.transcriptLength
|
|
97
|
+
? undefined
|
|
98
|
+
: `covers transcript residues ${q.transcriptStart}–${q.transcriptEnd}`;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=alignmentQuality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alignmentQuality.js","sourceRoot":"","sources":["../src/alignmentQuality.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { FetchOptions } from './fetchUtils.ts';
|
|
2
|
+
export interface AlphaFoldModel {
|
|
3
|
+
/** UniProt accession, with an isoform suffix on an isoform model */
|
|
4
|
+
accession: string;
|
|
5
|
+
url: string;
|
|
6
|
+
confidenceUrl?: string;
|
|
7
|
+
sequence: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function parseAlphaFoldModels(json: unknown): AlphaFoldModel[];
|
|
10
|
+
/**
|
|
11
|
+
* Every model AlphaFold DB has for an accession: the canonical one and any
|
|
12
|
+
* isoform models, each with its file url and sequence. Asked rather than
|
|
13
|
+
* derived from the accession, because a derived `AF-<acc>-F1-model_v6` does
|
|
14
|
+
* not exist past the length cap (dystrophin has fourteen isoform models and no
|
|
15
|
+
* F1) and moves with every model version. An accession AlphaFold has never
|
|
16
|
+
* folded answers 400 or 404, which is no models rather than an error.
|
|
17
|
+
*/
|
|
18
|
+
export declare function fetchAlphaFoldModels(uniprotId: string, opts?: FetchOptions): Promise<AlphaFoldModel[]>;
|
|
19
|
+
/**
|
|
20
|
+
* The model to open for a gene's transcripts: one folded from exactly a
|
|
21
|
+
* transcript's translation, canonical first, so the view maps it as an
|
|
22
|
+
* identity; else the canonical model; else the longest isoform model.
|
|
23
|
+
*
|
|
24
|
+
* Takes any record of sequences, since the structure loader knows one
|
|
25
|
+
* translation rather than a gene's isoforms.
|
|
26
|
+
*/
|
|
27
|
+
export declare function pickAlphaFoldModel(models: AlphaFoldModel[], isoformSequences: Record<string, {
|
|
28
|
+
seq: string;
|
|
29
|
+
}> | undefined): AlphaFoldModel | undefined;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { httpError, rawfetch } from "./fetchUtils.js";
|
|
2
|
+
import { stripStopCodon } from "./stripStopCodon.js";
|
|
3
|
+
function isPredictionEntry(value) {
|
|
4
|
+
return typeof value === 'object' && value !== null;
|
|
5
|
+
}
|
|
6
|
+
export function parseAlphaFoldModels(json) {
|
|
7
|
+
return (Array.isArray(json) ? json : []).flatMap(e => isPredictionEntry(e) &&
|
|
8
|
+
typeof e.uniprotAccession === 'string' &&
|
|
9
|
+
typeof e.cifUrl === 'string' &&
|
|
10
|
+
typeof e.sequence === 'string'
|
|
11
|
+
? [
|
|
12
|
+
{
|
|
13
|
+
accession: e.uniprotAccession,
|
|
14
|
+
url: e.cifUrl,
|
|
15
|
+
confidenceUrl: typeof e.plddtDocUrl === 'string' ? e.plddtDocUrl : undefined,
|
|
16
|
+
sequence: e.sequence,
|
|
17
|
+
},
|
|
18
|
+
]
|
|
19
|
+
: []);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Every model AlphaFold DB has for an accession: the canonical one and any
|
|
23
|
+
* isoform models, each with its file url and sequence. Asked rather than
|
|
24
|
+
* derived from the accession, because a derived `AF-<acc>-F1-model_v6` does
|
|
25
|
+
* not exist past the length cap (dystrophin has fourteen isoform models and no
|
|
26
|
+
* F1) and moves with every model version. An accession AlphaFold has never
|
|
27
|
+
* folded answers 400 or 404, which is no models rather than an error.
|
|
28
|
+
*/
|
|
29
|
+
export async function fetchAlphaFoldModels(uniprotId, opts) {
|
|
30
|
+
const url = `https://alphafold.ebi.ac.uk/api/prediction/${encodeURIComponent(uniprotId)}`;
|
|
31
|
+
const res = await rawfetch(url, opts);
|
|
32
|
+
if (res.status === 400 || res.status === 404) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
throw await httpError(res, url);
|
|
37
|
+
}
|
|
38
|
+
return parseAlphaFoldModels(await res.json());
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The model to open for a gene's transcripts: one folded from exactly a
|
|
42
|
+
* transcript's translation, canonical first, so the view maps it as an
|
|
43
|
+
* identity; else the canonical model; else the longest isoform model.
|
|
44
|
+
*
|
|
45
|
+
* Takes any record of sequences, since the structure loader knows one
|
|
46
|
+
* translation rather than a gene's isoforms.
|
|
47
|
+
*/
|
|
48
|
+
export function pickAlphaFoldModel(models, isoformSequences) {
|
|
49
|
+
const translations = new Set(Object.values(isoformSequences ?? {}).map(v => stripStopCodon(v.seq)));
|
|
50
|
+
const canonicalFirst = [...models].sort((a, b) => Number(a.accession.includes('-')) - Number(b.accession.includes('-')));
|
|
51
|
+
return (canonicalFirst.find(m => translations.has(m.sequence)) ??
|
|
52
|
+
canonicalFirst.find(m => !m.accession.includes('-')) ??
|
|
53
|
+
[...models].sort((a, b) => b.sequence.length - a.sequence.length)[0]);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=alphaFoldModels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"alphaFoldModels.js","sourceRoot":"","sources":["../src/alphaFoldModels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Convert Foldseek tCa coordinates and tSeq to PDB format
|
|
3
|
+
* tCa is a comma-separated string of x,y,z triplets
|
|
4
|
+
* tSeq is the amino acid sequence
|
|
5
|
+
*/
|
|
6
|
+
export declare function caCoordsToPdb(tCa: string, tSeq: string, chainId?: string, title?: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Whether a Foldseek hit carries tCa data that can be converted to PDB. A type
|
|
9
|
+
* predicate rather than a boolean so a guarded caller can pass `hit.tCa`/
|
|
10
|
+
* `hit.tSeq` straight to caCoordsToPdb without re-asserting they're defined.
|
|
11
|
+
*/
|
|
12
|
+
export declare function hasValidCaCoords<T extends {
|
|
13
|
+
tCa?: string;
|
|
14
|
+
tSeq?: string;
|
|
15
|
+
}>(hit: T): hit is T & {
|
|
16
|
+
tCa: string;
|
|
17
|
+
tSeq: string;
|
|
18
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// 3-letter amino acid codes
|
|
2
|
+
const AA_3LETTER = {
|
|
3
|
+
A: 'ALA',
|
|
4
|
+
C: 'CYS',
|
|
5
|
+
D: 'ASP',
|
|
6
|
+
E: 'GLU',
|
|
7
|
+
F: 'PHE',
|
|
8
|
+
G: 'GLY',
|
|
9
|
+
H: 'HIS',
|
|
10
|
+
I: 'ILE',
|
|
11
|
+
K: 'LYS',
|
|
12
|
+
L: 'LEU',
|
|
13
|
+
M: 'MET',
|
|
14
|
+
N: 'ASN',
|
|
15
|
+
P: 'PRO',
|
|
16
|
+
Q: 'GLN',
|
|
17
|
+
R: 'ARG',
|
|
18
|
+
S: 'SER',
|
|
19
|
+
T: 'THR',
|
|
20
|
+
V: 'VAL',
|
|
21
|
+
W: 'TRP',
|
|
22
|
+
Y: 'TYR',
|
|
23
|
+
X: 'UNK', // Unknown
|
|
24
|
+
};
|
|
25
|
+
function padLeft(str, len) {
|
|
26
|
+
return str.padStart(len, ' ');
|
|
27
|
+
}
|
|
28
|
+
function padRight(str, len) {
|
|
29
|
+
return str.padEnd(len, ' ');
|
|
30
|
+
}
|
|
31
|
+
function formatCoord(val) {
|
|
32
|
+
return val.toFixed(3).padStart(8, ' ');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Convert Foldseek tCa coordinates and tSeq to PDB format
|
|
36
|
+
* tCa is a comma-separated string of x,y,z triplets
|
|
37
|
+
* tSeq is the amino acid sequence
|
|
38
|
+
*/
|
|
39
|
+
export function caCoordsToPdb(tCa, tSeq, chainId = 'A', title) {
|
|
40
|
+
const coords = tCa.split(',').map(Number);
|
|
41
|
+
const lines = [];
|
|
42
|
+
// Add header
|
|
43
|
+
if (title) {
|
|
44
|
+
lines.push(`TITLE ${title}`);
|
|
45
|
+
}
|
|
46
|
+
lines.push('REMARK 1 Generated from Foldseek Cα coordinates');
|
|
47
|
+
let atomNum = 1;
|
|
48
|
+
let resNum = 1;
|
|
49
|
+
for (let i = 0; i < coords.length - 2; i += 3) {
|
|
50
|
+
const x = coords[i];
|
|
51
|
+
const y = coords[i + 1];
|
|
52
|
+
const z = coords[i + 2];
|
|
53
|
+
const aa = tSeq[resNum - 1] ?? 'X';
|
|
54
|
+
const resName = AA_3LETTER[aa] ?? 'UNK';
|
|
55
|
+
if (x === undefined || y === undefined || z === undefined) {
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
// PDB ATOM record format
|
|
59
|
+
// Columns: 1-6 "ATOM ", 7-11 serial, 13-16 name, 17 altLoc, 18-20 resName,
|
|
60
|
+
// 22 chainID, 23-26 resSeq, 27 iCode, 31-38 x, 39-46 y, 47-54 z,
|
|
61
|
+
// 55-60 occupancy, 61-66 tempFactor, 77-78 element
|
|
62
|
+
const line = 'ATOM ' +
|
|
63
|
+
padLeft(String(atomNum), 5) +
|
|
64
|
+
' CA ' +
|
|
65
|
+
padRight(resName, 3) +
|
|
66
|
+
' ' +
|
|
67
|
+
chainId +
|
|
68
|
+
padLeft(String(resNum), 4) +
|
|
69
|
+
' ' +
|
|
70
|
+
formatCoord(x) +
|
|
71
|
+
formatCoord(y) +
|
|
72
|
+
formatCoord(z) +
|
|
73
|
+
' 1.00 0.00 C';
|
|
74
|
+
lines.push(line);
|
|
75
|
+
atomNum++;
|
|
76
|
+
resNum++;
|
|
77
|
+
}
|
|
78
|
+
lines.push('END');
|
|
79
|
+
return lines.join('\n');
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Whether a Foldseek hit carries tCa data that can be converted to PDB. A type
|
|
83
|
+
* predicate rather than a boolean so a guarded caller can pass `hit.tCa`/
|
|
84
|
+
* `hit.tSeq` straight to caCoordsToPdb without re-asserting they're defined.
|
|
85
|
+
*/
|
|
86
|
+
export function hasValidCaCoords(hit) {
|
|
87
|
+
const { tCa, tSeq } = hit;
|
|
88
|
+
// Need at least 3 coordinates (x,y,z for one residue) and a sequence
|
|
89
|
+
return !!tCa && !!tSeq && tCa.split(',').length >= 3;
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=caCoordsToPdb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"caCoordsToPdb.js","sourceRoot":"","sources":["../src/caCoordsToPdb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { PairwiseAlignment } from './mappings.ts';
|
|
2
|
+
import type { AlignmentAlgorithm } from './types.ts';
|
|
3
|
+
/**
|
|
4
|
+
* Whether a structure interaction (hover/click) should drive genome navigation.
|
|
5
|
+
* Only the transcript's mapped entity may — a hover on any other chain carries
|
|
6
|
+
* that chain's own label_seq_id and would mis-map through the wrong alignment.
|
|
7
|
+
* A structure with no resolved mapping (`mappedEntityId` undefined, e.g. a
|
|
8
|
+
* standalone viewer with no transcript) stays fully interactive.
|
|
9
|
+
*/
|
|
10
|
+
export declare function interactionMatchesMappedEntity(entityId: string, mappedEntityId: string | undefined): boolean;
|
|
11
|
+
export interface EntitySelection extends ScoredAlignment {
|
|
12
|
+
/** index into the candidate array of the entity that is the transcript's */
|
|
13
|
+
index: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ScoredAlignment {
|
|
16
|
+
/** alignment of the transcript against the entity (stop codons stripped on
|
|
17
|
+
* both sides, matching the rest of the mapping pipeline) */
|
|
18
|
+
alignment: PairwiseAlignment;
|
|
19
|
+
/** identical aligned residues */
|
|
20
|
+
matches: number;
|
|
21
|
+
/** identical residues over the shorter sequence, the score that picks the
|
|
22
|
+
* entity; see `explainedFraction` */
|
|
23
|
+
explained: number;
|
|
24
|
+
/** the alignment's BLOSUM62 score, gap penalties included */
|
|
25
|
+
score: number;
|
|
26
|
+
}
|
|
27
|
+
/** A candidate entity: its sequence, and whether it is DNA/RNA, which is never
|
|
28
|
+
* the transcript's product however its letters happen to align. */
|
|
29
|
+
export interface EntityCandidate {
|
|
30
|
+
seq: string;
|
|
31
|
+
nucleicAcid?: boolean;
|
|
32
|
+
}
|
|
33
|
+
export declare function explainedFraction(matches: number, transcriptLength: number, entityLength: number): number;
|
|
34
|
+
/**
|
|
35
|
+
* Align one transcript to one entity, stop codons stripped on both sides. An
|
|
36
|
+
* exact match skips the DP entirely; an oversized pair returns undefined rather
|
|
37
|
+
* than locking up the tab. Used both to score every entity of a structure and
|
|
38
|
+
* to honour a user's explicit chain choice.
|
|
39
|
+
*/
|
|
40
|
+
export declare function alignTranscriptToEntity(transcript: string, entitySeq: string, algorithm: AlignmentAlgorithm): ScoredAlignment | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* Pick which polymer entity of a structure corresponds to the transcript.
|
|
43
|
+
*
|
|
44
|
+
* The plugin historically hardcoded entity `[0]`, which silently mis-maps every
|
|
45
|
+
* heteromeric / protein-DNA / processed-peptide structure where the protein of
|
|
46
|
+
* interest is some other chain. Selecting by alignment makes the structure self-
|
|
47
|
+
* describe which entity is the gene's protein: an exact sequence match wins
|
|
48
|
+
* outright, otherwise the entity with the highest identity over the shorter
|
|
49
|
+
* sequence (see `explainedFraction`). Nucleic-acid entities are never
|
|
50
|
+
* candidates.
|
|
51
|
+
*
|
|
52
|
+
* Returns `undefined` only when there is nothing to map (no transcript or no
|
|
53
|
+
* protein entities) — never a silent fallback to the wrong entity.
|
|
54
|
+
*/
|
|
55
|
+
export declare function chooseMappedEntity(transcript: string, entities: readonly (string | EntityCandidate)[], algorithm: AlignmentAlgorithm): EntitySelection | undefined;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { alignmentTooLarge, scoredAlignment, selfScore, } from "./pairwiseAlignment.js";
|
|
2
|
+
import { stripStopCodon } from "./stripStopCodon.js";
|
|
3
|
+
import { structureAlignedSeq, transcriptAlignedSeq } from "./mappings.js";
|
|
4
|
+
/**
|
|
5
|
+
* Whether a structure interaction (hover/click) should drive genome navigation.
|
|
6
|
+
* Only the transcript's mapped entity may — a hover on any other chain carries
|
|
7
|
+
* that chain's own label_seq_id and would mis-map through the wrong alignment.
|
|
8
|
+
* A structure with no resolved mapping (`mappedEntityId` undefined, e.g. a
|
|
9
|
+
* standalone viewer with no transcript) stays fully interactive.
|
|
10
|
+
*/
|
|
11
|
+
export function interactionMatchesMappedEntity(entityId, mappedEntityId) {
|
|
12
|
+
return mappedEntityId === undefined || entityId === mappedEntityId;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Identical residues over the shorter of the two sequences: how much of
|
|
16
|
+
* whichever is smaller, transcript or entity, the other reproduces.
|
|
17
|
+
*
|
|
18
|
+
* A raw match count favours whatever chain is longest, and a complex's partner
|
|
19
|
+
* usually is: on 1H26 the 11-residue p53 peptide matches 11 while CDK2 accrues
|
|
20
|
+
* 58 scattered identities, and on 4ZZJ SIRT1 beats the 7-residue p53 peptide
|
|
21
|
+
* 63 to 6. The Smith-Waterman score is no better there (56 vs 58). Dividing
|
|
22
|
+
* by length asks the question the picker actually has, which chain *is* this
|
|
23
|
+
* gene's product: the peptide scores 0.69 and 0.50, the partners 0.19 and
|
|
24
|
+
* 0.17, and across a ribosome's 55 chains no decoy passes 0.29.
|
|
25
|
+
*
|
|
26
|
+
* Dividing by the *entity's* length alone penalised a fusion construct: a
|
|
27
|
+
* 60-residue target fused to a 370-residue carrier scored 0.14, and a random
|
|
28
|
+
* 10-mer decoy chain with 3 identities beat it a third of the time (measured
|
|
29
|
+
* 2026-09-11). Dividing by the shorter sequence leaves every chain shorter
|
|
30
|
+
* than the transcript scored as before and lets a chain that contains the
|
|
31
|
+
* whole transcript score near 1 however long its tag is. The pseudocount
|
|
32
|
+
* keeps a two-residue fragment that happens to match (a tRNA end in 7K00)
|
|
33
|
+
* from scoring 1.0.
|
|
34
|
+
*/
|
|
35
|
+
const EXPLAINED_PSEUDOCOUNT = 5;
|
|
36
|
+
export function explainedFraction(matches, transcriptLength, entityLength) {
|
|
37
|
+
return (matches / (Math.min(transcriptLength, entityLength) + EXPLAINED_PSEUDOCOUNT));
|
|
38
|
+
}
|
|
39
|
+
function countMatches(pa) {
|
|
40
|
+
const a = transcriptAlignedSeq(pa);
|
|
41
|
+
const b = structureAlignedSeq(pa);
|
|
42
|
+
let matches = 0;
|
|
43
|
+
for (let i = 0; i < a.length; i++) {
|
|
44
|
+
const ca = a[i];
|
|
45
|
+
const cb = b[i];
|
|
46
|
+
if (ca !== '-' && cb !== '-' && ca?.toUpperCase() === cb?.toUpperCase()) {
|
|
47
|
+
matches++;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return matches;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Align one transcript to one entity, stop codons stripped on both sides. An
|
|
54
|
+
* exact match skips the DP entirely; an oversized pair returns undefined rather
|
|
55
|
+
* than locking up the tab. Used both to score every entity of a structure and
|
|
56
|
+
* to honour a user's explicit chain choice.
|
|
57
|
+
*/
|
|
58
|
+
export function alignTranscriptToEntity(transcript, entitySeq, algorithm) {
|
|
59
|
+
const t = stripStopCodon(transcript);
|
|
60
|
+
const s = stripStopCodon(entitySeq);
|
|
61
|
+
if (!t || !s || alignmentTooLarge(t.length, s.length)) {
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
if (s === t) {
|
|
65
|
+
return {
|
|
66
|
+
alignment: {
|
|
67
|
+
consensus: '|'.repeat(t.length),
|
|
68
|
+
alns: [
|
|
69
|
+
{ id: 'seq1', seq: t },
|
|
70
|
+
{ id: 'seq2', seq: s },
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
matches: t.length,
|
|
74
|
+
explained: explainedFraction(t.length, t.length, s.length),
|
|
75
|
+
score: selfScore(t),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
const { alignment, score } = scoredAlignment(t, s, algorithm);
|
|
79
|
+
const matches = countMatches(alignment);
|
|
80
|
+
return {
|
|
81
|
+
alignment,
|
|
82
|
+
matches,
|
|
83
|
+
explained: explainedFraction(matches, t.length, s.length),
|
|
84
|
+
score,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Pick which polymer entity of a structure corresponds to the transcript.
|
|
89
|
+
*
|
|
90
|
+
* The plugin historically hardcoded entity `[0]`, which silently mis-maps every
|
|
91
|
+
* heteromeric / protein-DNA / processed-peptide structure where the protein of
|
|
92
|
+
* interest is some other chain. Selecting by alignment makes the structure self-
|
|
93
|
+
* describe which entity is the gene's protein: an exact sequence match wins
|
|
94
|
+
* outright, otherwise the entity with the highest identity over the shorter
|
|
95
|
+
* sequence (see `explainedFraction`). Nucleic-acid entities are never
|
|
96
|
+
* candidates.
|
|
97
|
+
*
|
|
98
|
+
* Returns `undefined` only when there is nothing to map (no transcript or no
|
|
99
|
+
* protein entities) — never a silent fallback to the wrong entity.
|
|
100
|
+
*/
|
|
101
|
+
export function chooseMappedEntity(transcript, entities, algorithm) {
|
|
102
|
+
const t = stripStopCodon(transcript);
|
|
103
|
+
if (!t) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
const candidates = entities.map(e => typeof e === 'string'
|
|
107
|
+
? { seq: stripStopCodon(e) }
|
|
108
|
+
: { ...e, seq: stripStopCodon(e.seq) });
|
|
109
|
+
const exactIndex = candidates.findIndex(c => !c.nucleicAcid && c.seq.length > 0 && c.seq === t);
|
|
110
|
+
if (exactIndex !== -1) {
|
|
111
|
+
const exact = alignTranscriptToEntity(t, candidates[exactIndex].seq, algorithm);
|
|
112
|
+
return { index: exactIndex, ...exact };
|
|
113
|
+
}
|
|
114
|
+
// Each alignment is an O(len(t) * len(s)) main-thread DP, so a complex with
|
|
115
|
+
// many chains pays it once per chain. Homomers and repeated chains share a
|
|
116
|
+
// sequence, so align each distinct one once and reuse the result.
|
|
117
|
+
const bySeq = new Map();
|
|
118
|
+
let best;
|
|
119
|
+
for (let index = 0; index < candidates.length; index++) {
|
|
120
|
+
const { seq, nucleicAcid } = candidates[index];
|
|
121
|
+
if (nucleicAcid) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!bySeq.has(seq)) {
|
|
125
|
+
bySeq.set(seq, alignTranscriptToEntity(t, seq, algorithm));
|
|
126
|
+
}
|
|
127
|
+
const scored = bySeq.get(seq);
|
|
128
|
+
if (scored && (!best || scored.explained > best.explained)) {
|
|
129
|
+
best = { index, ...scored };
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return best;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=chooseMappedEntity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chooseMappedEntity.js","sourceRoot":"","sources":["../src/chooseMappedEntity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { PairwiseAlignment } from './mappings.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Branded coordinate spaces. Every position in this plugin is a bare `number`,
|
|
4
|
+
* but the *meaning* differs: a structure residue index is not interchangeable
|
|
5
|
+
* with a transcript residue index or an alignment column, and mixing them is
|
|
6
|
+
* the root cause of the off-by-one class of bugs. Branding makes the compiler
|
|
7
|
+
* reject cross-space mixing; construct values with the helpers below at the
|
|
8
|
+
* boundaries where raw numbers enter (molstar picks, hover events, features).
|
|
9
|
+
*
|
|
10
|
+
* Conventions: all are 0-based. StructurePos indexes the ungapped structure
|
|
11
|
+
* sequence; TranscriptPos the ungapped transcript sequence; AlignmentCol a
|
|
12
|
+
* column of the pairwise alignment (gaps included).
|
|
13
|
+
*/
|
|
14
|
+
type Branded<B extends string> = number & {
|
|
15
|
+
readonly __brand: B;
|
|
16
|
+
};
|
|
17
|
+
export type StructurePos = Branded<'StructurePos'>;
|
|
18
|
+
export type TranscriptPos = Branded<'TranscriptPos'>;
|
|
19
|
+
export type AlignmentCol = Branded<'AlignmentCol'>;
|
|
20
|
+
export declare const structurePos: (n: number) => StructurePos;
|
|
21
|
+
export declare const transcriptPos: (n: number) => TranscriptPos;
|
|
22
|
+
export declare const alignmentCol: (n: number) => AlignmentCol;
|
|
23
|
+
export interface CoordinateMaps {
|
|
24
|
+
structureSeqToTranscriptSeqPosition: Record<number, number>;
|
|
25
|
+
transcriptSeqToStructureSeqPosition: Record<number, number>;
|
|
26
|
+
structurePositionToAlignmentMap: Record<number, number>;
|
|
27
|
+
transcriptPositionToAlignmentMap: Record<number, number>;
|
|
28
|
+
alignmentToStructurePosition: Record<number, number>;
|
|
29
|
+
alignmentToTranscriptPosition: Record<number, number>;
|
|
30
|
+
}
|
|
31
|
+
export interface CoordinateMapper {
|
|
32
|
+
structureToTranscript: (p: StructurePos) => TranscriptPos | undefined;
|
|
33
|
+
transcriptToStructure: (p: TranscriptPos) => StructurePos | undefined;
|
|
34
|
+
structureToAlignment: (p: StructurePos) => AlignmentCol | undefined;
|
|
35
|
+
alignmentToStructure: (c: AlignmentCol) => StructurePos | undefined;
|
|
36
|
+
transcriptToAlignment: (p: TranscriptPos) => AlignmentCol | undefined;
|
|
37
|
+
alignmentToTranscript: (c: AlignmentCol) => TranscriptPos | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Raw lookup tables, for consumers that iterate the whole map rather than
|
|
40
|
+
* convert a single position (e.g. per-residue track rendering, selection of
|
|
41
|
+
* all aligned residues). Plain numbers — prefer the typed methods above for
|
|
42
|
+
* point conversions.
|
|
43
|
+
*/
|
|
44
|
+
readonly maps: CoordinateMaps;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Builds every coordinate conversion once from a pairwise alignment, replacing
|
|
48
|
+
* the scatter of per-getter map builds + repeated invertMap calls. The branded
|
|
49
|
+
* methods are the preferred API; `maps` stays unbranded for whole-map consumers.
|
|
50
|
+
*/
|
|
51
|
+
export declare function makeCoordinateMapper(pairwiseAlignment: PairwiseAlignment): CoordinateMapper;
|
|
52
|
+
/**
|
|
53
|
+
* The 0-based half-open structure-position range covering an inclusive range
|
|
54
|
+
* of 1-based transcript residues, the numbering a UniProt feature or a domain
|
|
55
|
+
* map uses. Residues the structure lacks are skipped, so a range that runs
|
|
56
|
+
* past a fragment's end clamps to the last modeled residue; undefined when none
|
|
57
|
+
* of the range aligns to the structure.
|
|
58
|
+
*/
|
|
59
|
+
export declare function transcriptRangeToStructureRange(mapper: CoordinateMapper, range: {
|
|
60
|
+
start: number;
|
|
61
|
+
end: number;
|
|
62
|
+
}): {
|
|
63
|
+
start: number;
|
|
64
|
+
end: number;
|
|
65
|
+
} | undefined;
|
|
66
|
+
export {};
|