@jbrowse/plugin-variants 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LinearVariantDisplay/model.d.ts +1 -1
- package/dist/MultiLinearVariantDisplay/model.d.ts +1 -1
- package/dist/MultiLinearVariantMatrixDisplay/model.d.ts +1 -1
- package/dist/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +7 -8
- package/dist/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +3 -3
- package/dist/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -1
- package/dist/MultiLinearVariantMatrixRenderer/makeImageData.js +61 -6
- package/dist/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +4 -4
- package/dist/MultiLinearVariantRenderer/MultiVariantRenderer.js +3 -3
- package/dist/MultiLinearVariantRenderer/makeImageData.js +79 -48
- package/dist/MultiLinearVariantRenderer/types.d.ts +1 -0
- package/dist/MultiVariantBaseRenderer.d.ts +4 -4
- package/dist/SplitVcfTabixAdapter/SplitVcfTabixAdapter.d.ts +0 -1
- package/dist/SplitVcfTabixAdapter/SplitVcfTabixAdapter.js +0 -1
- package/dist/VariantFeatureWidget/VariantFeatureWidget.js +9 -4
- package/dist/VariantFeatureWidget/stateModelFactory.d.ts +9 -6
- package/dist/VariantRPC/getGenotypeMatrix.js +10 -2
- package/dist/VcfAdapter/VcfAdapter.d.ts +0 -1
- package/dist/VcfAdapter/VcfAdapter.js +0 -1
- package/dist/VcfTabixAdapter/VcfTabixAdapter.d.ts +0 -1
- package/dist/VcfTabixAdapter/VcfTabixAdapter.js +0 -1
- package/dist/shared/MultiVariantBaseModel.d.ts +1 -1
- package/dist/shared/SharedVariantMixin.d.ts +1 -1
- package/dist/shared/drawAlleleCount.d.ts +2 -1
- package/dist/shared/drawAlleleCount.js +22 -44
- package/dist/shared/minorAlleleFrequencyUtils.d.ts +3 -3
- package/dist/shared/minorAlleleFrequencyUtils.js +15 -9
- package/esm/LinearVariantDisplay/model.d.ts +1 -1
- package/esm/MultiLinearVariantDisplay/model.d.ts +1 -1
- package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +1 -1
- package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +7 -8
- package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +3 -3
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -1
- package/esm/MultiLinearVariantMatrixRenderer/makeImageData.js +62 -7
- package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +4 -4
- package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.js +3 -3
- package/esm/MultiLinearVariantRenderer/makeImageData.js +81 -50
- package/esm/MultiLinearVariantRenderer/types.d.ts +1 -0
- package/esm/MultiVariantBaseRenderer.d.ts +4 -4
- package/esm/SplitVcfTabixAdapter/SplitVcfTabixAdapter.d.ts +0 -1
- package/esm/SplitVcfTabixAdapter/SplitVcfTabixAdapter.js +0 -1
- package/esm/VariantFeatureWidget/VariantFeatureWidget.js +9 -4
- package/esm/VariantFeatureWidget/stateModelFactory.d.ts +9 -6
- package/esm/VariantRPC/getGenotypeMatrix.js +10 -2
- package/esm/VcfAdapter/VcfAdapter.d.ts +0 -1
- package/esm/VcfAdapter/VcfAdapter.js +0 -1
- package/esm/VcfTabixAdapter/VcfTabixAdapter.d.ts +0 -1
- package/esm/VcfTabixAdapter/VcfTabixAdapter.js +0 -1
- package/esm/shared/MultiVariantBaseModel.d.ts +1 -1
- package/esm/shared/SharedVariantMixin.d.ts +1 -1
- package/esm/shared/drawAlleleCount.d.ts +2 -1
- package/esm/shared/drawAlleleCount.js +21 -44
- package/esm/shared/minorAlleleFrequencyUtils.d.ts +3 -3
- package/esm/shared/minorAlleleFrequencyUtils.js +15 -9
- package/package.json +8 -8
|
@@ -1,30 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getColorAlleleCount = getColorAlleleCount;
|
|
3
4
|
exports.drawColorAlleleCount = drawColorAlleleCount;
|
|
4
5
|
const colord_1 = require("@jbrowse/core/util/colord");
|
|
5
6
|
const constants_1 = require("./constants");
|
|
6
|
-
function getColorAlleleCount(
|
|
7
|
-
const total = alleles.length;
|
|
8
|
-
let alt = 0;
|
|
9
|
-
let uncalled = 0;
|
|
10
|
-
let alt2 = 0;
|
|
11
|
-
let ref = 0;
|
|
12
|
-
for (const allele of alleles) {
|
|
13
|
-
if (allele === mostFrequentAlt) {
|
|
14
|
-
alt++;
|
|
15
|
-
}
|
|
16
|
-
else if (allele === '0') {
|
|
17
|
-
ref++;
|
|
18
|
-
}
|
|
19
|
-
else if (allele === '.') {
|
|
20
|
-
uncalled++;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
alt2++;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
7
|
+
function getColorAlleleCount(ref, alt, alt2, uncalled, total, drawReference = true) {
|
|
26
8
|
if (ref === total) {
|
|
27
|
-
return drawReference ? '#ccc' :
|
|
9
|
+
return drawReference ? '#ccc' : '';
|
|
28
10
|
}
|
|
29
11
|
else {
|
|
30
12
|
let a1;
|
|
@@ -42,31 +24,27 @@ function getColorAlleleCount(alleles, mostFrequentAlt, drawReference = true) {
|
|
|
42
24
|
return (a1 === null || a1 === void 0 ? void 0 : a1.toHex()) || 'black';
|
|
43
25
|
}
|
|
44
26
|
}
|
|
45
|
-
function drawColorAlleleCount(
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
ctx.closePath();
|
|
56
|
-
ctx.fill();
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
ctx.beginPath();
|
|
60
|
-
ctx.moveTo(x + w + constants_1.f2, y - constants_1.f2);
|
|
61
|
-
ctx.lineTo(x + w + constants_1.f2, y + h + constants_1.f2);
|
|
62
|
-
ctx.lineTo(x - constants_1.f2, y + h / 2);
|
|
63
|
-
ctx.closePath();
|
|
64
|
-
ctx.fill();
|
|
65
|
-
}
|
|
27
|
+
function drawColorAlleleCount(c, ctx, x, y, w, h, featureType = '', featureStrand, alpha = 1) {
|
|
28
|
+
ctx.fillStyle = alpha !== 1 ? (0, colord_1.colord)(c).alpha(alpha).toHex() : c;
|
|
29
|
+
if (featureType === 'inversion') {
|
|
30
|
+
if (featureStrand === 1) {
|
|
31
|
+
ctx.beginPath();
|
|
32
|
+
ctx.moveTo(x - constants_1.f2, y - constants_1.f2);
|
|
33
|
+
ctx.lineTo(x - constants_1.f2, y + h + constants_1.f2);
|
|
34
|
+
ctx.lineTo(x + w + constants_1.f2, y + h / 2);
|
|
35
|
+
ctx.closePath();
|
|
36
|
+
ctx.fill();
|
|
66
37
|
}
|
|
67
38
|
else {
|
|
68
|
-
ctx.
|
|
39
|
+
ctx.beginPath();
|
|
40
|
+
ctx.moveTo(x + w + constants_1.f2, y - constants_1.f2);
|
|
41
|
+
ctx.lineTo(x + w + constants_1.f2, y + h + constants_1.f2);
|
|
42
|
+
ctx.lineTo(x - constants_1.f2, y + h / 2);
|
|
43
|
+
ctx.closePath();
|
|
44
|
+
ctx.fill();
|
|
69
45
|
}
|
|
70
46
|
}
|
|
71
|
-
|
|
47
|
+
else {
|
|
48
|
+
ctx.fillRect(x - constants_1.f2, y - constants_1.f2, w + constants_1.f2, h + constants_1.f2);
|
|
49
|
+
}
|
|
72
50
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Feature } from '@jbrowse/core/util';
|
|
2
2
|
export declare function findSecondLargestNumber(arr: Iterable<number>): number;
|
|
3
|
-
export declare function calculateAlleleCounts(feat: Feature):
|
|
4
|
-
export declare function calculateMinorAlleleFrequency(alleleCounts:
|
|
3
|
+
export declare function calculateAlleleCounts(feat: Feature): Record<string, number>;
|
|
4
|
+
export declare function calculateMinorAlleleFrequency(alleleCounts: Record<string, number>): number;
|
|
5
5
|
export declare function getFeaturesThatPassMinorAlleleFrequencyFilter({ features, minorAlleleFrequencyFilter, lengthCutoffFilter, stopToken, }: {
|
|
6
6
|
features: Iterable<Feature>;
|
|
7
7
|
minorAlleleFrequencyFilter: number;
|
|
@@ -10,5 +10,5 @@ export declare function getFeaturesThatPassMinorAlleleFrequencyFilter({ features
|
|
|
10
10
|
}): {
|
|
11
11
|
feature: Feature;
|
|
12
12
|
mostFrequentAlt: string;
|
|
13
|
-
alleleCounts:
|
|
13
|
+
alleleCounts: Record<string, number>;
|
|
14
14
|
}[];
|
|
@@ -20,24 +20,30 @@ function findSecondLargestNumber(arr) {
|
|
|
20
20
|
return secondMax;
|
|
21
21
|
}
|
|
22
22
|
function calculateAlleleCounts(feat) {
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
var _a;
|
|
24
|
+
const genotypes = feat.get('genotypes');
|
|
25
|
+
const alleleCounts = { 0: 0, 1: 0, '.': 0 };
|
|
26
|
+
const cacheSplit = {};
|
|
27
|
+
const vals = Object.values(genotypes);
|
|
28
|
+
const len = vals.length;
|
|
29
|
+
for (let i = 0; i < len; i++) {
|
|
30
|
+
const genotype = vals[i];
|
|
31
|
+
const alleles = cacheSplit[genotype] || (cacheSplit[genotype] = genotype.split(/[/|]/));
|
|
32
|
+
for (let i = 0, len = alleles.length; i < len; i++) {
|
|
33
|
+
const a = alleles[i];
|
|
34
|
+
alleleCounts[a] = ((_a = alleleCounts[a]) !== null && _a !== void 0 ? _a : 0) + 1;
|
|
29
35
|
}
|
|
30
36
|
}
|
|
31
37
|
return alleleCounts;
|
|
32
38
|
}
|
|
33
39
|
function calculateMinorAlleleFrequency(alleleCounts) {
|
|
34
|
-
return (findSecondLargestNumber(
|
|
35
|
-
((0, util_1.sum)(
|
|
40
|
+
return (findSecondLargestNumber(Object.values(alleleCounts)) /
|
|
41
|
+
((0, util_1.sum)(Object.values(alleleCounts)) || 1));
|
|
36
42
|
}
|
|
37
43
|
function getMostFrequentAlt(alleleCounts) {
|
|
38
44
|
let mostFrequentAlt;
|
|
39
45
|
let max = 0;
|
|
40
|
-
for (const [alt, altCount] of
|
|
46
|
+
for (const [alt, altCount] of Object.entries(alleleCounts)) {
|
|
41
47
|
if (alt !== '.' && alt !== '0') {
|
|
42
48
|
if (altCount > max) {
|
|
43
49
|
mostFrequentAlt = alt;
|
|
@@ -200,7 +200,7 @@ export default function stateModelFactory(configSchema: AnyConfigurationSchemaTy
|
|
|
200
200
|
} & {
|
|
201
201
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
202
202
|
deleteBlock(key: string): void;
|
|
203
|
-
selectFeature(feature: Feature): void
|
|
203
|
+
selectFeature(feature: Feature): Promise<void>;
|
|
204
204
|
navToFeature(feature: Feature): void;
|
|
205
205
|
clearFeatureSelection(): void;
|
|
206
206
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -208,7 +208,7 @@ export declare function stateModelFactory(configSchema: AnyConfigurationSchemaTy
|
|
|
208
208
|
} & {
|
|
209
209
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
210
210
|
deleteBlock(key: string): void;
|
|
211
|
-
selectFeature(feature: import("@jbrowse/core/util").Feature): void
|
|
211
|
+
selectFeature(feature: import("@jbrowse/core/util").Feature): Promise<void>;
|
|
212
212
|
navToFeature(feature: import("@jbrowse/core/util").Feature): void;
|
|
213
213
|
clearFeatureSelection(): void;
|
|
214
214
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -208,7 +208,7 @@ export default function stateModelFactory(configSchema: AnyConfigurationSchemaTy
|
|
|
208
208
|
} & {
|
|
209
209
|
addBlock(key: string, block: import("@jbrowse/core/util/blockTypes").BaseBlock): void;
|
|
210
210
|
deleteBlock(key: string): void;
|
|
211
|
-
selectFeature(feature: import("@jbrowse/core/util").Feature): void
|
|
211
|
+
selectFeature(feature: import("@jbrowse/core/util").Feature): Promise<void>;
|
|
212
212
|
navToFeature(feature: import("@jbrowse/core/util").Feature): void;
|
|
213
213
|
clearFeatureSelection(): void;
|
|
214
214
|
setFeatureIdUnderMouse(feature?: string): void;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import BoxRendererType from '@jbrowse/core/pluggableElementTypes/renderers/BoxRendererType';
|
|
2
2
|
import { SimpleFeature } from '@jbrowse/core/util';
|
|
3
3
|
import type { RenderArgsDeserialized } from './types';
|
|
4
|
-
import type { Feature } from '@jbrowse/core/util';
|
|
5
4
|
export default class LinearVariantMatrixRenderer extends BoxRendererType {
|
|
6
5
|
supportsSVG: boolean;
|
|
7
6
|
render(renderProps: RenderArgsDeserialized): Promise<{
|
|
@@ -10,8 +9,8 @@ export default class LinearVariantMatrixRenderer extends BoxRendererType {
|
|
|
10
9
|
height: number;
|
|
11
10
|
width: number;
|
|
12
11
|
arr: string[][];
|
|
13
|
-
canvasRecordedData:
|
|
14
|
-
layout: import("@jbrowse/core/util/layouts").BaseLayout<Feature>;
|
|
12
|
+
canvasRecordedData: Record<string, unknown>;
|
|
13
|
+
layout: import("@jbrowse/core/util/layouts/BaseLayout").BaseLayout<import("@jbrowse/core/util").Feature>;
|
|
15
14
|
reactElement?: React.ReactElement;
|
|
16
15
|
html?: string;
|
|
17
16
|
} | {
|
|
@@ -20,8 +19,9 @@ export default class LinearVariantMatrixRenderer extends BoxRendererType {
|
|
|
20
19
|
height: number;
|
|
21
20
|
width: number;
|
|
22
21
|
arr: string[][];
|
|
23
|
-
|
|
24
|
-
layout: import("@jbrowse/core/util/layouts").BaseLayout<Feature>;
|
|
22
|
+
imageData: any;
|
|
23
|
+
layout: import("@jbrowse/core/util/layouts/BaseLayout").BaseLayout<import("@jbrowse/core/util").Feature>;
|
|
24
|
+
reactElement?: React.ReactElement;
|
|
25
25
|
html?: string;
|
|
26
26
|
} | {
|
|
27
27
|
features: Map<any, any>;
|
|
@@ -29,9 +29,8 @@ export default class LinearVariantMatrixRenderer extends BoxRendererType {
|
|
|
29
29
|
height: number;
|
|
30
30
|
width: number;
|
|
31
31
|
arr: string[][];
|
|
32
|
-
|
|
33
|
-
layout: import("@jbrowse/core/util/layouts").BaseLayout<Feature>;
|
|
34
|
-
reactElement?: React.ReactElement;
|
|
32
|
+
reactElement: React.ReactElement;
|
|
33
|
+
layout: import("@jbrowse/core/util/layouts/BaseLayout").BaseLayout<import("@jbrowse/core/util").Feature>;
|
|
35
34
|
html?: string;
|
|
36
35
|
}>;
|
|
37
36
|
}
|
|
@@ -12,7 +12,7 @@ export default class LinearVariantMatrixRenderer extends BoxRendererType {
|
|
|
12
12
|
const { end, start } = region;
|
|
13
13
|
const width = (end - start) / bpPerPx;
|
|
14
14
|
const { makeImageData } = await import('./makeImageData');
|
|
15
|
-
const { mafs, ...
|
|
15
|
+
const { mafs, ...rest } = await renderToAbstractCanvas(width, height, renderProps, ctx => makeImageData({
|
|
16
16
|
ctx,
|
|
17
17
|
canvasWidth: width,
|
|
18
18
|
canvasHeight: height,
|
|
@@ -24,14 +24,14 @@ export default class LinearVariantMatrixRenderer extends BoxRendererType {
|
|
|
24
24
|
}));
|
|
25
25
|
const results = await super.render({
|
|
26
26
|
...renderProps,
|
|
27
|
-
...
|
|
27
|
+
...rest,
|
|
28
28
|
features,
|
|
29
29
|
height,
|
|
30
30
|
width,
|
|
31
31
|
});
|
|
32
32
|
return {
|
|
33
33
|
...results,
|
|
34
|
-
...
|
|
34
|
+
...rest,
|
|
35
35
|
features: new Map(),
|
|
36
36
|
simplifiedFeatures: mafs.map(({ feature }) => new SimpleFeature({
|
|
37
37
|
id: feature.id(),
|
|
@@ -8,7 +8,7 @@ export declare function makeImageData({ ctx, canvasWidth, canvasHeight, renderAr
|
|
|
8
8
|
mafs: {
|
|
9
9
|
feature: import("@jbrowse/core/util").Feature;
|
|
10
10
|
mostFrequentAlt: string;
|
|
11
|
-
alleleCounts:
|
|
11
|
+
alleleCounts: Record<string, number>;
|
|
12
12
|
}[];
|
|
13
13
|
arr: string[][];
|
|
14
14
|
}>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { forEachWithStopTokenCheck, updateStatus } from '@jbrowse/core/util';
|
|
2
2
|
import { checkStopToken } from '@jbrowse/core/util/stopToken';
|
|
3
3
|
import { f2 } from '../shared/constants';
|
|
4
|
-
import { drawColorAlleleCount } from '../shared/drawAlleleCount';
|
|
4
|
+
import { drawColorAlleleCount, getColorAlleleCount, } from '../shared/drawAlleleCount';
|
|
5
5
|
import { drawPhased } from '../shared/drawPhased';
|
|
6
6
|
import { getFeaturesThatPassMinorAlleleFrequencyFilter } from '../shared/minorAlleleFrequencyUtils';
|
|
7
7
|
export async function makeImageData({ ctx, canvasWidth, canvasHeight, renderArgs, }) {
|
|
@@ -9,17 +9,18 @@ export async function makeImageData({ ctx, canvasWidth, canvasHeight, renderArgs
|
|
|
9
9
|
const { statusCallback = () => { } } = renderArgs;
|
|
10
10
|
const h = canvasHeight / sources.length;
|
|
11
11
|
checkStopToken(stopToken);
|
|
12
|
-
const mafs = getFeaturesThatPassMinorAlleleFrequencyFilter({
|
|
12
|
+
const mafs = await updateStatus('Calculating stats', statusCallback, () => getFeaturesThatPassMinorAlleleFrequencyFilter({
|
|
13
13
|
stopToken,
|
|
14
14
|
features: features.values(),
|
|
15
15
|
minorAlleleFrequencyFilter,
|
|
16
16
|
lengthCutoffFilter,
|
|
17
|
-
});
|
|
17
|
+
}));
|
|
18
18
|
checkStopToken(stopToken);
|
|
19
19
|
const arr = [];
|
|
20
20
|
const m = mafs.length;
|
|
21
21
|
const w = canvasWidth / m;
|
|
22
22
|
await updateStatus('Drawing variant matrix', statusCallback, () => {
|
|
23
|
+
const colorCache = {};
|
|
23
24
|
forEachWithStopTokenCheck(mafs, stopToken, ({ feature, mostFrequentAlt }, idx) => {
|
|
24
25
|
var _a, _b, _c;
|
|
25
26
|
const arr2 = [];
|
|
@@ -49,8 +50,35 @@ export async function makeImageData({ ctx, canvasWidth, canvasHeight, renderArgs
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
else {
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
let c = colorCache[genotype];
|
|
54
|
+
if (c === undefined) {
|
|
55
|
+
let alt = 0;
|
|
56
|
+
let uncalled = 0;
|
|
57
|
+
let alt2 = 0;
|
|
58
|
+
let ref = 0;
|
|
59
|
+
const alleles = genotype.split(/[/|]/);
|
|
60
|
+
const total = alleles.length;
|
|
61
|
+
for (let i = 0; i < total; i++) {
|
|
62
|
+
const allele = alleles[i];
|
|
63
|
+
if (allele === mostFrequentAlt) {
|
|
64
|
+
alt++;
|
|
65
|
+
}
|
|
66
|
+
else if (allele === '0') {
|
|
67
|
+
ref++;
|
|
68
|
+
}
|
|
69
|
+
else if (allele === '.') {
|
|
70
|
+
uncalled++;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
alt2++;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
c = getColorAlleleCount(ref, alt, alt2, uncalled, total, true);
|
|
77
|
+
colorCache[genotype] = c;
|
|
78
|
+
}
|
|
79
|
+
if (c) {
|
|
80
|
+
drawColorAlleleCount(c, ctx, x, y, w, h);
|
|
81
|
+
}
|
|
54
82
|
}
|
|
55
83
|
}
|
|
56
84
|
}
|
|
@@ -78,8 +106,35 @@ export async function makeImageData({ ctx, canvasWidth, canvasHeight, renderArgs
|
|
|
78
106
|
}
|
|
79
107
|
}
|
|
80
108
|
else {
|
|
81
|
-
|
|
82
|
-
|
|
109
|
+
let c = colorCache[genotype];
|
|
110
|
+
if (c === undefined) {
|
|
111
|
+
let alt = 0;
|
|
112
|
+
let uncalled = 0;
|
|
113
|
+
let alt2 = 0;
|
|
114
|
+
let ref = 0;
|
|
115
|
+
const alleles = genotype.split(/[/|]/);
|
|
116
|
+
const total = alleles.length;
|
|
117
|
+
for (let i = 0; i < total; i++) {
|
|
118
|
+
const allele = alleles[i];
|
|
119
|
+
if (allele === mostFrequentAlt) {
|
|
120
|
+
alt++;
|
|
121
|
+
}
|
|
122
|
+
else if (allele === '0') {
|
|
123
|
+
ref++;
|
|
124
|
+
}
|
|
125
|
+
else if (allele === '.') {
|
|
126
|
+
uncalled++;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
alt2++;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
c = getColorAlleleCount(ref, alt, alt2, uncalled, total, true);
|
|
133
|
+
colorCache[genotype] = c;
|
|
134
|
+
}
|
|
135
|
+
if (c) {
|
|
136
|
+
drawColorAlleleCount(c, ctx, x, y, w, h);
|
|
137
|
+
}
|
|
83
138
|
}
|
|
84
139
|
}
|
|
85
140
|
}
|
|
@@ -18,7 +18,7 @@ export default class MultiVariantBaseRenderer extends FeatureRendererType {
|
|
|
18
18
|
length: number;
|
|
19
19
|
};
|
|
20
20
|
};
|
|
21
|
-
canvasRecordedData:
|
|
21
|
+
canvasRecordedData: Record<string, unknown>;
|
|
22
22
|
reactElement?: React.ReactElement;
|
|
23
23
|
html?: string;
|
|
24
24
|
} | {
|
|
@@ -36,7 +36,8 @@ export default class MultiVariantBaseRenderer extends FeatureRendererType {
|
|
|
36
36
|
length: number;
|
|
37
37
|
};
|
|
38
38
|
};
|
|
39
|
-
|
|
39
|
+
imageData: any;
|
|
40
|
+
reactElement?: React.ReactElement;
|
|
40
41
|
html?: string;
|
|
41
42
|
} | {
|
|
42
43
|
features: Map<string, Feature>;
|
|
@@ -53,8 +54,7 @@ export default class MultiVariantBaseRenderer extends FeatureRendererType {
|
|
|
53
54
|
length: number;
|
|
54
55
|
};
|
|
55
56
|
};
|
|
56
|
-
|
|
57
|
-
reactElement?: React.ReactElement;
|
|
57
|
+
reactElement: React.ReactElement;
|
|
58
58
|
html?: string;
|
|
59
59
|
}>;
|
|
60
60
|
}
|
|
@@ -11,7 +11,7 @@ export default class MultiVariantBaseRenderer extends FeatureRendererType {
|
|
|
11
11
|
const region = regions[0];
|
|
12
12
|
const width = (region.end - region.start) / bpPerPx;
|
|
13
13
|
const { makeImageData } = await import('./makeImageData');
|
|
14
|
-
const
|
|
14
|
+
const ret = await renderToAbstractCanvas(width, height, renderProps, ctx => {
|
|
15
15
|
if (referenceDrawingMode === 'skip') {
|
|
16
16
|
ctx.fillStyle = '#ccc';
|
|
17
17
|
ctx.fillRect(0, 0, width, height);
|
|
@@ -23,14 +23,14 @@ export default class MultiVariantBaseRenderer extends FeatureRendererType {
|
|
|
23
23
|
});
|
|
24
24
|
const results = await super.render({
|
|
25
25
|
...renderProps,
|
|
26
|
-
...
|
|
26
|
+
...ret,
|
|
27
27
|
features,
|
|
28
28
|
height,
|
|
29
29
|
width,
|
|
30
30
|
});
|
|
31
31
|
return {
|
|
32
32
|
...results,
|
|
33
|
-
...
|
|
33
|
+
...ret,
|
|
34
34
|
features: new Map(),
|
|
35
35
|
height,
|
|
36
36
|
width,
|
|
@@ -1,39 +1,97 @@
|
|
|
1
|
-
import { featureSpanPx, forEachWithStopTokenCheck } from '@jbrowse/core/util';
|
|
1
|
+
import { featureSpanPx, forEachWithStopTokenCheck, updateStatus, } from '@jbrowse/core/util';
|
|
2
2
|
import { checkStopToken } from '@jbrowse/core/util/stopToken';
|
|
3
3
|
import RBush from 'rbush';
|
|
4
4
|
import { f2 } from '../shared/constants';
|
|
5
|
-
import { drawColorAlleleCount } from '../shared/drawAlleleCount';
|
|
5
|
+
import { drawColorAlleleCount, getColorAlleleCount, } from '../shared/drawAlleleCount';
|
|
6
6
|
import { drawPhased } from '../shared/drawPhased';
|
|
7
7
|
import { getFeaturesThatPassMinorAlleleFrequencyFilter } from '../shared/minorAlleleFrequencyUtils';
|
|
8
8
|
export async function makeImageData(ctx, props) {
|
|
9
9
|
const { scrollTop, minorAlleleFrequencyFilter, sources, rowHeight, features, regions, bpPerPx, renderingMode, stopToken, lengthCutoffFilter, referenceDrawingMode, } = props;
|
|
10
10
|
const region = regions[0];
|
|
11
|
+
const { statusCallback = () => { } } = props;
|
|
11
12
|
checkStopToken(stopToken);
|
|
12
|
-
const mafs = getFeaturesThatPassMinorAlleleFrequencyFilter({
|
|
13
|
+
const mafs = await updateStatus('Calculating stats', statusCallback, () => getFeaturesThatPassMinorAlleleFrequencyFilter({
|
|
13
14
|
stopToken,
|
|
14
15
|
features: features.values(),
|
|
15
16
|
minorAlleleFrequencyFilter,
|
|
16
17
|
lengthCutoffFilter,
|
|
17
|
-
});
|
|
18
|
+
}));
|
|
18
19
|
checkStopToken(stopToken);
|
|
19
20
|
const rbush = new RBush();
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
if (
|
|
35
|
-
const
|
|
36
|
-
if (
|
|
21
|
+
await updateStatus('Drawing variants', statusCallback, () => {
|
|
22
|
+
forEachWithStopTokenCheck(mafs, stopToken, ({ mostFrequentAlt, feature }) => {
|
|
23
|
+
const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
|
|
24
|
+
const flen = feature.get('end') - feature.get('start');
|
|
25
|
+
const w = Math.max(Math.round(rightPx - leftPx), 2);
|
|
26
|
+
const samp = feature.get('genotypes');
|
|
27
|
+
let y = -scrollTop;
|
|
28
|
+
const s = sources.length;
|
|
29
|
+
if (renderingMode === 'phased') {
|
|
30
|
+
for (let j = 0; j < s; j++) {
|
|
31
|
+
const { name, HP } = sources[j];
|
|
32
|
+
const genotype = samp[name];
|
|
33
|
+
const x = Math.floor(leftPx);
|
|
34
|
+
const h = Math.max(rowHeight, 1);
|
|
35
|
+
if (genotype) {
|
|
36
|
+
const isPhased = genotype.includes('|');
|
|
37
|
+
if (isPhased) {
|
|
38
|
+
const alleles = genotype.split('|');
|
|
39
|
+
if (drawPhased(alleles, ctx, x, y, w, h, HP, undefined, referenceDrawingMode === 'draw')) {
|
|
40
|
+
rbush.insert({
|
|
41
|
+
minX: x,
|
|
42
|
+
maxX: x + w,
|
|
43
|
+
minY: y,
|
|
44
|
+
maxY: y + h,
|
|
45
|
+
genotype,
|
|
46
|
+
name,
|
|
47
|
+
featureId: feature.id(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
ctx.fillStyle = 'black';
|
|
53
|
+
ctx.fillRect(x - f2, y - f2, w + f2, h + f2);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
y += rowHeight;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const colorCache = {};
|
|
61
|
+
for (let j = 0; j < s; j++) {
|
|
62
|
+
const { name } = sources[j];
|
|
63
|
+
const genotype = samp[name];
|
|
64
|
+
const x = Math.floor(leftPx);
|
|
65
|
+
const h = Math.max(rowHeight, 1);
|
|
66
|
+
if (genotype) {
|
|
67
|
+
let c = colorCache[genotype];
|
|
68
|
+
if (c === undefined) {
|
|
69
|
+
let alt = 0;
|
|
70
|
+
let uncalled = 0;
|
|
71
|
+
let alt2 = 0;
|
|
72
|
+
let ref = 0;
|
|
73
|
+
const alleles = genotype.split(/[/|]/);
|
|
74
|
+
const total = alleles.length;
|
|
75
|
+
for (let i = 0; i < total; i++) {
|
|
76
|
+
const allele = alleles[i];
|
|
77
|
+
if (allele === mostFrequentAlt) {
|
|
78
|
+
alt++;
|
|
79
|
+
}
|
|
80
|
+
else if (allele === '0') {
|
|
81
|
+
ref++;
|
|
82
|
+
}
|
|
83
|
+
else if (allele === '.') {
|
|
84
|
+
uncalled++;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
alt2++;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
c = getColorAlleleCount(ref, alt, alt2, uncalled, total, referenceDrawingMode === 'draw');
|
|
91
|
+
colorCache[genotype] = c;
|
|
92
|
+
}
|
|
93
|
+
if (c) {
|
|
94
|
+
drawColorAlleleCount(c, ctx, x, y, w, h, feature.get('type'), feature.get('strand'), flen > 5 ? 0.75 : 1);
|
|
37
95
|
rbush.insert({
|
|
38
96
|
minX: x,
|
|
39
97
|
maxX: x + w,
|
|
@@ -45,37 +103,10 @@ export async function makeImageData(ctx, props) {
|
|
|
45
103
|
});
|
|
46
104
|
}
|
|
47
105
|
}
|
|
48
|
-
|
|
49
|
-
ctx.fillStyle = 'black';
|
|
50
|
-
ctx.fillRect(x - f2, y - f2, w + f2, h + f2);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
y += rowHeight;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
for (let j = 0; j < s; j++) {
|
|
58
|
-
const { name } = sources[j];
|
|
59
|
-
const genotype = samp[name];
|
|
60
|
-
const x = Math.floor(leftPx);
|
|
61
|
-
const h = Math.max(rowHeight, 1);
|
|
62
|
-
if (genotype) {
|
|
63
|
-
const alleles = genotype.split(/[/|]/);
|
|
64
|
-
if (drawColorAlleleCount(alleles, ctx, x, y, w, h, mostFrequentAlt, referenceDrawingMode === 'draw', feature.get('type'), feature.get('strand'), 0.75)) {
|
|
65
|
-
rbush.insert({
|
|
66
|
-
minX: x,
|
|
67
|
-
maxX: x + w,
|
|
68
|
-
minY: y,
|
|
69
|
-
maxY: y + h,
|
|
70
|
-
genotype,
|
|
71
|
-
name,
|
|
72
|
-
featureId: feature.id(),
|
|
73
|
-
});
|
|
74
|
-
}
|
|
106
|
+
y += rowHeight;
|
|
75
107
|
}
|
|
76
|
-
y += rowHeight;
|
|
77
108
|
}
|
|
78
|
-
}
|
|
109
|
+
});
|
|
79
110
|
});
|
|
80
111
|
return {
|
|
81
112
|
rbush: rbush.toJSON(),
|
|
@@ -22,7 +22,7 @@ export default abstract class MultiVariantBaseRenderer extends FeatureRendererTy
|
|
|
22
22
|
height: number;
|
|
23
23
|
width: number;
|
|
24
24
|
containsNoTransferables: boolean;
|
|
25
|
-
canvasRecordedData:
|
|
25
|
+
canvasRecordedData: Record<string, unknown>;
|
|
26
26
|
reactElement?: React.ReactElement;
|
|
27
27
|
html?: string;
|
|
28
28
|
} | {
|
|
@@ -30,15 +30,15 @@ export default abstract class MultiVariantBaseRenderer extends FeatureRendererTy
|
|
|
30
30
|
height: number;
|
|
31
31
|
width: number;
|
|
32
32
|
containsNoTransferables: boolean;
|
|
33
|
-
|
|
33
|
+
imageData: any;
|
|
34
|
+
reactElement?: React.ReactElement;
|
|
34
35
|
html?: string;
|
|
35
36
|
} | {
|
|
36
37
|
features: Map<string, Feature>;
|
|
37
38
|
height: number;
|
|
38
39
|
width: number;
|
|
39
40
|
containsNoTransferables: boolean;
|
|
40
|
-
|
|
41
|
-
reactElement?: React.ReactElement;
|
|
41
|
+
reactElement: React.ReactElement;
|
|
42
42
|
html?: string;
|
|
43
43
|
}>;
|
|
44
44
|
abstract draw<T extends RenderArgsDeserializedWithFeatures>(ctx: CanvasRenderingContext2D, props: T): Promise<Record<string, unknown> | undefined>;
|
|
@@ -44,10 +44,9 @@ function LaunchBreakendWidgetArea({ model, }) {
|
|
|
44
44
|
},
|
|
45
45
|
}, model: model, locStrings: [`${feat.refName}:${feat.end}`] })) : null;
|
|
46
46
|
}
|
|
47
|
-
const
|
|
48
|
-
const { model } = props;
|
|
49
|
-
const {
|
|
50
|
-
const feat = JSON.parse(JSON.stringify(featureData));
|
|
47
|
+
const FeatDefined = observer(function (props) {
|
|
48
|
+
const { feat, model } = props;
|
|
49
|
+
const { descriptions } = model;
|
|
51
50
|
const { samples, ...rest } = feat;
|
|
52
51
|
const { REF } = rest;
|
|
53
52
|
return (_jsxs(Paper, { "data-testid": "variant-side-drawer", children: [_jsx(FeatureDetails, { feature: rest, descriptions: {
|
|
@@ -57,4 +56,10 @@ const VariantFeatureWidget = observer(function (props) {
|
|
|
57
56
|
return key === 'ALT' ? (_jsx(AltFormatter, { value: `${value}`, ref: REF })) : (_jsx(Formatter, { value: value }));
|
|
58
57
|
}, ...props }), _jsxs(Suspense, { fallback: null, children: [_jsx(CsqPanel, { feature: rest, descriptions: descriptions }), _jsx(AnnPanel, { feature: rest, descriptions: descriptions }), _jsx(LaunchBreakendWidgetArea, { model: model })] }), _jsx(VariantSampleGrid, { feature: feat, ...props, descriptions: descriptions })] }));
|
|
59
58
|
});
|
|
59
|
+
const VariantFeatureWidget = observer(function (props) {
|
|
60
|
+
const { model } = props;
|
|
61
|
+
const { featureData } = model;
|
|
62
|
+
const feat = structuredClone(featureData);
|
|
63
|
+
return feat ? (_jsx(FeatDefined, { feat: feat, ...props })) : (_jsx("div", { children: "No feature loaded, may not be available after page refresh because it was too large for localStorage" }));
|
|
64
|
+
});
|
|
60
65
|
export default VariantFeatureWidget;
|