@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.
Files changed (128) hide show
  1. package/esm/LDDisplay/SharedLDConfigSchema.d.ts +102 -0
  2. package/esm/LDDisplay/SharedLDConfigSchema.js +83 -0
  3. package/esm/LDDisplay/afterAttach.d.ts +2 -0
  4. package/esm/LDDisplay/afterAttach.js +123 -0
  5. package/esm/LDDisplay/components/BaseDisplayComponent.d.ts +15 -0
  6. package/esm/LDDisplay/components/BaseDisplayComponent.js +39 -0
  7. package/esm/LDDisplay/components/LDColorLegend.d.ts +15 -0
  8. package/esm/LDDisplay/components/LDColorLegend.js +75 -0
  9. package/esm/LDDisplay/components/LDDisplayComponent.d.ts +5 -0
  10. package/esm/LDDisplay/components/LDDisplayComponent.js +203 -0
  11. package/esm/LDDisplay/components/LinesConnectingMatrixToGenomicPosition.d.ts +16 -0
  12. package/esm/LDDisplay/components/LinesConnectingMatrixToGenomicPosition.js +109 -0
  13. package/esm/LDDisplay/configSchema1.d.ts +115 -0
  14. package/esm/LDDisplay/configSchema1.js +16 -0
  15. package/esm/LDDisplay/configSchema2.d.ts +115 -0
  16. package/esm/LDDisplay/configSchema2.js +16 -0
  17. package/esm/LDDisplay/index.d.ts +2 -0
  18. package/esm/LDDisplay/index.js +35 -0
  19. package/esm/LDDisplay/renderSvg.d.ts +3 -0
  20. package/esm/LDDisplay/renderSvg.js +36 -0
  21. package/esm/LDDisplay/shared.d.ts +367 -0
  22. package/esm/LDDisplay/shared.js +467 -0
  23. package/esm/LDDisplay/stateModel1.d.ts +365 -0
  24. package/esm/LDDisplay/stateModel1.js +10 -0
  25. package/esm/LDDisplay/stateModel2.d.ts +365 -0
  26. package/esm/LDDisplay/stateModel2.js +10 -0
  27. package/esm/LDRenderer/LDRenderer.d.ts +30 -0
  28. package/esm/LDRenderer/LDRenderer.js +109 -0
  29. package/esm/LDRenderer/components/LDRendering.d.ts +2 -0
  30. package/esm/LDRenderer/components/LDRendering.js +4 -0
  31. package/esm/LDRenderer/configSchema.d.ts +8 -0
  32. package/esm/LDRenderer/configSchema.js +10 -0
  33. package/esm/LDRenderer/index.d.ts +2 -0
  34. package/esm/LDRenderer/index.js +11 -0
  35. package/esm/LDRenderer/makeImageData.d.ts +20 -0
  36. package/esm/LDRenderer/makeImageData.js +157 -0
  37. package/esm/LDRenderer/types.d.ts +8 -0
  38. package/esm/LDRenderer/types.js +1 -0
  39. package/esm/LDTrack/configSchema.d.ts +85 -0
  40. package/esm/LDTrack/configSchema.js +7 -0
  41. package/esm/LDTrack/index.d.ts +2 -0
  42. package/esm/LDTrack/index.js +14 -0
  43. package/esm/LinearVariantDisplay/model.d.ts +126 -42
  44. package/esm/LinearVariantDisplay/model.js +46 -8
  45. package/esm/MultiLinearVariantDisplay/configSchema.d.ts +27 -1
  46. package/esm/MultiLinearVariantDisplay/model.d.ts +2635 -31
  47. package/esm/MultiLinearVariantDisplay/model.js +6 -0
  48. package/esm/MultiLinearVariantDisplay/renderSvg.d.ts +10 -2
  49. package/esm/MultiLinearVariantMatrixDisplay/configSchema.d.ts +25 -0
  50. package/esm/MultiLinearVariantMatrixDisplay/configSchema.js +26 -0
  51. package/esm/MultiLinearVariantMatrixDisplay/model.d.ts +2636 -32
  52. package/esm/MultiLinearVariantMatrixDisplay/model.js +6 -0
  53. package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.d.ts +2 -2
  54. package/esm/MultiLinearVariantMatrixRenderer/MultiLinearVariantMatrixRenderer.js +11 -9
  55. package/esm/MultiLinearVariantMatrixRenderer/components/MultiLinearVariantMatrixRendering.d.ts +8 -0
  56. package/esm/MultiLinearVariantMatrixRenderer/components/MultiLinearVariantMatrixRendering.js +14 -2
  57. package/esm/MultiLinearVariantMatrixRenderer/makeImageData.js +8 -11
  58. package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.d.ts +2 -2
  59. package/esm/MultiLinearVariantRenderer/MultiVariantRenderer.js +4 -3
  60. package/esm/MultiLinearVariantRenderer/components/MultiLinearVariantRendering.d.ts +4 -0
  61. package/esm/MultiLinearVariantRenderer/components/MultiLinearVariantRendering.js +23 -2
  62. package/esm/MultiLinearVariantRenderer/makeImageData.js +12 -12
  63. package/esm/PlinkLDAdapter/PlinkLDAdapter.d.ts +25 -0
  64. package/esm/PlinkLDAdapter/PlinkLDAdapter.js +147 -0
  65. package/esm/PlinkLDAdapter/PlinkLDTabixAdapter.d.ts +24 -0
  66. package/esm/PlinkLDAdapter/PlinkLDTabixAdapter.js +156 -0
  67. package/esm/PlinkLDAdapter/configSchema.d.ts +10 -0
  68. package/esm/PlinkLDAdapter/configSchema.js +25 -0
  69. package/esm/PlinkLDAdapter/configSchemaTabix.d.ts +24 -0
  70. package/esm/PlinkLDAdapter/configSchemaTabix.js +46 -0
  71. package/esm/PlinkLDAdapter/index.d.ts +2 -0
  72. package/esm/PlinkLDAdapter/index.js +25 -0
  73. package/esm/PlinkLDAdapter/types.d.ts +29 -0
  74. package/esm/PlinkLDAdapter/types.js +1 -0
  75. package/esm/VariantFeatureWidget/VariantSampleGrid/VariantSampleGrid.js +1 -1
  76. package/esm/VariantRPC/MultiVariantGetFeatureDetails.d.ts +14 -0
  77. package/esm/VariantRPC/MultiVariantGetFeatureDetails.js +15 -0
  78. package/esm/VariantRPC/MultiVariantGetGenotypeMatrix.js +4 -1
  79. package/esm/VariantRPC/MultiVariantGetSimplifiedFeatures.js +3 -3
  80. package/esm/VariantRPC/executeClusterGenotypeMatrix.js +6 -3
  81. package/esm/VariantRPC/getGenotypeMatrix.d.ts +2 -3
  82. package/esm/VariantRPC/getGenotypeMatrix.js +4 -5
  83. package/esm/VariantRPC/getLDMatrix.d.ts +47 -0
  84. package/esm/VariantRPC/getLDMatrix.js +387 -0
  85. package/esm/VariantRPC/getLDMatrixFromPlink.d.ts +16 -0
  86. package/esm/VariantRPC/getLDMatrixFromPlink.js +105 -0
  87. package/esm/VariantRPC/getPhasedGenotypeMatrix.d.ts +2 -3
  88. package/esm/VariantRPC/getPhasedGenotypeMatrix.js +4 -5
  89. package/esm/VariantRPC/types.d.ts +3 -0
  90. package/esm/VcfAdapter/VcfAdapter.d.ts +1 -1
  91. package/esm/VcfAdapter/VcfAdapter.js +1 -2
  92. package/esm/VcfExtensionPoints/index.js +29 -3
  93. package/esm/VcfFeature/index.d.ts +2 -1
  94. package/esm/VcfFeature/index.js +4 -2
  95. package/esm/index.d.ts +1 -0
  96. package/esm/index.js +23 -0
  97. package/esm/shared/MultiVariantBaseModel.d.ts +2626 -26
  98. package/esm/shared/MultiVariantBaseModel.js +88 -39
  99. package/esm/shared/SharedVariantConfigSchema.d.ts +27 -1
  100. package/esm/shared/SharedVariantConfigSchema.js +28 -1
  101. package/esm/shared/VariantFeatureCache.d.ts +27 -0
  102. package/esm/shared/VariantFeatureCache.js +48 -0
  103. package/esm/shared/VariantRendererType.d.ts +23 -0
  104. package/esm/shared/VariantRendererType.js +15 -0
  105. package/esm/shared/applyColorPalette.d.ts +9 -0
  106. package/esm/shared/applyColorPalette.js +23 -0
  107. package/esm/shared/colorByAutorun.d.ts +10 -0
  108. package/esm/shared/colorByAutorun.js +39 -0
  109. package/esm/shared/components/AddFiltersDialog.d.ts +3 -3
  110. package/esm/shared/components/AddFiltersDialog.js +29 -22
  111. package/esm/shared/components/LDFilterDialog.d.ts +13 -0
  112. package/esm/shared/components/LDFilterDialog.js +102 -0
  113. package/esm/shared/components/MAFFilterDialog.js +23 -16
  114. package/esm/shared/components/RecombinationTrack.d.ts +21 -0
  115. package/esm/shared/components/RecombinationTrack.js +54 -0
  116. package/esm/shared/components/RecombinationYScaleBar.d.ts +7 -0
  117. package/esm/shared/components/RecombinationYScaleBar.js +34 -0
  118. package/esm/shared/components/SetColorDialogRowPalettizer.d.ts +3 -8
  119. package/esm/shared/components/SetColorDialogRowPalettizer.js +2 -14
  120. package/esm/shared/drawAlleleCount.js +9 -0
  121. package/esm/shared/drawPhased.d.ts +1 -1
  122. package/esm/shared/drawPhased.js +31 -2
  123. package/esm/shared/mafFilterUtils.d.ts +5 -0
  124. package/esm/shared/mafFilterUtils.js +17 -0
  125. package/esm/shared/minorAlleleFrequencyUtils.d.ts +4 -2
  126. package/esm/shared/minorAlleleFrequencyUtils.js +261 -19
  127. package/esm/shared/setupMultiVariantAutoruns.js +2 -0
  128. package/package.json +11 -10
