@jbrowse/plugin-dotplot-view 3.6.4 → 3.7.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/DiagonalizeDotplotRpc.d.ts +30 -0
- package/dist/DiagonalizeDotplotRpc.js +156 -0
- package/dist/DotplotDisplay/renderDotplotBlock.js +3 -0
- package/dist/DotplotDisplay/stateModelFactory.d.ts +6 -0
- package/dist/DotplotDisplay/stateModelFactory.js +15 -0
- package/dist/DotplotRenderer/DotplotRenderer.d.ts +3 -12
- package/dist/DotplotRenderer/clamp.d.ts +7 -0
- package/dist/DotplotRenderer/clamp.js +62 -0
- package/dist/DotplotRenderer/drawDotplot.d.ts +5 -4
- package/dist/DotplotRenderer/drawDotplot.js +92 -96
- package/dist/DotplotView/1dview.js +5 -3
- package/dist/DotplotView/components/ColorBySelector.d.ts +5 -0
- package/dist/DotplotView/components/ColorBySelector.js +79 -0
- package/dist/DotplotView/components/DiagonalizationProgressDialog.d.ts +6 -0
- package/dist/DotplotView/components/DiagonalizationProgressDialog.js +125 -0
- package/dist/DotplotView/components/DotplotControls.js +84 -12
- package/dist/DotplotView/components/DotplotTooltips.d.ts +15 -0
- package/dist/DotplotView/components/DotplotTooltips.js +43 -0
- package/dist/DotplotView/components/DotplotView.js +16 -191
- package/dist/DotplotView/components/DotplotWarnings.js +3 -3
- package/dist/DotplotView/components/ImportForm/index.js +0 -1
- package/dist/DotplotView/components/MinLengthSlider.d.ts +5 -0
- package/dist/DotplotView/components/MinLengthSlider.js +44 -0
- package/dist/DotplotView/components/MouseInteractionLayer.d.ts +17 -0
- package/dist/DotplotView/components/MouseInteractionLayer.js +18 -0
- package/dist/DotplotView/components/OpacitySlider.d.ts +5 -0
- package/dist/DotplotView/components/OpacitySlider.js +43 -0
- package/dist/DotplotView/components/SelectionContextMenu.d.ts +13 -0
- package/dist/DotplotView/components/SelectionContextMenu.js +42 -0
- package/dist/DotplotView/components/SliderTooltip.d.ts +2 -0
- package/dist/DotplotView/components/SliderTooltip.js +9 -0
- package/dist/DotplotView/components/hooks/useCtrlKeyTracking.d.ts +1 -0
- package/dist/DotplotView/components/hooks/useCtrlKeyTracking.js +24 -0
- package/dist/DotplotView/components/hooks/useCursorMode.d.ts +7 -0
- package/dist/DotplotView/components/hooks/useCursorMode.js +19 -0
- package/dist/DotplotView/components/hooks/useMouseCoordinates.d.ts +29 -0
- package/dist/DotplotView/components/hooks/useMouseCoordinates.js +52 -0
- package/dist/DotplotView/components/hooks/useMouseMoveHandler.d.ts +6 -0
- package/dist/DotplotView/components/hooks/useMouseMoveHandler.js +27 -0
- package/dist/DotplotView/components/hooks/useMouseUpHandler.d.ts +3 -0
- package/dist/DotplotView/components/hooks/useMouseUpHandler.js +31 -0
- package/dist/DotplotView/components/hooks/useWheelHandler.d.ts +8 -0
- package/dist/DotplotView/components/hooks/useWheelHandler.js +47 -0
- package/dist/DotplotView/components/util.js +1 -3
- package/dist/DotplotView/model.d.ts +5 -0
- package/dist/DotplotView/model.js +35 -20
- package/dist/ServerSideRenderedBlockContent.js +3 -20
- package/dist/index.js +2 -0
- package/esm/DiagonalizeDotplotRpc.d.ts +30 -0
- package/esm/DiagonalizeDotplotRpc.js +150 -0
- package/esm/DotplotDisplay/renderDotplotBlock.js +3 -0
- package/esm/DotplotDisplay/stateModelFactory.d.ts +6 -0
- package/esm/DotplotDisplay/stateModelFactory.js +15 -0
- package/esm/DotplotRenderer/DotplotRenderer.d.ts +3 -12
- package/esm/DotplotRenderer/clamp.d.ts +7 -0
- package/esm/DotplotRenderer/clamp.js +58 -0
- package/esm/DotplotRenderer/drawDotplot.d.ts +5 -4
- package/esm/DotplotRenderer/drawDotplot.js +92 -96
- package/esm/DotplotView/1dview.js +5 -3
- package/esm/DotplotView/components/ColorBySelector.d.ts +5 -0
- package/esm/DotplotView/components/ColorBySelector.js +74 -0
- package/esm/DotplotView/components/DiagonalizationProgressDialog.d.ts +6 -0
- package/esm/DotplotView/components/DiagonalizationProgressDialog.js +123 -0
- package/esm/DotplotView/components/DotplotControls.js +52 -13
- package/esm/DotplotView/components/DotplotTooltips.d.ts +15 -0
- package/esm/DotplotView/components/DotplotTooltips.js +7 -0
- package/esm/DotplotView/components/DotplotView.js +17 -159
- package/esm/DotplotView/components/DotplotWarnings.js +4 -4
- package/esm/DotplotView/components/ImportForm/index.js +0 -1
- package/esm/DotplotView/components/MinLengthSlider.d.ts +5 -0
- package/esm/DotplotView/components/MinLengthSlider.js +39 -0
- package/esm/DotplotView/components/MouseInteractionLayer.d.ts +17 -0
- package/esm/DotplotView/components/MouseInteractionLayer.js +12 -0
- package/esm/DotplotView/components/OpacitySlider.d.ts +5 -0
- package/esm/DotplotView/components/OpacitySlider.js +38 -0
- package/esm/DotplotView/components/SelectionContextMenu.d.ts +13 -0
- package/esm/DotplotView/components/SelectionContextMenu.js +39 -0
- package/esm/DotplotView/components/SliderTooltip.d.ts +2 -0
- package/esm/DotplotView/components/SliderTooltip.js +6 -0
- package/esm/DotplotView/components/hooks/useCtrlKeyTracking.d.ts +1 -0
- package/esm/DotplotView/components/hooks/useCtrlKeyTracking.js +21 -0
- package/esm/DotplotView/components/hooks/useCursorMode.d.ts +7 -0
- package/esm/DotplotView/components/hooks/useCursorMode.js +16 -0
- package/esm/DotplotView/components/hooks/useMouseCoordinates.d.ts +29 -0
- package/esm/DotplotView/components/hooks/useMouseCoordinates.js +49 -0
- package/esm/DotplotView/components/hooks/useMouseMoveHandler.d.ts +6 -0
- package/esm/DotplotView/components/hooks/useMouseMoveHandler.js +24 -0
- package/esm/DotplotView/components/hooks/useMouseUpHandler.d.ts +3 -0
- package/esm/DotplotView/components/hooks/useMouseUpHandler.js +28 -0
- package/esm/DotplotView/components/hooks/useWheelHandler.d.ts +8 -0
- package/esm/DotplotView/components/hooks/useWheelHandler.js +44 -0
- package/esm/DotplotView/components/util.js +1 -3
- package/esm/DotplotView/model.d.ts +5 -0
- package/esm/DotplotView/model.js +35 -20
- package/esm/ServerSideRenderedBlockContent.js +4 -21
- package/esm/index.js +2 -0
- package/package.json +4 -4
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Warning } from './clamp';
|
|
1
2
|
import type { Dotplot1DViewModel } from '../DotplotView/model';
|
|
2
3
|
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
3
4
|
import type { RenderArgsDeserialized } from '@jbrowse/core/pluggableElementTypes/renderers/ComparativeServerSideRendererType';
|
|
@@ -6,6 +7,9 @@ export interface DotplotRenderArgsDeserialized extends RenderArgsDeserialized {
|
|
|
6
7
|
height: number;
|
|
7
8
|
width: number;
|
|
8
9
|
highResolutionScaling: number;
|
|
10
|
+
alpha?: number;
|
|
11
|
+
minAlignmentLength?: number;
|
|
12
|
+
colorBy?: string;
|
|
9
13
|
view: {
|
|
10
14
|
hview: Dotplot1DViewModel;
|
|
11
15
|
vview: Dotplot1DViewModel;
|
|
@@ -14,8 +18,5 @@ export interface DotplotRenderArgsDeserialized extends RenderArgsDeserialized {
|
|
|
14
18
|
export declare function drawDotplot(ctx: CanvasRenderingContext2D, props: DotplotRenderArgsDeserialized & {
|
|
15
19
|
views: Dotplot1DViewModel[];
|
|
16
20
|
}): Promise<{
|
|
17
|
-
warnings:
|
|
18
|
-
message: string;
|
|
19
|
-
effect: string;
|
|
20
|
-
}[];
|
|
21
|
+
warnings: Warning[];
|
|
21
22
|
}>;
|
|
@@ -1,25 +1,38 @@
|
|
|
1
1
|
import { readConfObject } from '@jbrowse/core/configuration';
|
|
2
2
|
import { createJBrowseTheme } from '@jbrowse/core/ui';
|
|
3
|
+
import { category10 } from '@jbrowse/core/ui/colors';
|
|
3
4
|
import { bpToPx } from '@jbrowse/core/util/Base1DUtils';
|
|
5
|
+
import { colord } from '@jbrowse/core/util/colord';
|
|
4
6
|
import { MismatchParser } from '@jbrowse/plugin-alignments';
|
|
5
7
|
import { getSnapshot } from 'mobx-state-tree';
|
|
8
|
+
import { clampWithWarnX, clampWithWarnY } from './clamp';
|
|
6
9
|
const { parseCigar } = MismatchParser;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
function hashString(str) {
|
|
11
|
+
let hash = 0;
|
|
12
|
+
for (let i = 0; i < str.length; i++) {
|
|
13
|
+
const char = str.charCodeAt(i);
|
|
14
|
+
hash = (hash << 5) - hash + char;
|
|
15
|
+
hash = hash & hash;
|
|
16
|
+
}
|
|
17
|
+
return Math.abs(hash);
|
|
18
|
+
}
|
|
19
|
+
function getQueryColor(queryName) {
|
|
20
|
+
const hash = hashString(queryName);
|
|
21
|
+
return category10[hash % category10.length];
|
|
22
|
+
}
|
|
23
|
+
function applyAlpha(color, alpha) {
|
|
24
|
+
if (alpha === 1) {
|
|
25
|
+
return color;
|
|
26
|
+
}
|
|
27
|
+
return colord(color).alpha(alpha).toRgbString();
|
|
15
28
|
}
|
|
16
29
|
export async function drawDotplot(ctx, props) {
|
|
17
30
|
var _a, _b;
|
|
18
|
-
const { config, views, height, drawCigar, theme } = props;
|
|
31
|
+
const { config, views, height, drawCigar, theme, alpha = 1, minAlignmentLength = 0, colorBy: colorByOverride, } = props;
|
|
19
32
|
const color = readConfObject(config, 'color');
|
|
20
33
|
const posColor = readConfObject(config, 'posColor');
|
|
21
34
|
const negColor = readConfObject(config, 'negColor');
|
|
22
|
-
const colorBy = readConfObject(config, 'colorBy');
|
|
35
|
+
const colorBy = colorByOverride !== null && colorByOverride !== void 0 ? colorByOverride : readConfObject(config, 'colorBy');
|
|
23
36
|
const lineWidth = readConfObject(config, 'lineWidth');
|
|
24
37
|
const thresholds = readConfObject(config, 'thresholds');
|
|
25
38
|
const palette = readConfObject(config, 'thresholdsPalette');
|
|
@@ -32,60 +45,6 @@ export async function drawDotplot(ctx, props) {
|
|
|
32
45
|
ctx.lineWidth = lineWidth;
|
|
33
46
|
const { bpPerPx: hBpPerPx } = hview;
|
|
34
47
|
const { bpPerPx: vBpPerPx } = vview;
|
|
35
|
-
function clampWithWarnX(num, min, max, feature) {
|
|
36
|
-
const strand = feature.get('strand') || 1;
|
|
37
|
-
if (strand === -1) {
|
|
38
|
-
;
|
|
39
|
-
[max, min] = [min, max];
|
|
40
|
-
}
|
|
41
|
-
if (num < min - fudgeFactor) {
|
|
42
|
-
let start = feature.get('start');
|
|
43
|
-
let end = feature.get('end');
|
|
44
|
-
const refName = feature.get('refName');
|
|
45
|
-
if (strand === -1) {
|
|
46
|
-
;
|
|
47
|
-
[end, start] = [start, end];
|
|
48
|
-
}
|
|
49
|
-
warnings.push({
|
|
50
|
-
message: `feature at (X ${refName}:${start}-${end}) ${r} ${lt}`,
|
|
51
|
-
effect: 'clipped the feature',
|
|
52
|
-
});
|
|
53
|
-
return min;
|
|
54
|
-
}
|
|
55
|
-
if (num > max + fudgeFactor) {
|
|
56
|
-
const strand = feature.get('strand') || 1;
|
|
57
|
-
const start = strand === 1 ? feature.get('start') : feature.get('end');
|
|
58
|
-
const end = strand === 1 ? feature.get('end') : feature.get('start');
|
|
59
|
-
const refName = feature.get('refName');
|
|
60
|
-
warnings.push({
|
|
61
|
-
message: `feature at (X ${refName}:${start}-${end}) ${r} ${gt}`,
|
|
62
|
-
effect: 'clipped the feature',
|
|
63
|
-
});
|
|
64
|
-
return max;
|
|
65
|
-
}
|
|
66
|
-
return num;
|
|
67
|
-
}
|
|
68
|
-
function clampWithWarnY(num, min, max, feature) {
|
|
69
|
-
if (num < min - fudgeFactor) {
|
|
70
|
-
const mate = feature.get('mate');
|
|
71
|
-
const { refName, start, end } = mate;
|
|
72
|
-
warnings.push({
|
|
73
|
-
message: `feature at (Y ${refName}:${start}-${end}) ${r} ${lt}`,
|
|
74
|
-
effect: 'clipped the feature',
|
|
75
|
-
});
|
|
76
|
-
return min;
|
|
77
|
-
}
|
|
78
|
-
if (num > max + fudgeFactor) {
|
|
79
|
-
const mate = feature.get('mate');
|
|
80
|
-
const { refName, start, end } = mate;
|
|
81
|
-
warnings.push({
|
|
82
|
-
message: `feature at (Y ${refName}:${start}-${end}) ${r} ${gt}`,
|
|
83
|
-
effect: 'clipped the feature',
|
|
84
|
-
});
|
|
85
|
-
return max;
|
|
86
|
-
}
|
|
87
|
-
return num;
|
|
88
|
-
}
|
|
89
48
|
const hsnap = {
|
|
90
49
|
...getSnapshot(hview),
|
|
91
50
|
staticBlocks: hview.staticBlocks,
|
|
@@ -97,41 +56,76 @@ export async function drawDotplot(ctx, props) {
|
|
|
97
56
|
width: vview.width,
|
|
98
57
|
};
|
|
99
58
|
const t = createJBrowseTheme(theme);
|
|
100
|
-
|
|
59
|
+
const features = hview.features || [];
|
|
60
|
+
let posColorWithAlpha;
|
|
61
|
+
let negColorWithAlpha;
|
|
62
|
+
let defaultColorWithAlpha;
|
|
63
|
+
const queryColorCache = new Map();
|
|
64
|
+
const getQueryColorWithAlpha = (queryName) => {
|
|
65
|
+
if (!queryColorCache.has(queryName)) {
|
|
66
|
+
const c = getQueryColor(queryName);
|
|
67
|
+
queryColorCache.set(queryName, applyAlpha(c, alpha));
|
|
68
|
+
}
|
|
69
|
+
return queryColorCache.get(queryName);
|
|
70
|
+
};
|
|
71
|
+
if (colorBy === 'strand') {
|
|
72
|
+
posColorWithAlpha = applyAlpha(posColor, alpha);
|
|
73
|
+
negColorWithAlpha = applyAlpha(negColor, alpha);
|
|
74
|
+
}
|
|
75
|
+
else if (colorBy === 'default' && !isCallback) {
|
|
76
|
+
const c = color === '#f0f' ? t.palette.text.primary : color;
|
|
77
|
+
defaultColorWithAlpha = applyAlpha(c, alpha);
|
|
78
|
+
}
|
|
79
|
+
for (const feature of features) {
|
|
101
80
|
const strand = feature.get('strand') || 1;
|
|
102
|
-
const
|
|
103
|
-
const
|
|
81
|
+
const fStart = feature.get('start');
|
|
82
|
+
const fEnd = feature.get('end');
|
|
83
|
+
if (minAlignmentLength > 0) {
|
|
84
|
+
const alignmentLength = Math.abs(fEnd - fStart);
|
|
85
|
+
if (alignmentLength < minAlignmentLength) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
104
89
|
const refName = feature.get('refName');
|
|
105
90
|
const mate = feature.get('mate');
|
|
106
91
|
const mateRef = mate.refName;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
r = palette[i] || 'black';
|
|
113
|
-
break;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
else if (colorBy === 'meanQueryIdentity') {
|
|
118
|
-
r = `hsl(${feature.get('meanScore') * 200},100%,40%)`;
|
|
92
|
+
const start = strand === 1 ? fStart : fEnd;
|
|
93
|
+
const end = strand === 1 ? fEnd : fStart;
|
|
94
|
+
let colorWithAlpha;
|
|
95
|
+
if (colorBy === 'strand') {
|
|
96
|
+
colorWithAlpha = strand === -1 ? negColorWithAlpha : posColorWithAlpha;
|
|
119
97
|
}
|
|
120
|
-
else if (colorBy === '
|
|
121
|
-
|
|
98
|
+
else if (colorBy === 'query') {
|
|
99
|
+
const queryName = refName;
|
|
100
|
+
colorWithAlpha = getQueryColorWithAlpha(queryName);
|
|
122
101
|
}
|
|
123
|
-
else if (colorBy === '
|
|
124
|
-
|
|
102
|
+
else if (colorBy === 'default' && !isCallback) {
|
|
103
|
+
colorWithAlpha = defaultColorWithAlpha;
|
|
125
104
|
}
|
|
126
|
-
else
|
|
127
|
-
r =
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
105
|
+
else {
|
|
106
|
+
let r = 'black';
|
|
107
|
+
if (colorBy === 'identity') {
|
|
108
|
+
const identity = feature.get('identity');
|
|
109
|
+
for (let i = 0; i < thresholds.length; i++) {
|
|
110
|
+
if (identity > +thresholds[i]) {
|
|
111
|
+
r = palette[i] || 'black';
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
else if (colorBy === 'meanQueryIdentity') {
|
|
117
|
+
r = `hsl(${feature.get('meanScore') * 200},100%,40%)`;
|
|
118
|
+
}
|
|
119
|
+
else if (colorBy === 'mappingQuality') {
|
|
120
|
+
r = `hsl(${feature.get('mappingQual')},100%,40%)`;
|
|
121
|
+
}
|
|
122
|
+
else if (colorBy === 'default' && isCallback) {
|
|
123
|
+
r = readConfObject(config, 'color', { feature });
|
|
124
|
+
}
|
|
125
|
+
colorWithAlpha = applyAlpha(r, alpha);
|
|
132
126
|
}
|
|
133
|
-
ctx.fillStyle =
|
|
134
|
-
ctx.strokeStyle =
|
|
127
|
+
ctx.fillStyle = colorWithAlpha;
|
|
128
|
+
ctx.strokeStyle = colorWithAlpha;
|
|
135
129
|
const b10 = bpToPx({ self: hsnap, refName, coord: start });
|
|
136
130
|
const b20 = bpToPx({ self: hsnap, refName, coord: end });
|
|
137
131
|
const e10 = bpToPx({ self: vsnap, refName: mateRef, coord: mate.start });
|
|
@@ -145,7 +139,9 @@ export async function drawDotplot(ctx, props) {
|
|
|
145
139
|
const e1 = e10.offsetPx - db2;
|
|
146
140
|
const e2 = e20.offsetPx - db2;
|
|
147
141
|
if (Math.abs(b1 - b2) <= 4 && Math.abs(e1 - e2) <= 4) {
|
|
148
|
-
|
|
142
|
+
ctx.beginPath();
|
|
143
|
+
ctx.arc(b1, height - e1, lineWidth / 2, 0, 2 * Math.PI);
|
|
144
|
+
ctx.fill();
|
|
149
145
|
}
|
|
150
146
|
else {
|
|
151
147
|
let currX = b1;
|
|
@@ -170,8 +166,8 @@ export async function drawDotplot(ctx, props) {
|
|
|
170
166
|
else if (op === 'I') {
|
|
171
167
|
currY += val / vBpPerPx;
|
|
172
168
|
}
|
|
173
|
-
currX = clampWithWarnX(currX, b1, b2, feature);
|
|
174
|
-
currY = clampWithWarnY(currY, e1, e2, feature);
|
|
169
|
+
currX = clampWithWarnX(currX, b1, b2, feature, warnings);
|
|
170
|
+
currY = clampWithWarnY(currY, e1, e2, feature, warnings);
|
|
175
171
|
if (Math.abs(currX - lastDrawnX) > 0.5 ||
|
|
176
172
|
Math.abs(currY - lastDrawnY) > 0.5) {
|
|
177
173
|
ctx.lineTo(currX, height - currY);
|
|
@@ -193,13 +189,13 @@ export async function drawDotplot(ctx, props) {
|
|
|
193
189
|
if (warnings.length <= 5) {
|
|
194
190
|
if (b10 === undefined || b20 === undefined) {
|
|
195
191
|
warnings.push({
|
|
196
|
-
message: `feature at (X ${refName}:${start}-${end}) not plotted, fell outside of range`,
|
|
192
|
+
message: `feature at (X-coord: ${refName}:${start}-${end}) not plotted, fell outside of range`,
|
|
197
193
|
effect: 'feature not rendered',
|
|
198
194
|
});
|
|
199
195
|
}
|
|
200
196
|
else {
|
|
201
197
|
warnings.push({
|
|
202
|
-
message: `feature at (Y ${mateRef}:${mate.start}-${mate.end}) not plotted, fell outside of range`,
|
|
198
|
+
message: `feature at (Y-coord: ${mateRef}:${mate.start}-${mate.end}) not plotted, fell outside of range`,
|
|
203
199
|
effect: 'feature not rendered',
|
|
204
200
|
});
|
|
205
201
|
}
|
|
@@ -14,16 +14,18 @@ const Dotplot1DView = Base1DView.extend(self => {
|
|
|
14
14
|
return scaleFactor.get();
|
|
15
15
|
},
|
|
16
16
|
get maxBpPerPx() {
|
|
17
|
-
return self.totalBp / (self.width
|
|
17
|
+
return self.totalBp / (self.width * 0.9);
|
|
18
18
|
},
|
|
19
19
|
get minBpPerPx() {
|
|
20
20
|
return 1 / 50;
|
|
21
21
|
},
|
|
22
22
|
get maxOffset() {
|
|
23
|
-
|
|
23
|
+
const leftPadding = 10;
|
|
24
|
+
return self.displayedRegionsTotalPx - leftPadding;
|
|
24
25
|
},
|
|
25
26
|
get minOffset() {
|
|
26
|
-
|
|
27
|
+
const rightPadding = 30;
|
|
28
|
+
return -self.width + rightPadding;
|
|
27
29
|
},
|
|
28
30
|
},
|
|
29
31
|
actions: {
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import CascadingMenuButton from '@jbrowse/core/ui/CascadingMenuButton';
|
|
3
|
+
import PaletteIcon from '@mui/icons-material/Palette';
|
|
4
|
+
import { observer } from 'mobx-react';
|
|
5
|
+
const ColorBySelector = observer(function ({ model, }) {
|
|
6
|
+
var _a, _b;
|
|
7
|
+
const firstDisplay = (_a = model.tracks[0]) === null || _a === void 0 ? void 0 : _a.displays[0];
|
|
8
|
+
const colorBy = (_b = firstDisplay === null || firstDisplay === void 0 ? void 0 : firstDisplay.colorBy) !== null && _b !== void 0 ? _b : 'default';
|
|
9
|
+
const setColorBy = (value) => {
|
|
10
|
+
for (const track of model.tracks) {
|
|
11
|
+
for (const display of track.displays) {
|
|
12
|
+
;
|
|
13
|
+
display.setColorBy(value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
};
|
|
17
|
+
return (_jsx(CascadingMenuButton, { menuItems: [
|
|
18
|
+
{
|
|
19
|
+
label: 'Default',
|
|
20
|
+
type: 'radio',
|
|
21
|
+
checked: colorBy === 'default',
|
|
22
|
+
onClick: () => {
|
|
23
|
+
setColorBy('default');
|
|
24
|
+
},
|
|
25
|
+
helpText: 'Use the default color scheme specified in the track configuration. This respects the color settings defined in the config file.',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
label: 'Identity',
|
|
29
|
+
type: 'radio',
|
|
30
|
+
checked: colorBy === 'identity',
|
|
31
|
+
onClick: () => {
|
|
32
|
+
setColorBy('identity');
|
|
33
|
+
},
|
|
34
|
+
helpText: 'Color alignments by sequence identity percentage. Higher identity matches appear in warmer colors, while lower identity matches appear cooler. Useful for identifying highly conserved vs. divergent regions.',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
label: 'Mean Query Identity',
|
|
38
|
+
type: 'radio',
|
|
39
|
+
checked: colorBy === 'meanQueryIdentity',
|
|
40
|
+
onClick: () => {
|
|
41
|
+
setColorBy('meanQueryIdentity');
|
|
42
|
+
},
|
|
43
|
+
helpText: 'Color alignments based on the mean identity across the query sequence. This provides a smoothed view of overall alignment quality, reducing noise from local variations. For instance, a single long query of e.g. a contig of an assembly, when aligned to the target, may get split into many smaller "hits". This score aggregates across them, and colors them all the same. Similar code exists in the program dotPlotly',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
label: 'Mapping Quality',
|
|
47
|
+
type: 'radio',
|
|
48
|
+
checked: colorBy === 'mappingQuality',
|
|
49
|
+
onClick: () => {
|
|
50
|
+
setColorBy('mappingQuality');
|
|
51
|
+
},
|
|
52
|
+
helpText: 'Color alignments by mapping quality score (MAPQ). Higher quality mappings (more unique/confident) appear in darker colors. Useful for identifying ambiguous or multi-mapping regions.',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
label: 'Strand',
|
|
56
|
+
type: 'radio',
|
|
57
|
+
checked: colorBy === 'strand',
|
|
58
|
+
onClick: () => {
|
|
59
|
+
setColorBy('strand');
|
|
60
|
+
},
|
|
61
|
+
helpText: 'Color alignments by strand orientation. Forward strand alignments and reverse strand alignments are shown in different colors, making it easy to identify inversions and strand-specific patterns.',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
label: 'Query',
|
|
65
|
+
type: 'radio',
|
|
66
|
+
checked: colorBy === 'query',
|
|
67
|
+
onClick: () => {
|
|
68
|
+
setColorBy('query');
|
|
69
|
+
},
|
|
70
|
+
helpText: 'Color alignments by query sequence name. Each unique query sequence is assigned a consistent color based on its name, making it easy to visually distinguish between different sequences.',
|
|
71
|
+
},
|
|
72
|
+
], children: _jsx(PaletteIcon, {}) }));
|
|
73
|
+
});
|
|
74
|
+
export default ColorBySelector;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DotplotViewModel } from '../model';
|
|
2
|
+
declare const DiagonalizationProgressDialog: ({ handleClose, model, }: {
|
|
3
|
+
handleClose: () => void;
|
|
4
|
+
model: Pick<DotplotViewModel, "tracks" | "hview" | "vview" | "id" | "type" | "displayName">;
|
|
5
|
+
}) => import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export default DiagonalizationProgressDialog;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { Dialog, ErrorMessage } from '@jbrowse/core/ui';
|
|
4
|
+
import { getSession } from '@jbrowse/core/util';
|
|
5
|
+
import { createStopToken, stopStopToken } from '@jbrowse/core/util/stopToken';
|
|
6
|
+
import { Button, DialogActions, DialogContent, LinearProgress, Typography, } from '@mui/material';
|
|
7
|
+
import { transaction } from 'mobx';
|
|
8
|
+
import { observer } from 'mobx-react';
|
|
9
|
+
async function runDiagonalization({ model, session, stopToken, setProgress, setMessage, }) {
|
|
10
|
+
setProgress(0);
|
|
11
|
+
setMessage('Preparing diagonalization...');
|
|
12
|
+
const track = model.tracks[0];
|
|
13
|
+
if (!track) {
|
|
14
|
+
throw new Error('No tracks found');
|
|
15
|
+
}
|
|
16
|
+
const display = track.displays[0];
|
|
17
|
+
if (!display) {
|
|
18
|
+
throw new Error('No display found');
|
|
19
|
+
}
|
|
20
|
+
const result = (await session.rpcManager.call(model.id, 'DiagonalizeDotplot', {
|
|
21
|
+
sessionId: `diagonalize-${Date.now()}`,
|
|
22
|
+
view: {
|
|
23
|
+
hview: model.hview,
|
|
24
|
+
vview: model.vview,
|
|
25
|
+
},
|
|
26
|
+
adapterConfig: display.adapterConfig,
|
|
27
|
+
stopToken,
|
|
28
|
+
statusCallback: (msg) => {
|
|
29
|
+
setMessage(msg);
|
|
30
|
+
if (msg.includes('Initializing')) {
|
|
31
|
+
setProgress(5);
|
|
32
|
+
}
|
|
33
|
+
else if (msg.includes('Getting renderer')) {
|
|
34
|
+
setProgress(10);
|
|
35
|
+
}
|
|
36
|
+
else if (msg.includes('Fetching features')) {
|
|
37
|
+
setProgress(20);
|
|
38
|
+
}
|
|
39
|
+
else if (msg.includes('Extracting')) {
|
|
40
|
+
setProgress(30);
|
|
41
|
+
}
|
|
42
|
+
else if (msg.includes('Running diagonalization')) {
|
|
43
|
+
setProgress(40);
|
|
44
|
+
}
|
|
45
|
+
else if (msg.includes('Grouping')) {
|
|
46
|
+
setProgress(50);
|
|
47
|
+
}
|
|
48
|
+
else if (msg.includes('Determining')) {
|
|
49
|
+
setProgress(65);
|
|
50
|
+
}
|
|
51
|
+
else if (msg.includes('Sorting')) {
|
|
52
|
+
setProgress(80);
|
|
53
|
+
}
|
|
54
|
+
else if (msg.includes('Building')) {
|
|
55
|
+
setProgress(90);
|
|
56
|
+
}
|
|
57
|
+
else if (msg.includes('complete')) {
|
|
58
|
+
setProgress(100);
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
}));
|
|
62
|
+
setMessage('Applying new layout...');
|
|
63
|
+
setProgress(95);
|
|
64
|
+
if (result.newRegions.length > 0) {
|
|
65
|
+
transaction(() => {
|
|
66
|
+
model.vview.setDisplayedRegions(result.newRegions);
|
|
67
|
+
});
|
|
68
|
+
setProgress(100);
|
|
69
|
+
setMessage(`Diagonalization complete! Reordered ${result.stats.regionsReordered} regions, reversed ${result.stats.regionsReversed}`);
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
throw new Error('No regions to reorder');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const DiagonalizationProgressDialog = observer(function ({ handleClose, model, }) {
|
|
77
|
+
const [progress, setProgress] = useState(0);
|
|
78
|
+
const [message, setMessage] = useState('Ready to start diagonalization');
|
|
79
|
+
const [error, setError] = useState();
|
|
80
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
81
|
+
const [stopToken, setStopToken] = useState();
|
|
82
|
+
const handleStart = async () => {
|
|
83
|
+
const session = getSession(model);
|
|
84
|
+
const token = createStopToken();
|
|
85
|
+
setStopToken(token);
|
|
86
|
+
try {
|
|
87
|
+
setIsRunning(true);
|
|
88
|
+
await runDiagonalization({
|
|
89
|
+
model,
|
|
90
|
+
session,
|
|
91
|
+
stopToken: token,
|
|
92
|
+
setProgress,
|
|
93
|
+
setMessage,
|
|
94
|
+
});
|
|
95
|
+
setTimeout(() => {
|
|
96
|
+
handleClose();
|
|
97
|
+
}, 2000);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
console.error(err);
|
|
101
|
+
setError(err);
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
setIsRunning(false);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const handleCancel = () => {
|
|
108
|
+
if (stopToken) {
|
|
109
|
+
stopStopToken(stopToken);
|
|
110
|
+
setStopToken(undefined);
|
|
111
|
+
}
|
|
112
|
+
handleClose();
|
|
113
|
+
};
|
|
114
|
+
const handleDialogClose = () => {
|
|
115
|
+
if (!isRunning) {
|
|
116
|
+
handleClose();
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
return (_jsxs(Dialog, { open: true, title: "Diagonalize Dotplot", onClose: handleDialogClose, maxWidth: "lg", children: [_jsxs(DialogContent, { style: { minWidth: 400 }, children: [message ? _jsx(Typography, { children: message }) : null, error ? _jsx(ErrorMessage, { error: error }) : null, isRunning ? (_jsxs(_Fragment, { children: [_jsx(LinearProgress, { variant: "determinate", value: progress, style: { marginTop: 16 }, color: error ? 'error' : 'primary' }), _jsxs(Typography, { variant: "caption", color: "textSecondary", style: { marginTop: 8, display: 'block' }, children: [Math.round(progress), "% complete"] })] })) : null] }), _jsxs(DialogActions, { children: [!isRunning ? (_jsxs(_Fragment, { children: [_jsx(Button, { onClick: handleClose, color: "secondary", variant: "contained", children: "Cancel" }), _jsx(Button, { onClick: () => {
|
|
120
|
+
handleStart();
|
|
121
|
+
}, color: "primary", variant: "contained", children: "Start" })] })) : null, isRunning ? (_jsx(Button, { onClick: handleCancel, color: "secondary", variant: "contained", children: "Cancel" })) : null] })] }));
|
|
122
|
+
});
|
|
123
|
+
export default DiagonalizationProgressDialog;
|