@jbrowse/plugin-alignments 4.1.1 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/AlignmentsFeatureDetail/stateModelFactory.d.ts +1 -1
- package/esm/PileupRenderer/makeImageData.js +3 -4
- package/esm/RenderLinearReadArcsDisplayRPC/drawFeatsRPC.d.ts +2 -1
- package/esm/RenderLinearReadArcsDisplayRPC/drawFeatsRPC.js +3 -4
- package/esm/RenderLinearReadArcsDisplayRPC/executeRenderLinearReadArcsDisplay.js +5 -4
- package/esm/RenderLinearReadCloudDisplayRPC/drawFeatsCommon.d.ts +2 -2
- package/esm/RenderLinearReadCloudDisplayRPC/drawFeatsCommon.js +3 -3
- package/esm/RenderLinearReadCloudDisplayRPC/drawLongReadChains.d.ts +3 -2
- package/esm/RenderLinearReadCloudDisplayRPC/drawLongReadChains.js +3 -4
- package/esm/RenderLinearReadCloudDisplayRPC/drawPairChains.d.ts +3 -2
- package/esm/RenderLinearReadCloudDisplayRPC/drawPairChains.js +4 -5
- package/esm/RenderLinearReadCloudDisplayRPC/executeRenderLinearReadCloudDisplay.js +5 -4
- package/esm/SNPCoverageRenderer/buildClickMap.d.ts +5 -0
- package/esm/SNPCoverageRenderer/buildClickMap.js +17 -0
- package/esm/SNPCoverageRenderer/calculateModificationCounts.d.ts +1 -19
- package/esm/SNPCoverageRenderer/calculateModificationCounts.js +1 -6
- package/esm/SNPCoverageRenderer/constants.d.ts +12 -0
- package/esm/SNPCoverageRenderer/constants.js +12 -0
- package/esm/SNPCoverageRenderer/createInterbaseItem.d.ts +7 -0
- package/esm/SNPCoverageRenderer/createInterbaseItem.js +13 -0
- package/esm/SNPCoverageRenderer/drawCrossHatches.d.ts +3 -0
- package/esm/SNPCoverageRenderer/drawCrossHatches.js +10 -0
- package/esm/SNPCoverageRenderer/drawNoncovEvents.d.ts +3 -0
- package/esm/SNPCoverageRenderer/drawNoncovEvents.js +56 -0
- package/esm/SNPCoverageRenderer/drawSecondPassMethylation.d.ts +2 -0
- package/esm/SNPCoverageRenderer/drawSecondPassMethylation.js +30 -0
- package/esm/SNPCoverageRenderer/drawSecondPassModifications.d.ts +6 -0
- package/esm/SNPCoverageRenderer/drawSecondPassModifications.js +85 -0
- package/esm/SNPCoverageRenderer/drawSecondPassSNPs.d.ts +2 -0
- package/esm/SNPCoverageRenderer/drawSecondPassSNPs.js +64 -0
- package/esm/SNPCoverageRenderer/drawStackedBars.d.ts +3 -0
- package/esm/SNPCoverageRenderer/drawStackedBars.js +10 -0
- package/esm/SNPCoverageRenderer/makeImage.d.ts +1 -1
- package/esm/SNPCoverageRenderer/makeImage.js +10 -306
- package/esm/SNPCoverageRenderer/types.d.ts +62 -1
- package/package.json +5 -5
|
@@ -87,8 +87,8 @@ export declare function stateModelFactory(pluginManager: PluginManager): import(
|
|
|
87
87
|
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>, [undefined]>;
|
|
88
88
|
descriptions: import("@jbrowse/mobx-state-tree").IType<Record<string, unknown> | undefined, Record<string, unknown> | undefined, Record<string, unknown> | undefined>;
|
|
89
89
|
}>> & import("@jbrowse/mobx-state-tree/dist/internal").NonEmptyObject & import("@jbrowse/mobx-state-tree")._NotCustomized, {
|
|
90
|
-
id: string;
|
|
91
90
|
type: "BaseFeatureWidget";
|
|
91
|
+
id: string;
|
|
92
92
|
track: import("@jbrowse/mobx-state-tree").ReferenceIdentifier | undefined;
|
|
93
93
|
view: import("@jbrowse/mobx-state-tree").ReferenceIdentifier | undefined;
|
|
94
94
|
trackId: string | undefined;
|
|
@@ -3,7 +3,7 @@ import { getAdapter } from '@jbrowse/core/data_adapters/dataAdapterCache';
|
|
|
3
3
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
4
4
|
import { renderToAbstractCanvas } from '@jbrowse/core/util';
|
|
5
5
|
import Flatbush from '@jbrowse/core/util/flatbush';
|
|
6
|
-
import { checkStopToken2
|
|
6
|
+
import { checkStopToken2 } from '@jbrowse/core/util/stopToken';
|
|
7
7
|
import { layoutFeats } from "./layoutFeatures.js";
|
|
8
8
|
import { renderAlignment } from "./renderers/renderAlignment.js";
|
|
9
9
|
import { renderMismatchesCallback } from "./renderers/renderMismatchesCallback.js";
|
|
@@ -29,7 +29,7 @@ async function fetchRegionSequence(renderArgs, pluginManager) {
|
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
function renderFeatures({ ctx, layoutRecords, canvasWidth, renderArgs, }) {
|
|
32
|
-
const {
|
|
32
|
+
const { stopTokenCheck, config, showSoftClip, colorBy, theme: configTheme, } = renderArgs;
|
|
33
33
|
const mismatchAlpha = readConfObject(config, 'mismatchAlpha');
|
|
34
34
|
const minSubfeatureWidth = readConfObject(config, 'minSubfeatureWidth');
|
|
35
35
|
const largeInsertionIndicatorScale = readConfObject(config, 'largeInsertionIndicatorScale');
|
|
@@ -46,7 +46,6 @@ function renderFeatures({ ctx, layoutRecords, canvasWidth, renderArgs, }) {
|
|
|
46
46
|
const drawIndels = shouldDrawIndels();
|
|
47
47
|
const coords = [];
|
|
48
48
|
const items = [];
|
|
49
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
50
49
|
for (const feat of layoutRecords) {
|
|
51
50
|
const alignmentRet = renderAlignment({
|
|
52
51
|
ctx,
|
|
@@ -101,7 +100,7 @@ function renderFeatures({ ctx, layoutRecords, canvasWidth, renderArgs, }) {
|
|
|
101
100
|
canvasWidth,
|
|
102
101
|
});
|
|
103
102
|
}
|
|
104
|
-
checkStopToken2(
|
|
103
|
+
checkStopToken2(stopTokenCheck);
|
|
105
104
|
}
|
|
106
105
|
const flatbush = new Flatbush(Math.max(items.length, 1));
|
|
107
106
|
if (coords.length) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ChainData, ColorBy } from '../shared/types.ts';
|
|
2
|
+
import type { LastStopTokenCheck } from '@jbrowse/core/util';
|
|
2
3
|
interface DrawFeatsRPCParams {
|
|
3
4
|
ctx: CanvasRenderingContext2D;
|
|
4
5
|
width: number;
|
|
@@ -18,7 +19,7 @@ interface DrawFeatsRPCParams {
|
|
|
18
19
|
} | undefined;
|
|
19
20
|
};
|
|
20
21
|
offsetPx: number;
|
|
21
|
-
|
|
22
|
+
stopTokenCheck?: LastStopTokenCheck;
|
|
22
23
|
}
|
|
23
24
|
export declare function drawFeatsRPC(params: DrawFeatsRPCParams): void;
|
|
24
25
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { checkStopToken2
|
|
1
|
+
import { checkStopToken2 } from '@jbrowse/core/util/stopToken';
|
|
2
2
|
import { featurizeSA, getTag } from "../MismatchParser/index.js";
|
|
3
3
|
import { drawVerticalLine, extractCoreFeat, extractCoreFeatBasic, filterAndSortLongReadChain, filterPairedChain, getMateInfo, getStrandRelativeFirstClipLength, jitter, toCoreFeat, toCoreFeatBasic, } from "../shared/arcUtils.js";
|
|
4
4
|
import { getPairedInsertSizeAndOrientationColor, getPairedInsertSizeColor, getPairedOrientationColor, } from "../shared/color.js";
|
|
@@ -63,7 +63,7 @@ function drawBezierArc(ctx, startX, endX, destY, jitterVal) {
|
|
|
63
63
|
ctx.stroke();
|
|
64
64
|
}
|
|
65
65
|
export function drawFeatsRPC(params) {
|
|
66
|
-
const { ctx, height, chainData, colorBy, drawInter, drawLongRange, lineWidth, jitter: jitterVal, view, offsetPx,
|
|
66
|
+
const { ctx, height, chainData, colorBy, drawInter, drawLongRange, lineWidth, jitter: jitterVal, view, offsetPx, stopTokenCheck, } = params;
|
|
67
67
|
const { chains, stats } = chainData;
|
|
68
68
|
const colorByType = colorBy.type;
|
|
69
69
|
const hasPaired = hasPairedReads(chainData);
|
|
@@ -136,7 +136,6 @@ export function drawFeatsRPC(params) {
|
|
|
136
136
|
draw(extractCoreFeat(filtered[i]), extractCoreFeatBasic(filtered[i + 1]), false);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
140
139
|
for (const chain of chains) {
|
|
141
140
|
if (chain.length === 1 && drawLongRange) {
|
|
142
141
|
const f = chain[0];
|
|
@@ -151,6 +150,6 @@ export function drawFeatsRPC(params) {
|
|
|
151
150
|
else {
|
|
152
151
|
drawMultiFeatureChain(chain);
|
|
153
152
|
}
|
|
154
|
-
checkStopToken2(
|
|
153
|
+
checkStopToken2(stopTokenCheck);
|
|
155
154
|
}
|
|
156
155
|
}
|
|
@@ -3,7 +3,7 @@ import { collectTransferables, dedupe, groupBy, max, min, renderToAbstractCanvas
|
|
|
3
3
|
import { bpToPx } from '@jbrowse/core/util/Base1DUtils';
|
|
4
4
|
import Base1DView from '@jbrowse/core/util/Base1DViewModel';
|
|
5
5
|
import { rpcResult } from '@jbrowse/core/util/librpc';
|
|
6
|
-
import {
|
|
6
|
+
import { checkStopToken2, createStopTokenChecker, } from '@jbrowse/core/util/stopToken';
|
|
7
7
|
import { getSnapshot } from '@jbrowse/mobx-state-tree';
|
|
8
8
|
import { firstValueFrom } from 'rxjs';
|
|
9
9
|
import { toArray } from 'rxjs/operators';
|
|
@@ -11,6 +11,7 @@ import { drawFeatsRPC } from "./drawFeatsRPC.js";
|
|
|
11
11
|
import { getInsertSizeStats } from "../shared/insertSizeStats.js";
|
|
12
12
|
export async function executeRenderLinearReadArcsDisplay({ pluginManager, args, }) {
|
|
13
13
|
const { sessionId, view: viewSnapshot, adapterConfig, sequenceAdapter, colorBy, drawInter, drawLongRange, lineWidth, jitter, height, highResolutionScaling, exportSVG, statusCallback = () => { }, stopToken, } = args;
|
|
14
|
+
const stopTokenCheck = createStopTokenChecker(stopToken);
|
|
14
15
|
const view = Base1DView.create(viewSnapshot);
|
|
15
16
|
if (viewSnapshot.width) {
|
|
16
17
|
view.setVolatileWidth(viewSnapshot.width);
|
|
@@ -39,7 +40,7 @@ export async function executeRenderLinearReadArcsDisplay({ pluginManager, args,
|
|
|
39
40
|
dataAdapter.setSequenceAdapterConfig(sequenceAdapter);
|
|
40
41
|
}
|
|
41
42
|
const featuresArray = await updateStatus('Fetching alignments', statusCallback, () => firstValueFrom(dataAdapter.getFeaturesInMultipleRegions(regions, args).pipe(toArray())));
|
|
42
|
-
|
|
43
|
+
checkStopToken2(stopTokenCheck);
|
|
43
44
|
const { chains, stats } = await updateStatus('Processing alignments', statusCallback, async () => {
|
|
44
45
|
const deduped = dedupe(featuresArray, f => f.id());
|
|
45
46
|
const filtered = deduped.filter(f => {
|
|
@@ -78,7 +79,7 @@ export async function executeRenderLinearReadArcsDisplay({ pluginManager, args,
|
|
|
78
79
|
chains,
|
|
79
80
|
stats,
|
|
80
81
|
};
|
|
81
|
-
|
|
82
|
+
checkStopToken2(stopTokenCheck);
|
|
82
83
|
const renderOpts = {
|
|
83
84
|
highResolutionScaling,
|
|
84
85
|
exportSVG,
|
|
@@ -96,7 +97,7 @@ export async function executeRenderLinearReadArcsDisplay({ pluginManager, args,
|
|
|
96
97
|
jitter,
|
|
97
98
|
view: viewSnap,
|
|
98
99
|
offsetPx,
|
|
99
|
-
|
|
100
|
+
stopTokenCheck,
|
|
100
101
|
});
|
|
101
102
|
return undefined;
|
|
102
103
|
}));
|
|
@@ -3,7 +3,7 @@ import type { FlatbushItem } from '../PileupRenderer/types.ts';
|
|
|
3
3
|
import type { FlatbushEntry } from '../shared/flatbushType.ts';
|
|
4
4
|
import type { ChainData, ColorBy, ModificationTypeWithColor } from '../shared/types.ts';
|
|
5
5
|
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
6
|
-
import type { Feature } from '@jbrowse/core/util';
|
|
6
|
+
import type { Feature, LastStopTokenCheck } from '@jbrowse/core/util';
|
|
7
7
|
import type { BaseBlock } from '@jbrowse/core/util/blockTypes';
|
|
8
8
|
import type { ThemeOptions } from '@mui/material';
|
|
9
9
|
interface ViewForDrawing {
|
|
@@ -44,7 +44,7 @@ export interface DrawFeatsParams {
|
|
|
44
44
|
regions: BaseBlock[];
|
|
45
45
|
bpPerPx: number;
|
|
46
46
|
canvasWidth: number;
|
|
47
|
-
|
|
47
|
+
stopTokenCheck?: LastStopTokenCheck;
|
|
48
48
|
visibleModifications?: Record<string, ModificationTypeWithColor>;
|
|
49
49
|
hideSmallIndels?: boolean;
|
|
50
50
|
hideMismatches?: boolean;
|
|
@@ -176,7 +176,7 @@ export function addChainMouseoverRects(computedChains, chainYOffsets, featureHei
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
export function drawFeatsCore({ ctx, params, view, calculateYOffsets, }) {
|
|
179
|
-
const { chainData, featureHeight, colorBy, drawSingletons, drawProperPairs, flipStrandLongReadChains,
|
|
179
|
+
const { chainData, featureHeight, colorBy, drawSingletons, drawProperPairs, flipStrandLongReadChains, stopTokenCheck, } = params;
|
|
180
180
|
const type = colorBy.type || 'insertSizeAndOrientation';
|
|
181
181
|
const { chains } = chainData;
|
|
182
182
|
const filteredChains = filterChains(chains, drawSingletons, drawProperPairs, type, chainData);
|
|
@@ -210,7 +210,7 @@ export function drawFeatsCore({ ctx, params, view, calculateYOffsets, }) {
|
|
|
210
210
|
bpPerPx: params.bpPerPx,
|
|
211
211
|
colorBy: params.colorBy,
|
|
212
212
|
visibleModifications: params.visibleModifications,
|
|
213
|
-
|
|
213
|
+
stopTokenCheck,
|
|
214
214
|
hideSmallIndels: params.hideSmallIndels,
|
|
215
215
|
hideMismatches: params.hideMismatches,
|
|
216
216
|
hideLargeIndels: params.hideLargeIndels,
|
|
@@ -231,7 +231,7 @@ export function drawFeatsCore({ ctx, params, view, calculateYOffsets, }) {
|
|
|
231
231
|
bpPerPx: params.bpPerPx,
|
|
232
232
|
colorBy: params.colorBy,
|
|
233
233
|
visibleModifications: params.visibleModifications,
|
|
234
|
-
|
|
234
|
+
stopTokenCheck,
|
|
235
235
|
hideSmallIndels: params.hideSmallIndels,
|
|
236
236
|
hideMismatches: params.hideMismatches,
|
|
237
237
|
hideLargeIndels: params.hideLargeIndels,
|
|
@@ -2,9 +2,10 @@ import type { MismatchData } from './drawChainsUtil.ts';
|
|
|
2
2
|
import type { ComputedChain } from './drawFeatsCommon.ts';
|
|
3
3
|
import type { ChainData, ColorBy, ModificationTypeWithColor } from '../shared/types.ts';
|
|
4
4
|
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
5
|
+
import type { LastStopTokenCheck } from '@jbrowse/core/util';
|
|
5
6
|
import type { BaseBlock } from '@jbrowse/core/util/blockTypes';
|
|
6
7
|
import type { ThemeOptions } from '@mui/material';
|
|
7
|
-
export declare function drawLongReadChains({ ctx, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, flipStrandLongReadChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications,
|
|
8
|
+
export declare function drawLongReadChains({ ctx, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, flipStrandLongReadChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications, stopTokenCheck, hideSmallIndels, hideMismatches, hideLargeIndels, showOutline, }: {
|
|
8
9
|
ctx: CanvasRenderingContext2D;
|
|
9
10
|
chainData: ChainData;
|
|
10
11
|
chainYOffsets: Map<string, number>;
|
|
@@ -19,7 +20,7 @@ export declare function drawLongReadChains({ ctx, chainData, chainYOffsets, rend
|
|
|
19
20
|
bpPerPx: number;
|
|
20
21
|
colorBy: ColorBy;
|
|
21
22
|
visibleModifications?: Record<string, ModificationTypeWithColor>;
|
|
22
|
-
|
|
23
|
+
stopTokenCheck?: LastStopTokenCheck;
|
|
23
24
|
hideSmallIndels?: boolean;
|
|
24
25
|
hideMismatches?: boolean;
|
|
25
26
|
hideLargeIndels?: boolean;
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
import { checkStopToken2
|
|
1
|
+
import { checkStopToken2 } from '@jbrowse/core/util/stopToken';
|
|
2
2
|
import { calculateFeaturePositionPx, featureOverlapsRegion, getChainBoundsOnRef, getConnectingLineColor, getMismatchRenderingConfig, getStrandColorKey, renderFeatureMismatchesAndModifications, renderFeatureShape, } from "./drawChainsUtil.js";
|
|
3
3
|
import { lineToCtx } from "../shared/canvasUtils.js";
|
|
4
4
|
import { fillColor, getSingletonColor, strokeColor } from "../shared/color.js";
|
|
5
5
|
import { getPrimaryStrandFromFlags } from "../shared/primaryStrand.js";
|
|
6
|
-
export function drawLongReadChains({ ctx, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, flipStrandLongReadChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications,
|
|
6
|
+
export function drawLongReadChains({ ctx, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, flipStrandLongReadChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications, stopTokenCheck, hideSmallIndels, hideMismatches, hideLargeIndels, showOutline, }) {
|
|
7
7
|
const mismatchConfig = getMismatchRenderingConfig(ctx, config, configTheme, colorBy, { hideSmallIndels, hideMismatches, hideLargeIndels });
|
|
8
8
|
const canvasWidth = region.widthPx;
|
|
9
9
|
const regionStart = region.start;
|
|
10
10
|
const allCoords = [];
|
|
11
11
|
const allItems = [];
|
|
12
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
13
12
|
for (const computedChain of computedChains) {
|
|
14
|
-
checkStopToken2(
|
|
13
|
+
checkStopToken2(stopTokenCheck);
|
|
15
14
|
const { id, chain, isPairedEnd, nonSupplementary } = computedChain;
|
|
16
15
|
if (isPairedEnd) {
|
|
17
16
|
continue;
|
|
@@ -2,9 +2,10 @@ import type { MismatchData } from './drawChainsUtil.ts';
|
|
|
2
2
|
import type { ComputedChain } from './drawFeatsCommon.ts';
|
|
3
3
|
import type { ChainData, ColorBy, ModificationTypeWithColor } from '../shared/types.ts';
|
|
4
4
|
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
5
|
+
import type { LastStopTokenCheck } from '@jbrowse/core/util';
|
|
5
6
|
import type { BaseBlock } from '@jbrowse/core/util/blockTypes';
|
|
6
7
|
import type { ThemeOptions } from '@mui/material';
|
|
7
|
-
export declare function drawPairChains({ ctx, type, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications,
|
|
8
|
+
export declare function drawPairChains({ ctx, type, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications, stopTokenCheck, hideSmallIndels, hideMismatches, hideLargeIndels, showOutline, }: {
|
|
8
9
|
ctx: CanvasRenderingContext2D;
|
|
9
10
|
type: string;
|
|
10
11
|
chainData: ChainData;
|
|
@@ -19,7 +20,7 @@ export declare function drawPairChains({ ctx, type, chainData, chainYOffsets, re
|
|
|
19
20
|
bpPerPx: number;
|
|
20
21
|
colorBy: ColorBy;
|
|
21
22
|
visibleModifications?: Record<string, ModificationTypeWithColor>;
|
|
22
|
-
|
|
23
|
+
stopTokenCheck?: LastStopTokenCheck;
|
|
23
24
|
hideSmallIndels?: boolean;
|
|
24
25
|
hideMismatches?: boolean;
|
|
25
26
|
hideLargeIndels?: boolean;
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
import { checkStopToken2
|
|
1
|
+
import { checkStopToken2 } from '@jbrowse/core/util/stopToken';
|
|
2
2
|
import { calculateFeaturePositionPx, featureOverlapsRegion, getChainBoundsOnRef, getConnectingLineColor, getMismatchRenderingConfig, renderFeatureMismatchesAndModifications, renderFeatureShape, } from "./drawChainsUtil.js";
|
|
3
3
|
import { lineToCtx } from "../shared/canvasUtils.js";
|
|
4
4
|
import { fillColor, getPairedColor, strokeColor } from "../shared/color.js";
|
|
5
|
-
export function drawPairChains({ ctx, type, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications,
|
|
5
|
+
export function drawPairChains({ ctx, type, chainData, chainYOffsets, renderChevrons, featureHeight, computedChains, config, theme: configTheme, region, regionStartPx, bpPerPx, colorBy, visibleModifications, stopTokenCheck, hideSmallIndels, hideMismatches, hideLargeIndels, showOutline, }) {
|
|
6
6
|
const mismatchConfig = getMismatchRenderingConfig(ctx, config, configTheme, colorBy, { hideSmallIndels, hideMismatches, hideLargeIndels });
|
|
7
7
|
const canvasWidth = region.widthPx;
|
|
8
8
|
const regionStart = region.start;
|
|
9
9
|
const allCoords = [];
|
|
10
10
|
const allItems = [];
|
|
11
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
12
11
|
for (const computedChain of computedChains) {
|
|
13
|
-
checkStopToken2(
|
|
12
|
+
checkStopToken2(stopTokenCheck);
|
|
14
13
|
const { id, chain, isPairedEnd, nonSupplementary } = computedChain;
|
|
15
14
|
if (!isPairedEnd) {
|
|
16
15
|
continue;
|
|
@@ -89,7 +88,7 @@ export function drawPairChains({ ctx, type, chainData, chainYOffsets, renderChev
|
|
|
89
88
|
allItems,
|
|
90
89
|
});
|
|
91
90
|
}
|
|
92
|
-
checkStopToken2(
|
|
91
|
+
checkStopToken2(stopTokenCheck);
|
|
93
92
|
}
|
|
94
93
|
return { coords: allCoords, items: allItems };
|
|
95
94
|
}
|
|
@@ -3,7 +3,7 @@ import { collectTransferables, dedupe, groupBy, max, min, renderToAbstractCanvas
|
|
|
3
3
|
import { bpToPx } from '@jbrowse/core/util/Base1DUtils';
|
|
4
4
|
import Base1DView from '@jbrowse/core/util/Base1DViewModel';
|
|
5
5
|
import { rpcResult } from '@jbrowse/core/util/librpc';
|
|
6
|
-
import {
|
|
6
|
+
import { checkStopToken2, createStopTokenChecker, } from '@jbrowse/core/util/stopToken';
|
|
7
7
|
import { getSnapshot } from '@jbrowse/mobx-state-tree';
|
|
8
8
|
import { firstValueFrom } from 'rxjs';
|
|
9
9
|
import { toArray } from 'rxjs/operators';
|
|
@@ -13,6 +13,7 @@ import { calculateStackYOffsetsUtil } from "./drawFeatsStack.js";
|
|
|
13
13
|
import { getInsertSizeStats } from "../shared/insertSizeStats.js";
|
|
14
14
|
export async function executeRenderLinearReadCloudDisplay({ pluginManager, args, }) {
|
|
15
15
|
const { sessionId, view: viewSnapshot, adapterConfig, sequenceAdapter, config, theme, featureHeight, noSpacing, drawCloud, colorBy, drawSingletons, drawProperPairs, flipStrandLongReadChains, trackMaxHeight, cloudModeHeight, highResolutionScaling, exportSVG, statusCallback = () => { }, stopToken, visibleModifications, hideSmallIndels, hideMismatches, hideLargeIndels, showOutline, } = args;
|
|
16
|
+
const stopTokenCheck = createStopTokenChecker(stopToken);
|
|
16
17
|
const view = Base1DView.create(viewSnapshot);
|
|
17
18
|
if (viewSnapshot.width) {
|
|
18
19
|
view.setVolatileWidth(viewSnapshot.width);
|
|
@@ -45,7 +46,7 @@ export async function executeRenderLinearReadCloudDisplay({ pluginManager, args,
|
|
|
45
46
|
dataAdapter.setSequenceAdapterConfig(sequenceAdapter);
|
|
46
47
|
}
|
|
47
48
|
const featuresArray = await updateStatus('Fetching alignments', statusCallback, () => firstValueFrom(dataAdapter.getFeaturesInMultipleRegions(regions, args).pipe(toArray())));
|
|
48
|
-
|
|
49
|
+
checkStopToken2(stopTokenCheck);
|
|
49
50
|
const deduped = dedupe(featuresArray, f => f.id());
|
|
50
51
|
const { chains, stats } = await updateStatus('Processing alignments', statusCallback, async () => {
|
|
51
52
|
const tlens = [];
|
|
@@ -74,7 +75,7 @@ export async function executeRenderLinearReadCloudDisplay({ pluginManager, args,
|
|
|
74
75
|
};
|
|
75
76
|
});
|
|
76
77
|
const chainData = { chains, stats };
|
|
77
|
-
|
|
78
|
+
checkStopToken2(stopTokenCheck);
|
|
78
79
|
const { computedChains } = await updateStatus('Calculating layout', statusCallback, async () => {
|
|
79
80
|
const filtered = filterChains(chains, drawSingletons, drawProperPairs, colorBy.type || 'insertSizeAndOrientation', chainData);
|
|
80
81
|
const computed = computeChainBounds(filtered, viewSnap);
|
|
@@ -115,7 +116,7 @@ export async function executeRenderLinearReadCloudDisplay({ pluginManager, args,
|
|
|
115
116
|
theme,
|
|
116
117
|
regions,
|
|
117
118
|
bpPerPx,
|
|
118
|
-
|
|
119
|
+
stopTokenCheck,
|
|
119
120
|
visibleModifications,
|
|
120
121
|
hideSmallIndels,
|
|
121
122
|
hideMismatches,
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import Flatbush from '@jbrowse/core/util/flatbush';
|
|
2
|
+
export function buildClickMap(coords, items) {
|
|
3
|
+
const flatbush = new Flatbush(Math.max(items.length, 1));
|
|
4
|
+
if (coords.length) {
|
|
5
|
+
for (let i = 0; i < coords.length; i += 4) {
|
|
6
|
+
flatbush.add(coords[i], coords[i + 1], coords[i + 2], coords[i + 3]);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
flatbush.add(0, 0);
|
|
11
|
+
}
|
|
12
|
+
flatbush.finish();
|
|
13
|
+
return {
|
|
14
|
+
flatbush: flatbush.data,
|
|
15
|
+
items,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -1,20 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
readonly entryDepth: number;
|
|
3
|
-
readonly '1': number;
|
|
4
|
-
readonly '-1': number;
|
|
5
|
-
readonly '0': number;
|
|
6
|
-
}
|
|
7
|
-
export interface ModificationCountsParams {
|
|
8
|
-
readonly base: string;
|
|
9
|
-
readonly isSimplex: boolean;
|
|
10
|
-
readonly refbase: string | undefined;
|
|
11
|
-
readonly snps: Readonly<Record<string, Partial<StrandCounts>>>;
|
|
12
|
-
readonly ref: StrandCounts;
|
|
13
|
-
readonly score0: number;
|
|
14
|
-
}
|
|
15
|
-
interface ModificationCountsResult {
|
|
16
|
-
readonly modifiable: number;
|
|
17
|
-
readonly detectable: number;
|
|
18
|
-
}
|
|
1
|
+
import type { ModificationCountsParams, ModificationCountsResult } from './types.ts';
|
|
19
2
|
export declare function calculateModificationCounts({ base, isSimplex, refbase, snps, ref, score0, }: ModificationCountsParams): ModificationCountsResult;
|
|
20
|
-
export {};
|
|
@@ -1,9 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
C: 'G',
|
|
3
|
-
G: 'C',
|
|
4
|
-
A: 'T',
|
|
5
|
-
T: 'A',
|
|
6
|
-
};
|
|
1
|
+
import { complementBase } from "./constants.js";
|
|
7
2
|
export function calculateModificationCounts({ base, isSimplex, refbase, snps, ref, score0, }) {
|
|
8
3
|
if (base === 'N') {
|
|
9
4
|
return { modifiable: score0, detectable: score0 };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare const INTERBASE_INDICATOR_WIDTH = 7;
|
|
2
|
+
export declare const INTERBASE_INDICATOR_HEIGHT = 4.5;
|
|
3
|
+
export declare const MINIMUM_INTERBASE_INDICATOR_READ_DEPTH = 7;
|
|
4
|
+
export declare const INTERBASE_DRAW_THRESHOLD = 0.1;
|
|
5
|
+
export declare const complementBase: {
|
|
6
|
+
readonly C: "G";
|
|
7
|
+
readonly G: "C";
|
|
8
|
+
readonly A: "T";
|
|
9
|
+
readonly T: "A";
|
|
10
|
+
};
|
|
11
|
+
export declare const fudgeFactor = 0.6;
|
|
12
|
+
export declare const SNP_CLICKMAP_THRESHOLD = 0.04;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const INTERBASE_INDICATOR_WIDTH = 7;
|
|
2
|
+
export const INTERBASE_INDICATOR_HEIGHT = 4.5;
|
|
3
|
+
export const MINIMUM_INTERBASE_INDICATOR_READ_DEPTH = 7;
|
|
4
|
+
export const INTERBASE_DRAW_THRESHOLD = 0.1;
|
|
5
|
+
export const complementBase = {
|
|
6
|
+
C: 'G',
|
|
7
|
+
G: 'C',
|
|
8
|
+
A: 'T',
|
|
9
|
+
T: 'A',
|
|
10
|
+
};
|
|
11
|
+
export const fudgeFactor = 0.6;
|
|
12
|
+
export const SNP_CLICKMAP_THRESHOLD = 0.04;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InterbaseIndicatorItem } from './types.ts';
|
|
2
|
+
export declare function createInterbaseItem(maxBase: string, count: number, total: number, start: number, maxEntry?: {
|
|
3
|
+
avgLength?: number;
|
|
4
|
+
minLength?: number;
|
|
5
|
+
maxLength?: number;
|
|
6
|
+
topSequence?: string;
|
|
7
|
+
}): InterbaseIndicatorItem;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function createInterbaseItem(maxBase, count, total, start, maxEntry) {
|
|
2
|
+
return {
|
|
3
|
+
type: maxBase,
|
|
4
|
+
base: maxBase,
|
|
5
|
+
count,
|
|
6
|
+
total,
|
|
7
|
+
avgLength: maxEntry?.avgLength,
|
|
8
|
+
minLength: maxEntry?.minLength,
|
|
9
|
+
maxLength: maxEntry?.maxLength,
|
|
10
|
+
topSequence: maxEntry?.topSequence,
|
|
11
|
+
start,
|
|
12
|
+
};
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function drawCrossHatches(ctx, ticks, width, toY) {
|
|
2
|
+
ctx.lineWidth = 1;
|
|
3
|
+
ctx.strokeStyle = 'rgba(140,140,140,0.8)';
|
|
4
|
+
for (const tick of ticks.values) {
|
|
5
|
+
ctx.beginPath();
|
|
6
|
+
ctx.moveTo(0, Math.round(toY(tick)));
|
|
7
|
+
ctx.lineTo(width, Math.round(toY(tick)));
|
|
8
|
+
ctx.stroke();
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { SecondPassContext } from './types.ts';
|
|
2
|
+
import type { BaseCoverageBin } from '../shared/types.ts';
|
|
3
|
+
export declare function drawNoncovEvents(passCtx: SecondPassContext, snpinfo: BaseCoverageBin, leftPx: number, score0: number, prevTotal: number, skipDraw: boolean, fstart: number): void;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { INTERBASE_DRAW_THRESHOLD, INTERBASE_INDICATOR_HEIGHT, INTERBASE_INDICATOR_WIDTH, MINIMUM_INTERBASE_INDICATOR_READ_DEPTH, } from "./constants.js";
|
|
2
|
+
import { createInterbaseItem } from "./createInterbaseItem.js";
|
|
3
|
+
export function drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, fstart) {
|
|
4
|
+
const { ctx, colorMap, toHeight2, extraHorizontallyFlippedOffset, coords, items, bpPerPx, indicatorThreshold, showInterbaseCounts, showInterbaseIndicators, } = passCtx;
|
|
5
|
+
let totalCount = 0;
|
|
6
|
+
let maxDepth = 0;
|
|
7
|
+
let maxBase = '';
|
|
8
|
+
let totalHeight = 0;
|
|
9
|
+
const r = 0.6;
|
|
10
|
+
const x = leftPx - r + extraHorizontallyFlippedOffset;
|
|
11
|
+
for (const base in snpinfo.noncov) {
|
|
12
|
+
const { entryDepth } = snpinfo.noncov[base];
|
|
13
|
+
totalCount += entryDepth;
|
|
14
|
+
if (entryDepth > maxDepth) {
|
|
15
|
+
maxDepth = entryDepth;
|
|
16
|
+
maxBase = base;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
const isSignificant = score0 > 0 && totalCount > score0 * INTERBASE_DRAW_THRESHOLD;
|
|
20
|
+
const showCounts = showInterbaseCounts && (!skipDraw || isSignificant);
|
|
21
|
+
if (showCounts) {
|
|
22
|
+
for (const base in snpinfo.noncov) {
|
|
23
|
+
const { entryDepth } = snpinfo.noncov[base];
|
|
24
|
+
const barHeight = toHeight2(entryDepth);
|
|
25
|
+
ctx.fillStyle = colorMap[base];
|
|
26
|
+
ctx.fillRect(x, INTERBASE_INDICATOR_HEIGHT + totalHeight, r * 2, barHeight);
|
|
27
|
+
totalHeight += barHeight;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (totalCount > 0) {
|
|
31
|
+
const maxEntry = snpinfo.noncov[maxBase];
|
|
32
|
+
if (showCounts) {
|
|
33
|
+
if (bpPerPx < 50 || isSignificant) {
|
|
34
|
+
const clickWidth = Math.max(r * 2, 2);
|
|
35
|
+
coords.push(x, INTERBASE_INDICATOR_HEIGHT, x + clickWidth, INTERBASE_INDICATOR_HEIGHT + totalHeight);
|
|
36
|
+
items.push(createInterbaseItem(maxBase, totalCount, score0, fstart, maxEntry));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (showInterbaseIndicators && (!skipDraw || isSignificant)) {
|
|
40
|
+
const indicatorComparatorScore = Math.max(score0, prevTotal);
|
|
41
|
+
if (totalCount > indicatorComparatorScore * indicatorThreshold &&
|
|
42
|
+
indicatorComparatorScore > MINIMUM_INTERBASE_INDICATOR_READ_DEPTH) {
|
|
43
|
+
ctx.fillStyle = colorMap[maxBase];
|
|
44
|
+
ctx.beginPath();
|
|
45
|
+
const l = leftPx + extraHorizontallyFlippedOffset;
|
|
46
|
+
ctx.moveTo(l - INTERBASE_INDICATOR_WIDTH / 2, 0);
|
|
47
|
+
ctx.lineTo(l + INTERBASE_INDICATOR_WIDTH / 2, 0);
|
|
48
|
+
ctx.lineTo(l, INTERBASE_INDICATOR_HEIGHT);
|
|
49
|
+
ctx.fill();
|
|
50
|
+
const hitboxPadding = 1;
|
|
51
|
+
coords.push(l - INTERBASE_INDICATOR_WIDTH / 2 - hitboxPadding, 0, l + INTERBASE_INDICATOR_WIDTH / 2 + hitboxPadding, INTERBASE_INDICATOR_HEIGHT + hitboxPadding);
|
|
52
|
+
items.push(createInterbaseItem(maxBase, totalCount, indicatorComparatorScore, fstart, maxEntry));
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { checkStopToken2, featureSpanPx } from '@jbrowse/core/util';
|
|
2
|
+
import { drawNoncovEvents } from "./drawNoncovEvents.js";
|
|
3
|
+
import { drawStackedBars } from "./drawStackedBars.js";
|
|
4
|
+
export function drawSecondPassMethylation(passCtx) {
|
|
5
|
+
const { ctx, coverageFeatures, region, bpPerPx, colorMap, toY, toHeight, stopTokenCheck, } = passCtx;
|
|
6
|
+
let snpDrawn = 0;
|
|
7
|
+
const snpSkipped = 0;
|
|
8
|
+
let lastDrawnX = Number.NEGATIVE_INFINITY;
|
|
9
|
+
let prevTotal = 0;
|
|
10
|
+
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
11
|
+
checkStopToken2(stopTokenCheck);
|
|
12
|
+
const feature = coverageFeatures[i];
|
|
13
|
+
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
14
|
+
const snpinfo = feature.get('snpinfo');
|
|
15
|
+
const w = Math.max(rightPx - leftPx, 1);
|
|
16
|
+
const score0 = feature.get('score');
|
|
17
|
+
const drawX = Math.round(leftPx);
|
|
18
|
+
const skipDraw = drawX === lastDrawnX;
|
|
19
|
+
const { depth, nonmods, mods } = snpinfo;
|
|
20
|
+
const h = toHeight(score0);
|
|
21
|
+
const bottom = toY(score0) + h;
|
|
22
|
+
const curr = drawStackedBars(ctx, mods, colorMap, drawX, bottom, w, h, depth, 0);
|
|
23
|
+
drawStackedBars(ctx, nonmods, colorMap, drawX, bottom, w, h, depth, curr);
|
|
24
|
+
snpDrawn++;
|
|
25
|
+
lastDrawnX = drawX;
|
|
26
|
+
drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, feature.get('start'));
|
|
27
|
+
prevTotal = score0;
|
|
28
|
+
}
|
|
29
|
+
return { snpDrawn, snpSkipped };
|
|
30
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SecondPassContext, SecondPassStats } from './types.ts';
|
|
2
|
+
export declare function drawSecondPassModifications(passCtx: SecondPassContext, visibleModifications: Record<string, {
|
|
3
|
+
base: string;
|
|
4
|
+
type: string;
|
|
5
|
+
color?: string;
|
|
6
|
+
}>, isolatedModification: string | undefined, simplexSet: Set<string>): SecondPassStats;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { checkStopToken2, featureSpanPx } from '@jbrowse/core/util';
|
|
2
|
+
import { calculateModificationCounts } from "./calculateModificationCounts.js";
|
|
3
|
+
import { drawNoncovEvents } from "./drawNoncovEvents.js";
|
|
4
|
+
import { alphaColor } from "../shared/util.js";
|
|
5
|
+
export function drawSecondPassModifications(passCtx, visibleModifications, isolatedModification, simplexSet) {
|
|
6
|
+
const { ctx, coverageFeatures, region, bpPerPx, toY, toHeight, stopTokenCheck, } = passCtx;
|
|
7
|
+
let snpDrawn = 0;
|
|
8
|
+
let snpSkipped = 0;
|
|
9
|
+
let lastDrawnX = Number.NEGATIVE_INFINITY;
|
|
10
|
+
let prevTotal = 0;
|
|
11
|
+
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
12
|
+
checkStopToken2(stopTokenCheck);
|
|
13
|
+
const feature = coverageFeatures[i];
|
|
14
|
+
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
15
|
+
const snpinfo = feature.get('snpinfo');
|
|
16
|
+
const w = Math.max(rightPx - leftPx, 1);
|
|
17
|
+
const score0 = feature.get('score');
|
|
18
|
+
const drawX = Math.round(leftPx);
|
|
19
|
+
const skipDraw = drawX === lastDrawnX;
|
|
20
|
+
let curr = 0;
|
|
21
|
+
const refbase = snpinfo?.refbase?.toUpperCase();
|
|
22
|
+
const { nonmods, mods, snps, ref } = snpinfo || {};
|
|
23
|
+
const h = toHeight(score0);
|
|
24
|
+
const bottom = toY(score0) + h;
|
|
25
|
+
for (const key in nonmods) {
|
|
26
|
+
const modKey = key.slice(7);
|
|
27
|
+
const mod = visibleModifications[modKey];
|
|
28
|
+
if (!mod || (isolatedModification && mod.type !== isolatedModification)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const { modifiable, detectable } = calculateModificationCounts({
|
|
32
|
+
base: mod.base,
|
|
33
|
+
isSimplex: simplexSet.has(mod.type),
|
|
34
|
+
refbase,
|
|
35
|
+
snps: snps || {},
|
|
36
|
+
ref: ref || { entryDepth: 0, '1': 0, '-1': 0, '0': 0 },
|
|
37
|
+
score0,
|
|
38
|
+
});
|
|
39
|
+
const { entryDepth, avgProbability = 0 } = nonmods[key];
|
|
40
|
+
const modFraction = (modifiable / score0) * (entryDepth / detectable);
|
|
41
|
+
const barHeight = modFraction * h;
|
|
42
|
+
if (skipDraw) {
|
|
43
|
+
snpSkipped++;
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
ctx.fillStyle = alphaColor('blue', avgProbability);
|
|
47
|
+
ctx.fillRect(drawX, bottom - (curr + barHeight), w, barHeight);
|
|
48
|
+
snpDrawn++;
|
|
49
|
+
lastDrawnX = drawX;
|
|
50
|
+
}
|
|
51
|
+
curr += barHeight;
|
|
52
|
+
}
|
|
53
|
+
for (const key in mods) {
|
|
54
|
+
const modKey = key.slice(4);
|
|
55
|
+
const mod = visibleModifications[modKey];
|
|
56
|
+
if (!mod || (isolatedModification && mod.type !== isolatedModification)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const { modifiable, detectable } = calculateModificationCounts({
|
|
60
|
+
base: mod.base,
|
|
61
|
+
isSimplex: simplexSet.has(mod.type),
|
|
62
|
+
refbase,
|
|
63
|
+
snps: snps || {},
|
|
64
|
+
ref: ref || { entryDepth: 0, '1': 0, '-1': 0, '0': 0 },
|
|
65
|
+
score0,
|
|
66
|
+
});
|
|
67
|
+
const { entryDepth, avgProbability = 0 } = mods[key];
|
|
68
|
+
const modFraction = (modifiable / score0) * (entryDepth / detectable);
|
|
69
|
+
const barHeight = modFraction * h;
|
|
70
|
+
if (skipDraw) {
|
|
71
|
+
snpSkipped++;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
ctx.fillStyle = alphaColor(mod.color || 'black', avgProbability);
|
|
75
|
+
ctx.fillRect(drawX, bottom - (curr + barHeight), w, barHeight);
|
|
76
|
+
snpDrawn++;
|
|
77
|
+
lastDrawnX = drawX;
|
|
78
|
+
}
|
|
79
|
+
curr += barHeight;
|
|
80
|
+
}
|
|
81
|
+
drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, feature.get('start'));
|
|
82
|
+
prevTotal = score0;
|
|
83
|
+
}
|
|
84
|
+
return { snpDrawn, snpSkipped };
|
|
85
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { checkStopToken2, featureSpanPx } from '@jbrowse/core/util';
|
|
2
|
+
import { SNP_CLICKMAP_THRESHOLD } from "./constants.js";
|
|
3
|
+
import { drawNoncovEvents } from "./drawNoncovEvents.js";
|
|
4
|
+
export function drawSecondPassSNPs(passCtx) {
|
|
5
|
+
const { ctx, coverageFeatures, region, bpPerPx, colorMap, toY, toHeight, stopTokenCheck, coords, items, } = passCtx;
|
|
6
|
+
let snpDrawn = 0;
|
|
7
|
+
let snpSkipped = 0;
|
|
8
|
+
let lastDrawnX = Number.NEGATIVE_INFINITY;
|
|
9
|
+
let lastDrawnDepth = -1;
|
|
10
|
+
let prevTotal = 0;
|
|
11
|
+
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
12
|
+
checkStopToken2(stopTokenCheck);
|
|
13
|
+
const feature = coverageFeatures[i];
|
|
14
|
+
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
15
|
+
const snpinfo = feature.get('snpinfo');
|
|
16
|
+
const w = Math.max(rightPx - leftPx, 1);
|
|
17
|
+
const score0 = feature.get('score');
|
|
18
|
+
const drawX = Math.round(leftPx);
|
|
19
|
+
const skipDraw = drawX === lastDrawnX;
|
|
20
|
+
const { depth, snps, refbase } = snpinfo;
|
|
21
|
+
const refbaseUpper = refbase?.toUpperCase();
|
|
22
|
+
const h = toHeight(score0);
|
|
23
|
+
const bottom = toY(score0) + h;
|
|
24
|
+
let curr = 0;
|
|
25
|
+
for (const base in snps) {
|
|
26
|
+
const entry = snps[base];
|
|
27
|
+
const { entryDepth } = entry;
|
|
28
|
+
const y1 = bottom - ((entryDepth + curr) / depth) * h;
|
|
29
|
+
const barHeight = (entryDepth / depth) * h;
|
|
30
|
+
const isSignificant = entryDepth / score0 >= SNP_CLICKMAP_THRESHOLD;
|
|
31
|
+
const sameDepthAtSameX = skipDraw && entryDepth === lastDrawnDepth;
|
|
32
|
+
if ((skipDraw && !isSignificant) || sameDepthAtSameX) {
|
|
33
|
+
snpSkipped++;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
ctx.fillStyle = colorMap[base] || 'black';
|
|
37
|
+
ctx.fillRect(drawX, y1, w, barHeight);
|
|
38
|
+
snpDrawn++;
|
|
39
|
+
lastDrawnX = drawX;
|
|
40
|
+
lastDrawnDepth = entryDepth;
|
|
41
|
+
}
|
|
42
|
+
if (isSignificant) {
|
|
43
|
+
coords.push(drawX, y1, drawX + w, y1 + barHeight);
|
|
44
|
+
items.push({
|
|
45
|
+
type: 'snp',
|
|
46
|
+
base,
|
|
47
|
+
count: entryDepth,
|
|
48
|
+
total: score0,
|
|
49
|
+
refbase: refbaseUpper,
|
|
50
|
+
avgQual: entry.avgProbability,
|
|
51
|
+
fwdCount: entry['1'] || 0,
|
|
52
|
+
revCount: entry['-1'] || 0,
|
|
53
|
+
bin: snpinfo,
|
|
54
|
+
start: feature.get('start'),
|
|
55
|
+
end: feature.get('end'),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
curr += entryDepth;
|
|
59
|
+
}
|
|
60
|
+
drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, feature.get('start'));
|
|
61
|
+
prevTotal = score0;
|
|
62
|
+
}
|
|
63
|
+
return { snpDrawn, snpSkipped };
|
|
64
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function drawStackedBars(ctx, entries, colorMap, x, bottom, w, h, depth, startCurr) {
|
|
2
|
+
let curr = startCurr;
|
|
3
|
+
for (const base in entries) {
|
|
4
|
+
const { entryDepth } = entries[base];
|
|
5
|
+
ctx.fillStyle = colorMap[base] || 'black';
|
|
6
|
+
ctx.fillRect(x, bottom - ((entryDepth + curr) / depth) * h, w, (entryDepth / depth) * h);
|
|
7
|
+
curr += entryDepth;
|
|
8
|
+
}
|
|
9
|
+
return curr;
|
|
10
|
+
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { RenderArgsDeserializedWithFeatures } from './types
|
|
1
|
+
import type { RenderArgsDeserializedWithFeatures } from './types';
|
|
2
2
|
export declare function renderSNPCoverageToCanvas(props: RenderArgsDeserializedWithFeatures): Promise<import("librpc-web-mod").RpcResult>;
|
|
@@ -1,310 +1,15 @@
|
|
|
1
1
|
import { readConfObject } from '@jbrowse/core/configuration';
|
|
2
2
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
3
|
-
import { checkStopToken2,
|
|
4
|
-
import Flatbush from '@jbrowse/core/util/flatbush';
|
|
3
|
+
import { checkStopToken2, featureSpanPx, renderToAbstractCanvas, } from '@jbrowse/core/util';
|
|
5
4
|
import { rpcResult } from '@jbrowse/core/util/librpc';
|
|
6
5
|
import { collectTransferables } from '@jbrowse/core/util/offscreenCanvasPonyfill';
|
|
7
6
|
import { YSCALEBAR_LABEL_OFFSET, getOrigin, getScale, } from '@jbrowse/plugin-wiggle';
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
C: 'G',
|
|
15
|
-
G: 'C',
|
|
16
|
-
A: 'T',
|
|
17
|
-
T: 'A',
|
|
18
|
-
};
|
|
19
|
-
const fudgeFactor = 0.6;
|
|
20
|
-
const SNP_CLICKMAP_THRESHOLD = 0.04;
|
|
21
|
-
function createInterbaseItem(maxBase, count, total, start, maxEntry) {
|
|
22
|
-
return {
|
|
23
|
-
type: maxBase,
|
|
24
|
-
base: maxBase,
|
|
25
|
-
count,
|
|
26
|
-
total,
|
|
27
|
-
avgLength: maxEntry?.avgLength,
|
|
28
|
-
minLength: maxEntry?.minLength,
|
|
29
|
-
maxLength: maxEntry?.maxLength,
|
|
30
|
-
topSequence: maxEntry?.topSequence,
|
|
31
|
-
start,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function drawStackedBars(ctx, entries, colorMap, x, bottom, w, h, depth, startCurr) {
|
|
35
|
-
let curr = startCurr;
|
|
36
|
-
for (const base in entries) {
|
|
37
|
-
const { entryDepth } = entries[base];
|
|
38
|
-
ctx.fillStyle = colorMap[base] || 'black';
|
|
39
|
-
ctx.fillRect(x, bottom - ((entryDepth + curr) / depth) * h, w, (entryDepth / depth) * h);
|
|
40
|
-
curr += entryDepth;
|
|
41
|
-
}
|
|
42
|
-
return curr;
|
|
43
|
-
}
|
|
44
|
-
function drawCrossHatches(ctx, ticks, width, toY) {
|
|
45
|
-
ctx.lineWidth = 1;
|
|
46
|
-
ctx.strokeStyle = 'rgba(140,140,140,0.8)';
|
|
47
|
-
for (const tick of ticks.values) {
|
|
48
|
-
ctx.beginPath();
|
|
49
|
-
ctx.moveTo(0, Math.round(toY(tick)));
|
|
50
|
-
ctx.lineTo(width, Math.round(toY(tick)));
|
|
51
|
-
ctx.stroke();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
function calculateModificationCounts({ base, isSimplex, refbase, snps, ref, score0, }) {
|
|
55
|
-
if (base === 'N') {
|
|
56
|
-
return { modifiable: score0, detectable: score0 };
|
|
57
|
-
}
|
|
58
|
-
const cmp = complementBase[base];
|
|
59
|
-
const baseCount = (snps[base]?.entryDepth || 0) + (refbase === base ? ref.entryDepth : 0);
|
|
60
|
-
const complCount = (snps[cmp]?.entryDepth || 0) + (refbase === cmp ? ref.entryDepth : 0);
|
|
61
|
-
const modifiable = baseCount + complCount;
|
|
62
|
-
const detectable = isSimplex
|
|
63
|
-
? (snps[base]?.['1'] || 0) +
|
|
64
|
-
(snps[cmp]?.['-1'] || 0) +
|
|
65
|
-
(refbase === base ? ref['1'] : 0) +
|
|
66
|
-
(refbase === cmp ? ref['-1'] : 0)
|
|
67
|
-
: modifiable;
|
|
68
|
-
return { modifiable, detectable };
|
|
69
|
-
}
|
|
70
|
-
function buildClickMap(coords, items) {
|
|
71
|
-
const flatbush = new Flatbush(Math.max(items.length, 1));
|
|
72
|
-
if (coords.length) {
|
|
73
|
-
for (let i = 0; i < coords.length; i += 4) {
|
|
74
|
-
flatbush.add(coords[i], coords[i + 1], coords[i + 2], coords[i + 3]);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
else {
|
|
78
|
-
flatbush.add(0, 0);
|
|
79
|
-
}
|
|
80
|
-
flatbush.finish();
|
|
81
|
-
return {
|
|
82
|
-
flatbush: flatbush.data,
|
|
83
|
-
items,
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
function drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, fstart) {
|
|
87
|
-
const { ctx, colorMap, toHeight2, extraHorizontallyFlippedOffset, coords, items, bpPerPx, indicatorThreshold, showInterbaseCounts, showInterbaseIndicators, } = passCtx;
|
|
88
|
-
let totalCount = 0;
|
|
89
|
-
let maxDepth = 0;
|
|
90
|
-
let maxBase = '';
|
|
91
|
-
let totalHeight = 0;
|
|
92
|
-
const r = 0.6;
|
|
93
|
-
const x = leftPx - r + extraHorizontallyFlippedOffset;
|
|
94
|
-
for (const base in snpinfo.noncov) {
|
|
95
|
-
const { entryDepth } = snpinfo.noncov[base];
|
|
96
|
-
totalCount += entryDepth;
|
|
97
|
-
if (entryDepth > maxDepth) {
|
|
98
|
-
maxDepth = entryDepth;
|
|
99
|
-
maxBase = base;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
const isSignificant = score0 > 0 && totalCount > score0 * INTERBASE_DRAW_THRESHOLD;
|
|
103
|
-
const showCounts = showInterbaseCounts && (!skipDraw || isSignificant);
|
|
104
|
-
if (showCounts) {
|
|
105
|
-
for (const base in snpinfo.noncov) {
|
|
106
|
-
const { entryDepth } = snpinfo.noncov[base];
|
|
107
|
-
const barHeight = toHeight2(entryDepth);
|
|
108
|
-
ctx.fillStyle = colorMap[base];
|
|
109
|
-
ctx.fillRect(x, INTERBASE_INDICATOR_HEIGHT + totalHeight, r * 2, barHeight);
|
|
110
|
-
totalHeight += barHeight;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
if (totalCount > 0) {
|
|
114
|
-
const maxEntry = snpinfo.noncov[maxBase];
|
|
115
|
-
if (showCounts) {
|
|
116
|
-
if (bpPerPx < 50 || isSignificant) {
|
|
117
|
-
const clickWidth = Math.max(r * 2, 2);
|
|
118
|
-
coords.push(x, INTERBASE_INDICATOR_HEIGHT, x + clickWidth, INTERBASE_INDICATOR_HEIGHT + totalHeight);
|
|
119
|
-
items.push(createInterbaseItem(maxBase, totalCount, score0, fstart, maxEntry));
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
if (showInterbaseIndicators && (!skipDraw || isSignificant)) {
|
|
123
|
-
const indicatorComparatorScore = Math.max(score0, prevTotal);
|
|
124
|
-
if (totalCount > indicatorComparatorScore * indicatorThreshold &&
|
|
125
|
-
indicatorComparatorScore > MINIMUM_INTERBASE_INDICATOR_READ_DEPTH) {
|
|
126
|
-
ctx.fillStyle = colorMap[maxBase];
|
|
127
|
-
ctx.beginPath();
|
|
128
|
-
const l = leftPx + extraHorizontallyFlippedOffset;
|
|
129
|
-
ctx.moveTo(l - INTERBASE_INDICATOR_WIDTH / 2, 0);
|
|
130
|
-
ctx.lineTo(l + INTERBASE_INDICATOR_WIDTH / 2, 0);
|
|
131
|
-
ctx.lineTo(l, INTERBASE_INDICATOR_HEIGHT);
|
|
132
|
-
ctx.fill();
|
|
133
|
-
const hitboxPadding = 1;
|
|
134
|
-
coords.push(l - INTERBASE_INDICATOR_WIDTH / 2 - hitboxPadding, 0, l + INTERBASE_INDICATOR_WIDTH / 2 + hitboxPadding, INTERBASE_INDICATOR_HEIGHT + hitboxPadding);
|
|
135
|
-
items.push(createInterbaseItem(maxBase, totalCount, indicatorComparatorScore, fstart, maxEntry));
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
function drawSecondPassModifications(passCtx, visibleModifications, isolatedModification, simplexSet) {
|
|
141
|
-
const { ctx, coverageFeatures, region, bpPerPx, toY, toHeight, lastCheck } = passCtx;
|
|
142
|
-
let snpDrawn = 0;
|
|
143
|
-
let snpSkipped = 0;
|
|
144
|
-
let lastDrawnX = Number.NEGATIVE_INFINITY;
|
|
145
|
-
let prevTotal = 0;
|
|
146
|
-
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
147
|
-
checkStopToken2(lastCheck);
|
|
148
|
-
const feature = coverageFeatures[i];
|
|
149
|
-
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
150
|
-
const snpinfo = feature.get('snpinfo');
|
|
151
|
-
const w = Math.max(rightPx - leftPx, 1);
|
|
152
|
-
const score0 = feature.get('score');
|
|
153
|
-
const drawX = Math.round(leftPx);
|
|
154
|
-
const skipDraw = drawX === lastDrawnX;
|
|
155
|
-
let curr = 0;
|
|
156
|
-
const refbase = snpinfo.refbase?.toUpperCase();
|
|
157
|
-
const { nonmods, mods, snps, ref } = snpinfo;
|
|
158
|
-
const h = toHeight(score0);
|
|
159
|
-
const bottom = toY(score0) + h;
|
|
160
|
-
for (const key in nonmods) {
|
|
161
|
-
const modKey = key.slice(7);
|
|
162
|
-
const mod = visibleModifications[modKey];
|
|
163
|
-
if (!mod || (isolatedModification && mod.type !== isolatedModification)) {
|
|
164
|
-
continue;
|
|
165
|
-
}
|
|
166
|
-
const { modifiable, detectable } = calculateModificationCounts({
|
|
167
|
-
base: mod.base,
|
|
168
|
-
isSimplex: simplexSet.has(mod.type),
|
|
169
|
-
refbase,
|
|
170
|
-
snps,
|
|
171
|
-
ref,
|
|
172
|
-
score0,
|
|
173
|
-
});
|
|
174
|
-
const { entryDepth, avgProbability = 0 } = nonmods[key];
|
|
175
|
-
const modFraction = (modifiable / score0) * (entryDepth / detectable);
|
|
176
|
-
const barHeight = modFraction * h;
|
|
177
|
-
if (skipDraw) {
|
|
178
|
-
snpSkipped++;
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
181
|
-
ctx.fillStyle = alphaColor('blue', avgProbability);
|
|
182
|
-
ctx.fillRect(drawX, bottom - (curr + barHeight), w, barHeight);
|
|
183
|
-
snpDrawn++;
|
|
184
|
-
lastDrawnX = drawX;
|
|
185
|
-
}
|
|
186
|
-
curr += barHeight;
|
|
187
|
-
}
|
|
188
|
-
for (const key in mods) {
|
|
189
|
-
const modKey = key.slice(4);
|
|
190
|
-
const mod = visibleModifications[modKey];
|
|
191
|
-
if (!mod || (isolatedModification && mod.type !== isolatedModification)) {
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
const { modifiable, detectable } = calculateModificationCounts({
|
|
195
|
-
base: mod.base,
|
|
196
|
-
isSimplex: simplexSet.has(mod.type),
|
|
197
|
-
refbase,
|
|
198
|
-
snps,
|
|
199
|
-
ref,
|
|
200
|
-
score0,
|
|
201
|
-
});
|
|
202
|
-
const { entryDepth, avgProbability = 0 } = mods[key];
|
|
203
|
-
const modFraction = (modifiable / score0) * (entryDepth / detectable);
|
|
204
|
-
const barHeight = modFraction * h;
|
|
205
|
-
if (skipDraw) {
|
|
206
|
-
snpSkipped++;
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
ctx.fillStyle = alphaColor(mod.color || 'black', avgProbability);
|
|
210
|
-
ctx.fillRect(drawX, bottom - (curr + barHeight), w, barHeight);
|
|
211
|
-
snpDrawn++;
|
|
212
|
-
lastDrawnX = drawX;
|
|
213
|
-
}
|
|
214
|
-
curr += barHeight;
|
|
215
|
-
}
|
|
216
|
-
drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, feature.get('start'));
|
|
217
|
-
prevTotal = score0;
|
|
218
|
-
}
|
|
219
|
-
return { snpDrawn, snpSkipped };
|
|
220
|
-
}
|
|
221
|
-
function drawSecondPassMethylation(passCtx) {
|
|
222
|
-
const { ctx, coverageFeatures, region, bpPerPx, colorMap, toY, toHeight, lastCheck, } = passCtx;
|
|
223
|
-
let lastDrawnX = Number.NEGATIVE_INFINITY;
|
|
224
|
-
let prevTotal = 0;
|
|
225
|
-
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
226
|
-
checkStopToken2(lastCheck);
|
|
227
|
-
const feature = coverageFeatures[i];
|
|
228
|
-
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
229
|
-
const snpinfo = feature.get('snpinfo');
|
|
230
|
-
const w = Math.max(rightPx - leftPx, 1);
|
|
231
|
-
const score0 = feature.get('score');
|
|
232
|
-
const drawX = Math.round(leftPx);
|
|
233
|
-
const skipDraw = drawX === lastDrawnX;
|
|
234
|
-
if (!skipDraw) {
|
|
235
|
-
const { depth, nonmods, mods } = snpinfo;
|
|
236
|
-
const h = toHeight(score0);
|
|
237
|
-
const bottom = toY(score0) + h;
|
|
238
|
-
const curr = drawStackedBars(ctx, mods, colorMap, drawX, bottom, w, h, depth, 0);
|
|
239
|
-
drawStackedBars(ctx, nonmods, colorMap, drawX, bottom, w, h, depth, curr);
|
|
240
|
-
lastDrawnX = drawX;
|
|
241
|
-
}
|
|
242
|
-
drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, feature.get('start'));
|
|
243
|
-
prevTotal = score0;
|
|
244
|
-
}
|
|
245
|
-
return { snpDrawn: 0, snpSkipped: 0 };
|
|
246
|
-
}
|
|
247
|
-
function drawSecondPassSNPs(passCtx) {
|
|
248
|
-
const { ctx, coverageFeatures, region, bpPerPx, colorMap, toY, toHeight, lastCheck, coords, items, } = passCtx;
|
|
249
|
-
let snpDrawn = 0;
|
|
250
|
-
let snpSkipped = 0;
|
|
251
|
-
let lastDrawnX = Number.NEGATIVE_INFINITY;
|
|
252
|
-
let lastDrawnDepth = -1;
|
|
253
|
-
let prevTotal = 0;
|
|
254
|
-
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
255
|
-
checkStopToken2(lastCheck);
|
|
256
|
-
const feature = coverageFeatures[i];
|
|
257
|
-
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
258
|
-
const snpinfo = feature.get('snpinfo');
|
|
259
|
-
const w = Math.max(rightPx - leftPx, 1);
|
|
260
|
-
const score0 = feature.get('score');
|
|
261
|
-
const drawX = Math.round(leftPx);
|
|
262
|
-
const skipDraw = drawX === lastDrawnX;
|
|
263
|
-
const { depth, snps, refbase } = snpinfo;
|
|
264
|
-
const refbaseUpper = refbase?.toUpperCase();
|
|
265
|
-
const h = toHeight(score0);
|
|
266
|
-
const bottom = toY(score0) + h;
|
|
267
|
-
let curr = 0;
|
|
268
|
-
for (const base in snps) {
|
|
269
|
-
const entry = snps[base];
|
|
270
|
-
const { entryDepth } = entry;
|
|
271
|
-
const y1 = bottom - ((entryDepth + curr) / depth) * h;
|
|
272
|
-
const barHeight = (entryDepth / depth) * h;
|
|
273
|
-
const isSignificant = entryDepth / score0 >= SNP_CLICKMAP_THRESHOLD;
|
|
274
|
-
const sameDepthAtSameX = skipDraw && entryDepth === lastDrawnDepth;
|
|
275
|
-
if ((skipDraw && !isSignificant) || sameDepthAtSameX) {
|
|
276
|
-
snpSkipped++;
|
|
277
|
-
}
|
|
278
|
-
else {
|
|
279
|
-
ctx.fillStyle = colorMap[base] || 'black';
|
|
280
|
-
ctx.fillRect(drawX, y1, w, barHeight);
|
|
281
|
-
snpDrawn++;
|
|
282
|
-
lastDrawnX = drawX;
|
|
283
|
-
lastDrawnDepth = entryDepth;
|
|
284
|
-
}
|
|
285
|
-
if (isSignificant) {
|
|
286
|
-
coords.push(drawX, y1, drawX + w, y1 + barHeight);
|
|
287
|
-
items.push({
|
|
288
|
-
type: 'snp',
|
|
289
|
-
base,
|
|
290
|
-
count: entryDepth,
|
|
291
|
-
total: score0,
|
|
292
|
-
refbase: refbaseUpper,
|
|
293
|
-
avgQual: entry.avgProbability,
|
|
294
|
-
fwdCount: entry['1'] || 0,
|
|
295
|
-
revCount: entry['-1'] || 0,
|
|
296
|
-
bin: snpinfo,
|
|
297
|
-
start: feature.get('start'),
|
|
298
|
-
end: feature.get('end'),
|
|
299
|
-
});
|
|
300
|
-
}
|
|
301
|
-
curr += entryDepth;
|
|
302
|
-
}
|
|
303
|
-
drawNoncovEvents(passCtx, snpinfo, leftPx, score0, prevTotal, skipDraw, feature.get('start'));
|
|
304
|
-
prevTotal = score0;
|
|
305
|
-
}
|
|
306
|
-
return { snpDrawn, snpSkipped };
|
|
307
|
-
}
|
|
7
|
+
import { buildClickMap } from "./buildClickMap.js";
|
|
8
|
+
import { fudgeFactor } from "./constants.js";
|
|
9
|
+
import { drawCrossHatches } from "./drawCrossHatches.js";
|
|
10
|
+
import { drawSecondPassMethylation } from "./drawSecondPassMethylation.js";
|
|
11
|
+
import { drawSecondPassModifications } from "./drawSecondPassModifications.js";
|
|
12
|
+
import { drawSecondPassSNPs } from "./drawSecondPassSNPs.js";
|
|
308
13
|
export async function renderSNPCoverageToCanvas(props) {
|
|
309
14
|
const { features, regions, bpPerPx, adapterConfig } = props;
|
|
310
15
|
const region = regions[0];
|
|
@@ -345,7 +50,7 @@ export async function renderSNPCoverageToCanvas(props) {
|
|
|
345
50
|
return rpcResult(serialized, collectTransferables(rest));
|
|
346
51
|
}
|
|
347
52
|
function drawSNPCoverage(ctx, props, coverageFeatures) {
|
|
348
|
-
const { regions, bpPerPx, colorBy, displayCrossHatches, visibleModifications = {}, simplexModifications = [], scaleOpts, height: unadjustedHeight, theme: configTheme, config: cfg, ticks,
|
|
53
|
+
const { regions, bpPerPx, colorBy, displayCrossHatches, visibleModifications = {}, simplexModifications = [], scaleOpts, height: unadjustedHeight, theme: configTheme, config: cfg, ticks, stopTokenCheck, } = props;
|
|
349
54
|
const theme = createJBrowseTheme(configTheme);
|
|
350
55
|
const region = regions[0];
|
|
351
56
|
const width = (region.end - region.start) / bpPerPx;
|
|
@@ -384,9 +89,8 @@ function drawSNPCoverage(ctx, props, coverageFeatures) {
|
|
|
384
89
|
const coords = [];
|
|
385
90
|
const items = [];
|
|
386
91
|
ctx.fillStyle = colorMap.total;
|
|
387
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
388
92
|
for (let i = 0, l = coverageFeatures.length; i < l; i++) {
|
|
389
|
-
checkStopToken2(
|
|
93
|
+
checkStopToken2(stopTokenCheck);
|
|
390
94
|
const feature = coverageFeatures[i];
|
|
391
95
|
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
392
96
|
const w = rightPx - leftPx + fudgeFactor;
|
|
@@ -413,7 +117,7 @@ function drawSNPCoverage(ctx, props, coverageFeatures) {
|
|
|
413
117
|
toY,
|
|
414
118
|
toHeight,
|
|
415
119
|
toHeight2,
|
|
416
|
-
|
|
120
|
+
stopTokenCheck,
|
|
417
121
|
extraHorizontallyFlippedOffset,
|
|
418
122
|
coords,
|
|
419
123
|
items,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BaseCoverageBin, ColorBy, ModificationTypeWithColor } from '../shared/types.ts';
|
|
2
2
|
import type { RenderArgsDeserialized as FeatureRenderArgsDeserialized } from '@jbrowse/core/pluggableElementTypes/renderers/FeatureRendererType';
|
|
3
|
-
import type { Feature } from '@jbrowse/core/util';
|
|
3
|
+
import type { Feature, LastStopTokenCheck } from '@jbrowse/core/util';
|
|
4
4
|
import type { ScaleOpts } from '@jbrowse/plugin-wiggle';
|
|
5
5
|
export interface InterbaseIndicatorItem {
|
|
6
6
|
type: 'insertion' | 'softclip' | 'hardclip';
|
|
@@ -67,4 +67,65 @@ export interface RenderArgsDeserialized extends FeatureRenderArgsDeserialized {
|
|
|
67
67
|
export interface RenderArgsDeserializedWithFeatures extends RenderArgsDeserialized {
|
|
68
68
|
features: Map<string, Feature>;
|
|
69
69
|
}
|
|
70
|
+
export interface SecondPassContext {
|
|
71
|
+
ctx: CanvasRenderingContext2D;
|
|
72
|
+
coverageFeatures: Feature[];
|
|
73
|
+
region: {
|
|
74
|
+
start: number;
|
|
75
|
+
end: number;
|
|
76
|
+
refName: string;
|
|
77
|
+
reversed?: boolean;
|
|
78
|
+
};
|
|
79
|
+
bpPerPx: number;
|
|
80
|
+
colorMap: Record<string, string>;
|
|
81
|
+
toY: (n: number) => number;
|
|
82
|
+
toHeight: (n: number) => number;
|
|
83
|
+
toHeight2: (n: number) => number;
|
|
84
|
+
stopTokenCheck?: LastStopTokenCheck;
|
|
85
|
+
extraHorizontallyFlippedOffset: number;
|
|
86
|
+
coords: number[];
|
|
87
|
+
items: ClickMapItem[];
|
|
88
|
+
indicatorThreshold: number;
|
|
89
|
+
showInterbaseCounts: boolean;
|
|
90
|
+
showInterbaseIndicators: boolean;
|
|
91
|
+
}
|
|
92
|
+
export interface SecondPassStats {
|
|
93
|
+
snpDrawn: number;
|
|
94
|
+
snpSkipped: number;
|
|
95
|
+
}
|
|
96
|
+
export interface StrandCounts {
|
|
97
|
+
readonly entryDepth: number;
|
|
98
|
+
readonly '1': number;
|
|
99
|
+
readonly '-1': number;
|
|
100
|
+
readonly '0': number;
|
|
101
|
+
}
|
|
102
|
+
export interface ModificationCountsParams {
|
|
103
|
+
readonly base: string;
|
|
104
|
+
readonly isSimplex: boolean;
|
|
105
|
+
readonly refbase: string | undefined;
|
|
106
|
+
readonly snps: Readonly<Record<string, Partial<StrandCounts>>>;
|
|
107
|
+
readonly ref: StrandCounts;
|
|
108
|
+
readonly score0: number;
|
|
109
|
+
}
|
|
110
|
+
export interface ModificationCountsResult {
|
|
111
|
+
readonly modifiable: number;
|
|
112
|
+
readonly detectable: number;
|
|
113
|
+
}
|
|
114
|
+
export interface ReducedFeature {
|
|
115
|
+
start: number;
|
|
116
|
+
end: number;
|
|
117
|
+
score: number;
|
|
118
|
+
snpinfo: BaseCoverageBin;
|
|
119
|
+
refName: string;
|
|
120
|
+
}
|
|
121
|
+
export interface SkipFeatureSerialized {
|
|
122
|
+
uniqueId: string;
|
|
123
|
+
type: 'skip';
|
|
124
|
+
refName: string;
|
|
125
|
+
start: number;
|
|
126
|
+
end: number;
|
|
127
|
+
strand: number;
|
|
128
|
+
score: number;
|
|
129
|
+
effectiveStrand: number;
|
|
130
|
+
}
|
|
70
131
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-alignments",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 alignments adapters, tracks, etc.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"mobx": "^6.15.0",
|
|
35
35
|
"mobx-react": "^9.2.1",
|
|
36
36
|
"rxjs": "^7.8.2",
|
|
37
|
-
"@jbrowse/core": "^4.1.
|
|
38
|
-
"@jbrowse/plugin-linear-genome-view": "^4.1.
|
|
39
|
-
"@jbrowse/
|
|
40
|
-
"@jbrowse/
|
|
37
|
+
"@jbrowse/core": "^4.1.3",
|
|
38
|
+
"@jbrowse/plugin-linear-genome-view": "^4.1.3",
|
|
39
|
+
"@jbrowse/sv-core": "^4.1.3",
|
|
40
|
+
"@jbrowse/plugin-wiggle": "^4.1.3"
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"react": ">=18.0.0"
|