@@ -0,0 +1,102 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import Dialog from '@jbrowse/core/ui/Dialog';
4
+ import { Alert, Box, Button, DialogActions, DialogContent, FormControlLabel, Switch, TextField, Typography, } from '@mui/material';
5
+ export default function LDFilterDialog({ model, handleClose, }) {
6
+ const { minorAlleleFrequencyFilter, hweFilterThreshold, callRateFilter, filterStats, } = model;
7
+ const [maf, setMaf] = useState(`${minorAlleleFrequencyFilter}`);
8
+ const [hweEnabled, setHweEnabled] = useState(hweFilterThreshold > 0);
9
+ const [hweThreshold, setHweThreshold] = useState(hweFilterThreshold > 0 ? `${hweFilterThreshold}` : '0.001');
10
+ const [callRateEnabled, setCallRateEnabled] = useState(callRateFilter > 0);
11
+ const [callRate, setCallRate] = useState(callRateFilter > 0 ? `${callRateFilter}` : '0.95');
12
+ const [mafError, setMafError] = useState();
13
+ const [hweError, setHweError] = useState();
14
+ const [callRateError, setCallRateError] = useState();
15
+ const validateMaf = (val) => {
16
+ const num = Number.parseFloat(val);
17
+ if (Number.isNaN(num)) {
18
+ setMafError('Please enter a valid number');
19
+ return false;
20
+ }
21
+ if (num < 0 || num > 0.5) {
22
+ setMafError('MAF must be between 0 and 0.5');
23
+ return false;
24
+ }
25
+ setMafError(undefined);
26
+ return true;
27
+ };
28
+ const validateHwe = (val) => {
29
+ const num = Number.parseFloat(val);
30
+ if (Number.isNaN(num)) {
31
+ setHweError('Please enter a valid number');
32
+ return false;
33
+ }
34
+ if (num <= 0 || num > 1) {
35
+ setHweError('P-value must be between 0 and 1');
36
+ return false;
37
+ }
38
+ setHweError(undefined);
39
+ return true;
40
+ };
41
+ const validateCallRate = (val) => {
42
+ const num = Number.parseFloat(val);
43
+ if (Number.isNaN(num)) {
44
+ setCallRateError('Please enter a valid number');
45
+ return false;
46
+ }
47
+ if (num < 0 || num > 1) {
48
+ setCallRateError('Call rate must be between 0 and 1');
49
+ return false;
50
+ }
51
+ setCallRateError(undefined);
52
+ return true;
53
+ };
54
+ const hasError = !!mafError ||
55
+ (hweEnabled && !!hweError) ||
56
+ (callRateEnabled && !!callRateError);
57
+ return (_jsxs(Dialog, { open: true, onClose: handleClose, title: "LD Filter Settings", children: [_jsxs(DialogContent, { style: { width: 500 }, children: [filterStats ? (_jsxs(Alert, { severity: "info", style: { marginBottom: 16 }, children: [_jsx(Typography, { variant: "subtitle2", gutterBottom: true, children: "Filter Statistics" }), _jsxs(Box, { component: "ul", sx: { margin: 0, paddingLeft: 2 }, children: [_jsxs("li", { children: ["Total variants in region: ", filterStats.totalVariants] }), _jsxs("li", { children: ["Passed all filters: ", filterStats.passedVariants] }), filterStats.filteredByMaf > 0 && (_jsxs("li", { children: ["Filtered by MAF: ", filterStats.filteredByMaf] })), filterStats.filteredByLength > 0 && (_jsxs("li", { children: ["Filtered by length: ", filterStats.filteredByLength] })), filterStats.filteredByMultiallelic > 0 && (_jsxs("li", { children: ["Filtered by multiallelic: ", filterStats.filteredByMultiallelic] })), filterStats.filteredByHwe > 0 && (_jsxs("li", { children: ["Filtered by HWE: ", filterStats.filteredByHwe] })), filterStats.filteredByCallRate > 0 && (_jsxs("li", { children: ["Filtered by call rate: ", filterStats.filteredByCallRate] }))] })] })) : null, _jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: "Minor Allele Frequency (MAF) Filter" }), _jsx(Typography, { variant: "body2", color: "textSecondary", component: "p", children: "Exclude variants with minor allele frequency below this threshold." }), _jsx(TextField, { value: maf, fullWidth: true, size: "small", label: "MAF threshold (0-0.5)", error: !!mafError, helperText: mafError, onChange: event => {
58
+ const val = event.target.value;
59
+ setMaf(val);
60
+ validateMaf(val);
61
+ }, style: { marginBottom: 24 } }), _jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: "Hardy-Weinberg Equilibrium (HWE) Filter" }), _jsx(Typography, { variant: "body2", color: "textSecondary", component: "p", children: "Exclude variants that deviate significantly from HWE, which may indicate genotyping errors or population stratification. This follows Haploview's approach." }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: hweEnabled, onChange: e => {
62
+ setHweEnabled(e.target.checked);
63
+ } }), label: "Enable HWE filter" }), hweEnabled ? (_jsx(TextField, { value: hweThreshold, fullWidth: true, size: "small", label: "P-value threshold", error: !!hweError, helperText: hweError ||
64
+ 'Variants with HWE p-value below this threshold are excluded (default: 0.001)', onChange: event => {
65
+ const val = event.target.value;
66
+ setHweThreshold(val);
67
+ validateHwe(val);
68
+ }, style: { marginTop: 8, marginBottom: 24 } })) : (_jsx("div", { style: { marginBottom: 24 } })), _jsx(Typography, { variant: "subtitle1", gutterBottom: true, children: "Call Rate Filter" }), _jsx(Typography, { variant: "body2", color: "textSecondary", component: "p", children: "Exclude variants with too many missing genotypes. Call rate is the proportion of samples with non-missing genotype calls." }), _jsx(FormControlLabel, { control: _jsx(Switch, { checked: callRateEnabled, onChange: e => {
69
+ setCallRateEnabled(e.target.checked);
70
+ } }), label: "Enable call rate filter" }), callRateEnabled ? (_jsx(TextField, { value: callRate, fullWidth: true, size: "small", label: "Minimum call rate (0-1)", error: !!callRateError, helperText: callRateError ||
71
+ 'Variants with call rate below this threshold are excluded (default: 0.95 = 95%)', onChange: event => {
72
+ const val = event.target.value;
73
+ setCallRate(val);
74
+ validateCallRate(val);
75
+ }, style: { marginTop: 8 } })) : null] }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: handleClose, color: "primary", children: "Cancel" }), _jsx(Button, { onClick: () => {
76
+ const mafVal = Number.parseFloat(maf);
77
+ if (!Number.isNaN(mafVal) && mafVal >= 0 && mafVal <= 0.5) {
78
+ model.setMafFilter(mafVal);
79
+ }
80
+ if (hweEnabled) {
81
+ const hweVal = Number.parseFloat(hweThreshold);
82
+ if (!Number.isNaN(hweVal) && hweVal > 0 && hweVal <= 1) {
83
+ model.setHweFilter(hweVal);
84
+ }
85
+ }
86
+ else {
87
+ model.setHweFilter(0);
88
+ }
89
+ if (callRateEnabled) {
90
+ const callRateVal = Number.parseFloat(callRate);
91
+ if (!Number.isNaN(callRateVal) &&
92
+ callRateVal >= 0 &&
93
+ callRateVal <= 1) {
94
+ model.setCallRateFilter(callRateVal);
95
+ }
96
+ }
97
+ else {
98
+ model.setCallRateFilter(0);
99
+ }
100
+ handleClose();
101
+ }, color: "primary", variant: "contained", disabled: hasError, children: "Apply" })] })] }));
102
+ }
@@ -1,22 +1,29 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
- import { makeStyles } from '@jbrowse/core/util/tss-react';
4
- import { Button, Dialog, DialogActions, DialogContent, TextField, Typography, } from '@mui/material';
5
- const useStyles = makeStyles()({
6
- root: {
7
- width: 500,
8
- },
9
- });
3
+ import Dialog from '@jbrowse/core/ui/Dialog';
4
+ import { Button, DialogActions, DialogContent, TextField, Typography, } from '@mui/material';
10
5
  export default function MAFFilterDialog({ model, handleClose, }) {
11
- const { minorAlleleFrequencyFilter = '' } = model;
12
- const { classes } = useStyles();
6
+ const { minorAlleleFrequencyFilter = 0 } = model;
13
7
  const [maf, setMaf] = useState(`${minorAlleleFrequencyFilter}`);
14
- return (_jsx(Dialog, { open: true, onClose: handleClose, title: "Set minor allele frequency (MAF)", children: _jsxs(DialogContent, { className: classes.root, children: [_jsx(Typography, { children: "Set minor allele frequency cutoff track. This will filter out rare variants that might not contribute to meaningful large scale patterns" }), _jsx(TextField, { value: maf, autoFocus: true, placeholder: "Enter MAF", onChange: event => {
15
- setMaf(event.target.value);
16
- } }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", color: "primary", type: "submit", autoFocus: true, onClick: () => {
17
- if (!Number.isNaN(+maf)) {
18
- model.setMafFilter(+maf);
19
- }
8
+ const [error, setError] = useState();
9
+ return (_jsxs(Dialog, { open: true, onClose: handleClose, title: "Set minor allele frequency (MAF) filter", children: [_jsxs(DialogContent, { style: { width: 400 }, children: [_jsx(Typography, { children: "Filter out variants with minor allele frequency below this threshold. Valid range: 0 to 0.5" }), _jsx(TextField, { value: maf, autoFocus: true, fullWidth: true, margin: "normal", label: "MAF threshold", placeholder: "Enter MAF (0-0.5)", error: !!error, helperText: error, onChange: event => {
10
+ const val = event.target.value;
11
+ setMaf(val);
12
+ const num = Number.parseFloat(val);
13
+ if (Number.isNaN(num)) {
14
+ setError('Please enter a valid number');
15
+ }
16
+ else if (num < 0 || num > 0.5) {
17
+ setError('MAF must be between 0 and 0.5');
18
+ }
19
+ else {
20
+ setError(undefined);
21
+ }
22
+ } })] }), _jsxs(DialogActions, { children: [_jsx(Button, { onClick: handleClose, color: "primary", children: "Cancel" }), _jsx(Button, { onClick: () => {
23
+ const val = Number.parseFloat(maf);
24
+ if (!Number.isNaN(val) && val >= 0 && val <= 0.5) {
25
+ model.setMafFilter(val);
20
26
  handleClose();
21
- }, children: "Submit" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: handleClose, children: "Cancel" })] })] }) }));
27
+ }
28
+ }, color: "primary", variant: "contained", disabled: !!error, children: "Submit" })] })] }));
22
29
  }
