@jbrowse/plugin-alignments 3.1.0 → 3.3.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/LinkedPairedAlignments.d.ts +1 -1
- package/dist/AlignmentsFeatureDetail/LinkedPairedAlignments.js +1 -1
- package/dist/AlignmentsFeatureDetail/getSAFeatures.js +2 -2
- package/dist/AlignmentsFeatureDetail/stateModelFactory.js +1 -2
- package/dist/BamAdapter/BamAdapter.js +13 -11
- package/dist/CramAdapter/CramAdapter.js +3 -3
- package/dist/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +2 -2
- package/dist/LinearPileupDisplay/model.js +2 -2
- package/dist/LinearReadCloudDisplay/drawLongReadChains.js +10 -10
- package/dist/PileupRenderer/PileupRenderer.d.ts +1 -30
- package/dist/PileupRenderer/makeImageData.js +9 -14
- package/dist/PileupRenderer/renderModifications.js +29 -24
- package/dist/PileupRenderer/sortUtil.js +2 -2
- package/dist/SNPCoverageAdapter/SNPCoverageAdapter.js +19 -15
- package/dist/SNPCoverageAdapter/processModifications.js +38 -33
- package/dist/SNPCoverageRenderer/makeImage.js +25 -36
- package/esm/AlignmentsFeatureDetail/LinkedPairedAlignments.d.ts +1 -1
- package/esm/AlignmentsFeatureDetail/LinkedPairedAlignments.js +1 -1
- package/esm/AlignmentsFeatureDetail/getSAFeatures.js +2 -2
- package/esm/AlignmentsFeatureDetail/stateModelFactory.js +1 -2
- package/esm/BamAdapter/BamAdapter.js +13 -11
- package/esm/CramAdapter/CramAdapter.js +3 -3
- package/esm/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +2 -2
- package/esm/LinearPileupDisplay/model.js +2 -2
- package/esm/LinearReadCloudDisplay/drawLongReadChains.js +10 -10
- package/esm/PileupRenderer/PileupRenderer.d.ts +1 -30
- package/esm/PileupRenderer/makeImageData.js +3 -8
- package/esm/PileupRenderer/renderModifications.js +29 -24
- package/esm/PileupRenderer/sortUtil.js +2 -2
- package/esm/SNPCoverageAdapter/SNPCoverageAdapter.js +19 -15
- package/esm/SNPCoverageAdapter/processModifications.js +38 -33
- package/esm/SNPCoverageRenderer/makeImage.js +26 -37
- package/package.json +8 -8
|
@@ -12,5 +12,5 @@ export default function SuppAlignments(props) {
|
|
|
12
12
|
}
|
|
13
13
|
catch (e) {
|
|
14
14
|
}
|
|
15
|
-
return (_jsx(BaseCard, { ...props, title: "Paired alignments", children:
|
|
15
|
+
return hasBreakendSplitView ? (_jsx(BaseCard, { ...props, title: "Paired alignments", children: _jsx(LaunchPairedEndBreakpointSplitViewPanel, { model: model, feature: feature }) })) : null;
|
|
16
16
|
}
|
|
@@ -22,12 +22,12 @@ export async function getSAFeatures({ view, feature, }) {
|
|
|
22
22
|
end: clipPos + getLengthSansClipping(cigar),
|
|
23
23
|
};
|
|
24
24
|
const features = [feat, ...suppAlns];
|
|
25
|
-
features.
|
|
25
|
+
for (const [idx, f] of features.entries()) {
|
|
26
26
|
f.refName = assembly.getCanonicalRefName(f.refName) || f.refName;
|
|
27
27
|
f.syntenyId = idx;
|
|
28
28
|
f.mate.syntenyId = idx;
|
|
29
29
|
f.mate.uniqueId = `${f.uniqueId}_mate`;
|
|
30
|
-
}
|
|
30
|
+
}
|
|
31
31
|
features.sort((a, b) => a.clipPos - b.clipPos);
|
|
32
32
|
return features;
|
|
33
33
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { stateModelFactory as baseModelFactory } from '@jbrowse/core/BaseFeatureWidget';
|
|
2
2
|
import { types } from 'mobx-state-tree';
|
|
3
3
|
export function stateModelFactory(pluginManager) {
|
|
4
|
-
|
|
5
|
-
return types.compose(baseModel, types.model('AlignmentsFeatureWidget', {
|
|
4
|
+
return types.compose(baseModelFactory(pluginManager), types.model('AlignmentsFeatureWidget', {
|
|
6
5
|
type: types.literal('AlignmentsFeatureWidget'),
|
|
7
6
|
}));
|
|
8
7
|
}
|
|
@@ -56,14 +56,18 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
|
|
|
56
56
|
const samHeader = await bam.getHeader();
|
|
57
57
|
const idToName = [];
|
|
58
58
|
const nameToId = {};
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
if (samHeader) {
|
|
60
|
+
for (const [refId, sqLine] of samHeader
|
|
61
|
+
.filter(l => l.tag === 'SQ')
|
|
62
|
+
.entries()) {
|
|
63
|
+
const SN = sqLine.data.find(item => item.tag === 'SN');
|
|
64
|
+
if (SN) {
|
|
65
|
+
const refName = SN.value;
|
|
66
|
+
nameToId[refName] = refId;
|
|
67
|
+
idToName[refId] = refName;
|
|
68
|
+
}
|
|
65
69
|
}
|
|
66
|
-
}
|
|
70
|
+
}
|
|
67
71
|
this.samHeader = { idToName, nameToId };
|
|
68
72
|
return this.samHeader;
|
|
69
73
|
}
|
|
@@ -101,9 +105,7 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
|
|
|
101
105
|
});
|
|
102
106
|
const seqChunks = await firstValueFrom(features.pipe(toArray()));
|
|
103
107
|
let sequence = '';
|
|
104
|
-
seqChunks
|
|
105
|
-
.sort((a, b) => a.get('start') - b.get('start'))
|
|
106
|
-
.forEach(chunk => {
|
|
108
|
+
for (const chunk of seqChunks.sort((a, b) => a.get('start') - b.get('start'))) {
|
|
107
109
|
const chunkStart = chunk.get('start');
|
|
108
110
|
const chunkEnd = chunk.get('end');
|
|
109
111
|
const trimStart = Math.max(start - chunkStart, 0);
|
|
@@ -111,7 +113,7 @@ export default class BamAdapter extends BaseFeatureDataAdapter {
|
|
|
111
113
|
const trimLength = trimEnd - trimStart;
|
|
112
114
|
const chunkSeq = chunk.get('seq') || chunk.get('residues');
|
|
113
115
|
sequence += chunkSeq.slice(trimStart, trimStart + trimLength);
|
|
114
|
-
}
|
|
116
|
+
}
|
|
115
117
|
if (sequence.length !== end - start) {
|
|
116
118
|
throw new Error(`sequence fetch failed: fetching ${refName}:${(start - 1).toLocaleString()}-${end.toLocaleString()} returned ${sequence.length.toLocaleString()} bases, but should have returned ${(end - start).toLocaleString()}`);
|
|
117
119
|
}
|
|
@@ -95,16 +95,16 @@ export default class CramAdapter extends BaseFeatureDataAdapter {
|
|
|
95
95
|
const samHeader = await cram.cram.getSamHeader();
|
|
96
96
|
const idToName = [];
|
|
97
97
|
const nameToId = {};
|
|
98
|
-
samHeader
|
|
98
|
+
for (const [refId, sqLine] of samHeader
|
|
99
99
|
.filter(l => l.tag === 'SQ')
|
|
100
|
-
.
|
|
100
|
+
.entries()) {
|
|
101
101
|
const SN = sqLine.data.find(item => item.tag === 'SN');
|
|
102
102
|
if (SN) {
|
|
103
103
|
const refName = SN.value;
|
|
104
104
|
nameToId[refName] = refId;
|
|
105
105
|
idToName[refId] = refName;
|
|
106
106
|
}
|
|
107
|
-
}
|
|
107
|
+
}
|
|
108
108
|
const readGroups = samHeader
|
|
109
109
|
.filter(l => l.tag === 'RG')
|
|
110
110
|
.map(rgLine => { var _a; return (_a = rgLine.data.find(item => item.tag === 'ID')) === null || _a === void 0 ? void 0 : _a.value; });
|
|
@@ -93,12 +93,12 @@ export function SharedLinearPileupDisplayMixin(configSchema) {
|
|
|
93
93
|
'#CCEEFF',
|
|
94
94
|
'lightsalmon',
|
|
95
95
|
];
|
|
96
|
-
|
|
96
|
+
for (const value of uniqueTag) {
|
|
97
97
|
if (!self.colorTagMap.has(value)) {
|
|
98
98
|
const totalKeys = [...self.colorTagMap.keys()].length;
|
|
99
99
|
self.colorTagMap.set(value, colorPalette[totalKeys]);
|
|
100
100
|
}
|
|
101
|
-
}
|
|
101
|
+
}
|
|
102
102
|
},
|
|
103
103
|
setFeatureUnderMouse(feat) {
|
|
104
104
|
self.featureUnderMouseVolatile = feat;
|
|
@@ -31,14 +31,14 @@ function stateModelFactory(configSchema) {
|
|
|
31
31
|
self.currSortBpPerPx = n;
|
|
32
32
|
},
|
|
33
33
|
updateVisibleModifications(uniqueModifications) {
|
|
34
|
-
|
|
34
|
+
for (const value of uniqueModifications) {
|
|
35
35
|
if (!self.visibleModifications.has(value.type)) {
|
|
36
36
|
self.visibleModifications.set(value.type, {
|
|
37
37
|
...value,
|
|
38
38
|
color: getColorForModification(value.type),
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
-
}
|
|
41
|
+
}
|
|
42
42
|
},
|
|
43
43
|
setModificationsReady(flag) {
|
|
44
44
|
self.modificationsReady = flag;
|
|
@@ -4,8 +4,7 @@ import { fillRectCtx, strokeRectCtx } from './util';
|
|
|
4
4
|
import { fillColor, strokeColor } from '../shared/color';
|
|
5
5
|
export function drawLongReadChains({ ctx, self, chainData, view, asm, }) {
|
|
6
6
|
var _a, _b, _c, _d, _e;
|
|
7
|
-
const
|
|
8
|
-
const minXs = [];
|
|
7
|
+
const computedChains = [];
|
|
9
8
|
const { chains } = chainData;
|
|
10
9
|
const { height } = self;
|
|
11
10
|
const featureHeight = getConf(self, 'featureHeight');
|
|
@@ -21,20 +20,21 @@ export function drawLongReadChains({ ctx, self, chainData, view, asm, }) {
|
|
|
21
20
|
maxX = Math.max(maxX, re);
|
|
22
21
|
}
|
|
23
22
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
23
|
+
computedChains.push({
|
|
24
|
+
distance: Math.abs(maxX - minX),
|
|
25
|
+
minX,
|
|
26
|
+
chain,
|
|
27
|
+
});
|
|
27
28
|
}
|
|
29
|
+
const distances = computedChains.map(d => d.distance);
|
|
28
30
|
const maxD = Math.log(max(distances));
|
|
29
31
|
const minD = Math.max(Math.log(min(distances)) - 1, 0);
|
|
30
32
|
const scaler = (height - 20) / (maxD - minD);
|
|
31
33
|
const halfHeight = featureHeight / 2 - 0.5;
|
|
32
|
-
for (
|
|
33
|
-
const
|
|
34
|
-
const w = distances[i];
|
|
34
|
+
for (const { minX, distance, chain } of computedChains) {
|
|
35
|
+
const w = distance;
|
|
35
36
|
const top = (Math.log(w) - minD) * scaler;
|
|
36
|
-
|
|
37
|
-
fillRectCtx(min - view.offsetPx, top + halfHeight, w, 1, ctx, 'black');
|
|
37
|
+
fillRectCtx(minX - view.offsetPx, top + halfHeight, w, 1, ctx, 'black');
|
|
38
38
|
const c1 = chain[0];
|
|
39
39
|
let primaryStrand;
|
|
40
40
|
if (!(c1.flags & 2048)) {
|
|
@@ -13,36 +13,7 @@ export default class PileupRenderer extends BoxRendererType {
|
|
|
13
13
|
reversed?: boolean | undefined;
|
|
14
14
|
assemblyName: string;
|
|
15
15
|
};
|
|
16
|
-
render(renderProps: RenderArgsDeserialized): Promise<
|
|
17
|
-
features: Map<any, any>;
|
|
18
|
-
layout: import("@jbrowse/core/util/layouts").GranularRectLayout<unknown>;
|
|
19
|
-
height: number;
|
|
20
|
-
width: number;
|
|
21
|
-
maxHeightReached: boolean;
|
|
22
|
-
containsNoTransferables: boolean;
|
|
23
|
-
canvasRecordedData: any;
|
|
24
|
-
reactElement?: React.ReactElement;
|
|
25
|
-
html?: string;
|
|
26
|
-
} | {
|
|
27
|
-
features: Map<any, any>;
|
|
28
|
-
layout: import("@jbrowse/core/util/layouts").GranularRectLayout<unknown>;
|
|
29
|
-
height: number;
|
|
30
|
-
width: number;
|
|
31
|
-
maxHeightReached: boolean;
|
|
32
|
-
containsNoTransferables: boolean;
|
|
33
|
-
reactElement: import("react/jsx-runtime").JSX.Element;
|
|
34
|
-
html?: string;
|
|
35
|
-
} | {
|
|
36
|
-
features: Map<any, any>;
|
|
37
|
-
layout: import("@jbrowse/core/util/layouts").GranularRectLayout<unknown>;
|
|
38
|
-
height: number;
|
|
39
|
-
width: number;
|
|
40
|
-
maxHeightReached: boolean;
|
|
41
|
-
containsNoTransferables: boolean;
|
|
42
|
-
imageData: any;
|
|
43
|
-
reactElement?: React.ReactElement;
|
|
44
|
-
html?: string;
|
|
45
|
-
}>;
|
|
16
|
+
render(renderProps: RenderArgsDeserialized): Promise<any>;
|
|
46
17
|
createLayoutSession(args: PileupLayoutSessionProps): PileupLayoutSession;
|
|
47
18
|
}
|
|
48
19
|
export type { RenderArgs, RenderArgsSerialized, RenderResults, ResultsDeserialized, ResultsSerialized, } from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readConfObject } from '@jbrowse/core/configuration';
|
|
2
2
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
3
|
-
import {
|
|
3
|
+
import { forEachWithStopTokenCheck } from '@jbrowse/core/util';
|
|
4
4
|
import { renderAlignment } from './renderAlignment';
|
|
5
5
|
import { renderMismatches } from './renderMismatches';
|
|
6
6
|
import { renderSoftClipping } from './renderSoftClipping';
|
|
@@ -19,12 +19,7 @@ export function makeImageData({ ctx, layoutRecords, canvasWidth, renderArgs, })
|
|
|
19
19
|
const { charWidth, charHeight } = getCharWidthHeight();
|
|
20
20
|
const drawSNPsMuted = shouldDrawSNPsMuted(colorBy === null || colorBy === void 0 ? void 0 : colorBy.type);
|
|
21
21
|
const drawIndels = shouldDrawIndels();
|
|
22
|
-
|
|
23
|
-
for (const feat of layoutRecords) {
|
|
24
|
-
if (performance.now() - start > 400) {
|
|
25
|
-
checkStopToken(stopToken);
|
|
26
|
-
start = performance.now();
|
|
27
|
-
}
|
|
22
|
+
forEachWithStopTokenCheck(layoutRecords, stopToken, feat => {
|
|
28
23
|
renderAlignment({
|
|
29
24
|
ctx,
|
|
30
25
|
feat,
|
|
@@ -63,6 +58,6 @@ export function makeImageData({ ctx, layoutRecords, canvasWidth, renderArgs, })
|
|
|
63
58
|
canvasWidth,
|
|
64
59
|
});
|
|
65
60
|
}
|
|
66
|
-
}
|
|
61
|
+
});
|
|
67
62
|
return undefined;
|
|
68
63
|
}
|
|
@@ -3,7 +3,7 @@ import { fillRect } from './util';
|
|
|
3
3
|
import { getMaxProbModAtEachPosition } from '../shared/getMaximumModificationAtEachPosition';
|
|
4
4
|
import { alphaColor } from '../shared/util';
|
|
5
5
|
export function renderModifications({ ctx, feat, region, bpPerPx, renderArgs, canvasWidth, cigarOps, }) {
|
|
6
|
-
var _a, _b
|
|
6
|
+
var _a, _b;
|
|
7
7
|
const { feature, topPx, heightPx } = feat;
|
|
8
8
|
const { colorBy, visibleModifications = {} } = renderArgs;
|
|
9
9
|
const seq = feature.get('seq');
|
|
@@ -13,28 +13,33 @@ export function renderModifications({ ctx, feat, region, bpPerPx, renderArgs, ca
|
|
|
13
13
|
const start = feature.get('start');
|
|
14
14
|
const isolatedModification = (_a = colorBy === null || colorBy === void 0 ? void 0 : colorBy.modifications) === null || _a === void 0 ? void 0 : _a.isolatedModification;
|
|
15
15
|
const twoColor = (_b = colorBy === null || colorBy === void 0 ? void 0 : colorBy.modifications) === null || _b === void 0 ? void 0 : _b.twoColor;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
const probs = getMaxProbModAtEachPosition(feature, cigarOps);
|
|
17
|
+
if (probs) {
|
|
18
|
+
let pos = 0;
|
|
19
|
+
for (const { allProbs, prob, type } of probs) {
|
|
20
|
+
const r = start + pos;
|
|
21
|
+
const [leftPx, rightPx] = bpSpanPx(r, r + 1, region, bpPerPx);
|
|
22
|
+
const mod = visibleModifications[type];
|
|
23
|
+
if (!mod) {
|
|
24
|
+
console.warn(`${type} not known yet`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (isolatedModification && mod.type !== isolatedModification) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const col = mod.color || 'black';
|
|
31
|
+
const s = 1 - sum(allProbs);
|
|
32
|
+
if (twoColor && s > max(allProbs)) {
|
|
33
|
+
const c = alphaColor('blue', s);
|
|
34
|
+
const w = rightPx - leftPx + 0.5;
|
|
35
|
+
fillRect(ctx, leftPx, topPx, w, heightPx, canvasWidth, c);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
const c = alphaColor(col, prob);
|
|
39
|
+
const w = rightPx - leftPx + 0.5;
|
|
40
|
+
fillRect(ctx, leftPx, topPx, w, heightPx, canvasWidth, c);
|
|
41
|
+
}
|
|
42
|
+
pos++;
|
|
23
43
|
}
|
|
24
|
-
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const col = mod.color || 'black';
|
|
28
|
-
const s = 1 - sum(allProbs);
|
|
29
|
-
if (twoColor && s > max(allProbs)) {
|
|
30
|
-
const c = alphaColor('blue', s);
|
|
31
|
-
const w = rightPx - leftPx + 0.5;
|
|
32
|
-
fillRect(ctx, leftPx, topPx, w, heightPx, canvasWidth, c);
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
const c = alphaColor(col, prob);
|
|
36
|
-
const w = rightPx - leftPx + 0.5;
|
|
37
|
-
fillRect(ctx, leftPx, topPx, w, heightPx, canvasWidth, c);
|
|
38
|
-
}
|
|
39
|
-
});
|
|
44
|
+
}
|
|
40
45
|
}
|
|
@@ -4,7 +4,7 @@ export const sortFeature = (features, sortedBy) => {
|
|
|
4
4
|
const featuresInCenterLine = [];
|
|
5
5
|
const featuresOutsideCenter = [];
|
|
6
6
|
const { pos, type } = sortedBy;
|
|
7
|
-
|
|
7
|
+
for (const innerArray of featureArray) {
|
|
8
8
|
const feature = innerArray;
|
|
9
9
|
const start = feature.get('start');
|
|
10
10
|
const end = feature.get('end');
|
|
@@ -14,7 +14,7 @@ export const sortFeature = (features, sortedBy) => {
|
|
|
14
14
|
else {
|
|
15
15
|
featuresOutsideCenter.push(innerArray);
|
|
16
16
|
}
|
|
17
|
-
}
|
|
17
|
+
}
|
|
18
18
|
const isCram = featureArray.length ? featureArray[0].get('tags') : false;
|
|
19
19
|
switch (type) {
|
|
20
20
|
case 'Start location': {
|
|
@@ -39,20 +39,24 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
39
39
|
opts,
|
|
40
40
|
fetchSequence: (region) => this.fetchSequence(region),
|
|
41
41
|
});
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
let index = 0;
|
|
43
|
+
for (const bin of bins) {
|
|
44
|
+
if (bin) {
|
|
45
|
+
const start = region.start + index;
|
|
46
|
+
observer.next(new SimpleFeature({
|
|
47
|
+
id: `${this.id}-${start}`,
|
|
48
|
+
data: {
|
|
49
|
+
score: bin.depth,
|
|
50
|
+
snpinfo: bin,
|
|
51
|
+
start,
|
|
52
|
+
end: start + 1,
|
|
53
|
+
refName: region.refName,
|
|
54
|
+
},
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
index++;
|
|
58
|
+
}
|
|
59
|
+
for (const [key, skip] of Object.entries(skipmap)) {
|
|
56
60
|
observer.next(new SimpleFeature({
|
|
57
61
|
id: key,
|
|
58
62
|
data: {
|
|
@@ -64,7 +68,7 @@ export default class SNPCoverageAdapter extends BaseFeatureDataAdapter {
|
|
|
64
68
|
effectiveStrand: skip.effectiveStrand,
|
|
65
69
|
},
|
|
66
70
|
}));
|
|
67
|
-
}
|
|
71
|
+
}
|
|
68
72
|
observer.complete();
|
|
69
73
|
}, opts.stopToken);
|
|
70
74
|
}
|
|
@@ -2,45 +2,50 @@ import { max, sum } from '@jbrowse/core/util';
|
|
|
2
2
|
import { incWithProbabilities } from './util';
|
|
3
3
|
import { getMaxProbModAtEachPosition } from '../shared/getMaximumModificationAtEachPosition';
|
|
4
4
|
export function processModifications({ feature, colorBy, region, bins, regionSequence, }) {
|
|
5
|
-
var _a, _b
|
|
5
|
+
var _a, _b;
|
|
6
6
|
const fstart = feature.get('start');
|
|
7
7
|
const fstrand = feature.get('strand');
|
|
8
8
|
const fend = feature.get('end');
|
|
9
9
|
const twoColor = (_a = colorBy === null || colorBy === void 0 ? void 0 : colorBy.modifications) === null || _a === void 0 ? void 0 : _a.twoColor;
|
|
10
10
|
const isolatedModification = (_b = colorBy === null || colorBy === void 0 ? void 0 : colorBy.modifications) === null || _b === void 0 ? void 0 : _b.isolatedModification;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
if (bins[epos] === undefined) {
|
|
18
|
-
bins[epos] = {
|
|
19
|
-
depth: 0,
|
|
20
|
-
readsCounted: 0,
|
|
21
|
-
snps: {},
|
|
22
|
-
ref: {
|
|
23
|
-
probabilities: [],
|
|
24
|
-
entryDepth: 0,
|
|
25
|
-
'-1': 0,
|
|
26
|
-
0: 0,
|
|
27
|
-
1: 0,
|
|
28
|
-
},
|
|
29
|
-
mods: {},
|
|
30
|
-
nonmods: {},
|
|
31
|
-
delskips: {},
|
|
32
|
-
noncov: {},
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
const s = 1 - sum(allProbs);
|
|
36
|
-
const bin = bins[epos];
|
|
37
|
-
bin.refbase = regionSequence[epos];
|
|
38
|
-
if (twoColor && s > max(allProbs)) {
|
|
39
|
-
incWithProbabilities(bin, fstrand, 'nonmods', `nonmod_${type}`, s);
|
|
11
|
+
const probs = getMaxProbModAtEachPosition(feature);
|
|
12
|
+
if (probs) {
|
|
13
|
+
let pos = 0;
|
|
14
|
+
for (const { type, prob, allProbs } of probs) {
|
|
15
|
+
if (isolatedModification && type !== isolatedModification) {
|
|
16
|
+
return;
|
|
40
17
|
}
|
|
41
|
-
|
|
42
|
-
|
|
18
|
+
const epos = pos + fstart - region.start;
|
|
19
|
+
if (epos >= 0 && epos < bins.length && pos + fstart < fend) {
|
|
20
|
+
if (bins[epos] === undefined) {
|
|
21
|
+
bins[epos] = {
|
|
22
|
+
depth: 0,
|
|
23
|
+
readsCounted: 0,
|
|
24
|
+
snps: {},
|
|
25
|
+
ref: {
|
|
26
|
+
probabilities: [],
|
|
27
|
+
entryDepth: 0,
|
|
28
|
+
'-1': 0,
|
|
29
|
+
0: 0,
|
|
30
|
+
1: 0,
|
|
31
|
+
},
|
|
32
|
+
mods: {},
|
|
33
|
+
nonmods: {},
|
|
34
|
+
delskips: {},
|
|
35
|
+
noncov: {},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const s = 1 - sum(allProbs);
|
|
39
|
+
const bin = bins[epos];
|
|
40
|
+
bin.refbase = regionSequence[epos];
|
|
41
|
+
if (twoColor && s > max(allProbs)) {
|
|
42
|
+
incWithProbabilities(bin, fstrand, 'nonmods', `nonmod_${type}`, s);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
incWithProbabilities(bin, fstrand, 'mods', `mod_${type}`, prob);
|
|
46
|
+
}
|
|
43
47
|
}
|
|
48
|
+
pos++;
|
|
44
49
|
}
|
|
45
|
-
}
|
|
50
|
+
}
|
|
46
51
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { readConfObject } from '@jbrowse/core/configuration';
|
|
2
2
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
3
|
-
import { bpSpanPx, featureSpanPx } from '@jbrowse/core/util';
|
|
4
|
-
import { checkStopToken } from '@jbrowse/core/util/stopToken';
|
|
3
|
+
import { bpSpanPx, featureSpanPx, forEachWithStopTokenCheck, } from '@jbrowse/core/util';
|
|
5
4
|
import { YSCALEBAR_LABEL_OFFSET, getOrigin, getScale, } from '@jbrowse/plugin-wiggle';
|
|
6
5
|
import { alphaColor } from '../shared/util';
|
|
7
6
|
const INTERBASE_INDICATOR_WIDTH = 7;
|
|
@@ -15,7 +14,7 @@ const complementBase = {
|
|
|
15
14
|
};
|
|
16
15
|
const fudgeFactor = 0.6;
|
|
17
16
|
export async function makeImage(ctx, props) {
|
|
18
|
-
var _a
|
|
17
|
+
var _a;
|
|
19
18
|
const { features, regions, bpPerPx, colorBy, displayCrossHatches, visibleModifications = {}, scaleOpts, height: unadjustedHeight, theme: configTheme, config: cfg, ticks, stopToken, } = props;
|
|
20
19
|
const theme = createJBrowseTheme(configTheme);
|
|
21
20
|
const region = regions[0];
|
|
@@ -53,35 +52,25 @@ export async function makeImage(ctx, props) {
|
|
|
53
52
|
cpg_meth: 'red',
|
|
54
53
|
cpg_unmeth: 'blue',
|
|
55
54
|
};
|
|
56
|
-
const feats = [...features.values()];
|
|
57
55
|
ctx.fillStyle = colorMap.total;
|
|
58
|
-
|
|
59
|
-
for (const feature of feats) {
|
|
56
|
+
forEachWithStopTokenCheck(features.values(), stopToken, feature => {
|
|
60
57
|
if (feature.get('type') === 'skip') {
|
|
61
|
-
|
|
58
|
+
return;
|
|
62
59
|
}
|
|
63
60
|
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
64
61
|
const w = rightPx - leftPx + fudgeFactor;
|
|
65
62
|
const score = feature.get('score');
|
|
66
63
|
ctx.fillRect(leftPx, toY(score), w, toHeight(score));
|
|
67
|
-
|
|
68
|
-
checkStopToken(stopToken);
|
|
69
|
-
start = performance.now();
|
|
70
|
-
}
|
|
71
|
-
}
|
|
64
|
+
});
|
|
72
65
|
let prevTotal = 0;
|
|
73
66
|
const extraHorizontallyFlippedOffset = region.reversed ? 1 / bpPerPx : 0;
|
|
74
67
|
const drawingModifications = colorBy.type === 'modifications';
|
|
75
68
|
const drawingMethylation = colorBy.type === 'methylation';
|
|
76
69
|
const isolatedModification = (_a = colorBy.modifications) === null || _a === void 0 ? void 0 : _a.isolatedModification;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const now = performance.now();
|
|
80
|
-
if (now - start > 400) {
|
|
81
|
-
checkStopToken(stopToken);
|
|
82
|
-
}
|
|
70
|
+
forEachWithStopTokenCheck(features.values(), stopToken, feature => {
|
|
71
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
83
72
|
if (feature.get('type') === 'skip') {
|
|
84
|
-
|
|
73
|
+
return;
|
|
85
74
|
}
|
|
86
75
|
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
87
76
|
const snpinfo = feature.get('snpinfo');
|
|
@@ -89,7 +78,7 @@ export async function makeImage(ctx, props) {
|
|
|
89
78
|
const score0 = feature.get('score');
|
|
90
79
|
if (drawingModifications) {
|
|
91
80
|
let curr = 0;
|
|
92
|
-
const refbase = (
|
|
81
|
+
const refbase = (_a = snpinfo.refbase) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
93
82
|
const { nonmods, mods, snps, ref } = snpinfo;
|
|
94
83
|
for (const m of Object.keys(nonmods).sort().reverse()) {
|
|
95
84
|
const mod = visibleModifications[m.replace('nonmod_', '')] ||
|
|
@@ -104,14 +93,14 @@ export async function makeImage(ctx, props) {
|
|
|
104
93
|
const cmp = complementBase[mod.base];
|
|
105
94
|
const detectable = mod.base === 'N'
|
|
106
95
|
? score0
|
|
107
|
-
: (((
|
|
108
|
-
(((
|
|
96
|
+
: (((_b = snps[mod.base]) === null || _b === void 0 ? void 0 : _b.entryDepth) || 0) +
|
|
97
|
+
(((_c = snps[cmp]) === null || _c === void 0 ? void 0 : _c.entryDepth) || 0) +
|
|
109
98
|
(refbase === mod.base ? ref['1'] : 0) +
|
|
110
99
|
(refbase === cmp ? ref['-1'] : 0);
|
|
111
100
|
const modifiable = mod.base === 'N'
|
|
112
101
|
? score0
|
|
113
|
-
: (((
|
|
114
|
-
(((
|
|
102
|
+
: (((_d = snps[mod.base]) === null || _d === void 0 ? void 0 : _d.entryDepth) || 0) +
|
|
103
|
+
(((_e = snps[cmp]) === null || _e === void 0 ? void 0 : _e.entryDepth) || 0) +
|
|
115
104
|
(refbase === mod.base ? ref.entryDepth : 0) +
|
|
116
105
|
(refbase === cmp ? ref.entryDepth : 0);
|
|
117
106
|
const { entryDepth, avgProbability = 0 } = snpinfo.nonmods[m];
|
|
@@ -136,14 +125,14 @@ export async function makeImage(ctx, props) {
|
|
|
136
125
|
const cmp = complementBase[mod.base];
|
|
137
126
|
const detectable = mod.base === 'N'
|
|
138
127
|
? score0
|
|
139
|
-
: (((
|
|
140
|
-
(((
|
|
128
|
+
: (((_f = snps[mod.base]) === null || _f === void 0 ? void 0 : _f.entryDepth) || 0) +
|
|
129
|
+
(((_g = snps[cmp]) === null || _g === void 0 ? void 0 : _g.entryDepth) || 0) +
|
|
141
130
|
(refbase === mod.base ? ref['1'] : 0) +
|
|
142
131
|
(refbase === cmp ? ref['-1'] : 0);
|
|
143
132
|
const modifiable = mod.base === 'N'
|
|
144
133
|
? score0
|
|
145
|
-
: (((
|
|
146
|
-
(((
|
|
134
|
+
: (((_h = snps[mod.base]) === null || _h === void 0 ? void 0 : _h.entryDepth) || 0) +
|
|
135
|
+
(((_j = snps[cmp]) === null || _j === void 0 ? void 0 : _j.entryDepth) || 0) +
|
|
147
136
|
(refbase === mod.base ? ref.entryDepth : 0) +
|
|
148
137
|
(refbase === cmp ? ref.entryDepth : 0);
|
|
149
138
|
const { entryDepth, avgProbability = 0 } = mods[m];
|
|
@@ -225,17 +214,17 @@ export async function makeImage(ctx, props) {
|
|
|
225
214
|
}
|
|
226
215
|
}
|
|
227
216
|
prevTotal = score0;
|
|
228
|
-
}
|
|
217
|
+
});
|
|
229
218
|
if (showArcs) {
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
|
|
219
|
+
forEachWithStopTokenCheck(features.values(), stopToken, feature => {
|
|
220
|
+
if (feature.get('type') !== 'skip') {
|
|
221
|
+
return;
|
|
233
222
|
}
|
|
234
|
-
const s =
|
|
235
|
-
const e =
|
|
223
|
+
const s = feature.get('start');
|
|
224
|
+
const e = feature.get('end');
|
|
236
225
|
const [left, right] = bpSpanPx(s, e, region, bpPerPx);
|
|
237
226
|
ctx.beginPath();
|
|
238
|
-
const effectiveStrand =
|
|
227
|
+
const effectiveStrand = feature.get('effectiveStrand');
|
|
239
228
|
const pos = 'rgba(255,200,200,0.7)';
|
|
240
229
|
const neg = 'rgba(200,200,255,0.7)';
|
|
241
230
|
const neutral = 'rgba(200,200,200,0.7)';
|
|
@@ -248,11 +237,11 @@ export async function makeImage(ctx, props) {
|
|
|
248
237
|
else {
|
|
249
238
|
ctx.strokeStyle = neutral;
|
|
250
239
|
}
|
|
251
|
-
ctx.lineWidth = Math.log(
|
|
240
|
+
ctx.lineWidth = Math.log(feature.get('score') + 1);
|
|
252
241
|
ctx.moveTo(left, height - offset * 2);
|
|
253
242
|
ctx.bezierCurveTo(left, 0, right, 0, right, height - offset * 2);
|
|
254
243
|
ctx.stroke();
|
|
255
|
-
}
|
|
244
|
+
});
|
|
256
245
|
}
|
|
257
246
|
if (displayCrossHatches) {
|
|
258
247
|
ctx.lineWidth = 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-alignments",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "JBrowse 2 alignments adapters, tracks, etc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -38,12 +38,12 @@
|
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@gmod/bam": "^5.0.0",
|
|
40
40
|
"@gmod/cram": "^4.0.1",
|
|
41
|
-
"@jbrowse/core": "^3.
|
|
42
|
-
"@jbrowse/plugin-linear-genome-view": "^3.
|
|
43
|
-
"@jbrowse/plugin-wiggle": "^3.
|
|
44
|
-
"@jbrowse/sv-core": "^3.
|
|
45
|
-
"@mui/icons-material": "^
|
|
46
|
-
"@mui/material": "^
|
|
41
|
+
"@jbrowse/core": "^3.3.0",
|
|
42
|
+
"@jbrowse/plugin-linear-genome-view": "^3.3.0",
|
|
43
|
+
"@jbrowse/plugin-wiggle": "^3.3.0",
|
|
44
|
+
"@jbrowse/sv-core": "^3.3.0",
|
|
45
|
+
"@mui/icons-material": "^7.0.0",
|
|
46
|
+
"@mui/material": "^7.0.0",
|
|
47
47
|
"canvas2svg": "^1.0.16",
|
|
48
48
|
"copy-to-clipboard": "^3.3.1",
|
|
49
49
|
"fast-deep-equal": "^3.1.3",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"distModule": "esm/index.js",
|
|
64
64
|
"srcModule": "src/index.ts",
|
|
65
65
|
"module": "esm/index.js",
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "0bb64d8cc7ecdd167515308b31eec3d9acbc59e4"
|
|
67
67
|
}
|