@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.
Files changed (55) hide show
  1. package/dist/LinearVariantDisplay/model.d.ts +1 -1
  2. package/dist/MultiLinearVariantDisplay/model.d.ts +1 -1
  3. package/dist/MultiLinearVariantMatrixDisplay/model.d.ts +1 -1
  4. package/dist/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +7 -8
  5. package/dist/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +3 -3
  6. package/dist/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -1
  7. package/dist/MultiLinearVariantMatrixRenderer/makeImageData.js +61 -6
  8. package/dist/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +4 -4
  9. package/dist/MultiLinearVariantRenderer/MultiVariantRenderer.js +3 -3
  10. package/dist/MultiLinearVariantRenderer/makeImageData.js +79 -48
  11. package/dist/MultiLinearVariantRenderer/types.d.ts +1 -0
  12. package/dist/MultiVariantBaseRenderer.d.ts +4 -4
  13. package/dist/SplitVcfTabixAdapter/SplitVcfTabixAdapter.d.ts +0 -1
  14. package/dist/SplitVcfTabixAdapter/SplitVcfTabixAdapter.js +0 -1
  15. package/dist/VariantFeatureWidget/VariantFeatureWidget.js +9 -4
  16. package/dist/VariantFeatureWidget/stateModelFactory.d.ts +9 -6
  17. package/dist/VariantRPC/getGenotypeMatrix.js +10 -2
  18. package/dist/VcfAdapter/VcfAdapter.d.ts +0 -1
  19. package/dist/VcfAdapter/VcfAdapter.js +0 -1
  20. package/dist/VcfTabixAdapter/VcfTabixAdapter.d.ts +0 -1
  21. package/dist/VcfTabixAdapter/VcfTabixAdapter.js +0 -1
  22. package/dist/shared/MultiVariantBaseModel.d.ts +1 -1
  23. package/dist/shared/SharedVariantMixin.d.ts +1 -1
  24. package/dist/shared/drawAlleleCount.d.ts +2 -1
  25. package/dist/shared/drawAlleleCount.js +22 -44
  26. package/dist/shared/minorAlleleFrequencyUtils.d.ts +3 -3
  27. package/dist/shared/minorAlleleFrequencyUtils.js +15 -9
  28. package/esm/LinearVariantDisplay/model.d.ts +1 -1
  29. package/esm/MultiLinearVariantDisplay/model.d.ts +1 -1
  30. package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +1 -1
  31. package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +7 -8
  32. package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +3 -3
  33. package/esm/MultiLinearVariantMatrixRenderer/makeImageData.d.ts +1 -1
  34. package/esm/MultiLinearVariantMatrixRenderer/makeImageData.js +62 -7
  35. package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +4 -4
  36. package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.js +3 -3
  37. package/esm/MultiLinearVariantRenderer/makeImageData.js +81 -50
  38. package/esm/MultiLinearVariantRenderer/types.d.ts +1 -0
  39. package/esm/MultiVariantBaseRenderer.d.ts +4 -4
  40. package/esm/SplitVcfTabixAdapter/SplitVcfTabixAdapter.d.ts +0 -1
  41. package/esm/SplitVcfTabixAdapter/SplitVcfTabixAdapter.js +0 -1
  42. package/esm/VariantFeatureWidget/VariantFeatureWidget.js +9 -4
  43. package/esm/VariantFeatureWidget/stateModelFactory.d.ts +9 -6
  44. package/esm/VariantRPC/getGenotypeMatrix.js +10 -2
  45. package/esm/VcfAdapter/VcfAdapter.d.ts +0 -1
  46. package/esm/VcfAdapter/VcfAdapter.js +0 -1
  47. package/esm/VcfTabixAdapter/VcfTabixAdapter.d.ts +0 -1
  48. package/esm/VcfTabixAdapter/VcfTabixAdapter.js +0 -1
  49. package/esm/shared/MultiVariantBaseModel.d.ts +1 -1
  50. package/esm/shared/SharedVariantMixin.d.ts +1 -1
  51. package/esm/shared/drawAlleleCount.d.ts +2 -1
  52. package/esm/shared/drawAlleleCount.js +21 -44
  53. package/esm/shared/minorAlleleFrequencyUtils.d.ts +3 -3
  54. package/esm/shared/minorAlleleFrequencyUtils.js +15 -9
  55. 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(alleles, mostFrequentAlt, drawReference = true) {
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' : undefined;
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(alleles, ctx, x, y, w, h, mostFrequentAlt, drawReference = true, featureType = '', featureStrand, alpha = 1) {
46
- const c = getColorAlleleCount(alleles, mostFrequentAlt, drawReference);
47
- if (c) {
48
- ctx.fillStyle = alpha !== 1 ? (0, colord_1.colord)(c).alpha(alpha).toHex() : c;
49
- if (featureType === 'inversion') {
50
- if (featureStrand === 1) {
51
- ctx.beginPath();
52
- ctx.moveTo(x - constants_1.f2, y - constants_1.f2);
53
- ctx.lineTo(x - constants_1.f2, y + h + constants_1.f2);
54
- ctx.lineTo(x + w + constants_1.f2, y + h / 2);
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.fillRect(x - constants_1.f2, y - constants_1.f2, w + constants_1.f2, h + constants_1.f2);
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
- return c;
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): Map<any, any>;
4
- export declare function calculateMinorAlleleFrequency(alleleCounts: Map<string, number>): number;
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: Map<string, number>;
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
- const samp = feat.get('genotypes');
24
- const alleleCounts = new Map();
25
- for (const val of Object.values(samp)) {
26
- const alleles = val.split(/[/|]/);
27
- for (const allele of alleles) {
28
- alleleCounts.set(allele, (alleleCounts.get(allele) || 0) + 1);
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(alleleCounts.values()) /
35
- ((0, util_1.sum)(alleleCounts.values()) || 1));
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 alleleCounts.entries()) {
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: any;
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
- reactElement: import("react/jsx-runtime").JSX.Element;
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
- imageData: any;
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, ...res } = await renderToAbstractCanvas(width, height, renderProps, ctx => makeImageData({
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
- ...res,
27
+ ...rest,
28
28
  features,
29
29
  height,
30
30
  width,
31
31
  });
32
32
  return {
33
33
  ...results,
34
- ...res,
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: Map<string, number>;
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
- const alleles = genotype.split(/[/|]/);
53
- drawColorAlleleCount(alleles, ctx, x, y, w, h, mostFrequentAlt);
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
- const alleles = genotype.split(/[/|]/);
82
- drawColorAlleleCount(alleles, ctx, x, y, w, h, mostFrequentAlt);
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: any;
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
- reactElement: import("react/jsx-runtime").JSX.Element;
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
- imageData: any;
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 rest = await renderToAbstractCanvas(width, height, renderProps, ctx => {
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
- ...rest,
26
+ ...ret,
27
27
  features,
28
28
  height,
29
29
  width,
30
30
  });
31
31
  return {
32
32
  ...results,
33
- ...rest,
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
- forEachWithStopTokenCheck(mafs, stopToken, ({ mostFrequentAlt, feature }) => {
21
- const [leftPx, rightPx] = featureSpanPx(feature, region, bpPerPx);
22
- const w = Math.max(Math.round(rightPx - leftPx), 2);
23
- const samp = feature.get('genotypes');
24
- let y = -scrollTop;
25
- const s = sources.length;
26
- if (renderingMode === 'phased') {
27
- for (let j = 0; j < s; j++) {
28
- const { name, HP } = sources[j];
29
- const genotype = samp[name];
30
- const x = Math.floor(leftPx);
31
- const h = Math.max(rowHeight, 1);
32
- if (genotype) {
33
- const isPhased = genotype.includes('|');
34
- if (isPhased) {
35
- const alleles = genotype.split('|');
36
- if (drawPhased(alleles, ctx, x, y, w, h, HP, undefined, referenceDrawingMode === 'draw')) {
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
- else {
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(),
@@ -17,4 +17,5 @@ export interface MultiRenderArgsDeserialized extends RenderArgsDeserializedWithF
17
17
  scrollTop: number;
18
18
  minorAlleleFrequencyFilter: number;
19
19
  lengthCutoffFilter: number;
20
+ statusCallback?: (arg: string) => void;
20
21
  }
@@ -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: any;
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
- reactElement: import("react/jsx-runtime").JSX.Element;
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
- imageData: any;
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>;
@@ -15,5 +15,4 @@ export default class SplitVcfTabixAdapter extends BaseFeatureDataAdapter {
15
15
  getSources(): Promise<{
16
16
  name: string;
17
17
  }[]>;
18
- freeResources(): void;
19
18
  }
@@ -83,5 +83,4 @@ export default class SplitVcfTabixAdapter extends BaseFeatureDataAdapter {
83
83
  .filter(f => s.has(f.name));
84
84
  }
85
85
  }
86
- freeResources() { }
87
86
  }
@@ -44,10 +44,9 @@ function LaunchBreakendWidgetArea({ model, }) {
44
44
  },
45
45
  }, model: model, locStrings: [`${feat.refName}:${feat.end}`] })) : null;
46
46
  }
47
- const VariantFeatureWidget = observer(function (props) {
48
- const { model } = props;
49
- const { featureData, descriptions } = model;
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;