@@ -0,0 +1,21 @@
1
+ interface RecombinationTrackModel {
2
+ recombination?: {
3
+ values: number[];
4
+ positions: number[];
5
+ };
6
+ recombinationZoneHeight: number;
7
+ }
8
+ declare const RecombinationTrack: ({ model, recombination: recombinationProp, width, height, exportSVG, useGenomicPositions, regionStart, bpPerPx, }: {
9
+ model?: RecombinationTrackModel;
10
+ recombination?: {
11
+ values: number[];
12
+ positions: number[];
13
+ };
14
+ width: number;
15
+ height?: number;
16
+ exportSVG?: boolean;
17
+ useGenomicPositions?: boolean;
18
+ regionStart?: number;
19
+ bpPerPx?: number;
20
+ }) => import("react/jsx-runtime").JSX.Element | null;
21
+ export default RecombinationTrack;
@@ -0,0 +1,54 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { getFillProps, getStrokeProps } from '@jbrowse/core/util';
3
+ import { observer } from 'mobx-react';
4
+ const YSCALEBAR_LABEL_OFFSET = 5;
5
+ const FILL_COLOR = 'rgba(59, 130, 246, 0.2)';
6
+ const STROKE_COLOR = 'rgb(59, 130, 246)';
7
+ const RecombinationTrack = observer(function RecombinationTrack({ model, recombination: recombinationProp, width, height, exportSVG, useGenomicPositions, regionStart, bpPerPx, }) {
8
+ const recombination = recombinationProp ?? model?.recombination;
9
+ const trackHeight = height ?? model?.recombinationZoneHeight ?? 50;
10
+ if (!recombination || recombination.values.length === 0) {
11
+ return null;
12
+ }
13
+ const topPadding = YSCALEBAR_LABEL_OFFSET;
14
+ const bottomPadding = YSCALEBAR_LABEL_OFFSET;
15
+ const plotHeight = trackHeight - topPadding - bottomPadding;
16
+ const maxValue = Math.max(...recombination.values, 0.1);
17
+ const points = [];
18
+ let firstX;
19
+ let lastX;
20
+ const numSnps = recombination.values.length + 1;
21
+ for (let i = 0; i < recombination.values.length; i++) {
22
+ const value = recombination.values[i];
23
+ let x;
24
+ if (useGenomicPositions && regionStart !== undefined && bpPerPx) {
25
+ x = (recombination.positions[i] - regionStart) / bpPerPx;
26
+ }
27
+ else {
28
+ x = ((i + 1) * width) / numSnps;
29
+ }
30
+ const y = topPadding + plotHeight * (1 - value / maxValue);
31
+ if (firstX === undefined) {
32
+ firstX = x;
33
+ }
34
+ lastX = x;
35
+ points.push(`${points.length === 0 ? 'M' : 'L'} ${x.toFixed(1)} ${y.toFixed(1)}`);
36
+ }
37
+ if (points.length < 2 || firstX === undefined || lastX === undefined) {
38
+ return null;
39
+ }
40
+ const baseY = topPadding + plotHeight;
41
+ const areaPath = `${points.join(' ')} L ${lastX.toFixed(1)} ${baseY.toFixed(1)} L ${firstX.toFixed(1)} ${baseY.toFixed(1)} Z`;
42
+ if (exportSVG) {
43
+ return (_jsxs("g", { children: [_jsx("path", { d: areaPath, ...getFillProps(FILL_COLOR) }), _jsx("path", { d: points.join(' '), fill: "none", ...getStrokeProps(STROKE_COLOR), strokeWidth: 1.5 })] }));
44
+ }
45
+ return (_jsxs("svg", { style: {
46
+ position: 'absolute',
47
+ left: 0,
48
+ top: 0,
49
+ width,
50
+ height: trackHeight,
51
+ pointerEvents: 'none',
52
+ }, children: [_jsx("path", { d: areaPath, fill: FILL_COLOR }), _jsx("path", { d: points.join(' '), fill: "none", stroke: STROKE_COLOR, strokeWidth: 1.5 })] }));
53
+ });
54
+ export default RecombinationTrack;
@@ -0,0 +1,7 @@
1
+ declare const Y_AXIS_WIDTH = 40;
2
+ export default function RecombinationYScaleBar({ height, maxValue, exportSVG, }: {
3
+ height: number;
4
+ maxValue: number;
5
+ exportSVG?: boolean;
6
+ }): import("react/jsx-runtime").JSX.Element;
7
+ export { Y_AXIS_WIDTH };
@@ -0,0 +1,34 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useTheme } from '@mui/material';
3
+ const Y_AXIS_WIDTH = 40;
4
+ const YSCALEBAR_LABEL_OFFSET = 5;
5
+ export default function RecombinationYScaleBar({ height, maxValue, exportSVG, }) {
6
+ const theme = useTheme();
7
+ const topPadding = YSCALEBAR_LABEL_OFFSET;
8
+ const bottomPadding = YSCALEBAR_LABEL_OFFSET;
9
+ const plotHeight = height - topPadding - bottomPadding;
10
+ const fg = exportSVG ? '#333' : theme.palette.text.primary;
11
+ const bg = exportSVG ? '#fafafa' : theme.palette.background.default;
12
+ const numTicks = 4;
13
+ const ticks = [];
14
+ for (let i = 0; i <= numTicks; i++) {
15
+ const value = (maxValue * i) / numTicks;
16
+ const y = topPadding + plotHeight * (1 - i / numTicks);
17
+ ticks.push({ value, y });
18
+ }
19
+ const range0 = topPadding + 0.5;
20
+ const range1 = topPadding + plotHeight + 0.5;
21
+ const content = (_jsxs(_Fragment, { children: [_jsx("rect", { x: 0, y: 0, width: Y_AXIS_WIDTH, height: height, fill: bg }), _jsxs("g", { fill: "none", fontSize: 9, fontFamily: "sans-serif", textAnchor: "end", strokeWidth: 1, children: [_jsx("path", { stroke: fg, d: `M${Y_AXIS_WIDTH - 6},${range0}H${Y_AXIS_WIDTH - 0.5}V${range1}H${Y_AXIS_WIDTH - 6}` }), ticks.map((tick, idx) => (_jsxs("g", { transform: `translate(0,${tick.y})`, children: [_jsx("line", { stroke: fg, x1: Y_AXIS_WIDTH - 6, x2: Y_AXIS_WIDTH, y1: 0.5, y2: 0.5 }), _jsx("text", { stroke: bg, strokeWidth: 2, paintOrder: "stroke", fill: fg, dy: "0.32em", x: Y_AXIS_WIDTH - 9, y: 0.5, children: tick.value.toFixed(2) })] }, idx)))] }), _jsx("text", { x: 10, y: height / 2, fontSize: 10, fill: fg, fontFamily: "sans-serif", textAnchor: "middle", transform: `rotate(-90, 10, ${height / 2})`, children: "1 - r\u00B2" })] }));
22
+ if (exportSVG) {
23
+ return _jsx("g", { children: content });
24
+ }
25
+ return (_jsx("svg", { style: {
26
+ position: 'absolute',
27
+ left: 0,
28
+ top: 0,
29
+ width: Y_AXIS_WIDTH,
30
+ height,
31
+ zIndex: 1,
32
+ }, width: Y_AXIS_WIDTH, height: height, children: content }));
33
+ }
34
+ export { Y_AXIS_WIDTH };
@@ -1,10 +1,5 @@
1
+ import type { Source } from '../types.ts';
1
2
  export default function SetColorDialogRowPalettizer({ setCurrLayout, currLayout, }: {
2
- currLayout: {
3
- name: string;
4
- [key: string]: unknown;
5
- }[];
6
- setCurrLayout: (arg: {
7
- name: string;
8
- [key: string]: unknown;
9
- }[]) => void;
3
+ currLayout: Source[];
4
+ setCurrLayout: (arg: Source[]) => void;
10
5
  }): import("react/jsx-runtime").JSX.Element | null;
