@jbrowse/plugin-variants 4.0.4 → 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/LDDisplay/SharedLDConfigSchema.d.ts +102 -0
- package/esm/LDDisplay/SharedLDConfigSchema.js +83 -0
- package/esm/LDDisplay/afterAttach.d.ts +2 -0
- package/esm/LDDisplay/afterAttach.js +123 -0
- package/esm/LDDisplay/components/BaseDisplayComponent.d.ts +15 -0
- package/esm/LDDisplay/components/BaseDisplayComponent.js +39 -0
- package/esm/LDDisplay/components/LDColorLegend.d.ts +15 -0
- package/esm/LDDisplay/components/LDColorLegend.js +75 -0
- package/esm/LDDisplay/components/LDDisplayComponent.d.ts +5 -0
- package/esm/LDDisplay/components/LDDisplayComponent.js +203 -0
- package/esm/LDDisplay/components/LinesConnectingMatrixToGenomicPosition.d.ts +16 -0
- package/esm/LDDisplay/components/LinesConnectingMatrixToGenomicPosition.js +109 -0
- package/esm/LDDisplay/configSchema1.d.ts +115 -0
- package/esm/LDDisplay/configSchema1.js +16 -0
- package/esm/LDDisplay/configSchema2.d.ts +115 -0
- package/esm/LDDisplay/configSchema2.js +16 -0
- package/esm/LDDisplay/index.d.ts +2 -0
- package/esm/LDDisplay/index.js +35 -0
- package/esm/LDDisplay/renderSvg.d.ts +3 -0
- package/esm/LDDisplay/renderSvg.js +36 -0
- package/esm/LDDisplay/shared.d.ts +367 -0
- package/esm/LDDisplay/shared.js +467 -0
- package/esm/LDDisplay/stateModel1.d.ts +365 -0
- package/esm/LDDisplay/stateModel1.js +10 -0
- package/esm/LDDisplay/stateModel2.d.ts +365 -0
- package/esm/LDDisplay/stateModel2.js +10 -0
- package/esm/LDRenderer/LDRenderer.d.ts +30 -0
- package/esm/LDRenderer/LDRenderer.js +109 -0
- package/esm/LDRenderer/components/LDRendering.d.ts +2 -0
- package/esm/LDRenderer/components/LDRendering.js +4 -0
- package/esm/LDRenderer/configSchema.d.ts +8 -0
- package/esm/LDRenderer/configSchema.js +10 -0
- package/esm/LDRenderer/index.d.ts +2 -0
- package/esm/LDRenderer/index.js +11 -0
- package/esm/LDRenderer/makeImageData.d.ts +20 -0
- package/esm/LDRenderer/makeImageData.js +157 -0
- package/esm/LDRenderer/types.d.ts +8 -0
- package/esm/LDRenderer/types.js +1 -0
- package/esm/LDTrack/configSchema.d.ts +85 -0
- package/esm/LDTrack/configSchema.js +7 -0
- package/esm/LDTrack/index.d.ts +2 -0
- package/esm/LDTrack/index.js +14 -0
- package/esm/LinearVariantDisplay/model.d.ts +126 -42
- package/esm/LinearVariantDisplay/model.js +46 -8
- package/esm/MultiLinearVariantDisplay/configSchema.d.ts +27 -1
- package/esm/MultiLinearVariantDisplay/model.d.ts +2635 -31
- package/esm/MultiLinearVariantDisplay/model.js +6 -0
- package/esm/MultiLinearVariantDisplay/renderSvg.d.ts +10 -2
- package/esm/MultiLinearVariantMatrixDisplay/configSchema.d.ts +25 -0
- package/esm/MultiLinearVariantMatrixDisplay/configSchema.js +26 -0
- package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +2636 -32
- package/esm/MultiLinearVariantMatrixDisplay/model.js +6 -0
- package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +2 -2
- package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +11 -9
- package/esm/MultiLinearVariantMatrixRenderer/components/MultiLinearVariantMatrixRendering.d.ts +8 -0
- package/esm/MultiLinearVariantMatrixRenderer/components/MultiLinearVariantMatrixRendering.js +14 -2
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.js +8 -11
- package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +2 -2
- package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.js +4 -3
- package/esm/MultiLinearVariantRenderer/components/MultiLinearVariantRendering.d.ts +4 -0
- package/esm/MultiLinearVariantRenderer/components/MultiLinearVariantRendering.js +23 -2
- package/esm/MultiLinearVariantRenderer/makeImageData.js +12 -12
- package/esm/PlinkLDAdapter/PlinkLDAdapter.d.ts +25 -0
- package/esm/PlinkLDAdapter/PlinkLDAdapter.js +147 -0
- package/esm/PlinkLDAdapter/PlinkLDTabixAdapter.d.ts +24 -0
- package/esm/PlinkLDAdapter/PlinkLDTabixAdapter.js +156 -0
- package/esm/PlinkLDAdapter/configSchema.d.ts +10 -0
- package/esm/PlinkLDAdapter/configSchema.js +25 -0
- package/esm/PlinkLDAdapter/configSchemaTabix.d.ts +24 -0
- package/esm/PlinkLDAdapter/configSchemaTabix.js +46 -0
- package/esm/PlinkLDAdapter/index.d.ts +2 -0
- package/esm/PlinkLDAdapter/index.js +25 -0
- package/esm/PlinkLDAdapter/types.d.ts +29 -0
- package/esm/PlinkLDAdapter/types.js +1 -0
- package/esm/VariantFeatureWidget/VariantSampleGrid/VariantSampleGrid.js +1 -1
- package/esm/VariantRPC/MultiVariantGetFeatureDetails.d.ts +14 -0
- package/esm/VariantRPC/MultiVariantGetFeatureDetails.js +15 -0
- package/esm/VariantRPC/MultiVariantGetGenotypeMatrix.js +4 -1
- package/esm/VariantRPC/MultiVariantGetSimplifiedFeatures.js +3 -3
- package/esm/VariantRPC/executeClusterGenotypeMatrix.js +6 -3
- package/esm/VariantRPC/getGenotypeMatrix.d.ts +2 -3
- package/esm/VariantRPC/getGenotypeMatrix.js +4 -5
- package/esm/VariantRPC/getLDMatrix.d.ts +47 -0
- package/esm/VariantRPC/getLDMatrix.js +387 -0
- package/esm/VariantRPC/getLDMatrixFromPlink.d.ts +16 -0
- package/esm/VariantRPC/getLDMatrixFromPlink.js +105 -0
- package/esm/VariantRPC/getPhasedGenotypeMatrix.d.ts +2 -3
- package/esm/VariantRPC/getPhasedGenotypeMatrix.js +4 -5
- package/esm/VariantRPC/types.d.ts +3 -0
- package/esm/VcfAdapter/VcfAdapter.d.ts +1 -1
- package/esm/VcfAdapter/VcfAdapter.js +1 -2
- package/esm/VcfExtensionPoints/index.js +29 -3
- package/esm/VcfFeature/index.d.ts +2 -1
- package/esm/VcfFeature/index.js +4 -2
- package/esm/index.d.ts +1 -0
- package/esm/index.js +23 -0
- package/esm/shared/MultiVariantBaseModel.d.ts +2626 -26
- package/esm/shared/MultiVariantBaseModel.js +88 -39
- package/esm/shared/SharedVariantConfigSchema.d.ts +27 -1
- package/esm/shared/SharedVariantConfigSchema.js +28 -1
- package/esm/shared/VariantFeatureCache.d.ts +27 -0
- package/esm/shared/VariantFeatureCache.js +48 -0
- package/esm/shared/VariantRendererType.d.ts +23 -0
- package/esm/shared/VariantRendererType.js +15 -0
- package/esm/shared/applyColorPalette.d.ts +9 -0
- package/esm/shared/applyColorPalette.js +23 -0
- package/esm/shared/colorByAutorun.d.ts +10 -0
- package/esm/shared/colorByAutorun.js +39 -0
- package/esm/shared/components/AddFiltersDialog.d.ts +3 -3
- package/esm/shared/components/AddFiltersDialog.js +29 -22
- package/esm/shared/components/LDFilterDialog.d.ts +13 -0
- package/esm/shared/components/LDFilterDialog.js +102 -0
- package/esm/shared/components/MAFFilterDialog.js +23 -16
- package/esm/shared/components/RecombinationTrack.d.ts +21 -0
- package/esm/shared/components/RecombinationTrack.js +54 -0
- package/esm/shared/components/RecombinationYScaleBar.d.ts +7 -0
- package/esm/shared/components/RecombinationYScaleBar.js +34 -0
- package/esm/shared/components/SetColorDialogRowPalettizer.d.ts +3 -8
- package/esm/shared/components/SetColorDialogRowPalettizer.js +2 -14
- package/esm/shared/drawAlleleCount.js +9 -0
- package/esm/shared/drawPhased.d.ts +1 -1
- package/esm/shared/drawPhased.js +31 -2
- package/esm/shared/mafFilterUtils.d.ts +5 -0
- package/esm/shared/mafFilterUtils.js +17 -0
- package/esm/shared/minorAlleleFrequencyUtils.d.ts +4 -2
- package/esm/shared/minorAlleleFrequencyUtils.js +261 -19
- package/esm/shared/setupMultiVariantAutoruns.js +2 -0
- package/package.json +11 -10
|
@@ -14,6 +14,12 @@ export default function stateModelFactory(configSchema) {
|
|
|
14
14
|
get prefersOffset() {
|
|
15
15
|
return true;
|
|
16
16
|
},
|
|
17
|
+
get featureWidgetType() {
|
|
18
|
+
return {
|
|
19
|
+
type: 'VariantFeatureWidget',
|
|
20
|
+
id: 'variantFeature',
|
|
21
|
+
};
|
|
22
|
+
},
|
|
17
23
|
}))
|
|
18
24
|
.views(self => ({
|
|
19
25
|
renderProps() {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import VariantRendererType from '../shared/VariantRendererType.ts';
|
|
2
2
|
import type { RenderArgsDeserialized } from './types.ts';
|
|
3
|
-
export default class LinearVariantMatrixRenderer extends
|
|
3
|
+
export default class LinearVariantMatrixRenderer extends VariantRendererType {
|
|
4
4
|
supportsSVG: boolean;
|
|
5
5
|
render(renderProps: RenderArgsDeserialized): Promise<import("librpc-web-mod").RpcResult>;
|
|
6
6
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import FeatureRendererType from '@jbrowse/core/pluggableElementTypes/renderers/FeatureRendererType';
|
|
2
1
|
import { renderToAbstractCanvas } from '@jbrowse/core/util';
|
|
3
2
|
import { rpcResult } from '@jbrowse/core/util/librpc';
|
|
4
3
|
import { collectTransferables } from '@jbrowse/core/util/offscreenCanvasPonyfill';
|
|
5
|
-
|
|
4
|
+
import VariantRendererType from "../shared/VariantRendererType.js";
|
|
5
|
+
export default class LinearVariantMatrixRenderer extends VariantRendererType {
|
|
6
6
|
supportsSVG = true;
|
|
7
7
|
async render(renderProps) {
|
|
8
8
|
const features = await this.getFeatures(renderProps);
|
|
9
|
-
const { height, regions, bpPerPx, scrollTop, rowHeight } = renderProps;
|
|
9
|
+
const { height, regions, bpPerPx, scrollTop, rowHeight, sessionId, trackInstanceId, } = renderProps;
|
|
10
10
|
const region = regions[0];
|
|
11
11
|
const width = (region.end - region.start) / bpPerPx;
|
|
12
|
+
this.cacheFeatures({ sessionId, trackInstanceId }, region.refName, features);
|
|
12
13
|
const { makeImageData } = await import("./makeImageData.js");
|
|
13
14
|
const { mafs, ...rest } = await renderToAbstractCanvas(width, height, renderProps, ctx => makeImageData({
|
|
14
15
|
ctx,
|
|
@@ -16,14 +17,15 @@ export default class LinearVariantMatrixRenderer extends FeatureRendererType {
|
|
|
16
17
|
canvasHeight: height,
|
|
17
18
|
renderArgs: { ...renderProps, features },
|
|
18
19
|
}));
|
|
20
|
+
const simplifiedFeatures = mafs.map(({ feature }) => ({
|
|
21
|
+
uniqueId: feature.id(),
|
|
22
|
+
start: feature.get('start'),
|
|
23
|
+
end: feature.get('end'),
|
|
24
|
+
refName: feature.get('refName'),
|
|
25
|
+
}));
|
|
19
26
|
const serialized = {
|
|
20
27
|
...rest,
|
|
21
|
-
simplifiedFeatures
|
|
22
|
-
uniqueId: feature.id(),
|
|
23
|
-
start: feature.get('start'),
|
|
24
|
-
end: feature.get('end'),
|
|
25
|
-
refName: feature.get('refName'),
|
|
26
|
-
})),
|
|
28
|
+
simplifiedFeatures,
|
|
27
29
|
height,
|
|
28
30
|
width,
|
|
29
31
|
origScrollTop: scrollTop,
|
package/esm/MultiLinearVariantMatrixRenderer/components/MultiLinearVariantMatrixRendering.d.ts
CHANGED
|
@@ -6,6 +6,12 @@ interface FeatureData {
|
|
|
6
6
|
description: string;
|
|
7
7
|
length: number;
|
|
8
8
|
}
|
|
9
|
+
interface SimplifiedFeature {
|
|
10
|
+
uniqueId: string;
|
|
11
|
+
}
|
|
12
|
+
interface RenderingProps {
|
|
13
|
+
onFeatureClick?: (event: React.MouseEvent, featureId: string) => void;
|
|
14
|
+
}
|
|
9
15
|
declare const MultiLinearVariantMatrixRendering: (props: {
|
|
10
16
|
width: number;
|
|
11
17
|
height: number;
|
|
@@ -15,5 +21,7 @@ declare const MultiLinearVariantMatrixRendering: (props: {
|
|
|
15
21
|
rowHeight: number;
|
|
16
22
|
origScrollTop: number;
|
|
17
23
|
totalHeight: number;
|
|
24
|
+
simplifiedFeatures?: SimplifiedFeature[];
|
|
25
|
+
renderingProps?: RenderingProps;
|
|
18
26
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
19
27
|
export default MultiLinearVariantMatrixRendering;
|
package/esm/MultiLinearVariantMatrixRenderer/components/MultiLinearVariantMatrixRendering.js
CHANGED
|
@@ -5,7 +5,7 @@ import { getBpDisplayStr } from '@jbrowse/core/util';
|
|
|
5
5
|
import { observer } from 'mobx-react';
|
|
6
6
|
import { makeSimpleAltString } from "../../VcfFeature/util.js";
|
|
7
7
|
const MultiLinearVariantMatrixRendering = observer(function MultiLinearVariantMatrixRendering(props) {
|
|
8
|
-
const { arr, width, displayModel, featureData, totalHeight, origScrollTop, rowHeight, } = props;
|
|
8
|
+
const { arr, width, displayModel, featureData, totalHeight, origScrollTop, rowHeight, simplifiedFeatures, renderingProps, } = props;
|
|
9
9
|
const ref = useRef(null);
|
|
10
10
|
const lastHoveredRef = useRef(undefined);
|
|
11
11
|
const getFeatureUnderMouse = useCallback((eventClientX, eventClientY) => {
|
|
@@ -52,7 +52,19 @@ const MultiLinearVariantMatrixRendering = observer(function MultiLinearVariantMa
|
|
|
52
52
|
displayModel.setHoveredGenotype(undefined);
|
|
53
53
|
}
|
|
54
54
|
}, [displayModel]);
|
|
55
|
-
|
|
55
|
+
const handleClick = useCallback((e) => {
|
|
56
|
+
if (!ref.current || !simplifiedFeatures) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const r = ref.current.getBoundingClientRect();
|
|
60
|
+
const offsetX = e.clientX - r.left;
|
|
61
|
+
const featureIdx = Math.floor((offsetX / width) * arr.length);
|
|
62
|
+
const feature = simplifiedFeatures[featureIdx];
|
|
63
|
+
if (feature) {
|
|
64
|
+
renderingProps?.onFeatureClick?.(e, feature.uniqueId);
|
|
65
|
+
}
|
|
66
|
+
}, [arr.length, width, simplifiedFeatures, renderingProps]);
|
|
67
|
+
return (_jsx("div", { ref: ref, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, onMouseOut: handleMouseLeave, onClick: handleClick, style: {
|
|
56
68
|
overflow: 'visible',
|
|
57
69
|
position: 'relative',
|
|
58
70
|
height: totalHeight,
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { updateStatus } from '@jbrowse/core/util';
|
|
2
|
-
import { checkStopToken2
|
|
2
|
+
import { checkStopToken2 } from '@jbrowse/core/util/stopToken';
|
|
3
3
|
import { f2 } from "../shared/constants.js";
|
|
4
4
|
import { drawColorAlleleCount, getAlleleColor, } from "../shared/drawAlleleCount.js";
|
|
5
5
|
import { drawPhased } from "../shared/drawPhased.js";
|
|
6
6
|
import { getFeaturesThatPassMinorAlleleFrequencyFilter } from "../shared/minorAlleleFrequencyUtils.js";
|
|
7
7
|
function drawPhasedMode(drawCtx, mafs) {
|
|
8
|
-
const { ctx, sources, startRow, endRow, h, w, scrollTop, splitCache, genotypesCache,
|
|
8
|
+
const { ctx, sources, startRow, endRow, h, w, scrollTop, splitCache, genotypesCache, stopTokenCheck, } = drawCtx;
|
|
9
9
|
const arr = [];
|
|
10
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
11
10
|
for (let idx = 0, l = mafs.length; idx < l; idx++) {
|
|
12
11
|
const { feature } = mafs[idx];
|
|
13
12
|
const arr2 = [];
|
|
@@ -69,14 +68,13 @@ function drawPhasedMode(drawCtx, mafs) {
|
|
|
69
68
|
}
|
|
70
69
|
}
|
|
71
70
|
arr.push(arr2);
|
|
72
|
-
checkStopToken2(
|
|
71
|
+
checkStopToken2(stopTokenCheck);
|
|
73
72
|
}
|
|
74
73
|
return arr;
|
|
75
74
|
}
|
|
76
75
|
function drawAlleleCountMode(drawCtx, mafs) {
|
|
77
|
-
const { ctx, sources, startRow, endRow, h, w, scrollTop, splitCache,
|
|
76
|
+
const { ctx, sources, startRow, endRow, h, w, scrollTop, splitCache, stopTokenCheck, colorCache, genotypesCache, } = drawCtx;
|
|
78
77
|
const arr = [];
|
|
79
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
80
78
|
for (let idx = 0, l = mafs.length; idx < l; idx++) {
|
|
81
79
|
const { feature, mostFrequentAlt } = mafs[idx];
|
|
82
80
|
const arr2 = [];
|
|
@@ -123,21 +121,20 @@ function drawAlleleCountMode(drawCtx, mafs) {
|
|
|
123
121
|
}
|
|
124
122
|
}
|
|
125
123
|
arr.push(arr2);
|
|
126
|
-
checkStopToken2(
|
|
124
|
+
checkStopToken2(stopTokenCheck);
|
|
127
125
|
}
|
|
128
126
|
return arr;
|
|
129
127
|
}
|
|
130
128
|
export async function makeImageData({ ctx, canvasWidth, canvasHeight, renderArgs, }) {
|
|
131
|
-
const { renderingMode, minorAlleleFrequencyFilter, sources, features,
|
|
129
|
+
const { renderingMode, minorAlleleFrequencyFilter, sources, features, stopTokenCheck, lengthCutoffFilter, rowHeight, scrollTop, statusCallback = () => { }, } = renderArgs;
|
|
132
130
|
const h = rowHeight;
|
|
133
131
|
const startRow = Math.floor(scrollTop / h);
|
|
134
132
|
const endRow = Math.min(sources.length, Math.ceil((scrollTop + canvasHeight) / h));
|
|
135
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
136
133
|
const genotypesCache = new Map();
|
|
137
134
|
const colorCache = {};
|
|
138
135
|
const splitCache = {};
|
|
139
136
|
const mafs = await updateStatus('Calculating stats', statusCallback, () => getFeaturesThatPassMinorAlleleFrequencyFilter({
|
|
140
|
-
|
|
137
|
+
stopTokenCheck,
|
|
141
138
|
features: features.values(),
|
|
142
139
|
minorAlleleFrequencyFilter,
|
|
143
140
|
lengthCutoffFilter,
|
|
@@ -157,7 +154,7 @@ export async function makeImageData({ ctx, canvasWidth, canvasHeight, renderArgs
|
|
|
157
154
|
splitCache,
|
|
158
155
|
colorCache,
|
|
159
156
|
genotypesCache,
|
|
160
|
-
|
|
157
|
+
stopTokenCheck,
|
|
161
158
|
};
|
|
162
159
|
const arr = await updateStatus('Drawing variant matrix', statusCallback, () => renderingMode === 'phased'
|
|
163
160
|
? drawPhasedMode(drawCtx, mafs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import VariantRendererType from '../shared/VariantRendererType.ts';
|
|
2
2
|
import type { MultiRenderArgsDeserialized } from './types.ts';
|
|
3
|
-
export default class MultiVariantRenderer extends
|
|
3
|
+
export default class MultiVariantRenderer extends VariantRendererType {
|
|
4
4
|
supportsSVG: boolean;
|
|
5
5
|
render(renderProps: MultiRenderArgsDeserialized): Promise<import("librpc-web-mod").RpcResult>;
|
|
6
6
|
}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import FeatureRendererType from '@jbrowse/core/pluggableElementTypes/renderers/FeatureRendererType';
|
|
2
1
|
import { renderToAbstractCanvas } from '@jbrowse/core/util';
|
|
3
2
|
import { rpcResult } from '@jbrowse/core/util/librpc';
|
|
4
3
|
import { collectTransferables } from '@jbrowse/core/util/offscreenCanvasPonyfill';
|
|
5
|
-
|
|
4
|
+
import VariantRendererType from "../shared/VariantRendererType.js";
|
|
5
|
+
export default class MultiVariantRenderer extends VariantRendererType {
|
|
6
6
|
supportsSVG = true;
|
|
7
7
|
async render(renderProps) {
|
|
8
8
|
const features = await this.getFeatures(renderProps);
|
|
9
|
-
const { height, referenceDrawingMode, regions, bpPerPx, scrollTop } = renderProps;
|
|
9
|
+
const { height, referenceDrawingMode, regions, bpPerPx, scrollTop, sessionId, trackInstanceId, } = renderProps;
|
|
10
10
|
const region = regions[0];
|
|
11
11
|
const width = (region.end - region.start) / bpPerPx;
|
|
12
|
+
this.cacheFeatures({ sessionId, trackInstanceId }, region.refName, features);
|
|
12
13
|
const { makeImageData } = await import("./makeImageData.js");
|
|
13
14
|
const ret = await renderToAbstractCanvas(width, height, renderProps, ctx => {
|
|
14
15
|
if (referenceDrawingMode === 'skip') {
|
|
@@ -17,6 +17,9 @@ interface MinimizedVariantRecord {
|
|
|
17
17
|
interface MultiVariantDisplayModel {
|
|
18
18
|
setHoveredGenotype?: (genotype?: Record<string, unknown>) => void;
|
|
19
19
|
}
|
|
20
|
+
interface RenderingProps {
|
|
21
|
+
onFeatureClick?: (event: React.MouseEvent, featureId: string) => void;
|
|
22
|
+
}
|
|
20
23
|
declare const MultiVariantRendering: (props: {
|
|
21
24
|
regions: Region[];
|
|
22
25
|
features: Map<string, Feature>;
|
|
@@ -30,5 +33,6 @@ declare const MultiVariantRendering: (props: {
|
|
|
30
33
|
flatbush: any;
|
|
31
34
|
items: Item[];
|
|
32
35
|
displayModel: MultiVariantDisplayModel;
|
|
36
|
+
renderingProps?: RenderingProps;
|
|
33
37
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
34
38
|
export default MultiVariantRendering;
|
|
@@ -7,7 +7,7 @@ import { observer } from 'mobx-react';
|
|
|
7
7
|
import { minElt } from "./util.js";
|
|
8
8
|
import { makeSimpleAltString } from "../../VcfFeature/util.js";
|
|
9
9
|
const MultiVariantRendering = observer(function MultiVariantRendering(props) {
|
|
10
|
-
const { flatbush, items, displayModel, featureGenotypeMap, totalHeight, origScrollTop, } = props;
|
|
10
|
+
const { flatbush, items, displayModel, featureGenotypeMap, totalHeight, origScrollTop, renderingProps, } = props;
|
|
11
11
|
const ref = useRef(null);
|
|
12
12
|
const lastHoveredRef = useRef(undefined);
|
|
13
13
|
const flatbush2 = useMemo(() => Flatbush.from(flatbush), [flatbush]);
|
|
@@ -53,7 +53,28 @@ const MultiVariantRendering = observer(function MultiVariantRendering(props) {
|
|
|
53
53
|
displayModel.setHoveredGenotype?.(undefined);
|
|
54
54
|
}
|
|
55
55
|
}, [displayModel]);
|
|
56
|
-
|
|
56
|
+
const getFeatureIdUnderMouse = useCallback((eventClientX, eventClientY) => {
|
|
57
|
+
if (!ref.current) {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
const rect = ref.current.getBoundingClientRect();
|
|
61
|
+
const offsetX = eventClientX - rect.left;
|
|
62
|
+
const offsetY = eventClientY - rect.top;
|
|
63
|
+
const canvasOffsetY = offsetY - origScrollTop;
|
|
64
|
+
const x = flatbush2.search(offsetX, canvasOffsetY, offsetX + 1, canvasOffsetY + 1);
|
|
65
|
+
if (x.length) {
|
|
66
|
+
const res = minElt(x, idx => items[idx]?.bpLen ?? 0);
|
|
67
|
+
return items[res]?.featureId;
|
|
68
|
+
}
|
|
69
|
+
return undefined;
|
|
70
|
+
}, [flatbush2, items, origScrollTop]);
|
|
71
|
+
const handleClick = useCallback((e) => {
|
|
72
|
+
const featureId = getFeatureIdUnderMouse(e.clientX, e.clientY);
|
|
73
|
+
if (featureId) {
|
|
74
|
+
renderingProps?.onFeatureClick?.(e, featureId);
|
|
75
|
+
}
|
|
76
|
+
}, [getFeatureIdUnderMouse, renderingProps]);
|
|
77
|
+
return (_jsx("div", { ref: ref, onMouseMove: handleMouseMove, onMouseLeave: handleMouseLeave, onMouseOut: handleMouseLeave, onClick: handleClick, style: {
|
|
57
78
|
overflow: 'visible',
|
|
58
79
|
position: 'relative',
|
|
59
80
|
height: totalHeight,
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { featureSpanPx, updateStatus } from '@jbrowse/core/util';
|
|
2
2
|
import Flatbush from '@jbrowse/core/util/flatbush';
|
|
3
|
-
import { checkStopToken2
|
|
3
|
+
import { checkStopToken2 } from '@jbrowse/core/util/stopToken';
|
|
4
4
|
import { f2 } from "../shared/constants.js";
|
|
5
5
|
import { drawColorAlleleCount, getAlleleColor, } from "../shared/drawAlleleCount.js";
|
|
6
6
|
import { drawPhased } from "../shared/drawPhased.js";
|
|
7
7
|
import { getFeaturesThatPassMinorAlleleFrequencyFilter } from "../shared/minorAlleleFrequencyUtils.js";
|
|
8
8
|
function drawPhasedMode(drawCtx, itemData, mafs) {
|
|
9
|
-
const { ctx, sources, region, bpPerPx, startRow, endRow, h, drawH, scrollTop, splitCache, drawRef, genotypesCache,
|
|
9
|
+
const { ctx, sources, region, bpPerPx, startRow, endRow, h, drawH, scrollTop, splitCache, drawRef, genotypesCache, stopTokenCheck, } = drawCtx;
|
|
10
10
|
const { items, coords } = itemData;
|
|
11
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
12
11
|
for (const { feature } of mafs) {
|
|
13
12
|
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
14
13
|
const featureId = feature.id();
|
|
@@ -20,6 +19,9 @@ function drawPhasedMode(drawCtx, itemData, mafs) {
|
|
|
20
19
|
samp = feature.get('genotypes');
|
|
21
20
|
genotypesCache.set(featureId, samp);
|
|
22
21
|
}
|
|
22
|
+
const featureType = feature.get('type');
|
|
23
|
+
const featureStrand = feature.get('strand');
|
|
24
|
+
const alpha = bpLen > 5 ? 0.75 : 1;
|
|
23
25
|
for (let j = startRow; j < endRow; j++) {
|
|
24
26
|
const y = j * h - scrollTop;
|
|
25
27
|
const source = sources[j];
|
|
@@ -30,7 +32,7 @@ function drawPhasedMode(drawCtx, itemData, mafs) {
|
|
|
30
32
|
const isPhased = genotype.includes('|');
|
|
31
33
|
if (isPhased) {
|
|
32
34
|
const alleles = splitCache[genotype] ?? (splitCache[genotype] = genotype.split('|'));
|
|
33
|
-
if (drawPhased(alleles, ctx, x, y, w, drawH, HP, undefined, drawRef)) {
|
|
35
|
+
if (drawPhased(alleles, ctx, x, y, w, drawH, HP, undefined, drawRef, alpha, featureType, featureStrand)) {
|
|
34
36
|
items.push({ name, genotype, featureId, bpLen });
|
|
35
37
|
coords.push(x, y, x + w, y + drawH);
|
|
36
38
|
}
|
|
@@ -41,13 +43,12 @@ function drawPhasedMode(drawCtx, itemData, mafs) {
|
|
|
41
43
|
}
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
|
-
checkStopToken2(
|
|
46
|
+
checkStopToken2(stopTokenCheck);
|
|
45
47
|
}
|
|
46
48
|
}
|
|
47
49
|
function drawAlleleCountMode(drawCtx, itemData, mafs, colorCache) {
|
|
48
|
-
const { ctx, sources, region, bpPerPx, startRow, endRow, h, drawH, scrollTop, splitCache, drawRef, genotypesCache,
|
|
50
|
+
const { ctx, sources, region, bpPerPx, startRow, endRow, h, drawH, scrollTop, splitCache, drawRef, genotypesCache, stopTokenCheck, } = drawCtx;
|
|
49
51
|
const { items, coords } = itemData;
|
|
50
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
51
52
|
for (const { mostFrequentAlt, feature } of mafs) {
|
|
52
53
|
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
53
54
|
const featureId = feature.id();
|
|
@@ -75,13 +76,12 @@ function drawAlleleCountMode(drawCtx, itemData, mafs, colorCache) {
|
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
}
|
|
78
|
-
checkStopToken2(
|
|
79
|
+
checkStopToken2(stopTokenCheck);
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
export async function makeImageData(ctx, props) {
|
|
82
|
-
const { scrollTop, minorAlleleFrequencyFilter, sources, rowHeight, height: canvasHeight, features, regions, bpPerPx, renderingMode,
|
|
83
|
+
const { scrollTop, minorAlleleFrequencyFilter, sources, rowHeight, height: canvasHeight, features, regions, bpPerPx, renderingMode, stopTokenCheck, lengthCutoffFilter, referenceDrawingMode, statusCallback = () => { }, } = props;
|
|
83
84
|
const region = regions[0];
|
|
84
|
-
const lastCheck = createStopTokenChecker(stopToken);
|
|
85
85
|
const coords = [];
|
|
86
86
|
const items = [];
|
|
87
87
|
const colorCache = {};
|
|
@@ -93,7 +93,7 @@ export async function makeImageData(ctx, props) {
|
|
|
93
93
|
const startRow = Math.floor(scrollTop / h);
|
|
94
94
|
const endRow = Math.min(sources.length, Math.ceil((scrollTop + canvasHeight) / h));
|
|
95
95
|
const mafs = await updateStatus('Calculating stats', statusCallback, () => getFeaturesThatPassMinorAlleleFrequencyFilter({
|
|
96
|
-
|
|
96
|
+
stopTokenCheck,
|
|
97
97
|
features: features.values(),
|
|
98
98
|
minorAlleleFrequencyFilter,
|
|
99
99
|
lengthCutoffFilter,
|
|
@@ -113,7 +113,7 @@ export async function makeImageData(ctx, props) {
|
|
|
113
113
|
splitCache,
|
|
114
114
|
drawRef,
|
|
115
115
|
genotypesCache,
|
|
116
|
-
|
|
116
|
+
stopTokenCheck,
|
|
117
117
|
};
|
|
118
118
|
const itemData = { items, coords };
|
|
119
119
|
await updateStatus('Drawing variants', statusCallback, () => {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { BaseAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
+
import type { PlinkLDHeader, PlinkLDRecord } from './types.ts';
|
|
3
|
+
import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
4
|
+
import type { NoAssemblyRegion } from '@jbrowse/core/util/types';
|
|
5
|
+
export default class PlinkLDAdapter extends BaseAdapter {
|
|
6
|
+
private configured?;
|
|
7
|
+
private configurePre;
|
|
8
|
+
private parseHeader;
|
|
9
|
+
protected configurePre2(opts?: BaseOptions): Promise<{
|
|
10
|
+
records: PlinkLDRecord[];
|
|
11
|
+
header: PlinkLDHeader;
|
|
12
|
+
refNames: string[];
|
|
13
|
+
}>;
|
|
14
|
+
configure(opts?: BaseOptions): Promise<{
|
|
15
|
+
records: PlinkLDRecord[];
|
|
16
|
+
header: PlinkLDHeader;
|
|
17
|
+
refNames: string[];
|
|
18
|
+
}>;
|
|
19
|
+
getRefNames(opts?: BaseOptions): Promise<string[]>;
|
|
20
|
+
getHeader(opts?: BaseOptions): Promise<PlinkLDHeader>;
|
|
21
|
+
getLDRecords(query: NoAssemblyRegion, opts?: BaseOptions): Promise<PlinkLDRecord[]>;
|
|
22
|
+
getLDRecordsInRegion(query: NoAssemblyRegion, opts?: BaseOptions): Promise<PlinkLDRecord[]>;
|
|
23
|
+
private parseLine;
|
|
24
|
+
freeResources(): void;
|
|
25
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { BaseAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
2
|
+
import { fetchAndMaybeUnzipText, updateStatus } from '@jbrowse/core/util';
|
|
3
|
+
export default class PlinkLDAdapter extends BaseAdapter {
|
|
4
|
+
configured;
|
|
5
|
+
async configurePre(opts) {
|
|
6
|
+
const ldLocation = this.getConf('ldLocation');
|
|
7
|
+
const text = await fetchAndMaybeUnzipText(ldLocation, opts);
|
|
8
|
+
const lines = text.split('\n').filter(line => line.trim());
|
|
9
|
+
if (lines.length === 0) {
|
|
10
|
+
throw new Error('Empty LD file');
|
|
11
|
+
}
|
|
12
|
+
const header = this.parseHeader(lines[0]);
|
|
13
|
+
const records = [];
|
|
14
|
+
const refNamesSet = new Set();
|
|
15
|
+
for (let i = 1; i < lines.length; i++) {
|
|
16
|
+
const record = this.parseLine(lines[i], header);
|
|
17
|
+
if (record) {
|
|
18
|
+
records.push(record);
|
|
19
|
+
refNamesSet.add(record.chrA);
|
|
20
|
+
refNamesSet.add(record.chrB);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
const refNames = [...refNamesSet].sort();
|
|
24
|
+
return { records, header, refNames };
|
|
25
|
+
}
|
|
26
|
+
parseHeader(headerLine) {
|
|
27
|
+
const columns = headerLine.trim().split(/\s+/);
|
|
28
|
+
const findIdx = (names) => {
|
|
29
|
+
for (const name of names) {
|
|
30
|
+
const idx = columns.indexOf(name);
|
|
31
|
+
if (idx !== -1) {
|
|
32
|
+
return idx;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return -1;
|
|
36
|
+
};
|
|
37
|
+
const chrAIdx = findIdx(['CHR_A', 'CHR1']);
|
|
38
|
+
const bpAIdx = findIdx(['BP_A', 'BP1', 'POS_A', 'POS1']);
|
|
39
|
+
const snpAIdx = findIdx(['SNP_A', 'SNP1', 'ID_A', 'ID1']);
|
|
40
|
+
const chrBIdx = findIdx(['CHR_B', 'CHR2']);
|
|
41
|
+
const bpBIdx = findIdx(['BP_B', 'BP2', 'POS_B', 'POS2']);
|
|
42
|
+
const snpBIdx = findIdx(['SNP_B', 'SNP2', 'ID_B', 'ID2']);
|
|
43
|
+
const r2Idx = findIdx(['R2', 'R^2', 'RSQ']);
|
|
44
|
+
const dprimeIdx = findIdx(['DP', 'DPRIME', "D'"]);
|
|
45
|
+
const mafAIdx = findIdx(['MAF_A', 'MAF1']);
|
|
46
|
+
const mafBIdx = findIdx(['MAF_B', 'MAF2']);
|
|
47
|
+
if (chrAIdx === -1 || bpAIdx === -1 || chrBIdx === -1 || bpBIdx === -1) {
|
|
48
|
+
throw new Error(`Invalid PLINK LD header. Expected columns CHR_A, BP_A, CHR_B, BP_B. Got: ${columns.join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
if (r2Idx === -1 && dprimeIdx === -1) {
|
|
51
|
+
throw new Error(`Invalid PLINK LD header. Expected at least R2 or DP column. Got: ${columns.join(', ')}`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
columns,
|
|
55
|
+
hasR2: r2Idx !== -1,
|
|
56
|
+
hasDprime: dprimeIdx !== -1,
|
|
57
|
+
hasMafA: mafAIdx !== -1,
|
|
58
|
+
hasMafB: mafBIdx !== -1,
|
|
59
|
+
chrAIdx,
|
|
60
|
+
bpAIdx,
|
|
61
|
+
snpAIdx,
|
|
62
|
+
chrBIdx,
|
|
63
|
+
bpBIdx,
|
|
64
|
+
snpBIdx,
|
|
65
|
+
r2Idx,
|
|
66
|
+
dprimeIdx,
|
|
67
|
+
mafAIdx,
|
|
68
|
+
mafBIdx,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async configurePre2(opts) {
|
|
72
|
+
if (!this.configured) {
|
|
73
|
+
this.configured = this.configurePre(opts).catch((e) => {
|
|
74
|
+
this.configured = undefined;
|
|
75
|
+
throw e;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
return this.configured;
|
|
79
|
+
}
|
|
80
|
+
async configure(opts) {
|
|
81
|
+
const { statusCallback = () => { } } = opts || {};
|
|
82
|
+
return updateStatus('Loading LD data', statusCallback, () => this.configurePre2(opts));
|
|
83
|
+
}
|
|
84
|
+
async getRefNames(opts = {}) {
|
|
85
|
+
const { refNames } = await this.configure(opts);
|
|
86
|
+
return refNames;
|
|
87
|
+
}
|
|
88
|
+
async getHeader(opts) {
|
|
89
|
+
const { header } = await this.configure(opts);
|
|
90
|
+
return header;
|
|
91
|
+
}
|
|
92
|
+
async getLDRecords(query, opts = {}) {
|
|
93
|
+
const { refName, start, end } = query;
|
|
94
|
+
const { records } = await this.configure(opts);
|
|
95
|
+
const filtered = records.filter(r => r.chrA === refName && r.bpA >= start && r.bpA <= end);
|
|
96
|
+
return filtered;
|
|
97
|
+
}
|
|
98
|
+
async getLDRecordsInRegion(query, opts = {}) {
|
|
99
|
+
const { refName, start, end } = query;
|
|
100
|
+
const records = await this.getLDRecords(query, opts);
|
|
101
|
+
const filtered = records.filter(r => r.chrB === refName &&
|
|
102
|
+
r.bpB >= start &&
|
|
103
|
+
r.bpB <= end &&
|
|
104
|
+
r.chrA === refName &&
|
|
105
|
+
r.bpA >= start &&
|
|
106
|
+
r.bpA <= end);
|
|
107
|
+
return filtered;
|
|
108
|
+
}
|
|
109
|
+
parseLine(line, header) {
|
|
110
|
+
const fields = line.trim().split(/\s+/);
|
|
111
|
+
const chrA = fields[header.chrAIdx];
|
|
112
|
+
const bpA = Number.parseInt(fields[header.bpAIdx] ?? '', 10);
|
|
113
|
+
const snpA = header.snpAIdx >= 0 ? fields[header.snpAIdx] : `${chrA}:${bpA}`;
|
|
114
|
+
const chrB = fields[header.chrBIdx];
|
|
115
|
+
const bpB = Number.parseInt(fields[header.bpBIdx] ?? '', 10);
|
|
116
|
+
const snpB = header.snpBIdx >= 0 ? fields[header.snpBIdx] : `${chrB}:${bpB}`;
|
|
117
|
+
if (!chrA || !chrB || Number.isNaN(bpA) || Number.isNaN(bpB)) {
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
const r2 = header.r2Idx >= 0
|
|
121
|
+
? Number.parseFloat(fields[header.r2Idx] ?? '')
|
|
122
|
+
: undefined;
|
|
123
|
+
const dprime = header.dprimeIdx >= 0
|
|
124
|
+
? Number.parseFloat(fields[header.dprimeIdx] ?? '')
|
|
125
|
+
: undefined;
|
|
126
|
+
const mafA = header.mafAIdx >= 0
|
|
127
|
+
? Number.parseFloat(fields[header.mafAIdx] ?? '')
|
|
128
|
+
: undefined;
|
|
129
|
+
const mafB = header.mafBIdx >= 0
|
|
130
|
+
? Number.parseFloat(fields[header.mafBIdx] ?? '')
|
|
131
|
+
: undefined;
|
|
132
|
+
return {
|
|
133
|
+
chrA,
|
|
134
|
+
bpA,
|
|
135
|
+
snpA: snpA ?? `${chrA}:${bpA}`,
|
|
136
|
+
chrB,
|
|
137
|
+
bpB,
|
|
138
|
+
snpB: snpB ?? `${chrB}:${bpB}`,
|
|
139
|
+
r2: r2 ?? 0,
|
|
140
|
+
dprime,
|
|
141
|
+
mafA,
|
|
142
|
+
mafB,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
freeResources() {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { TabixIndexedFile } from '@gmod/tabix';
|
|
2
|
+
import { BaseAdapter } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
3
|
+
import type { PlinkLDHeader, PlinkLDRecord } from './types.ts';
|
|
4
|
+
import type { BaseOptions } from '@jbrowse/core/data_adapters/BaseAdapter';
|
|
5
|
+
import type { NoAssemblyRegion } from '@jbrowse/core/util/types';
|
|
6
|
+
export default class PlinkLDTabixAdapter extends BaseAdapter {
|
|
7
|
+
private configured?;
|
|
8
|
+
private configurePre;
|
|
9
|
+
private parseHeader;
|
|
10
|
+
protected configurePre2(): Promise<{
|
|
11
|
+
ld: TabixIndexedFile;
|
|
12
|
+
header: PlinkLDHeader;
|
|
13
|
+
}>;
|
|
14
|
+
configure(opts?: BaseOptions): Promise<{
|
|
15
|
+
ld: TabixIndexedFile;
|
|
16
|
+
header: PlinkLDHeader;
|
|
17
|
+
}>;
|
|
18
|
+
getRefNames(opts?: BaseOptions): Promise<string[]>;
|
|
19
|
+
getHeader(opts?: BaseOptions): Promise<PlinkLDHeader>;
|
|
20
|
+
getLDRecords(query: NoAssemblyRegion, opts?: BaseOptions): Promise<PlinkLDRecord[]>;
|
|
21
|
+
getLDRecordsInRegion(query: NoAssemblyRegion, opts?: BaseOptions): Promise<PlinkLDRecord[]>;
|
|
22
|
+
private parseLine;
|
|
23
|
+
freeResources(): void;
|
|
24
|
+
}
|