@jbrowse/plugin-wiggle 3.1.0 → 3.2.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 (89) hide show
  1. package/dist/BigWigAdapter/BigWigAdapter.js +1 -1
  2. package/dist/LinearWiggleDisplay/model.d.ts +10 -10
  3. package/dist/MultiDensityRenderer/MultiDensityRenderer.js +2 -2
  4. package/dist/MultiLineRenderer/MultiLineRenderer.js +2 -2
  5. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialog.d.ts +6 -0
  6. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialog.js +29 -0
  7. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogAuto.d.ts +7 -0
  8. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogAuto.js +76 -0
  9. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogManual.d.ts +7 -0
  10. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogManual.js +155 -0
  11. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/types.d.ts +7 -0
  12. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog/types.js +2 -0
  13. package/dist/MultiLinearWiggleDisplay/components/SourcesGrid.js +2 -2
  14. package/dist/MultiLinearWiggleDisplay/model.d.ts +15 -9
  15. package/dist/MultiLinearWiggleDisplay/model.js +28 -14
  16. package/dist/MultiRowLineRenderer/MultiRowLineRenderer.js +2 -2
  17. package/dist/MultiRowXYPlotRenderer/MultiRowXYPlotRenderer.js +2 -2
  18. package/dist/MultiXYPlotRenderer/MultiXYPlotRenderer.js +3 -3
  19. package/dist/WiggleBaseRenderer.d.ts +1 -0
  20. package/dist/WiggleBaseRenderer.js +3 -3
  21. package/dist/WiggleRPC/MultiWiggleClusterScoreMatrix.d.ts +14 -0
  22. package/dist/WiggleRPC/MultiWiggleClusterScoreMatrix.js +34 -0
  23. package/dist/WiggleRPC/MultiWiggleGetScoreMatrix.d.ts +2 -13
  24. package/dist/WiggleRPC/MultiWiggleGetScoreMatrix.js +5 -37
  25. package/dist/WiggleRPC/cluster.d.ts +17 -0
  26. package/dist/WiggleRPC/cluster.js +84 -0
  27. package/dist/WiggleRPC/getScoreMatrix.d.ts +6 -0
  28. package/dist/WiggleRPC/getScoreMatrix.js +35 -0
  29. package/dist/WiggleRPC/rpcMethods.d.ts +1 -0
  30. package/dist/WiggleRPC/rpcMethods.js +1 -0
  31. package/dist/WiggleRPC/type.d.ts +0 -0
  32. package/dist/WiggleRPC/type.js +1 -0
  33. package/dist/WiggleRPC/types.d.ts +13 -0
  34. package/dist/WiggleRPC/types.js +2 -0
  35. package/dist/drawDensity.d.ts +1 -0
  36. package/dist/drawDensity.js +12 -2
  37. package/dist/drawLine.d.ts +1 -0
  38. package/dist/drawLine.js +9 -3
  39. package/dist/drawXY.js +8 -8
  40. package/dist/index.js +1 -0
  41. package/dist/shared/SharedWiggleMixin.d.ts +8 -8
  42. package/dist/shared/SharedWiggleMixin.js +11 -8
  43. package/esm/BigWigAdapter/BigWigAdapter.js +1 -1
  44. package/esm/LinearWiggleDisplay/model.d.ts +10 -10
  45. package/esm/MultiDensityRenderer/MultiDensityRenderer.js +3 -3
  46. package/esm/MultiLineRenderer/MultiLineRenderer.js +3 -3
  47. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialog.d.ts +6 -0
  48. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialog.js +24 -0
  49. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogAuto.d.ts +7 -0
  50. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogAuto.js +74 -0
  51. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogManual.d.ts +7 -0
  52. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/ClusterDialogManual.js +150 -0
  53. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/types.d.ts +7 -0
  54. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog/types.js +1 -0
  55. package/esm/MultiLinearWiggleDisplay/components/SourcesGrid.js +2 -2
  56. package/esm/MultiLinearWiggleDisplay/model.d.ts +15 -9
  57. package/esm/MultiLinearWiggleDisplay/model.js +28 -14
  58. package/esm/MultiRowLineRenderer/MultiRowLineRenderer.js +3 -3
  59. package/esm/MultiRowXYPlotRenderer/MultiRowXYPlotRenderer.js +3 -3
  60. package/esm/MultiXYPlotRenderer/MultiXYPlotRenderer.js +4 -4
  61. package/esm/WiggleBaseRenderer.d.ts +1 -0
  62. package/esm/WiggleBaseRenderer.js +4 -4
  63. package/esm/WiggleRPC/MultiWiggleClusterScoreMatrix.d.ts +14 -0
  64. package/esm/WiggleRPC/MultiWiggleClusterScoreMatrix.js +27 -0
  65. package/esm/WiggleRPC/MultiWiggleGetScoreMatrix.d.ts +2 -13
  66. package/esm/WiggleRPC/MultiWiggleGetScoreMatrix.js +5 -37
  67. package/esm/WiggleRPC/cluster.d.ts +17 -0
  68. package/esm/WiggleRPC/cluster.js +79 -0
  69. package/esm/WiggleRPC/getScoreMatrix.d.ts +6 -0
  70. package/esm/WiggleRPC/getScoreMatrix.js +32 -0
  71. package/esm/WiggleRPC/rpcMethods.d.ts +1 -0
  72. package/esm/WiggleRPC/rpcMethods.js +1 -0
  73. package/esm/WiggleRPC/type.d.ts +0 -0
  74. package/esm/WiggleRPC/type.js +1 -0
  75. package/esm/WiggleRPC/types.d.ts +13 -0
  76. package/esm/WiggleRPC/types.js +1 -0
  77. package/esm/drawDensity.d.ts +1 -0
  78. package/esm/drawDensity.js +12 -2
  79. package/esm/drawLine.d.ts +1 -0
  80. package/esm/drawLine.js +9 -3
  81. package/esm/drawXY.js +8 -8
  82. package/esm/index.js +2 -1
  83. package/esm/shared/SharedWiggleMixin.d.ts +8 -8
  84. package/esm/shared/SharedWiggleMixin.js +11 -8
  85. package/package.json +5 -5
  86. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog.d.ts +0 -11
  87. package/dist/MultiLinearWiggleDisplay/components/ClusterDialog.js +0 -115
  88. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog.d.ts +0 -11
  89. package/esm/MultiLinearWiggleDisplay/components/ClusterDialog.js +0 -109
