@jbrowse/plugin-alignments 2.16.1 → 2.17.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/dist/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +1 -2
- package/dist/AlignmentsFeatureDetail/getSAFeatures.js +2 -2
- package/dist/AlignmentsFeatureDetail/stateModelFactory.d.ts +1 -1
- package/dist/BamAdapter/BamAdapter.d.ts +3 -2
- package/dist/BamAdapter/BamAdapter.js +34 -11
- package/dist/BamAdapter/BamSlightlyLazyFeature.d.ts +3 -17
- package/dist/BamAdapter/BamSlightlyLazyFeature.js +42 -72
- package/dist/CramAdapter/CramAdapter.d.ts +4 -3
- package/dist/CramAdapter/CramAdapter.js +24 -7
- package/dist/CramAdapter/CramSlightlyLazyFeature.d.ts +21 -27
- package/dist/CramAdapter/CramSlightlyLazyFeature.js +74 -73
- package/dist/CramAdapter/util.d.ts +1 -10
- package/dist/LinearAlignmentsDisplay/components/AlignmentsDisplay.d.ts +1 -1
- package/dist/LinearAlignmentsDisplay/index.js +2 -2
- package/dist/LinearAlignmentsDisplay/{models/model.d.ts → model.d.ts} +6 -3
- package/dist/LinearAlignmentsDisplay/{models/model.js → model.js} +11 -7
- package/dist/LinearPileupDisplay/SharedLinearPileupDisplayMixin.d.ts +6 -27
- package/dist/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +43 -21
- package/dist/LinearPileupDisplay/components/ColorByTagDialog.d.ts +5 -4
- package/dist/LinearPileupDisplay/components/ColorByTagDialog.js +3 -1
- package/dist/LinearPileupDisplay/components/GroupByDialog.js +8 -6
- package/dist/LinearPileupDisplay/components/SortByTagDialog.js +6 -4
- package/dist/LinearPileupDisplay/model.d.ts +40 -40
- package/dist/LinearPileupDisplay/model.js +118 -41
- package/dist/LinearReadArcsDisplay/components/ReactComponent.js +1 -1
- package/dist/LinearReadArcsDisplay/model.d.ts +22 -21
- package/dist/LinearReadArcsDisplay/model.js +13 -14
- package/dist/LinearReadCloudDisplay/components/ReactComponent.js +1 -1
- package/dist/LinearReadCloudDisplay/model.d.ts +14 -22
- package/dist/LinearReadCloudDisplay/model.js +12 -13
- package/dist/LinearSNPCoverageDisplay/components/Tooltip.js +49 -19
- package/dist/LinearSNPCoverageDisplay/index.js +3 -2
- package/dist/LinearSNPCoverageDisplay/{models/model.d.ts → model.d.ts} +3 -13
- package/dist/LinearSNPCoverageDisplay/{models/model.js → model.js} +71 -45
- package/dist/MismatchParser/cigarToMismatches.d.ts +3 -0
- package/dist/MismatchParser/cigarToMismatches.js +94 -0
- package/dist/MismatchParser/getNextRefPos.d.ts +4 -0
- package/dist/MismatchParser/getNextRefPos.js +40 -0
- package/dist/MismatchParser/index.d.ts +4 -29
- package/dist/MismatchParser/index.js +10 -327
- package/dist/MismatchParser/mdToMismatches.d.ts +3 -0
- package/dist/MismatchParser/mdToMismatches.js +80 -0
- package/dist/ModificationParser/index.d.ts +19 -0
- package/dist/ModificationParser/index.js +144 -0
- package/dist/PileupRPC/methods/GetGlobalValueForTag.js +1 -2
- package/dist/PileupRPC/methods/GetReducedFeatures.d.ts +1 -1
- package/dist/PileupRPC/methods/GetReducedFeatures.js +19 -16
- package/dist/PileupRPC/methods/GetVisibleModifications.d.ts +2 -1
- package/dist/PileupRPC/methods/GetVisibleModifications.js +9 -6
- package/dist/PileupRenderer/PileupLayoutSession.d.ts +8 -7
- package/dist/PileupRenderer/PileupRenderer.d.ts +6 -14
- package/dist/PileupRenderer/PileupRenderer.js +7 -5
- package/dist/PileupRenderer/renderAlignment.js +17 -4
- package/dist/PileupRenderer/renderAlignmentShape.js +102 -21
- package/dist/PileupRenderer/renderMethylation.d.ts +2 -1
- package/dist/PileupRenderer/renderMethylation.js +17 -9
- package/dist/PileupRenderer/renderMismatches.js +19 -19
- package/dist/PileupRenderer/renderModifications.d.ts +3 -2
- package/dist/PileupRenderer/renderModifications.js +31 -34
- package/dist/PileupRenderer/renderPerBaseLettering.d.ts +2 -1
- package/dist/PileupRenderer/renderPerBaseLettering.js +1 -3
- package/dist/PileupRenderer/renderPerBaseQuality.d.ts +2 -1
- package/dist/PileupRenderer/renderPerBaseQuality.js +1 -3
- package/dist/PileupRenderer/renderSoftClipping.js +6 -6
- package/dist/PileupRenderer/sortUtil.d.ts +2 -7
- package/dist/PileupRenderer/sortUtil.js +13 -13
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +10 -5
- package/dist/SNPCoverageAdapter/generateCoverageBins.d.ts +13 -9
- package/dist/SNPCoverageAdapter/generateCoverageBins.js +269 -166
- package/dist/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +2 -1
- package/dist/SNPCoverageRenderer/SNPCoverageRenderer.js +171 -54
- package/dist/shared/color.d.ts +0 -10
- package/dist/shared/color.js +1 -7
- package/{esm/shared → dist/shared/components}/BaseDisplayComponent.d.ts +2 -2
- package/{esm/shared → dist/shared/components}/FilterByTagDialog.d.ts +3 -3
- package/dist/shared/{FilterByTagDialog.js → components/FilterByTagDialog.js} +5 -1
- package/dist/shared/fetchChains.js +1 -2
- package/dist/shared/getMaximumModificationAtEachPosition.d.ts +8 -0
- package/dist/shared/getMaximumModificationAtEachPosition.js +42 -0
- package/dist/shared/getUniqueModifications.d.ts +14 -0
- package/dist/shared/getUniqueModifications.js +16 -0
- package/dist/shared/getUniqueTags.d.ts +15 -0
- package/dist/shared/getUniqueTags.js +18 -0
- package/dist/shared/types.d.ts +94 -0
- package/dist/shared/util.d.ts +8 -0
- package/dist/shared/util.js +26 -0
- package/dist/util.d.ts +6 -3
- package/dist/util.js +24 -29
- package/esm/AlignmentsFeatureDetail/AlignmentsFeatureDetail.js +1 -2
- package/esm/AlignmentsFeatureDetail/getSAFeatures.js +2 -2
- package/esm/AlignmentsFeatureDetail/stateModelFactory.d.ts +1 -1
- package/esm/BamAdapter/BamAdapter.d.ts +3 -2
- package/esm/BamAdapter/BamAdapter.js +31 -8
- package/esm/BamAdapter/BamSlightlyLazyFeature.d.ts +3 -17
- package/esm/BamAdapter/BamSlightlyLazyFeature.js +43 -73
- package/esm/CramAdapter/CramAdapter.d.ts +4 -3
- package/esm/CramAdapter/CramAdapter.js +22 -5
- package/esm/CramAdapter/CramSlightlyLazyFeature.d.ts +21 -27
- package/esm/CramAdapter/CramSlightlyLazyFeature.js +74 -73
- package/esm/CramAdapter/util.d.ts +1 -10
- package/esm/LinearAlignmentsDisplay/components/AlignmentsDisplay.d.ts +1 -1
- package/esm/LinearAlignmentsDisplay/index.js +2 -2
- package/esm/LinearAlignmentsDisplay/{models/model.d.ts → model.d.ts} +6 -3
- package/esm/LinearAlignmentsDisplay/{models/model.js → model.js} +11 -7
- package/esm/LinearPileupDisplay/SharedLinearPileupDisplayMixin.d.ts +6 -27
- package/esm/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +45 -23
- package/esm/LinearPileupDisplay/components/ColorByTagDialog.d.ts +5 -4
- package/esm/LinearPileupDisplay/components/ColorByTagDialog.js +3 -1
- package/esm/LinearPileupDisplay/components/GroupByDialog.js +8 -6
- package/esm/LinearPileupDisplay/components/SortByTagDialog.js +6 -4
- package/esm/LinearPileupDisplay/model.d.ts +40 -40
- package/esm/LinearPileupDisplay/model.js +119 -42
- package/esm/LinearReadArcsDisplay/components/ReactComponent.js +1 -1
- package/esm/LinearReadArcsDisplay/model.d.ts +22 -21
- package/esm/LinearReadArcsDisplay/model.js +14 -15
- package/esm/LinearReadCloudDisplay/components/ReactComponent.js +1 -1
- package/esm/LinearReadCloudDisplay/model.d.ts +14 -22
- package/esm/LinearReadCloudDisplay/model.js +13 -14
- package/esm/LinearSNPCoverageDisplay/components/Tooltip.js +49 -19
- package/esm/LinearSNPCoverageDisplay/index.js +3 -2
- package/esm/LinearSNPCoverageDisplay/{models/model.d.ts → model.d.ts} +3 -13
- package/esm/LinearSNPCoverageDisplay/{models/model.js → model.js} +72 -46
- package/esm/MismatchParser/cigarToMismatches.d.ts +3 -0
- package/esm/MismatchParser/cigarToMismatches.js +91 -0
- package/esm/MismatchParser/getNextRefPos.d.ts +4 -0
- package/esm/MismatchParser/getNextRefPos.js +37 -0
- package/esm/MismatchParser/index.d.ts +4 -29
- package/esm/MismatchParser/index.js +5 -317
- package/esm/MismatchParser/mdToMismatches.d.ts +3 -0
- package/esm/MismatchParser/mdToMismatches.js +77 -0
- package/esm/ModificationParser/index.d.ts +19 -0
- package/esm/ModificationParser/index.js +138 -0
- package/esm/PileupRPC/methods/GetGlobalValueForTag.js +1 -2
- package/esm/PileupRPC/methods/GetReducedFeatures.d.ts +1 -1
- package/esm/PileupRPC/methods/GetReducedFeatures.js +19 -16
- package/esm/PileupRPC/methods/GetVisibleModifications.d.ts +2 -1
- package/esm/PileupRPC/methods/GetVisibleModifications.js +9 -6
- package/esm/PileupRenderer/PileupLayoutSession.d.ts +8 -7
- package/esm/PileupRenderer/PileupRenderer.d.ts +6 -14
- package/esm/PileupRenderer/PileupRenderer.js +8 -6
- package/esm/PileupRenderer/renderAlignment.js +17 -4
- package/esm/PileupRenderer/renderAlignmentShape.js +102 -21
- package/esm/PileupRenderer/renderMethylation.d.ts +2 -1
- package/esm/PileupRenderer/renderMethylation.js +17 -9
- package/esm/PileupRenderer/renderMismatches.js +19 -19
- package/esm/PileupRenderer/renderModifications.d.ts +3 -2
- package/esm/PileupRenderer/renderModifications.js +30 -33
- package/esm/PileupRenderer/renderPerBaseLettering.d.ts +2 -1
- package/esm/PileupRenderer/renderPerBaseLettering.js +1 -3
- package/esm/PileupRenderer/renderPerBaseQuality.d.ts +2 -1
- package/esm/PileupRenderer/renderPerBaseQuality.js +1 -3
- package/esm/PileupRenderer/renderSoftClipping.js +6 -6
- package/esm/PileupRenderer/sortUtil.d.ts +2 -7
- package/esm/PileupRenderer/sortUtil.js +13 -13
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js +10 -5
- package/esm/SNPCoverageAdapter/generateCoverageBins.d.ts +13 -9
- package/esm/SNPCoverageAdapter/generateCoverageBins.js +269 -166
- package/esm/SNPCoverageRenderer/SNPCoverageRenderer.d.ts +2 -1
- package/esm/SNPCoverageRenderer/SNPCoverageRenderer.js +171 -54
- package/esm/shared/color.d.ts +0 -10
- package/esm/shared/color.js +0 -6
- package/{dist/shared → esm/shared/components}/BaseDisplayComponent.d.ts +2 -2
- package/{dist/shared → esm/shared/components}/FilterByTagDialog.d.ts +3 -3
- package/esm/shared/{FilterByTagDialog.js → components/FilterByTagDialog.js} +5 -1
- package/esm/shared/fetchChains.js +1 -2
- package/esm/shared/getMaximumModificationAtEachPosition.d.ts +8 -0
- package/esm/shared/getMaximumModificationAtEachPosition.js +39 -0
- package/esm/shared/getUniqueModifications.d.ts +14 -0
- package/esm/shared/getUniqueModifications.js +13 -0
- package/esm/shared/getUniqueTags.d.ts +15 -0
- package/esm/shared/getUniqueTags.js +15 -0
- package/esm/shared/types.d.ts +94 -0
- package/esm/shared/util.d.ts +8 -0
- package/esm/shared/util.js +23 -0
- package/esm/util.d.ts +6 -3
- package/esm/util.js +22 -26
- package/package.json +4 -4
- package/dist/LinearPileupDisplay/components/ColorByModificationsDialog.d.ts +0 -15
- package/dist/LinearPileupDisplay/components/ColorByModificationsDialog.js +0 -41
- package/dist/LinearPileupDisplay/components/ModificationsTable.d.ts +0 -4
- package/dist/LinearPileupDisplay/components/ModificationsTable.js +0 -28
- package/dist/SNPCoverageAdapter/util.d.ts +0 -25
- package/dist/shared/index.d.ts +0 -49
- package/dist/shared/index.js +0 -41
- package/esm/LinearPileupDisplay/components/ColorByModificationsDialog.d.ts +0 -15
- package/esm/LinearPileupDisplay/components/ColorByModificationsDialog.js +0 -36
- package/esm/LinearPileupDisplay/components/ModificationsTable.d.ts +0 -4
- package/esm/LinearPileupDisplay/components/ModificationsTable.js +0 -22
- package/esm/SNPCoverageAdapter/util.d.ts +0 -25
- package/esm/shared/index.d.ts +0 -49
- package/esm/shared/index.js +0 -36
- /package/dist/LinearAlignmentsDisplay/{models/alignmentsModel.d.ts → alignmentsModel.d.ts} +0 -0
- /package/dist/LinearAlignmentsDisplay/{models/alignmentsModel.js → alignmentsModel.js} +0 -0
- /package/dist/LinearAlignmentsDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
- /package/dist/LinearAlignmentsDisplay/{models/configSchema.js → configSchema.js} +0 -0
- /package/dist/LinearAlignmentsDisplay/{models/util.d.ts → util.d.ts} +0 -0
- /package/dist/LinearAlignmentsDisplay/{models/util.js → util.js} +0 -0
- /package/dist/LinearSNPCoverageDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
- /package/dist/LinearSNPCoverageDisplay/{models/configSchema.js → configSchema.js} +0 -0
- /package/dist/shared/{BaseDisplayComponent.js → components/BaseDisplayComponent.js} +0 -0
- /package/dist/shared/{renderSvg.d.ts → renderSvgUtil.d.ts} +0 -0
- /package/dist/shared/{renderSvg.js → renderSvgUtil.js} +0 -0
- /package/dist/{SNPCoverageAdapter/util.js → shared/types.js} +0 -0
- /package/esm/LinearAlignmentsDisplay/{models/alignmentsModel.d.ts → alignmentsModel.d.ts} +0 -0
- /package/esm/LinearAlignmentsDisplay/{models/alignmentsModel.js → alignmentsModel.js} +0 -0
- /package/esm/LinearAlignmentsDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
- /package/esm/LinearAlignmentsDisplay/{models/configSchema.js → configSchema.js} +0 -0
- /package/esm/LinearAlignmentsDisplay/{models/util.d.ts → util.d.ts} +0 -0
- /package/esm/LinearAlignmentsDisplay/{models/util.js → util.js} +0 -0
- /package/esm/LinearSNPCoverageDisplay/{models/configSchema.d.ts → configSchema.d.ts} +0 -0
- /package/esm/LinearSNPCoverageDisplay/{models/configSchema.js → configSchema.js} +0 -0
- /package/esm/shared/{BaseDisplayComponent.js → components/BaseDisplayComponent.js} +0 -0
- /package/esm/shared/{renderSvg.d.ts → renderSvgUtil.d.ts} +0 -0
- /package/esm/shared/{renderSvg.js → renderSvgUtil.js} +0 -0
- /package/esm/{SNPCoverageAdapter/util.js → shared/types.js} +0 -0
|
@@ -1,41 +1,15 @@
|
|
|
1
1
|
import { Feature } from '@jbrowse/core/util';
|
|
2
2
|
import type { Buffer } from 'buffer';
|
|
3
|
-
|
|
4
|
-
qual?: number;
|
|
5
|
-
start: number;
|
|
6
|
-
length: number;
|
|
7
|
-
type: string;
|
|
8
|
-
base: string;
|
|
9
|
-
altbase?: string;
|
|
10
|
-
seq?: string;
|
|
11
|
-
cliplen?: number;
|
|
12
|
-
}
|
|
3
|
+
import { Mismatch } from '../shared/types';
|
|
13
4
|
export declare function parseCigar(cigar?: string): string[];
|
|
14
|
-
export declare function
|
|
15
|
-
/**
|
|
16
|
-
* parse a SAM MD tag to find mismatching bases of the template versus the
|
|
17
|
-
* reference @returns array of mismatches and their positions
|
|
18
|
-
*/
|
|
19
|
-
export declare function mdToMismatches(mdstring: string, ops: string[], cigarMismatches: Mismatch[], seq: string, qual?: Buffer): Mismatch[];
|
|
20
|
-
export declare function getMismatches(cigar: string, md?: string, seq?: string, ref?: string, qual?: Buffer): Mismatch[];
|
|
21
|
-
export declare function getNextRefPos(cigarOps: string[], positions: number[]): Generator<number, void, unknown>;
|
|
22
|
-
export declare function getModificationProbabilities(feature: Feature): number[] | undefined;
|
|
23
|
-
export declare function getMethBins(feature: Feature): {
|
|
24
|
-
methBins: number[];
|
|
25
|
-
methProbs: number[];
|
|
26
|
-
};
|
|
27
|
-
export declare function getModificationPositions(mm: string, fseq: string, fstrand: number): {
|
|
28
|
-
type: string;
|
|
29
|
-
positions: number[];
|
|
30
|
-
}[];
|
|
31
|
-
export declare function getModificationTypes(mm: string): string[];
|
|
5
|
+
export declare function getMismatches(cigar?: string, md?: string, seq?: string, ref?: string, qual?: Buffer): Mismatch[];
|
|
32
6
|
export declare function getOrientedCigar(flip: boolean, cigar: string[]): string[];
|
|
33
7
|
export declare function getOrientedMismatches(flip: boolean, cigar: string): Mismatch[];
|
|
34
8
|
export declare function getLengthOnRef(cigar: string): number;
|
|
35
9
|
export declare function getLength(cigar: string): number;
|
|
36
10
|
export declare function getLengthSansClipping(cigar: string): number;
|
|
37
11
|
export declare function getClip(cigar: string, strand: number): number;
|
|
38
|
-
export declare function getTag(
|
|
12
|
+
export declare function getTag(feature: Feature, tag: string): any;
|
|
39
13
|
export declare function featurizeSA(SA: string | undefined, id: string, strand: number, readName: string, normalize?: boolean): {
|
|
40
14
|
refName: string;
|
|
41
15
|
start: number;
|
|
@@ -51,3 +25,4 @@ export declare function featurizeSA(SA: string | undefined, id: string, strand:
|
|
|
51
25
|
refName: string;
|
|
52
26
|
};
|
|
53
27
|
}[];
|
|
28
|
+
export { getNextRefPos } from './getNextRefPos';
|
|
@@ -1,184 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
const mdRegex = new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
|
|
4
|
-
const modificationRegex = new RegExp(/([A-Z])([-+])([^,.?]+)([.?])?/);
|
|
1
|
+
import { mdToMismatches } from './mdToMismatches';
|
|
2
|
+
import { cigarToMismatches } from './cigarToMismatches';
|
|
5
3
|
const cigarRegex = new RegExp(/([MIDNSHPX=])/);
|
|
6
4
|
const startClip = new RegExp(/(\d+)[SH]$/);
|
|
7
5
|
const endClip = new RegExp(/^(\d+)([SH])/);
|
|
8
6
|
export function parseCigar(cigar = '') {
|
|
9
7
|
return cigar.split(cigarRegex).slice(0, -1);
|
|
10
8
|
}
|
|
11
|
-
export function cigarToMismatches(ops, seq, ref, qual) {
|
|
12
|
-
let roffset = 0; // reference offset
|
|
13
|
-
let soffset = 0; // seq offset
|
|
14
|
-
const mismatches = [];
|
|
15
|
-
const hasRefAndSeq = ref && seq;
|
|
16
|
-
for (let i = 0; i < ops.length; i += 2) {
|
|
17
|
-
const len = +ops[i];
|
|
18
|
-
const op = ops[i + 1];
|
|
19
|
-
if (op === 'M' || op === '=' || op === 'E') {
|
|
20
|
-
if (hasRefAndSeq) {
|
|
21
|
-
for (let j = 0; j < len; j++) {
|
|
22
|
-
if (
|
|
23
|
-
// @ts-ignore in the full yarn build of the repo, this says that object is possibly undefined for some reason, ignored
|
|
24
|
-
seq[soffset + j].toUpperCase() !== ref[roffset + j].toUpperCase()) {
|
|
25
|
-
mismatches.push({
|
|
26
|
-
start: roffset + j,
|
|
27
|
-
type: 'mismatch',
|
|
28
|
-
base: seq[soffset + j],
|
|
29
|
-
altbase: ref[roffset + j],
|
|
30
|
-
length: 1,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
soffset += len;
|
|
36
|
-
}
|
|
37
|
-
if (op === 'I') {
|
|
38
|
-
mismatches.push({
|
|
39
|
-
start: roffset,
|
|
40
|
-
type: 'insertion',
|
|
41
|
-
base: `${len}`,
|
|
42
|
-
length: 0,
|
|
43
|
-
});
|
|
44
|
-
soffset += len;
|
|
45
|
-
}
|
|
46
|
-
else if (op === 'D') {
|
|
47
|
-
mismatches.push({
|
|
48
|
-
start: roffset,
|
|
49
|
-
type: 'deletion',
|
|
50
|
-
base: '*',
|
|
51
|
-
length: len,
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
else if (op === 'N') {
|
|
55
|
-
mismatches.push({
|
|
56
|
-
start: roffset,
|
|
57
|
-
type: 'skip',
|
|
58
|
-
base: 'N',
|
|
59
|
-
length: len,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
else if (op === 'X') {
|
|
63
|
-
const r = (seq === null || seq === void 0 ? void 0 : seq.slice(soffset, soffset + len)) || [];
|
|
64
|
-
const q = (qual === null || qual === void 0 ? void 0 : qual.subarray(soffset, soffset + len)) || [];
|
|
65
|
-
for (let j = 0; j < len; j++) {
|
|
66
|
-
mismatches.push({
|
|
67
|
-
start: roffset + j,
|
|
68
|
-
type: 'mismatch',
|
|
69
|
-
base: r[j],
|
|
70
|
-
qual: q[j],
|
|
71
|
-
length: 1,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
soffset += len;
|
|
75
|
-
}
|
|
76
|
-
else if (op === 'H') {
|
|
77
|
-
mismatches.push({
|
|
78
|
-
start: roffset,
|
|
79
|
-
type: 'hardclip',
|
|
80
|
-
base: `H${len}`,
|
|
81
|
-
cliplen: len,
|
|
82
|
-
length: 1,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
else if (op === 'S') {
|
|
86
|
-
mismatches.push({
|
|
87
|
-
start: roffset,
|
|
88
|
-
type: 'softclip',
|
|
89
|
-
base: `S${len}`,
|
|
90
|
-
cliplen: len,
|
|
91
|
-
length: 1,
|
|
92
|
-
});
|
|
93
|
-
soffset += len;
|
|
94
|
-
}
|
|
95
|
-
if (op !== 'I' && op !== 'S' && op !== 'H') {
|
|
96
|
-
roffset += len;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return mismatches;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* parse a SAM MD tag to find mismatching bases of the template versus the
|
|
103
|
-
* reference @returns array of mismatches and their positions
|
|
104
|
-
*/
|
|
105
|
-
export function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
106
|
-
let curr = { start: 0, base: '', length: 0, type: 'mismatch' };
|
|
107
|
-
let lastCigar = 0;
|
|
108
|
-
let lastTemplateOffset = 0;
|
|
109
|
-
let lastRefOffset = 0;
|
|
110
|
-
let lastSkipPos = 0;
|
|
111
|
-
const mismatchRecords = [];
|
|
112
|
-
const skips = cigarMismatches.filter(cigar => cigar.type === 'skip');
|
|
113
|
-
// convert a position on the reference sequence to a position
|
|
114
|
-
// on the template sequence, taking into account hard and soft
|
|
115
|
-
// clipping of reads
|
|
116
|
-
function nextRecord() {
|
|
117
|
-
mismatchRecords.push(curr);
|
|
118
|
-
// get a new mismatch record ready
|
|
119
|
-
curr = {
|
|
120
|
-
start: curr.start + curr.length,
|
|
121
|
-
length: 0,
|
|
122
|
-
base: '',
|
|
123
|
-
type: 'mismatch',
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
function getTemplateCoordLocal(refCoord) {
|
|
127
|
-
let templateOffset = lastTemplateOffset;
|
|
128
|
-
let refOffset = lastRefOffset;
|
|
129
|
-
for (let i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
|
|
130
|
-
const len = +ops[i];
|
|
131
|
-
const op = ops[i + 1];
|
|
132
|
-
if (op === 'S' || op === 'I') {
|
|
133
|
-
templateOffset += len;
|
|
134
|
-
}
|
|
135
|
-
else if (op === 'D' || op === 'P' || op === 'N') {
|
|
136
|
-
refOffset += len;
|
|
137
|
-
}
|
|
138
|
-
else if (op !== 'H') {
|
|
139
|
-
templateOffset += len;
|
|
140
|
-
refOffset += len;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
lastTemplateOffset = templateOffset;
|
|
144
|
-
lastRefOffset = refOffset;
|
|
145
|
-
return templateOffset - (refOffset - refCoord);
|
|
146
|
-
}
|
|
147
|
-
// now actually parse the MD string
|
|
148
|
-
const md = mdstring.match(mdRegex) || [];
|
|
149
|
-
for (const token of md) {
|
|
150
|
-
const num = +token;
|
|
151
|
-
if (!Number.isNaN(num)) {
|
|
152
|
-
curr.start += num;
|
|
153
|
-
}
|
|
154
|
-
else if (token.startsWith('^')) {
|
|
155
|
-
curr.start += token.length - 1;
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
// mismatch
|
|
159
|
-
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
160
|
-
for (let j = 0; j < token.length; j += 1) {
|
|
161
|
-
curr.length = 1;
|
|
162
|
-
while (lastSkipPos < skips.length) {
|
|
163
|
-
const mismatch = skips[lastSkipPos];
|
|
164
|
-
if (curr.start >= mismatch.start) {
|
|
165
|
-
curr.start += mismatch.length;
|
|
166
|
-
lastSkipPos++;
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
break;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
const s = getTemplateCoordLocal(curr.start);
|
|
173
|
-
curr.base = seq[s] || 'X';
|
|
174
|
-
curr.qual = qual === null || qual === void 0 ? void 0 : qual[s];
|
|
175
|
-
curr.altbase = token;
|
|
176
|
-
nextRecord();
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return mismatchRecords;
|
|
181
|
-
}
|
|
182
9
|
export function getMismatches(cigar, md, seq, ref, qual) {
|
|
183
10
|
let mismatches = [];
|
|
184
11
|
const ops = parseCigar(cigar);
|
|
@@ -192,145 +19,6 @@ export function getMismatches(cigar, md, seq, ref, qual) {
|
|
|
192
19
|
}
|
|
193
20
|
return mismatches;
|
|
194
21
|
}
|
|
195
|
-
// get relative reference sequence positions for positions given relative to
|
|
196
|
-
// the read sequence
|
|
197
|
-
export function* getNextRefPos(cigarOps, positions) {
|
|
198
|
-
let readPos = 0;
|
|
199
|
-
let refPos = 0;
|
|
200
|
-
let currPos = 0;
|
|
201
|
-
for (let i = 0; i < cigarOps.length && currPos < positions.length; i += 2) {
|
|
202
|
-
const len = +cigarOps[i];
|
|
203
|
-
const op = cigarOps[i + 1];
|
|
204
|
-
if (op === 'S' || op === 'I') {
|
|
205
|
-
for (let i = 0; i < len && currPos < positions.length; i++) {
|
|
206
|
-
if (positions[currPos] === readPos + i) {
|
|
207
|
-
currPos++;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
readPos += len;
|
|
211
|
-
}
|
|
212
|
-
else if (op === 'D' || op === 'N') {
|
|
213
|
-
refPos += len;
|
|
214
|
-
}
|
|
215
|
-
else if (op === 'M' || op === 'X' || op === '=') {
|
|
216
|
-
for (let i = 0; i < len && currPos < positions.length; i++) {
|
|
217
|
-
if (positions[currPos] === readPos + i) {
|
|
218
|
-
yield refPos + i;
|
|
219
|
-
currPos++;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
readPos += len;
|
|
223
|
-
refPos += len;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
export function getModificationProbabilities(feature) {
|
|
228
|
-
var _a;
|
|
229
|
-
const m = getTagAlt(feature, 'ML', 'Ml') || [];
|
|
230
|
-
return m
|
|
231
|
-
? (typeof m === 'string' ? m.split(',').map(e => +e) : m).map(e => e / 255)
|
|
232
|
-
: (_a = getTagAlt(feature, 'MP', 'Mp')) === null || _a === void 0 ? void 0 : _a.split('').map(s => s.charCodeAt(0) - 33).map(elt => Math.min(1, elt / 50));
|
|
233
|
-
}
|
|
234
|
-
export function getMethBins(feature) {
|
|
235
|
-
const fstart = feature.get('start');
|
|
236
|
-
const fend = feature.get('end');
|
|
237
|
-
const fstrand = feature.get('strand');
|
|
238
|
-
const flen = fend - fstart;
|
|
239
|
-
const mm = getTagAlt(feature, 'MM', 'Mm') || '';
|
|
240
|
-
const methBins = new Array(flen);
|
|
241
|
-
const methProbs = new Array(flen);
|
|
242
|
-
const seq = feature.get('seq');
|
|
243
|
-
if (seq) {
|
|
244
|
-
const ops = parseCigar(feature.get('CIGAR'));
|
|
245
|
-
const probabilities = getModificationProbabilities(feature);
|
|
246
|
-
const modifications = getModificationPositions(mm, seq, fstrand);
|
|
247
|
-
let probIndex = 0;
|
|
248
|
-
for (const { type, positions } of modifications) {
|
|
249
|
-
if (type === 'm') {
|
|
250
|
-
for (const ref of getNextRefPos(ops, positions)) {
|
|
251
|
-
const prob = (probabilities === null || probabilities === void 0 ? void 0 : probabilities[probIndex]) || 0;
|
|
252
|
-
probIndex++;
|
|
253
|
-
if (ref >= 0 && ref < flen) {
|
|
254
|
-
methBins[ref] = 1;
|
|
255
|
-
methProbs[ref] = prob;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return { methBins, methProbs };
|
|
262
|
-
}
|
|
263
|
-
export function getModificationPositions(mm, fseq, fstrand) {
|
|
264
|
-
const seq = fstrand === -1 ? revcom(fseq) : fseq;
|
|
265
|
-
const mods = mm.split(';').filter(mod => !!mod);
|
|
266
|
-
const result = [];
|
|
267
|
-
for (const mod of mods) {
|
|
268
|
-
const [basemod, ...skips] = mod.split(',');
|
|
269
|
-
// regexes based on parse_mm.pl from hts-specs
|
|
270
|
-
const matches = modificationRegex.exec(basemod);
|
|
271
|
-
if (!matches) {
|
|
272
|
-
throw new Error('bad format for MM tag');
|
|
273
|
-
}
|
|
274
|
-
const [, base, strand, typestr] = matches;
|
|
275
|
-
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
|
|
276
|
-
// split, and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
277
|
-
const types = typestr.split(/(\d+|.)/).filter(f => !!f);
|
|
278
|
-
if (strand === '-') {
|
|
279
|
-
console.warn('unsupported negative strand modifications');
|
|
280
|
-
// make sure to return a somewhat matching type even in this case
|
|
281
|
-
result.push({ type: 'unsupported', positions: [] });
|
|
282
|
-
}
|
|
283
|
-
// this logic also based on parse_mm.pl from hts-specs is that in the
|
|
284
|
-
// sequence of the read, if we have a modification type e.g. C+m;2 and a
|
|
285
|
-
// sequence ACGTACGTAC we skip the two instances of C and go to the last
|
|
286
|
-
// C
|
|
287
|
-
for (const type of types) {
|
|
288
|
-
let i = 0;
|
|
289
|
-
const positions = [];
|
|
290
|
-
for (const d of skips) {
|
|
291
|
-
let delta = +d;
|
|
292
|
-
do {
|
|
293
|
-
if (base === 'N' || base === seq[i]) {
|
|
294
|
-
delta--;
|
|
295
|
-
}
|
|
296
|
-
i++;
|
|
297
|
-
} while (delta >= 0 && i < seq.length);
|
|
298
|
-
if (fstrand === -1) {
|
|
299
|
-
const pos = seq.length - i;
|
|
300
|
-
if (pos >= 0) {
|
|
301
|
-
// avoid negative-number-positions in array, seen in #4629 cause
|
|
302
|
-
// unknown, could warrant some further investigation
|
|
303
|
-
positions.unshift(pos);
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
else {
|
|
307
|
-
positions.push(i - 1);
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
result.push({
|
|
311
|
-
type,
|
|
312
|
-
positions,
|
|
313
|
-
});
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
return result;
|
|
317
|
-
}
|
|
318
|
-
export function getModificationTypes(mm) {
|
|
319
|
-
return mm
|
|
320
|
-
.split(';')
|
|
321
|
-
.filter(mod => !!mod)
|
|
322
|
-
.flatMap(mod => {
|
|
323
|
-
const basemod = mod.split(',')[0];
|
|
324
|
-
const matches = modificationRegex.exec(basemod);
|
|
325
|
-
if (!matches) {
|
|
326
|
-
throw new Error(`bad format for MM tag: ${mm}`);
|
|
327
|
-
}
|
|
328
|
-
const typestr = matches[3];
|
|
329
|
-
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
|
|
330
|
-
// split, and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
331
|
-
return typestr.split(/(\d+|.)/).filter(f => !!f);
|
|
332
|
-
});
|
|
333
|
-
}
|
|
334
22
|
export function getOrientedCigar(flip, cigar) {
|
|
335
23
|
if (flip) {
|
|
336
24
|
const ret = [];
|
|
@@ -394,9 +82,8 @@ export function getClip(cigar, strand) {
|
|
|
394
82
|
? +(startClip.exec(cigar) || [])[1] || 0
|
|
395
83
|
: +(endClip.exec(cigar) || [])[1] || 0;
|
|
396
84
|
}
|
|
397
|
-
export function getTag(
|
|
398
|
-
|
|
399
|
-
return tags ? tags[tag] : f.get(tag);
|
|
85
|
+
export function getTag(feature, tag) {
|
|
86
|
+
return feature.get('tags')[tag];
|
|
400
87
|
}
|
|
401
88
|
// produces a list of "feature-like" object from parsing supplementary
|
|
402
89
|
// alignments in the SA tag
|
|
@@ -434,3 +121,4 @@ export function featurizeSA(SA, id, strand, readName, normalize) {
|
|
|
434
121
|
};
|
|
435
122
|
})) || []);
|
|
436
123
|
}
|
|
124
|
+
export { getNextRefPos } from './getNextRefPos';
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const mdRegex = new RegExp(/(\d+|\^[a-z]+|[a-z])/gi);
|
|
2
|
+
export function mdToMismatches(mdstring, ops, cigarMismatches, seq, qual) {
|
|
3
|
+
let curr = { start: 0, base: '', length: 0, type: 'mismatch' };
|
|
4
|
+
let lastCigar = 0;
|
|
5
|
+
let lastTemplateOffset = 0;
|
|
6
|
+
let lastRefOffset = 0;
|
|
7
|
+
let lastSkipPos = 0;
|
|
8
|
+
const mismatchRecords = [];
|
|
9
|
+
const skips = cigarMismatches.filter(cigar => cigar.type === 'skip');
|
|
10
|
+
// convert a position on the reference sequence to a position on the template
|
|
11
|
+
// sequence, taking into account hard and soft clipping of reads
|
|
12
|
+
function nextRecord() {
|
|
13
|
+
mismatchRecords.push(curr);
|
|
14
|
+
// get a new mismatch record ready
|
|
15
|
+
curr = {
|
|
16
|
+
start: curr.start + curr.length,
|
|
17
|
+
length: 0,
|
|
18
|
+
base: '',
|
|
19
|
+
type: 'mismatch',
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function getTemplateCoordLocal(refCoord) {
|
|
23
|
+
let templateOffset = lastTemplateOffset;
|
|
24
|
+
let refOffset = lastRefOffset;
|
|
25
|
+
for (let i = lastCigar; i < ops.length && refOffset <= refCoord; i += 2, lastCigar = i) {
|
|
26
|
+
const len = +ops[i];
|
|
27
|
+
const op = ops[i + 1];
|
|
28
|
+
if (op === 'S' || op === 'I') {
|
|
29
|
+
templateOffset += len;
|
|
30
|
+
}
|
|
31
|
+
else if (op === 'D' || op === 'P' || op === 'N') {
|
|
32
|
+
refOffset += len;
|
|
33
|
+
}
|
|
34
|
+
else if (op !== 'H') {
|
|
35
|
+
templateOffset += len;
|
|
36
|
+
refOffset += len;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
lastTemplateOffset = templateOffset;
|
|
40
|
+
lastRefOffset = refOffset;
|
|
41
|
+
return templateOffset - (refOffset - refCoord);
|
|
42
|
+
}
|
|
43
|
+
// now actually parse the MD string
|
|
44
|
+
const md = mdstring.match(mdRegex) || [];
|
|
45
|
+
for (const token of md) {
|
|
46
|
+
const num = +token;
|
|
47
|
+
if (!Number.isNaN(num)) {
|
|
48
|
+
curr.start += num;
|
|
49
|
+
}
|
|
50
|
+
else if (token.startsWith('^')) {
|
|
51
|
+
curr.start += token.length - 1;
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// mismatch
|
|
55
|
+
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
|
56
|
+
for (let j = 0; j < token.length; j += 1) {
|
|
57
|
+
curr.length = 1;
|
|
58
|
+
while (lastSkipPos < skips.length) {
|
|
59
|
+
const mismatch = skips[lastSkipPos];
|
|
60
|
+
if (curr.start >= mismatch.start) {
|
|
61
|
+
curr.start += mismatch.length;
|
|
62
|
+
lastSkipPos++;
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const s = getTemplateCoordLocal(curr.start);
|
|
69
|
+
curr.base = seq[s] || 'X';
|
|
70
|
+
curr.qual = qual === null || qual === void 0 ? void 0 : qual[s];
|
|
71
|
+
curr.altbase = token;
|
|
72
|
+
nextRecord();
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return mismatchRecords;
|
|
77
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Feature } from '@jbrowse/core/util';
|
|
2
|
+
export declare function getModProbabilities(feature: Feature): number[] | undefined;
|
|
3
|
+
export declare function getModPositions(mm: string, fseq: string, fstrand: number): {
|
|
4
|
+
type: string;
|
|
5
|
+
positions: number[];
|
|
6
|
+
base: string;
|
|
7
|
+
strand: string;
|
|
8
|
+
}[];
|
|
9
|
+
export declare function getModTypes(mm: string): {
|
|
10
|
+
type: string;
|
|
11
|
+
base: string;
|
|
12
|
+
strand: string;
|
|
13
|
+
}[];
|
|
14
|
+
export declare function getMethBins(feature: Feature, cigarOps: string[]): {
|
|
15
|
+
methBins: number[];
|
|
16
|
+
hydroxyMethBins: number[];
|
|
17
|
+
methProbs: number[];
|
|
18
|
+
hydroxyMethProbs: number[];
|
|
19
|
+
};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { revcom } from '@jbrowse/core/util';
|
|
2
|
+
import { getTagAlt } from '../util';
|
|
3
|
+
import { getNextRefPos } from '../MismatchParser';
|
|
4
|
+
const modificationRegex = new RegExp(/([A-Z])([-+])([^,.?]+)([.?])?/);
|
|
5
|
+
// ML stores probabilities as array of numerics and MP is scaled phred scores
|
|
6
|
+
// https://github.com/samtools/hts-specs/pull/418/files#diff-e765c6479316309f56b636f88189cdde8c40b854c7bdcce9ee7fe87a4e76febcR596
|
|
7
|
+
//
|
|
8
|
+
// if we have ML or Ml, it is an 8bit probability, divide by 255
|
|
9
|
+
//
|
|
10
|
+
// if we have MP or Mp it is phred scaled ASCII, which can go up to 90 but has
|
|
11
|
+
// very high likelihood basecalls at that point, we really only care about low
|
|
12
|
+
// qual calls <20 approx
|
|
13
|
+
export function getModProbabilities(feature) {
|
|
14
|
+
var _a;
|
|
15
|
+
const m = getTagAlt(feature, 'ML', 'Ml') || [];
|
|
16
|
+
return m
|
|
17
|
+
? (typeof m === 'string' ? m.split(',').map(e => +e) : m).map(e => e / 255)
|
|
18
|
+
: (_a = getTagAlt(feature, 'MP', 'Mp')) === null || _a === void 0 ? void 0 : _a.split('').map(s => s.charCodeAt(0) - 33).map(elt => Math.min(1, elt / 50));
|
|
19
|
+
}
|
|
20
|
+
export function getModPositions(mm, fseq, fstrand) {
|
|
21
|
+
const seq = fstrand === -1 ? revcom(fseq) : fseq;
|
|
22
|
+
const mods = mm.split(';').filter(mod => !!mod);
|
|
23
|
+
const result = [];
|
|
24
|
+
for (const mod of mods) {
|
|
25
|
+
const [basemod, ...skips] = mod.split(',');
|
|
26
|
+
// regexes based on parse_mm.pl from hts-specs
|
|
27
|
+
// https://github.com/samtools/hts-specs/blob/master/test/SAMtags/parse_mm.pl
|
|
28
|
+
const matches = modificationRegex.exec(basemod);
|
|
29
|
+
if (!matches) {
|
|
30
|
+
throw new Error('bad format for MM tag');
|
|
31
|
+
}
|
|
32
|
+
const [, base, strand, typestr] = matches;
|
|
33
|
+
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so split,
|
|
34
|
+
// and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
35
|
+
const types = typestr.split(/(\d+|.)/).filter(f => !!f);
|
|
36
|
+
if (strand === '-') {
|
|
37
|
+
console.warn('unsupported negative strand modifications');
|
|
38
|
+
result.push({
|
|
39
|
+
type: 'unsupported',
|
|
40
|
+
positions: [],
|
|
41
|
+
base: base,
|
|
42
|
+
strand: strand,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
// this logic based on parse_mm.pl from hts-specs
|
|
46
|
+
for (const type of types) {
|
|
47
|
+
let i = 0;
|
|
48
|
+
const positions = [];
|
|
49
|
+
for (const d of skips) {
|
|
50
|
+
let delta = +d;
|
|
51
|
+
do {
|
|
52
|
+
if (base === 'N' || base === seq[i]) {
|
|
53
|
+
delta--;
|
|
54
|
+
}
|
|
55
|
+
i++;
|
|
56
|
+
} while (delta >= 0 && i < seq.length);
|
|
57
|
+
if (fstrand === -1) {
|
|
58
|
+
const pos = seq.length - i;
|
|
59
|
+
if (pos >= 0) {
|
|
60
|
+
// avoid negative-number-positions in array, seen in #4629 cause
|
|
61
|
+
// unknown, could warrant some further investigation
|
|
62
|
+
positions.unshift(pos);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
positions.push(i - 1);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
result.push({
|
|
70
|
+
type,
|
|
71
|
+
base: base,
|
|
72
|
+
strand: strand,
|
|
73
|
+
positions,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
export function getModTypes(mm) {
|
|
80
|
+
return mm
|
|
81
|
+
.split(';')
|
|
82
|
+
.filter(mod => !!mod)
|
|
83
|
+
.flatMap(mod => {
|
|
84
|
+
const basemod = mod.split(',')[0];
|
|
85
|
+
const matches = modificationRegex.exec(basemod);
|
|
86
|
+
if (!matches) {
|
|
87
|
+
throw new Error('bad format for MM tag');
|
|
88
|
+
}
|
|
89
|
+
const [, base, strand, typestr] = matches;
|
|
90
|
+
// can be a multi e.g. C+mh for both meth (m) and hydroxymeth (h) so
|
|
91
|
+
// split, and they can also be chemical codes (ChEBI) e.g. C+16061
|
|
92
|
+
return typestr
|
|
93
|
+
.split(/(\d+|.)/)
|
|
94
|
+
.filter(f => !!f)
|
|
95
|
+
.map(type => ({
|
|
96
|
+
type,
|
|
97
|
+
base: base,
|
|
98
|
+
strand: strand,
|
|
99
|
+
}));
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
export function getMethBins(feature, cigarOps) {
|
|
103
|
+
const fstart = feature.get('start');
|
|
104
|
+
const fend = feature.get('end');
|
|
105
|
+
const fstrand = feature.get('strand');
|
|
106
|
+
const flen = fend - fstart;
|
|
107
|
+
const mm = getTagAlt(feature, 'MM', 'Mm') || '';
|
|
108
|
+
const methBins = [];
|
|
109
|
+
const hydroxyMethBins = [];
|
|
110
|
+
const methProbs = [];
|
|
111
|
+
const hydroxyMethProbs = [];
|
|
112
|
+
const seq = feature.get('seq');
|
|
113
|
+
if (seq) {
|
|
114
|
+
const probabilities = getModProbabilities(feature);
|
|
115
|
+
const modifications = getModPositions(mm, seq, fstrand);
|
|
116
|
+
let probIndex = 0;
|
|
117
|
+
for (const { type, positions } of modifications) {
|
|
118
|
+
for (const { ref, idx } of getNextRefPos(cigarOps, positions)) {
|
|
119
|
+
const idx2 = probIndex + (fstrand === -1 ? positions.length - 1 - idx : idx);
|
|
120
|
+
const prob = (probabilities === null || probabilities === void 0 ? void 0 : probabilities[idx2]) || 0;
|
|
121
|
+
if (type === 'm') {
|
|
122
|
+
if (ref >= 0 && ref < flen) {
|
|
123
|
+
methBins[ref] = 1;
|
|
124
|
+
methProbs[ref] = prob;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else if (type === 'h') {
|
|
128
|
+
if (ref >= 0 && ref < flen) {
|
|
129
|
+
hydroxyMethBins[ref] = 1;
|
|
130
|
+
hydroxyMethProbs[ref] = prob;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
probIndex += positions.length;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return { methBins, hydroxyMethBins, methProbs, hydroxyMethProbs };
|
|
138
|
+
}
|
|
@@ -3,7 +3,6 @@ import { toArray } from 'rxjs/operators';
|
|
|
3
3
|
import { firstValueFrom } from 'rxjs';
|
|
4
4
|
// locals
|
|
5
5
|
import PileupBaseRPC from '../base';
|
|
6
|
-
import { getTag } from '../../util';
|
|
7
6
|
export default class PileupGetGlobalValueForTag extends PileupBaseRPC {
|
|
8
7
|
constructor() {
|
|
9
8
|
super(...arguments);
|
|
@@ -16,7 +15,7 @@ export default class PileupGetGlobalValueForTag extends PileupBaseRPC {
|
|
|
16
15
|
const featuresArray = await firstValueFrom(features.pipe(toArray()));
|
|
17
16
|
return [
|
|
18
17
|
...new Set(featuresArray
|
|
19
|
-
.map(feature =>
|
|
18
|
+
.map(feature => { var _a; return (_a = feature.get('tags')) === null || _a === void 0 ? void 0 : _a[tag]; })
|
|
20
19
|
.filter(f => f !== undefined)
|
|
21
20
|
.map(f => `${f}`)),
|
|
22
21
|
];
|