@@ -1,7 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { set1 } from '@jbrowse/core/ui/colors';
3
- import { randomColor } from '@jbrowse/core/util/color';
4
2
  import { Button } from '@mui/material';
3
+ import { applyColorPalette } from "../applyColorPalette.js";
5
4
  const excludedFields = new Set(['name', 'color', 'label', 'id', 'HP']);
6
5
  export default function SetColorDialogRowPalettizer({ setCurrLayout, currLayout, }) {
7
6
  const firstRow = currLayout[0];
@@ -10,18 +9,7 @@ export default function SetColorDialogRowPalettizer({ setCurrLayout, currLayout,
10
9
  }
11
10
  const fields = Object.keys(firstRow).filter(f => !excludedFields.has(f));
12
11
  return (_jsxs("div", { children: ["Create color palette based on...", fields.map(field => (_jsx(Button, { variant: "contained", color: "inherit", onClick: () => {
13
- const counts = new Map();
14
- for (const row of currLayout) {
15
- const key = row[field];
16
- counts.set(key, (counts.get(key) || 0) + 1);
17
- }
18
- const colorMap = Object.fromEntries([...counts.entries()]
19
- .sort((a, b) => a[1] - b[1])
20
- .map(([key], idx) => [key, set1[idx] || randomColor(key)]));
21
- setCurrLayout(currLayout.map(row => ({
22
- ...row,
23
- color: colorMap[row[field]],
24
- })));
12
+ setCurrLayout(applyColorPalette(currLayout, field));
25
13
  }, children: field }, field))), _jsx(Button, { onClick: () => {
26
14
  setCurrLayout(currLayout.map(row => ({ ...row, color: undefined })));
27
15
  }, children: "Clear colors" })] }));
@@ -74,6 +74,15 @@ export function drawColorAlleleCount(c, ctx, x, y, w, h, featureType = '', featu
74
74
  ctx.fill();
75
75
  }
76
76
  }
77
+ else if (featureType === 'insertion') {
78
+ const widthExtension = 3;
79
+ ctx.beginPath();
80
+ ctx.moveTo(x - f2 - widthExtension, y - f2);
81
+ ctx.lineTo(x + w + f2 + widthExtension, y - f2);
82
+ ctx.lineTo(x + w / 2, y + h + f2);
83
+ ctx.closePath();
84
+ ctx.fill();
85
+ }
77
86
  else {
78
87
  ctx.fillRect(x - f2, y - f2, w + f2, h + f2);
79
88
  }
@@ -1 +1 @@
1
- export declare function drawPhased(alleles: string[], ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, HP: number, PS?: string, drawReference?: boolean, alpha?: number): string | undefined;
1
+ export declare function drawPhased(alleles: string[], ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, HP: number, PS?: string, drawReference?: boolean, alpha?: number, featureType?: string, featureStrand?: number): string | undefined;
@@ -4,7 +4,7 @@ import { REFERENCE_COLOR, UNPHASED_COLOR, f2 } from "./constants.js";
4
4
  function colorify(n) {
5
5
  return `hsl(${n % 255}, 50%, 50%)`;
6
6
  }
7
- export function drawPhased(alleles, ctx, x, y, w, h, HP, PS, drawReference = true, alpha = 1) {
7
+ export function drawPhased(alleles, ctx, x, y, w, h, HP, PS, drawReference = true, alpha = 1, featureType = '', featureStrand) {
8
8
  const allele = +alleles[HP];
9
9
  const c = allele
10
10
  ? PS !== undefined
@@ -15,7 +15,36 @@ export function drawPhased(alleles, ctx, x, y, w, h, HP, PS, drawReference = tru
15
15
  : undefined;
16
16
  if (c) {
17
17
  ctx.fillStyle = alpha !== 1 ? colord(c).alpha(alpha).toHex() : c;
18
- ctx.fillRect(x - f2, y - f2, w + f2, h + f2);
18
+ if (featureType === 'inversion') {
19
+ if (featureStrand === 1) {
20
+ ctx.beginPath();
21
+ ctx.moveTo(x - f2, y - f2);
22
+ ctx.lineTo(x - f2, y + h + f2);
23
+ ctx.lineTo(x + w + f2, y + h / 2);
24
+ ctx.closePath();
25
+ ctx.fill();
26
+ }
27
+ else {
28
+ ctx.beginPath();
29
+ ctx.moveTo(x + w + f2, y - f2);
30
+ ctx.lineTo(x + w + f2, y + h + f2);
31
+ ctx.lineTo(x - f2, y + h / 2);
32
+ ctx.closePath();
33
+ ctx.fill();
34
+ }
35
+ }
36
+ else if (featureType === 'insertion') {
37
+ const widthExtension = 3;
38
+ ctx.beginPath();
39
+ ctx.moveTo(x - f2 - widthExtension, y - f2);
40
+ ctx.lineTo(x + w + f2 + widthExtension, y - f2);
41
+ ctx.lineTo(x + w / 2, y + h + f2);
42
+ ctx.closePath();
43
+ ctx.fill();
44
+ }
45
+ else {
46
+ ctx.fillRect(x - f2, y - f2, w + f2, h + f2);
47
+ }
19
48
  }
20
49
  return c;
21
50
  }
@@ -0,0 +1,5 @@
1
+ import type { MenuItem } from '@jbrowse/core/ui';
2
+ export declare function createMAFFilterMenuItem(model: {
3
+ minorAlleleFrequencyFilter?: number;
4
+ setMafFilter: (arg: number) => void;
5
+ }): MenuItem;
@@ -0,0 +1,17 @@
1
+ import { lazy } from 'react';
2
+ import { getSession } from '@jbrowse/core/util';
3
+ const MAFFilterDialog = lazy(() => import("./components/MAFFilterDialog.js"));
4
+ export function createMAFFilterMenuItem(model) {
5
+ return {
6
+ label: 'Minor allele frequency',
7
+ onClick: () => {
8
+ getSession(model).queueDialog(handleClose => [
9
+ MAFFilterDialog,
10
+ {
11
+ model,
12
+ handleClose,
13
+ },
14
+ ]);
15
+ },
16
+ };
17
+ }
@@ -1,11 +1,13 @@
1
+ import type VcfFeature from '../VcfFeature/index.ts';
1
2
  import type { Feature, LastStopTokenCheck } from '@jbrowse/core/util';
3
+ export declare function calculateAlleleCountsFast(feature: VcfFeature): Record<string, number>;
2
4
  export declare function calculateAlleleCounts(genotypes: Record<string, string>, cacheSplit: Record<string, string[]>): Record<string, number>;
3
5
  export declare function calculateMinorAlleleFrequency(alleleCounts: Record<string, number>): number;
4
- export declare function getFeaturesThatPassMinorAlleleFrequencyFilter({ features, minorAlleleFrequencyFilter, lengthCutoffFilter, lastCheck, genotypesCache, splitCache, }: {
6
+ export declare function getFeaturesThatPassMinorAlleleFrequencyFilter({ features, minorAlleleFrequencyFilter, lengthCutoffFilter, stopTokenCheck, genotypesCache, splitCache, }: {
5
7
  features: Iterable<Feature>;
6
8
  minorAlleleFrequencyFilter: number;
7
9
  lengthCutoffFilter: number;
8
- lastCheck?: LastStopTokenCheck;
10
+ stopTokenCheck?: LastStopTokenCheck;
9
11
  genotypesCache?: Map<string, Record<string, string>>;
10
12
  splitCache?: Record<string, string[]>;
11
13
  }): {