@@ -1,14 +1,14 @@
1
- import { groupBy } from '@jbrowse/core/util';
1
+ import { forEachWithStopTokenCheck, groupBy } from '@jbrowse/core/util';
2
2
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
3
3
  export default class MultiDensityPlotRenderer extends WiggleBaseRenderer {
4
4
  async draw(ctx, props) {
5
- const { sources, features } = props;
5
+ const { stopToken, sources, features } = props;
6
6
  const groups = groupBy(features.values(), f => f.get('source'));
7
7
  const height = props.height / sources.length;
8
8
  let feats = [];
9
9
  const { drawDensity } = await import('../drawDensity');
10
10
  ctx.save();
11
- sources.forEach(source => {
11
+ forEachWithStopTokenCheck(sources, stopToken, source => {
12
12
  const features = groups[source.name] || [];
13
13
  const { reducedFeatures } = drawDensity(ctx, {
14
14
  ...props,
@@ -1,12 +1,12 @@
1
- import { groupBy } from '@jbrowse/core/util';
1
+ import { forEachWithStopTokenCheck, groupBy } from '@jbrowse/core/util';
2
2
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
3
3
  export default class MultiLineRenderer extends WiggleBaseRenderer {
4
4
  async draw(ctx, props) {
5
- const { sources, features } = props;
5
+ const { stopToken, sources, features } = props;
6
6
  const groups = groupBy(features.values(), f => f.get('source'));
7
7
  const { drawLine } = await import('../drawLine');
8
8
  let feats = [];
9
- sources.forEach(source => {
9
+ forEachWithStopTokenCheck(sources, stopToken, source => {
10
10
  const { reducedFeatures } = drawLine(ctx, {
11
11
  ...props,
12
12
  features: groups[source.name] || [],
@@ -0,0 +1,6 @@
1
+ import type { ReducedModel } from './types';
2
+ declare const ClusterDialog: ({ model, handleClose, }: {
3
+ model: ReducedModel;
4
+ handleClose: () => void;
5
+ }) => import("react/jsx-runtime").JSX.Element;
6
+ export default ClusterDialog;
@@ -0,0 +1,24 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { Dialog } from '@jbrowse/core/ui';
4
+ import { FormControlLabel, Radio, RadioGroup } from '@mui/material';
5
+ import { observer } from 'mobx-react';
6
+ import ClusterDialogAuto from './ClusterDialogAuto';
7
+ import ClusterDialogManual from './ClusterDialogManual';
8
+ function Header({ activeMode, setActiveMode, }) {
9
+ return (_jsx("div", { children: _jsx(RadioGroup, { children: Object.entries({
10
+ auto: (_jsx("div", { children: "Run in-app clustering (slow for large data, built in JS clustering)" })),
11
+ manual: (_jsx("div", { children: "Download R script to run clustering (faster for large data, uses hclust, may be more accurate)" })),
12
+ }).map(([key, val]) => (_jsx(FormControlLabel, { control: _jsx(Radio, { checked: activeMode === key, onChange: () => {
13
+ setActiveMode(key);
14
+ } }), label: val }, key))) }) }));
15
+ }
16
+ const ClusterDialog = observer(function ({ model, handleClose, }) {
17
+ const [activeMode, setActiveMode] = useState('auto');
18
+ return (_jsx(Dialog, { open: true, title: "Cluster by score", maxWidth: "xl", onClose: (_, reason) => {
19
+ if (reason !== 'backdropClick') {
20
+ handleClose();
21
+ }
22
+ }, children: activeMode === 'auto' ? (_jsx(ClusterDialogAuto, { model: model, handleClose: handleClose, children: _jsx(Header, { activeMode: activeMode, setActiveMode: setActiveMode }) })) : (_jsx(ClusterDialogManual, { model: model, handleClose: handleClose, children: _jsx(Header, { activeMode: activeMode, setActiveMode: setActiveMode }) })) }));
23
+ });
24
+ export default ClusterDialog;
@@ -0,0 +1,7 @@
1
+ import type { ReducedModel } from './types';
2
+ declare const ClusterDialogAuto: ({ model, children, handleClose, }: {
3
+ model: ReducedModel;
4
+ children: React.ReactNode;
5
+ handleClose: () => void;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ export default ClusterDialogAuto;
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ import { ErrorMessage } from '@jbrowse/core/ui';
4
+ import { getContainingView, getSession, isAbortException, useLocalStorage, } from '@jbrowse/core/util';
5
+ import { createStopToken, stopStopToken } from '@jbrowse/core/util/stopToken';
6
+ import { getRpcSessionId } from '@jbrowse/core/util/tracks';
7
+ import { Button, DialogActions, DialogContent, TextField, Typography, } from '@mui/material';
8
+ import { observer } from 'mobx-react';
9
+ import { isAlive } from 'mobx-state-tree';
10
+ const ClusterDialogAuto = observer(function ({ model, children, handleClose, }) {
11
+ const [progress, setProgress] = useState('');
12
+ const [error, setError] = useState();
13
+ const [stopToken, setStopToken] = useState('');
14
+ const [showAdvanced, setShowAdvanced] = useState(false);
15
+ const [samplesPerPixel, setSamplesPerPixel] = useLocalStorage('cluster-samplesPerPixel', '1');
16
+ return (_jsxs(_Fragment, { children: [_jsxs(DialogContent, { children: [children, _jsxs("div", { style: { marginTop: 50 }, children: [_jsx(Button, { variant: "contained", onClick: () => {
17
+ setShowAdvanced(!showAdvanced);
18
+ }, children: showAdvanced ? 'Hide advanced options' : 'Show advanced options' }), showAdvanced ? (_jsxs("div", { style: { marginTop: 20 }, children: [_jsx(Typography, { children: "This procedure samples the data at each 'pixel' across the visible by default" }), _jsx(TextField, { label: "Samples per pixel (>1 for denser sampling, between 0-1 for sparser sampling)", variant: "outlined", size: "small", value: samplesPerPixel, onChange: event => {
19
+ setSamplesPerPixel(event.target.value);
20
+ } })] })) : null] }), _jsxs("div", { children: [progress ? (_jsxs("div", { style: { padding: 50 }, children: [_jsxs("span", { style: { width: 400 }, children: ["Progress: ", progress] }), _jsx(Button, { onClick: () => {
21
+ stopStopToken(stopToken);
22
+ }, children: "Stop" })] })) : null, error ? _jsx(ErrorMessage, { error: error }) : null] })] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", onClick: async () => {
23
+ try {
24
+ setError(undefined);
25
+ setProgress('');
26
+ const view = getContainingView(model);
27
+ if (!view.initialized) {
28
+ return;
29
+ }
30
+ const { rpcManager } = getSession(model);
31
+ const { sourcesWithoutLayout, adapterConfig } = model;
32
+ if (sourcesWithoutLayout) {
33
+ const sessionId = getRpcSessionId(model);
34
+ const stopToken = createStopToken();
35
+ setStopToken(stopToken);
36
+ const ret = (await rpcManager.call(sessionId, 'MultiWiggleClusterScoreMatrix', {
37
+ regions: view.dynamicBlocks.contentBlocks,
38
+ sources: sourcesWithoutLayout,
39
+ sessionId,
40
+ adapterConfig,
41
+ stopToken,
42
+ bpPerPx: view.bpPerPx / +samplesPerPixel,
43
+ statusCallback: (arg) => {
44
+ setProgress(arg);
45
+ },
46
+ }));
47
+ model.setLayout(ret.order.map(idx => {
48
+ const ret = sourcesWithoutLayout[idx];
49
+ if (!ret) {
50
+ throw new Error(`out of bounds at ${idx}`);
51
+ }
52
+ return ret;
53
+ }));
54
+ }
55
+ handleClose();
56
+ }
57
+ catch (e) {
58
+ if (!isAbortException(e) && isAlive(model)) {
59
+ console.error(e);
60
+ setError(e);
61
+ }
62
+ }
63
+ finally {
64
+ setProgress('');
65
+ setStopToken('');
66
+ }
67
+ }, children: "Run clustering" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
68
+ handleClose();
69
+ if (stopToken) {
70
+ stopStopToken(stopToken);
71
+ }
72
+ }, children: "Cancel" })] })] }));
73
+ });
74
+ export default ClusterDialogAuto;
@@ -0,0 +1,7 @@
1
+ import type { ReducedModel } from './types';
2
+ declare const ClusterDialogManuals: ({ model, handleClose, children, }: {
3
+ model: ReducedModel;
4
+ handleClose: () => void;
5
+ children: React.ReactNode;
6
+ }) => import("react/jsx-runtime").JSX.Element;
7
+ export default ClusterDialogManuals;
@@ -0,0 +1,150 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useEffect, useState } from 'react';
3
+ import { CascadingMenuButton, ErrorMessage, LoadingEllipses, } from '@jbrowse/core/ui';
4
+ import { getContainingView, getSession, isAbortException, useLocalStorage, } from '@jbrowse/core/util';
5
+ import { getRpcSessionId } from '@jbrowse/core/util/tracks';
6
+ import MenuIcon from '@mui/icons-material/Menu';
7
+ import { Button, DialogActions, DialogContent, FormControlLabel, Radio, RadioGroup, TextField, Typography, } from '@mui/material';
8
+ import copy from 'copy-to-clipboard';
9
+ import { saveAs } from 'file-saver';
10
+ import { observer } from 'mobx-react';
11
+ import { isAlive } from 'mobx-state-tree';
12
+ import { makeStyles } from 'tss-react/mui';
13
+ const useStyles = makeStyles()(theme => ({
14
+ textAreaFont: {
15
+ fontFamily: 'Courier New',
16
+ },
17
+ mgap: {
18
+ display: 'flex',
19
+ flexDirection: 'column',
20
+ gap: theme.spacing(4),
21
+ },
22
+ }));
23
+ const ClusterDialogManuals = observer(function ({ model, handleClose, children, }) {
24
+ const { classes } = useStyles();
25
+ const [paste, setPaste] = useState('');
26
+ const [ret, setRet] = useState();
27
+ const [error, setError] = useState();
28
+ const [loading, setLoading] = useState(false);
29
+ const [showAdvanced, setShowAdvanced] = useState(false);
30
+ const [clusterMethod, setClusterMethod] = useLocalStorage('cluster-clusterMethod', 'single');
31
+ const [samplesPerPixel, setSamplesPerPixel] = useLocalStorage('cluster-samplesPerPixel', '1');
32
+ useEffect(() => {
33
+ ;
34
+ (async () => {
35
+ try {
36
+ setError(undefined);
37
+ setRet(undefined);
38
+ setLoading(true);
39
+ const view = getContainingView(model);
40
+ const { dynamicBlocks, bpPerPx } = view;
41
+ const { rpcManager } = getSession(model);
42
+ const { sourcesWithoutLayout, adapterConfig } = model;
43
+ const sessionId = getRpcSessionId(model);
44
+ const ret = (await rpcManager.call(sessionId, 'MultiWiggleGetScoreMatrix', {
45
+ regions: dynamicBlocks.contentBlocks,
46
+ sources: sourcesWithoutLayout,
47
+ sessionId,
48
+ adapterConfig,
49
+ bpPerPx: bpPerPx / +samplesPerPixel,
50
+ }));
51
+ setRet(ret);
52
+ }
53
+ catch (e) {
54
+ if (!isAbortException(e) && isAlive(model)) {
55
+ console.error(e);
56
+ setError(e);
57
+ }
58
+ }
59
+ finally {
60
+ setLoading(false);
61
+ }
62
+ })();
63
+ }, [model, samplesPerPixel]);
64
+ const results = ret
65
+ ? `inputMatrix<-matrix(c(${Object.values(ret)
66
+ .map(val => val.join(','))
67
+ .join(',\n')}
68
+ ),nrow=${Object.values(ret).length},byrow=TRUE)
69
+ rownames(inputMatrix)<-c(${Object.keys(ret)
70
+ .map(key => `'${key}'`)
71
+ .join(',')})
72
+ resultClusters<-hclust(dist(inputMatrix), method='${clusterMethod}')
73
+ cat(resultClusters$order,sep='\\n')`
74
+ : undefined;
75
+ const resultsTsv = ret
76
+ ? Object.entries(ret)
77
+ .map(([key, val]) => [key, ...val].join('\t'))
78
+ .join('\n')
79
+ : undefined;
80
+ return (_jsxs(_Fragment, { children: [_jsxs(DialogContent, { children: [children, _jsxs("div", { style: { marginTop: 50 }, children: [_jsxs("div", { style: {
81
+ display: 'flex',
82
+ gap: '8px',
83
+ flexWrap: 'wrap',
84
+ marginBottom: '16px',
85
+ }, children: [_jsx(Button, { variant: "contained", onClick: () => {
86
+ saveAs(new Blob([results || ''], {
87
+ type: 'text/plain;charset=utf-8',
88
+ }), 'cluster.R');
89
+ }, children: "Download Rscript" }), ' ', "or", ' ', _jsx(Button, { variant: "contained", onClick: () => {
90
+ copy(results || '');
91
+ }, children: "Copy Rscript to clipboard" }), ' ', _jsx("div", { style: { float: 'right' }, children: _jsx(CascadingMenuButton, { menuItems: [
92
+ {
93
+ label: 'Download TSV',
94
+ onClick: () => {
95
+ saveAs(new Blob([resultsTsv || ''], {
96
+ type: 'text/plain;charset=utf-8',
97
+ }), 'scores.tsv');
98
+ },
99
+ },
100
+ {
101
+ label: showAdvanced
102
+ ? 'Hide advanced options'
103
+ : 'Show advanced options',
104
+ onClick: () => {
105
+ setShowAdvanced(!showAdvanced);
106
+ },
107
+ },
108
+ ], children: _jsx(MenuIcon, {}) }) }), _jsx("div", { children: showAdvanced ? (_jsxs("div", { children: [_jsx(Typography, { variant: "h6", children: "Advanced options" }), _jsx(RadioGroup, { children: Object.entries({
109
+ single: 'Single',
110
+ complete: 'Complete',
111
+ }).map(([key, val]) => (_jsx(FormControlLabel, { control: _jsx(Radio, { checked: clusterMethod === key, onChange: () => {
112
+ setClusterMethod(key);
113
+ } }), label: val }, key))) }), _jsxs("div", { style: { marginTop: 20 }, children: [_jsx(Typography, { children: "This procedure samples the data at each 'pixel' across the visible by default" }), _jsx(TextField, { label: "Samples per pixel (>1 for denser sampling, between 0-1 for sparser sampling)", variant: "outlined", size: "small", value: samplesPerPixel, onChange: event => {
114
+ setSamplesPerPixel(event.target.value);
115
+ } })] })] })) : null }), results ? (_jsx("div", {})) : loading ? (_jsx(LoadingEllipses, { variant: "h6", title: "Generating score matrix" })) : error ? (_jsx(ErrorMessage, { error: error })) : null] }), _jsxs("div", { children: [_jsx(Typography, { variant: "subtitle2", gutterBottom: true, style: { marginTop: '16px' }, children: "Clustering Results:" }), _jsx(TextField, { multiline: true, fullWidth: true, variant: "outlined", placeholder: "Paste results from Rscript here (sequence of numbers, one per line, specifying the new ordering)", rows: 10, value: paste, onChange: event => {
116
+ setPaste(event.target.value);
117
+ }, slotProps: {
118
+ input: {
119
+ classes: {
120
+ input: classes.textAreaFont,
121
+ },
122
+ },
123
+ } })] })] })] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", onClick: () => {
124
+ const { sourcesWithoutLayout } = model;
125
+ if (sourcesWithoutLayout) {
126
+ try {
127
+ model.setLayout(paste
128
+ .split('\n')
129
+ .map(t => t.trim())
130
+ .filter(f => !!f)
131
+ .map(r => +r)
132
+ .map(idx => {
133
+ const ret = sourcesWithoutLayout[idx - 1];
134
+ if (!ret) {
135
+ throw new Error(`out of bounds at ${idx}`);
136
+ }
137
+ return ret;
138
+ }));
139
+ }
140
+ catch (e) {
141
+ console.error(e);
142
+ getSession(model).notifyError(`${e}`, e);
143
+ }
144
+ }
145
+ handleClose();
146
+ }, children: "Apply clustering" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: () => {
147
+ handleClose();
148
+ }, children: "Cancel" })] })] }));
149
+ });
150
+ export default ClusterDialogManuals;
@@ -0,0 +1,7 @@
1
+ import type { Source } from '../../types';
2
+ import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
3
+ export interface ReducedModel {
4
+ sourcesWithoutLayout?: Source[];
5
+ adapterConfig: AnyConfigurationModel;
6
+ setLayout: (arg: Source[]) => void;
7
+ }
@@ -40,12 +40,12 @@ function SourcesGrid({ rows, onChange, showTips, }) {
40
40
  onChange(moveDown([...rows], selected, rows.length));
41
41
  }, disabled: !selected.length, children: [_jsx(KeyboardDoubleArrowDownIcon, {}), showTips ? 'Move selected items to bottom' : null] }), _jsx(ColorPopover, { anchorEl: anchorEl, color: widgetColor, onChange: c => {
42
42
  setWidgetColor(c);
43
- selected.forEach(id => {
43
+ for (const id of selected) {
44
44
  const elt = rows.find(f => f.name === id);
45
45
  if (elt) {
46
46
  elt.color = c;
47
47
  }
48
- });
48
+ }
49
49
  onChange([...rows]);
50
50
  }, onClose: () => {
51
51
  setAnchorEl(null);
@@ -259,11 +259,11 @@ export declare function stateModelFactory(_pluginManager: PluginManager, configS
259
259
  setCrossHatches(cross: boolean): void;
260
260
  } & {
261
261
  readonly adapterTypeName: any;
262
- readonly rendererTypeNameSimple: any;
262
+ readonly rendererTypeNameSimple: string;
263
263
  readonly filters: undefined;
264
- readonly scaleType: any;
265
- readonly maxScore: any;
266
- readonly minScore: any;
264
+ readonly scaleType: string;
265
+ readonly maxScore: number;
266
+ readonly minScore: number;
267
267
  } & {
268
268
  readonly adapterCapabilities: string[];
269
269
  readonly rendererConfig: {
@@ -277,7 +277,7 @@ export declare function stateModelFactory(_pluginManager: PluginManager, configS
277
277
  } & import("mobx-state-tree/dist/internal").NonEmptyObject & any & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
278
278
  } & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>);
279
279
  } & import("mobx-state-tree").IStateTreeNode<AnyConfigurationSchemaType>;
280
- readonly autoscaleType: any;
280
+ readonly autoscaleType: string;
281
281
  } & {
282
282
  readonly domain: number[] | undefined;
283
283
  } & {
@@ -290,9 +290,9 @@ export declare function stateModelFactory(_pluginManager: PluginManager, configS
290
290
  scoreMin: number;
291
291
  scoreMax: number;
292
292
  } | undefined;
293
- autoscaleType: any;
294
- scaleType: any;
295
- inverted: any;
293
+ autoscaleType: string;
294
+ scaleType: string;
295
+ inverted: boolean;
296
296
  };
297
297
  readonly canHaveFill: boolean;
298
298
  readonly displayCrossHatchesSetting: boolean;
@@ -344,6 +344,12 @@ export declare function stateModelFactory(_pluginManager: PluginManager, configS
344
344
  readonly canHaveFill: boolean;
345
345
  readonly renderColorBoxes: boolean;
346
346
  readonly prefersOffset: boolean;
347
+ readonly sourcesWithoutLayout: {
348
+ color: string;
349
+ baseUri?: string;
350
+ name: string;
351
+ group?: string;
352
+ }[] | undefined;
347
353
  readonly sources: {
348
354
  color: string;
349
355
  baseUri?: string;
@@ -354,7 +360,7 @@ export declare function stateModelFactory(_pluginManager: PluginManager, configS
354
360
  } & {
355
361
  readonly rowHeight: number;
356
362
  readonly rowHeightTooSmallForScalebar: boolean;
357
- readonly useMinimalTicks: any;
363
+ readonly useMinimalTicks: boolean;
358
364
  } & {
359
365
  adapterProps(): any;
360
366
  readonly ticks: {
@@ -11,7 +11,7 @@ import { YSCALEBAR_LABEL_OFFSET, getScale } from '../util';
11
11
  const randomColor = () => '#000000'.replaceAll('0', () => (~~(Math.random() * 16)).toString(16));
12
12
  const Tooltip = lazy(() => import('./components/Tooltip'));
13
13
  const SetColorDialog = lazy(() => import('./components/SetColorDialog'));
14
- const ClusterDialog = lazy(() => import('./components/ClusterDialog'));
14
+ const ClusterDialog = lazy(() => import('./components/ClusterDialog/ClusterDialog'));
15
15
  const rendererTypes = new Map([
16
16
  ['xyplot', 'MultiXYPlotRenderer'],
17
17
  ['multirowxy', 'MultiRowXYPlotRenderer'],
@@ -98,6 +98,19 @@ export function stateModelFactory(_pluginManager, configSchema) {
98
98
  get prefersOffset() {
99
99
  return this.isMultiRow;
100
100
  },
101
+ get sourcesWithoutLayout() {
102
+ var _a;
103
+ const sources = Object.fromEntries(((_a = self.sourcesVolatile) === null || _a === void 0 ? void 0 : _a.map(s => [s.name, s])) || []);
104
+ const iter = self.sourcesVolatile;
105
+ return iter === null || iter === void 0 ? void 0 : iter.map(s => ({
106
+ ...sources[s.name],
107
+ ...s,
108
+ })).map((s, i) => ({
109
+ ...s,
110
+ color: s.color ||
111
+ (!this.isMultiRow ? colors[i] || randomColor() : 'blue'),
112
+ }));
113
+ },
101
114
  get sources() {
102
115
  var _a;
103
116
  const sources = Object.fromEntries(((_a = self.sourcesVolatile) === null || _a === void 0 ? void 0 : _a.map(s => [s.name, s])) || []);
@@ -125,7 +138,8 @@ export function stateModelFactory(_pluginManager, configSchema) {
125
138
  return this.rowHeight < 70;
126
139
  },
127
140
  get useMinimalTicks() {
128
- return (getConf(self, 'minimalTicks') || this.rowHeightTooSmallForScalebar);
141
+ return (getConf(self, 'minimalTicks') ||
142
+ this.rowHeightTooSmallForScalebar);
129
143
  },
130
144
  }))
131
145
  .views(self => {
@@ -255,18 +269,6 @@ export function stateModelFactory(_pluginManager, configSchema) {
255
269
  },
256
270
  ]
257
271
  : []),
258
- ...(self.graphType
259
- ? [
260
- {
261
- type: 'checkbox',
262
- label: 'Draw cross hatches',
263
- checked: self.displayCrossHatchesSetting,
264
- onClick: () => {
265
- self.toggleCrossHatches();
266
- },
267
- },
268
- ]
269
- : []),
270
272
  ...(hasRenderings
271
273
  ? [
272
274
  {
@@ -288,6 +290,18 @@ export function stateModelFactory(_pluginManager, configSchema) {
288
290
  },
289
291
  ]
290
292
  : []),
293
+ ...(self.graphType
294
+ ? [
295
+ {
296
+ type: 'checkbox',
297
+ label: 'Draw cross hatches',
298
+ checked: self.displayCrossHatchesSetting,
299
+ onClick: () => {
300
+ self.toggleCrossHatches();
301
+ },
302
+ },
303
+ ]
304
+ : []),
291
305
  {
292
306
  label: 'Cluster by score',
293
307
  onClick: () => {
@@ -1,8 +1,8 @@
1
- import { groupBy } from '@jbrowse/core/util';
1
+ import { forEachWithStopTokenCheck, groupBy } from '@jbrowse/core/util';
2
2
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
3
3
  export default class MultiRowLineRenderer extends WiggleBaseRenderer {
4
4
  async draw(ctx, props) {
5
- const { bpPerPx, sources, regions, features } = props;
5
+ const { stopToken, bpPerPx, sources, regions, features } = props;
6
6
  const region = regions[0];
7
7
  const groups = groupBy(features.values(), f => f.get('source'));
8
8
  const height = props.height / sources.length;
@@ -10,7 +10,7 @@ export default class MultiRowLineRenderer extends WiggleBaseRenderer {
10
10
  const { drawLine } = await import('../drawLine');
11
11
  let feats = [];
12
12
  ctx.save();
13
- sources.forEach(source => {
13
+ forEachWithStopTokenCheck(sources, stopToken, source => {
14
14
  const { reducedFeatures } = drawLine(ctx, {
15
15
  ...props,
16
16
  features: groups[source.name] || [],
@@ -1,8 +1,8 @@
1
- import { groupBy } from '@jbrowse/core/util';
1
+ import { forEachWithStopTokenCheck, groupBy } from '@jbrowse/core/util';
2
2
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
3
3
  export default class MultiXYPlotRenderer extends WiggleBaseRenderer {
4
4
  async draw(ctx, props) {
5
- const { bpPerPx, sources, regions, features } = props;
5
+ const { stopToken, bpPerPx, sources, regions, features } = props;
6
6
  const region = regions[0];
7
7
  const groups = groupBy(features.values(), f => f.get('source'));
8
8
  const height = props.height / sources.length;
@@ -10,7 +10,7 @@ export default class MultiXYPlotRenderer extends WiggleBaseRenderer {
10
10
  const { drawXY } = await import('../drawXY');
11
11
  let feats = [];
12
12
  ctx.save();
13
- sources.forEach(source => {
13
+ forEachWithStopTokenCheck(sources, stopToken, source => {
14
14
  const { reducedFeatures } = drawXY(ctx, {
15
15
  ...props,
16
16
  features: groups[source.name] || [],
@@ -1,13 +1,13 @@
1
- import { groupBy } from '@jbrowse/core/util';
1
+ import { forEachWithStopTokenCheck, groupBy } from '@jbrowse/core/util';
2
2
  import WiggleBaseRenderer from '../WiggleBaseRenderer';
3
3
  import { YSCALEBAR_LABEL_OFFSET } from '../util';
4
4
  export default class MultiXYPlotRenderer extends WiggleBaseRenderer {
5
5
  async draw(ctx, props) {
6
- const { sources, features } = props;
6
+ const { stopToken, sources, features } = props;
7
7
  const groups = groupBy(features.values(), f => f.get('source'));
8
8
  const { drawXY } = await import('../drawXY');
9
9
  let feats = [];
10
- for (const source of sources) {
10
+ forEachWithStopTokenCheck(sources, stopToken, source => {
11
11
  const features = groups[source.name] || [];
12
12
  const { reducedFeatures } = drawXY(ctx, {
13
13
  ...props,
@@ -16,7 +16,7 @@ export default class MultiXYPlotRenderer extends WiggleBaseRenderer {
16
16
  colorCallback: () => source.color || 'blue',
17
17
  });
18
18
  feats = feats.concat(reducedFeatures);
19
- }
19
+ });
20
20
  return { reducedFeatures: feats };
21
21
  }
22
22
  }
@@ -17,6 +17,7 @@ export interface RenderArgsDeserialized extends FeatureRenderArgsDeserialized {
17
17
  };
18
18
  inverted: boolean;
19
19
  themeOptions: ThemeOptions;
20
+ statusCallback?: (arg: string) => void;
20
21
  }
21
22
  export interface RenderArgsDeserializedWithFeatures extends RenderArgsDeserialized {
22
23
  features: Map<string, Feature>;
@@ -1,5 +1,5 @@
1
1
  import FeatureRendererType from '@jbrowse/core/pluggableElementTypes/renderers/FeatureRendererType';
2
- import { renderToAbstractCanvas } from '@jbrowse/core/util';
2
+ import { renderToAbstractCanvas, updateStatus } from '@jbrowse/core/util';
3
3
  export default class WiggleBaseRenderer extends FeatureRendererType {
4
4
  constructor() {
5
5
  super(...arguments);
@@ -7,14 +7,14 @@ export default class WiggleBaseRenderer extends FeatureRendererType {
7
7
  }
8
8
  async render(renderProps) {
9
9
  const features = await this.getFeatures(renderProps);
10
- const { inverted, height, regions, bpPerPx } = renderProps;
10
+ const { inverted, height, regions, bpPerPx, statusCallback = () => { }, } = renderProps;
11
11
  const region = regions[0];
12
12
  const width = (region.end - region.start) / bpPerPx;
13
- const { reducedFeatures, ...rest } = await renderToAbstractCanvas(width, height, renderProps, ctx => this.draw(ctx, {
13
+ const { reducedFeatures, ...rest } = await updateStatus('Rendering plot', statusCallback, () => renderToAbstractCanvas(width, height, renderProps, ctx => this.draw(ctx, {
14
14
  ...renderProps,
15
15
  features,
16
16
  inverted,
17
- }));
17
+ })));
18
18
  const results = await super.render({
19
19
  ...renderProps,
20
20
  ...rest,
@@ -0,0 +1,14 @@
1
+ import RpcMethodTypeWithFiltersAndRenameRegions from '@jbrowse/core/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions';
2
+ import type { GetScoreMatrixArgs } from './types';
3
+ export declare class MultiWiggleClusterScoreMatrix extends RpcMethodTypeWithFiltersAndRenameRegions {
4
+ name: string;
5
+ execute(args: GetScoreMatrixArgs, rpcDriverClassName: string): Promise<{
6
+ clusters: {
7
+ height: number;
8
+ indexes: number[];
9
+ } | undefined;
10
+ distances: number[][];
11
+ order: number[];
12
+ clustersGivenK: number[][][];
13
+ }>;
14
+ }
@@ -0,0 +1,27 @@
1
+ import RpcMethodTypeWithFiltersAndRenameRegions from '@jbrowse/core/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions';
2
+ import { clusterData } from './cluster';
3
+ import { getScoreMatrix } from './getScoreMatrix';
4
+ export class MultiWiggleClusterScoreMatrix extends RpcMethodTypeWithFiltersAndRenameRegions {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.name = 'MultiWiggleClusterScoreMatrix';
8
+ }
9
+ async execute(args, rpcDriverClassName) {
10
+ const deserializedArgs = await this.deserializeArguments(args, rpcDriverClassName);
11
+ const matrix = await getScoreMatrix({
12
+ pluginManager: this.pluginManager,
13
+ args: deserializedArgs,
14
+ });
15
+ return clusterData({
16
+ data: Object.values(matrix),
17
+ stopToken: deserializedArgs.stopToken,
18
+ onProgress: a => {
19
+ var _a;
20
+ (_a = deserializedArgs.statusCallback) === null || _a === void 0 ? void 0 : _a.call(deserializedArgs, `${toP(a * 100)}%`);
21
+ },
22
+ });
23
+ }
24
+ }
25
+ function toP(n) {
26
+ return Number.parseFloat(n.toPrecision(3));
27
+ }
@@ -1,17 +1,6 @@
1
1
  import RpcMethodTypeWithFiltersAndRenameRegions from '@jbrowse/core/pluggableElementTypes/RpcMethodTypeWithFiltersAndRenameRegions';
2
- import { type Region } from '@jbrowse/core/util';
3
- import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
2
+ import type { GetScoreMatrixArgs } from './types';
4
3
  export declare class MultiWiggleGetScoreMatrix extends RpcMethodTypeWithFiltersAndRenameRegions {
5
4
  name: string;
6
- execute(args: {
7
- adapterConfig: AnyConfigurationModel;
8
- stopToken?: string;
9
- sessionId: string;
10
- headers?: Record<string, string>;
11
- regions: Region[];
12
- bpPerPx: number;
13
- }, rpcDriverClassName: string): Promise<Record<string, {
14
- name: string;
15
- scores: string[];
16
- }>>;
5
+ execute(args: GetScoreMatrixArgs, rpcDriverClassName: string): Promise<Record<string, number[]>>;
17
6
  }