@jbrowse/wiggle-core 5.0.0-beta.1 → 5.0.0-beta.11
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/README.md +76 -107
- package/esm/AutoscaleGroupDialog.d.ts +7 -0
- package/esm/AutoscaleGroupDialog.js +26 -0
- package/esm/ScoreAxisMixin.d.ts +134 -0
- package/esm/ScoreAxisMixin.js +213 -0
- package/esm/ScoreFieldConfigMixin.d.ts +72 -0
- package/esm/ScoreFieldConfigMixin.js +25 -0
- package/esm/ScorePlotChrome.d.ts +45 -0
- package/esm/ScorePlotChrome.js +47 -0
- package/esm/ScorePlotSvgFrame.d.ts +27 -0
- package/esm/ScorePlotSvgFrame.js +23 -0
- package/esm/ScoreScaleMixin.d.ts +113 -50
- package/esm/ScoreScaleMixin.js +148 -70
- package/esm/SetMinMaxDialog.d.ts +3 -2
- package/esm/SetMinMaxDialog.js +20 -6
- package/esm/SetScoreRulesDialog.d.ts +14 -0
- package/esm/SetScoreRulesDialog.js +45 -0
- package/esm/WiggleScoreConfigMixin.d.ts +89 -0
- package/esm/WiggleScoreConfigMixin.js +54 -0
- package/esm/autoscale.d.ts +54 -14
- package/esm/autoscale.js +105 -180
- package/esm/autoscaleGroup.d.ts +30 -0
- package/esm/autoscaleGroup.js +97 -0
- package/esm/chrome.d.ts +5 -0
- package/esm/chrome.js +7 -0
- package/esm/computeYTicks.d.ts +1 -1
- package/esm/computeYTicks.js +4 -3
- package/esm/constants.d.ts +1 -2
- package/esm/constants.js +1 -10
- package/esm/dataTypes.d.ts +4 -6
- package/esm/displayModel.d.ts +1 -2
- package/esm/gapBreak.d.ts +2 -3
- package/esm/gapBreak.js +2 -3
- package/esm/index.d.ts +24 -25
- package/esm/index.js +20 -18
- package/esm/normalize.d.ts +1 -26
- package/esm/normalize.js +1 -86
- package/esm/pointMarker.d.ts +7 -2
- package/esm/pointMarker.js +14 -18
- package/esm/pointSizeMenu.d.ts +30 -11
- package/esm/pointSizeMenu.js +42 -19
- package/esm/renderingBackendTypes.d.ts +13 -4
- package/esm/renderingBackendTypes.js +4 -1
- package/esm/rowLabelOffset.d.ts +8 -0
- package/esm/rowLabelOffset.js +16 -0
- package/esm/scale.d.ts +12 -8
- package/esm/scale.js +27 -14
- package/esm/scoreFieldConfigSchemaFields.d.ts +10 -0
- package/esm/scoreFieldConfigSchemaFields.js +8 -0
- package/esm/scoreMenuItems.d.ts +35 -16
- package/esm/scoreMenuItems.js +95 -62
- package/esm/scoreRuleMarks.d.ts +14 -39
- package/esm/scoreRuleMarks.js +12 -45
- package/esm/transferables.js +4 -9
- package/esm/valueScaleConfigSchema.d.ts +253 -0
- package/esm/valueScaleConfigSchema.js +270 -0
- package/esm/visibleStatsDomain.d.ts +19 -8
- package/esm/visibleStatsDomain.js +32 -27
- package/esm/wiggleRenderModes.generated.d.ts +1 -2
- package/esm/wiggleRenderModes.generated.js +1 -2
- package/package.json +17 -10
- package/esm/CrossHatches.d.ts +0 -11
- package/esm/CrossHatches.js +0 -32
- package/esm/ScoreRules.d.ts +0 -11
- package/esm/ScoreRules.js +0 -37
- package/esm/YScaleBar.d.ts +0 -6
- package/esm/YScaleBar.js +0 -46
- package/esm/YScaleBarOverlay.d.ts +0 -6
- package/esm/YScaleBarOverlay.js +0 -24
- package/esm/scoreAxisConfigSchemaFields.d.ts +0 -44
- package/esm/scoreAxisConfigSchemaFields.js +0 -54
- package/esm/yScaleTicks.d.ts +0 -59
- package/esm/yScaleTicks.js +0 -59
package/esm/ScoreScaleMixin.js
CHANGED
|
@@ -1,110 +1,159 @@
|
|
|
1
|
-
import { getConf, setConf } from '@jbrowse/core/configuration';
|
|
2
|
-
import {
|
|
1
|
+
import { getConf, getSlotDefinition, readConfObject, setConf, } from '@jbrowse/core/configuration';
|
|
2
|
+
import { noticeLines, scaleEndProblems } from '@jbrowse/core/util/colorScale';
|
|
3
|
+
import { clipQuantileOf } from '@jbrowse/core/util/quantileExtent';
|
|
4
|
+
import { rulesABand } from '@jbrowse/display-ui/axisPlacement';
|
|
5
|
+
import { ScoreAxisMixin } from './ScoreAxisMixin.js';
|
|
3
6
|
// The mixin composes onto a display that declares this, not the other way
|
|
4
7
|
// round, so its own `self` isn't typed with it. Cast once, narrowed to the
|
|
5
|
-
//
|
|
6
|
-
//
|
|
8
|
+
// factory's schema rather than `AnyConfigurationModel`, which is what keeps the
|
|
9
|
+
// member names below checked.
|
|
7
10
|
const confNode = (self) => self;
|
|
8
11
|
/**
|
|
9
12
|
* #stateModel ScoreScaleMixin
|
|
10
13
|
* #category display
|
|
11
|
-
* #crossCuttingMixin
|
|
14
|
+
* #crossCuttingMixin Value scale, written in `scales.y`. `valueScaleSchema` / `scalesSchema`. Brings `ScoreAxisMixin` plus `scaleType` / `scaleZero` / `domainQuantile` / `clipQuantile` / `symlogConstant` / `manual*` and their setters, i.e. the whole `ScoreScaleModel` interface the shared score menu and `SetMinMaxDialog` consume
|
|
12
15
|
*
|
|
13
|
-
* The
|
|
14
|
-
*
|
|
15
|
-
* {@link
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* score display cannot satisfy it *partially*.
|
|
16
|
+
* The value scale of every quantitative display: wiggle, the alignments
|
|
17
|
+
* coverage band and the mark display, Manhattan among them, each declare
|
|
18
|
+
* `scales.y` through {@link valueScaleSchema} and compose this. It backs
|
|
19
|
+
* {@link ScoreAxisMixin}'s three overridable members off that object and adds
|
|
20
|
+
* the setters that write it, so composing this is how a display satisfies
|
|
21
|
+
* {@link ScoreScaleModel} in `scoreMenuItems.ts` — the interface the shared
|
|
22
|
+
* Score menu, the scale and autoscale submenus and `SetMinMaxDialog` consume.
|
|
21
23
|
*
|
|
22
|
-
* Deliberately just the
|
|
23
|
-
* autoscale *computation* stay in `WiggleScoreConfigMixin` /
|
|
24
|
-
* — the alignments coverage band shares this
|
|
25
|
-
*
|
|
26
|
-
* `minScore`/`maxScore` are the **raw** slot values with their
|
|
27
|
-
* `Number.MIN_VALUE`/`Number.MAX_VALUE` "unset" sentinels intact, because that
|
|
28
|
-
* is what the dialog round-trips; `minScoreBound`/`maxScoreBound` are the
|
|
29
|
-
* resolved bounds, where `undefined` means "autoscale this end". Every consumer
|
|
30
|
-
* that computes a domain reads the `*Bound` pair.
|
|
24
|
+
* Deliberately just the scale and the guides it owns. Colors, `resolution`
|
|
25
|
+
* and the autoscale *computation* stay in `WiggleScoreConfigMixin` /
|
|
26
|
+
* `WiggleCommonMixin` — the alignments coverage band shares this scale but
|
|
27
|
+
* none of the rest.
|
|
31
28
|
*/
|
|
32
29
|
export function ScoreScaleMixin() {
|
|
33
|
-
return
|
|
34
|
-
.
|
|
30
|
+
return ScoreAxisMixin()
|
|
31
|
+
.volatile(() => ({
|
|
32
|
+
unclippedQuantile: undefined,
|
|
33
|
+
}))
|
|
35
34
|
.views(self => ({
|
|
36
35
|
/**
|
|
37
36
|
* #getter
|
|
38
37
|
*/
|
|
39
38
|
get scaleType() {
|
|
40
|
-
return getConf(confNode(self), '
|
|
39
|
+
return getConf(confNode(self), ['scales', 'y', 'type']);
|
|
40
|
+
},
|
|
41
|
+
/**
|
|
42
|
+
* #getter
|
|
43
|
+
* `scales.y.zero`: whether an autoscaled linear or symlog axis reaches
|
|
44
|
+
* 0.
|
|
45
|
+
*/
|
|
46
|
+
get scaleZero() {
|
|
47
|
+
return getConf(confNode(self), ['scales', 'y', 'zero']);
|
|
48
|
+
},
|
|
49
|
+
/**
|
|
50
|
+
* #getter
|
|
51
|
+
* `scales.y.domainQuantile`: what an unpinned end follows, 1 the
|
|
52
|
+
* extremes and below it that quantile of each sign.
|
|
53
|
+
*/
|
|
54
|
+
get domainQuantile() {
|
|
55
|
+
return getConf(confNode(self), ['scales', 'y', 'domainQuantile']);
|
|
56
|
+
},
|
|
57
|
+
/**
|
|
58
|
+
* #getter
|
|
59
|
+
* The quantile "Clip outliers" clips at: the one an untick this session
|
|
60
|
+
* wrote over, else the scale's own default where that is below 1, else
|
|
61
|
+
* 0.99.
|
|
62
|
+
*/
|
|
63
|
+
get clipQuantile() {
|
|
64
|
+
return (self.unclippedQuantile ??
|
|
65
|
+
clipQuantileOf(getSlotDefinition(confNode(self).configuration.scales.y, 'domainQuantile').defaultValue));
|
|
41
66
|
},
|
|
42
67
|
/**
|
|
43
68
|
* #getter
|
|
69
|
+
* Raw slot; `0` means "derive from the domain". Resolve it with
|
|
70
|
+
* `resolveSymlogConstant` once the domain is known.
|
|
44
71
|
*/
|
|
45
|
-
get
|
|
46
|
-
return getConf(confNode(self), '
|
|
72
|
+
get symlogConstant() {
|
|
73
|
+
return getConf(confNode(self), ['scales', 'y', 'symlogConstant']);
|
|
47
74
|
},
|
|
48
75
|
/**
|
|
49
76
|
* #getter
|
|
77
|
+
* The lower bound the config pins, `undefined` where it pins none.
|
|
50
78
|
*/
|
|
51
|
-
get
|
|
52
|
-
return getConf(confNode(self), '
|
|
79
|
+
get manualMinScore() {
|
|
80
|
+
return getConf(confNode(self), ['scales', 'y', 'domainMin']);
|
|
53
81
|
},
|
|
54
82
|
/**
|
|
55
83
|
* #getter
|
|
56
|
-
*
|
|
84
|
+
* The upper bound the config pins, `undefined` where it pins none.
|
|
57
85
|
*/
|
|
58
|
-
get
|
|
59
|
-
return getConf(confNode(self), '
|
|
86
|
+
get manualMaxScore() {
|
|
87
|
+
return getConf(confNode(self), ['scales', 'y', 'domainMax']);
|
|
60
88
|
},
|
|
61
89
|
/**
|
|
62
90
|
* #getter
|
|
63
|
-
*
|
|
91
|
+
* What `scales.y`'s ends say together that the axis cannot draw as
|
|
92
|
+
* written, as corner-notice lines, by the rule a colour ramp's ends
|
|
93
|
+
* answer to. The mark display reports them through its rule list.
|
|
64
94
|
*/
|
|
65
|
-
get
|
|
66
|
-
return
|
|
95
|
+
get valueScaleNotices() {
|
|
96
|
+
return noticeLines('scales.y', scaleEndProblems({
|
|
97
|
+
domainMin: this.manualMinScore,
|
|
98
|
+
domainMax: this.manualMaxScore,
|
|
99
|
+
domainQuantile: this.domainQuantile,
|
|
100
|
+
}));
|
|
67
101
|
},
|
|
68
102
|
/**
|
|
69
103
|
* #getter
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
* A display whose scores are bounded *by construction* overrides it, so
|
|
76
|
-
* the axis stops being a function of what happens to be on screen: GC
|
|
77
|
-
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
78
|
-
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
79
|
-
* heights depending on where the user had panned, and the track could not
|
|
80
|
-
* be read across loci.
|
|
81
|
-
*
|
|
82
|
-
* A hook rather than a config default because the answer can depend on
|
|
83
|
-
* display state — GC's does, on `gcMode` — and rather than each display
|
|
84
|
-
* re-resolving the sentinels below, which is the one thing that must not
|
|
85
|
-
* be duplicated: config bounds still win, precisely because they are
|
|
86
|
-
* checked before this is consulted.
|
|
87
|
-
*/
|
|
88
|
-
get defaultScoreDomain() {
|
|
89
|
-
return [undefined, undefined];
|
|
104
|
+
* `scales.y.autoscaleGroup`, `undefined` while it names none.
|
|
105
|
+
*/
|
|
106
|
+
get autoscaleGroup() {
|
|
107
|
+
return (getConf(confNode(self), ['scales', 'y', 'autoscaleGroup']) ||
|
|
108
|
+
undefined);
|
|
90
109
|
},
|
|
91
110
|
/**
|
|
92
111
|
* #getter
|
|
93
|
-
*
|
|
112
|
+
* `scales.y.title`, `''` while unset
|
|
94
113
|
*/
|
|
95
|
-
get
|
|
96
|
-
return
|
|
97
|
-
? this.defaultScoreDomain[0]
|
|
98
|
-
: this.minScore;
|
|
114
|
+
get scaleTitle() {
|
|
115
|
+
return getConf(confNode(self), ['scales', 'y', 'title']) ?? '';
|
|
99
116
|
},
|
|
100
117
|
/**
|
|
101
118
|
* #getter
|
|
102
|
-
*
|
|
119
|
+
* `scales.y.grid`
|
|
103
120
|
*/
|
|
104
|
-
get
|
|
105
|
-
return
|
|
106
|
-
|
|
107
|
-
|
|
121
|
+
get grid() {
|
|
122
|
+
return getConf(confNode(self), ['scales', 'y', 'grid']);
|
|
123
|
+
},
|
|
124
|
+
/**
|
|
125
|
+
* #getter
|
|
126
|
+
* `scales.y.minimalTicks`
|
|
127
|
+
*/
|
|
128
|
+
get minimalTicks() {
|
|
129
|
+
return getConf(confNode(self), ['scales', 'y', 'minimalTicks']);
|
|
130
|
+
},
|
|
131
|
+
/**
|
|
132
|
+
* #getter
|
|
133
|
+
* Whether this display draws `scales.y.rules`, which is whether the
|
|
134
|
+
* score menu offers the reference lines: a scale it places y through
|
|
135
|
+
* rules a band for them to cross, which a density plot's colour-mapped
|
|
136
|
+
* rows and a colour ramp do not.
|
|
137
|
+
*/
|
|
138
|
+
get scoreRulesDrawn() {
|
|
139
|
+
return self.valueScales.some(rulesABand);
|
|
140
|
+
},
|
|
141
|
+
/**
|
|
142
|
+
* #getter
|
|
143
|
+
* `scales.y.rules`, read off the live nodes: a snapshot strips a slot at
|
|
144
|
+
* its default, and a rule at 0 is one.
|
|
145
|
+
*/
|
|
146
|
+
get scoreRules() {
|
|
147
|
+
const { rules } = confNode(self).configuration.scales.y;
|
|
148
|
+
return rules.map((rule) => {
|
|
149
|
+
const label = readConfObject(rule, 'label');
|
|
150
|
+
const color = readConfObject(rule, 'color');
|
|
151
|
+
return {
|
|
152
|
+
value: readConfObject(rule, 'value'),
|
|
153
|
+
...(color ? { color } : {}),
|
|
154
|
+
...(label ? { label } : {}),
|
|
155
|
+
};
|
|
156
|
+
});
|
|
108
157
|
},
|
|
109
158
|
}))
|
|
110
159
|
.actions(self => ({
|
|
@@ -112,25 +161,54 @@ export function ScoreScaleMixin() {
|
|
|
112
161
|
* #action
|
|
113
162
|
*/
|
|
114
163
|
setScaleType(scaleType) {
|
|
115
|
-
setConf(confNode(self), '
|
|
164
|
+
setConf(confNode(self), ['scales', 'y', 'type'], scaleType);
|
|
116
165
|
},
|
|
117
166
|
/**
|
|
118
167
|
* #action
|
|
119
168
|
*/
|
|
120
|
-
|
|
121
|
-
setConf(confNode(self), '
|
|
169
|
+
setScaleZero(zero) {
|
|
170
|
+
setConf(confNode(self), ['scales', 'y', 'zero'], zero);
|
|
171
|
+
},
|
|
172
|
+
/**
|
|
173
|
+
* #action
|
|
174
|
+
*/
|
|
175
|
+
setDomainQuantile(quantile) {
|
|
176
|
+
if (!(quantile < 1) && self.domainQuantile < 1) {
|
|
177
|
+
self.unclippedQuantile = self.domainQuantile;
|
|
178
|
+
}
|
|
179
|
+
setConf(confNode(self), ['scales', 'y', 'domainQuantile'], quantile);
|
|
122
180
|
},
|
|
123
181
|
/**
|
|
124
182
|
* #action
|
|
125
183
|
*/
|
|
126
184
|
setMinScore(val) {
|
|
127
|
-
setConf(confNode(self), '
|
|
185
|
+
setConf(confNode(self), ['scales', 'y', 'domainMin'], val);
|
|
128
186
|
},
|
|
129
187
|
/**
|
|
130
188
|
* #action
|
|
131
189
|
*/
|
|
132
190
|
setMaxScore(val) {
|
|
133
|
-
setConf(confNode(self), '
|
|
191
|
+
setConf(confNode(self), ['scales', 'y', 'domainMax'], val);
|
|
192
|
+
},
|
|
193
|
+
/**
|
|
194
|
+
* #action
|
|
195
|
+
*/
|
|
196
|
+
setAutoscaleGroup(group) {
|
|
197
|
+
setConf(confNode(self), ['scales', 'y', 'autoscaleGroup'], group);
|
|
198
|
+
},
|
|
199
|
+
/**
|
|
200
|
+
* #action
|
|
201
|
+
*/
|
|
202
|
+
setGrid(grid) {
|
|
203
|
+
setConf(confNode(self), ['scales', 'y', 'grid'], grid);
|
|
204
|
+
},
|
|
205
|
+
/**
|
|
206
|
+
* #action
|
|
207
|
+
* Replaces `scales.y.rules` whole, each entry in a form the config
|
|
208
|
+
* takes: a number, or `{ value, color, label }`.
|
|
209
|
+
*/
|
|
210
|
+
setScoreRules(rules) {
|
|
211
|
+
setConf(confNode(self), ['scales', 'y', 'rules'], rules);
|
|
134
212
|
},
|
|
135
213
|
}));
|
|
136
214
|
}
|
package/esm/SetMinMaxDialog.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
declare const _default: (props: {
|
|
2
2
|
model: {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
manualMinScore: number | undefined;
|
|
4
|
+
manualMaxScore: number | undefined;
|
|
5
5
|
scaleType: string;
|
|
6
6
|
setMinScore: (arg?: number) => void;
|
|
7
7
|
setMaxScore: (arg?: number) => void;
|
|
8
8
|
};
|
|
9
|
+
domain?: [number, number];
|
|
9
10
|
handleClose: () => void;
|
|
10
11
|
}) => import("react").JSX.Element;
|
|
11
12
|
export default _default;
|
package/esm/SetMinMaxDialog.js
CHANGED
|
@@ -1,18 +1,32 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { NumberTextField, SubmitDialog } from '@jbrowse/core/ui';
|
|
4
|
-
import { Typography } from '@mui/material';
|
|
4
|
+
import { Button, Typography } from '@mui/material';
|
|
5
5
|
import { observer } from 'mobx-react';
|
|
6
|
+
// The two fields open on what the config really pins, which is the mixin's
|
|
7
|
+
// `manual*` pair rather than the raw slots — the sentinel comparison is one
|
|
8
|
+
// answer per end and lives there. Submitting `undefined` writes the sentinel
|
|
9
|
+
// back, so an emptied field is how autoscale resumes.
|
|
6
10
|
export default observer(function SetMinMaxDialog(props) {
|
|
7
|
-
const { model, handleClose } = props;
|
|
8
|
-
const {
|
|
9
|
-
const [min, setMin] = useState(
|
|
10
|
-
const [max, setMax] = useState(
|
|
11
|
+
const { model, domain, handleClose } = props;
|
|
12
|
+
const { manualMinScore, manualMaxScore, scaleType } = model;
|
|
13
|
+
const [min, setMin] = useState(manualMinScore);
|
|
14
|
+
const [max, setMax] = useState(manualMaxScore);
|
|
15
|
+
// The fields own their text, so filling them from the button remounts them.
|
|
16
|
+
const [fill, setFill] = useState(0);
|
|
11
17
|
const rangeOk = min === undefined || max === undefined || max > min;
|
|
12
18
|
const logOk = !(scaleType === 'log' && min !== undefined && min <= 0);
|
|
13
19
|
return (_jsxs(SubmitDialog, { open: true, title: "Set min/max score for track", submitDisabled: !rangeOk || !logOk, onCancel: handleClose, onSubmit: () => {
|
|
14
20
|
model.setMinScore(min);
|
|
15
21
|
model.setMaxScore(max);
|
|
16
22
|
handleClose();
|
|
17
|
-
}, children: [_jsx(Typography, { children: "Enter min/max score
|
|
23
|
+
}, children: [_jsx(Typography, { children: "Enter min/max score, or leave a field empty to autoscale that end" }), !rangeOk ? (_jsx(Typography, { color: "error", children: "Max must be greater than min" })) : null, !logOk ? (_jsx(Typography, { color: "error", children: "Min score should be greater than 0 for log scale" })) : null, _jsx(NumberTextField, { defaultValue: min, onValueChange: setMin, placeholder: "Enter min score" }, `min-${fill}`), _jsx(NumberTextField, { defaultValue: max, onValueChange: setMax, placeholder: "Enter max score" }, `max-${fill}`), _jsxs("div", { children: [domain ? (_jsx(Button, { onClick: () => {
|
|
24
|
+
setMin(domain[0]);
|
|
25
|
+
setMax(domain[1]);
|
|
26
|
+
setFill(n => n + 1);
|
|
27
|
+
}, children: "Use current range" })) : null, _jsx(Button, { disabled: min === undefined && max === undefined, onClick: () => {
|
|
28
|
+
setMin(undefined);
|
|
29
|
+
setMax(undefined);
|
|
30
|
+
setFill(n => n + 1);
|
|
31
|
+
}, children: "Clear" })] })] }));
|
|
18
32
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ValueScaleRule } from '@jbrowse/display-ui';
|
|
2
|
+
/**
|
|
3
|
+
* The score menu's editor for `scales.y.rules`: one row per reference line,
|
|
4
|
+
* its value on the plot's own scale, its label and its colour. An empty colour
|
|
5
|
+
* is the display's default, and removing every row removes every line.
|
|
6
|
+
*/
|
|
7
|
+
declare const _default: ({ model, handleClose, }: {
|
|
8
|
+
model: {
|
|
9
|
+
scoreRules: ValueScaleRule[];
|
|
10
|
+
setScoreRules: (rules: ValueScaleRule[]) => void;
|
|
11
|
+
};
|
|
12
|
+
handleClose: () => void;
|
|
13
|
+
}) => import("react").JSX.Element;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { SubmitDialog } from '@jbrowse/core/ui';
|
|
4
|
+
import { isCssColor } from '@jbrowse/core/util/colorBits';
|
|
5
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
6
|
+
import { Button, IconButton, TextField, Typography } from '@mui/material';
|
|
7
|
+
import { observer } from 'mobx-react';
|
|
8
|
+
function rowOf({ value, label = '', color = '' }) {
|
|
9
|
+
return { value: String(value), label, color };
|
|
10
|
+
}
|
|
11
|
+
function valueOk({ value }) {
|
|
12
|
+
return value.trim() !== '' && Number.isFinite(Number(value));
|
|
13
|
+
}
|
|
14
|
+
function colorOk({ color }) {
|
|
15
|
+
return color.trim() === '' || isCssColor(color);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The score menu's editor for `scales.y.rules`: one row per reference line,
|
|
19
|
+
* its value on the plot's own scale, its label and its colour. An empty colour
|
|
20
|
+
* is the display's default, and removing every row removes every line.
|
|
21
|
+
*/
|
|
22
|
+
export default observer(function SetScoreRulesDialog({ model, handleClose, }) {
|
|
23
|
+
const [rows, setRows] = useState(() => model.scoreRules.map(rowOf));
|
|
24
|
+
const setRow = (index, patch) => {
|
|
25
|
+
setRows(rows.map((row, i) => (i === index ? { ...row, ...patch } : row)));
|
|
26
|
+
};
|
|
27
|
+
return (_jsxs(SubmitDialog, { open: true, title: "Reference lines", submitDisabled: !rows.every(row => valueOk(row) && colorOk(row)), onCancel: handleClose, onSubmit: () => {
|
|
28
|
+
model.setScoreRules(rows.map(row => ({
|
|
29
|
+
value: Number(row.value),
|
|
30
|
+
...(row.label ? { label: row.label } : {}),
|
|
31
|
+
...(row.color.trim() ? { color: row.color.trim() } : {}),
|
|
32
|
+
})));
|
|
33
|
+
handleClose();
|
|
34
|
+
}, children: [_jsx(Typography, { children: "A horizontal line at each value, on the same scale as the plot" }), rows.map((row, index) => (_jsxs("div", { style: { display: 'flex', gap: 8, marginTop: 8 }, children: [_jsx(TextField, { label: "Value", value: row.value, error: !valueOk(row), onChange: event => {
|
|
35
|
+
setRow(index, { value: event.target.value });
|
|
36
|
+
} }), _jsx(TextField, { label: "Label", value: row.label, onChange: event => {
|
|
37
|
+
setRow(index, { label: event.target.value });
|
|
38
|
+
} }), _jsx(TextField, { label: "Color", value: row.color, error: !colorOk(row), onChange: event => {
|
|
39
|
+
setRow(index, { color: event.target.value });
|
|
40
|
+
} }), _jsx(IconButton, { "aria-label": "remove line", onClick: () => {
|
|
41
|
+
setRows(rows.filter((_, i) => i !== index));
|
|
42
|
+
}, children: _jsx(DeleteIcon, {}) })] }, index))), _jsx(Button, { onClick: () => {
|
|
43
|
+
setRows([...rows, { value: '', label: '', color: '' }]);
|
|
44
|
+
}, children: "Add line" })] }));
|
|
45
|
+
});
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { scalesSchema } from './valueScaleConfigSchema.ts';
|
|
2
|
+
import type { ConfigModelForFields } from '@jbrowse/core/configuration';
|
|
3
|
+
/** The slots its composers each declare, with their own defaults. */
|
|
4
|
+
export declare const wiggleScoreConfigExtraSlots: {
|
|
5
|
+
readonly size: {
|
|
6
|
+
readonly type: 'number';
|
|
7
|
+
readonly defaultValue: 2;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export interface WiggleScoreConfigHost {
|
|
11
|
+
configuration: ConfigModelForFields<{
|
|
12
|
+
scales: ReturnType<typeof scalesSchema>;
|
|
13
|
+
} & typeof wiggleScoreConfigExtraSlots>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* #stateModel WiggleScoreConfigMixin
|
|
17
|
+
* #category display
|
|
18
|
+
*
|
|
19
|
+
* The score-plot config every display with a score axis shares: the axis
|
|
20
|
+
* and its guides (`ScoreScaleMixin`) and the scatter point size. A
|
|
21
|
+
* display plotting one configured field composes `ScoreFieldConfigMixin`,
|
|
22
|
+
* which adds `scoreField`.
|
|
23
|
+
*/
|
|
24
|
+
export declare function WiggleScoreConfigMixin(): import("@jbrowse/mobx-state-tree").IModelType<Omit<{}, never>, {
|
|
25
|
+
readonly scaleType: string;
|
|
26
|
+
readonly scaleZero: boolean;
|
|
27
|
+
readonly manualMinScore: number | undefined;
|
|
28
|
+
readonly manualMaxScore: number | undefined;
|
|
29
|
+
readonly defaultScoreDomain: [number | undefined, number | undefined];
|
|
30
|
+
readonly valueScales: import("@jbrowse/display-ui").ValueScale[];
|
|
31
|
+
readonly autoscaleGroup: string | undefined;
|
|
32
|
+
readonly autoscaleRange: [number, number] | undefined;
|
|
33
|
+
} & {
|
|
34
|
+
readonly axisReachesZero: boolean;
|
|
35
|
+
} & {
|
|
36
|
+
readonly autoscaledDomain: [number, number] | undefined;
|
|
37
|
+
readonly minScoreBound: number | undefined;
|
|
38
|
+
readonly maxScoreBound: number | undefined;
|
|
39
|
+
readonly hasManualScoreBounds: boolean;
|
|
40
|
+
readonly axes: import("@jbrowse/display-ui").YAxis[];
|
|
41
|
+
} & {
|
|
42
|
+
unclippedQuantile: number | undefined;
|
|
43
|
+
} & {
|
|
44
|
+
readonly scaleType: string;
|
|
45
|
+
readonly scaleZero: boolean;
|
|
46
|
+
readonly domainQuantile: number;
|
|
47
|
+
readonly clipQuantile: number;
|
|
48
|
+
readonly symlogConstant: number;
|
|
49
|
+
readonly manualMinScore: number | undefined;
|
|
50
|
+
readonly manualMaxScore: number | undefined;
|
|
51
|
+
readonly valueScaleNotices: string[];
|
|
52
|
+
readonly autoscaleGroup: string | undefined;
|
|
53
|
+
readonly scaleTitle: string;
|
|
54
|
+
readonly grid: boolean;
|
|
55
|
+
readonly minimalTicks: boolean;
|
|
56
|
+
readonly scoreRulesDrawn: boolean;
|
|
57
|
+
readonly scoreRules: import("@jbrowse/display-ui").ValueScaleRule[];
|
|
58
|
+
} & {
|
|
59
|
+
setScaleType(scaleType: string): void;
|
|
60
|
+
setScaleZero(zero: boolean): void;
|
|
61
|
+
setDomainQuantile(quantile: number): void;
|
|
62
|
+
setMinScore(val?: number): void;
|
|
63
|
+
setMaxScore(val?: number): void;
|
|
64
|
+
setAutoscaleGroup(group?: string): void;
|
|
65
|
+
setGrid(grid: boolean): void;
|
|
66
|
+
setScoreRules(rules: (number | import("@jbrowse/display-ui").ValueScaleRule)[]): void;
|
|
67
|
+
} & {
|
|
68
|
+
/**
|
|
69
|
+
* #getter
|
|
70
|
+
*/
|
|
71
|
+
readonly size: number;
|
|
72
|
+
/**
|
|
73
|
+
* #getter
|
|
74
|
+
* Whether score maps to color instead of height; a display overrides it.
|
|
75
|
+
*/
|
|
76
|
+
readonly isDensityMode: boolean;
|
|
77
|
+
} & {
|
|
78
|
+
/**
|
|
79
|
+
* #getter
|
|
80
|
+
* A density row maps score to colour and has no axis to start at 0, so
|
|
81
|
+
* its domain spans the values whatever `scales.y.zero` says.
|
|
82
|
+
*/
|
|
83
|
+
readonly axisReachesZero: boolean;
|
|
84
|
+
} & {
|
|
85
|
+
/**
|
|
86
|
+
* #action
|
|
87
|
+
*/
|
|
88
|
+
setSize(val?: number): void;
|
|
89
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { getConf, setConf } from '@jbrowse/core/configuration';
|
|
2
|
+
import { types } from '@jbrowse/mobx-state-tree';
|
|
3
|
+
import { ScoreScaleMixin } from './ScoreScaleMixin.js';
|
|
4
|
+
/** The slots its composers each declare, with their own defaults. */
|
|
5
|
+
export const wiggleScoreConfigExtraSlots = {
|
|
6
|
+
size: { type: 'number', defaultValue: 2 },
|
|
7
|
+
};
|
|
8
|
+
const confNode = (self) => self;
|
|
9
|
+
/**
|
|
10
|
+
* #stateModel WiggleScoreConfigMixin
|
|
11
|
+
* #category display
|
|
12
|
+
*
|
|
13
|
+
* The score-plot config every display with a score axis shares: the axis
|
|
14
|
+
* and its guides (`ScoreScaleMixin`) and the scatter point size. A
|
|
15
|
+
* display plotting one configured field composes `ScoreFieldConfigMixin`,
|
|
16
|
+
* which adds `scoreField`.
|
|
17
|
+
*/
|
|
18
|
+
export function WiggleScoreConfigMixin() {
|
|
19
|
+
return types
|
|
20
|
+
.compose('WiggleScoreConfigMixin', ScoreScaleMixin(), types.model({}))
|
|
21
|
+
.views(self => ({
|
|
22
|
+
/**
|
|
23
|
+
* #getter
|
|
24
|
+
*/
|
|
25
|
+
get size() {
|
|
26
|
+
return getConf(confNode(self), 'size');
|
|
27
|
+
},
|
|
28
|
+
/**
|
|
29
|
+
* #getter
|
|
30
|
+
* Whether score maps to color instead of height; a display overrides it.
|
|
31
|
+
*/
|
|
32
|
+
get isDensityMode() {
|
|
33
|
+
return false;
|
|
34
|
+
},
|
|
35
|
+
}))
|
|
36
|
+
.views(self => ({
|
|
37
|
+
/**
|
|
38
|
+
* #getter
|
|
39
|
+
* A density row maps score to colour and has no axis to start at 0, so
|
|
40
|
+
* its domain spans the values whatever `scales.y.zero` says.
|
|
41
|
+
*/
|
|
42
|
+
get axisReachesZero() {
|
|
43
|
+
return self.scaleZero && !self.isDensityMode;
|
|
44
|
+
},
|
|
45
|
+
}))
|
|
46
|
+
.actions(self => ({
|
|
47
|
+
/**
|
|
48
|
+
* #action
|
|
49
|
+
*/
|
|
50
|
+
setSize(val) {
|
|
51
|
+
setConf(confNode(self), 'size', val);
|
|
52
|
+
},
|
|
53
|
+
}));
|
|
54
|
+
}
|
package/esm/autoscale.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export declare const DEFAULT_AUTOSCALE_OPTIONS: [string, string][];
|
|
2
1
|
export interface FeatureArrays {
|
|
3
2
|
featurePositions: Uint32Array;
|
|
4
3
|
featureScores: Float32Array;
|
|
@@ -15,9 +14,42 @@ export interface Dataset {
|
|
|
15
14
|
export interface ScoreStats {
|
|
16
15
|
scoreMin: number;
|
|
17
16
|
scoreMax: number;
|
|
18
|
-
scoreMean: number;
|
|
19
|
-
scoreStdDev: number;
|
|
20
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* #api
|
|
20
|
+
* One block's worth of values to fold into a domain, whatever packed them: a
|
|
21
|
+
* wiggle source's interleaved `featurePositions` and its summary arrays, or a
|
|
22
|
+
* mark layer's separate `x`/`x2` and its one `y` lane. `starts[i * stride]` and
|
|
23
|
+
* `ends[i * stride + endOffset]` give instance `i`'s span, and `low` and `high`
|
|
24
|
+
* the two ends of its value, one array where the packer ships a single scalar.
|
|
25
|
+
*/
|
|
26
|
+
export interface ScoreSpan {
|
|
27
|
+
count: number;
|
|
28
|
+
starts: Uint32Array;
|
|
29
|
+
ends: Uint32Array;
|
|
30
|
+
stride: number;
|
|
31
|
+
endOffset: number;
|
|
32
|
+
low: Float32Array;
|
|
33
|
+
high: Float32Array;
|
|
34
|
+
visStart?: number;
|
|
35
|
+
visEnd?: number;
|
|
36
|
+
/**
|
|
37
|
+
* Whether the instances are bins sorted by start that never overlap, as a
|
|
38
|
+
* wiggle source's are, so a binary search finds the window's. A mark
|
|
39
|
+
* layer's features overlap and arrive source after source or section after
|
|
40
|
+
* section, so each is tested against the window instead.
|
|
41
|
+
*/
|
|
42
|
+
sortedBins: boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Instance `i`'s row key, and 1 at each key that draws: an instance whose
|
|
45
|
+
* key draws nothing, or lies past the end, folds into no domain. Absent,
|
|
46
|
+
* every instance folds in.
|
|
47
|
+
*/
|
|
48
|
+
row?: Uint32Array;
|
|
49
|
+
drawnKeys?: Uint8Array;
|
|
50
|
+
}
|
|
51
|
+
/** The wiggle packer's arrays as a span, under a summary mode. */
|
|
52
|
+
export declare function datasetSpan({ data, visStart, visEnd }: Dataset, summaryScoreMode: string): ScoreSpan;
|
|
21
53
|
/**
|
|
22
54
|
* #api
|
|
23
55
|
* Per-feature scalar score array for a summary mode: the min/max summary array
|
|
@@ -28,28 +60,36 @@ export declare function getEffectiveScores(data: {
|
|
|
28
60
|
featureMinScores: Float32Array;
|
|
29
61
|
featureMaxScores: Float32Array;
|
|
30
62
|
}, summaryScoreMode: string): Float32Array<ArrayBufferLike>;
|
|
63
|
+
export declare function computeSpanStats(spans: ScoreSpan[]): ScoreStats | undefined;
|
|
64
|
+
/** `computeSpanStats` over the wiggle packer's datasets. */
|
|
31
65
|
export declare function computeScoreStats(summaryScoreMode: string, datasets: Dataset[]): ScoreStats | undefined;
|
|
32
66
|
/**
|
|
33
67
|
* #api
|
|
34
|
-
*
|
|
35
|
-
*
|
|
68
|
+
* The domain the visible instances autoscale to: at a `quantile` of 1 their
|
|
69
|
+
* extremes, `stats`; below it `quantileExtent`'s ends, the bottom read off
|
|
70
|
+
* the `low`s and the top off the `high`s less the zeros where any is
|
|
71
|
+
* positive, so whiskers open to their spread, a sparse window's empty bins
|
|
72
|
+
* lower no top, and a window of nothing above 0 keeps the top it has.
|
|
36
73
|
*/
|
|
37
|
-
export declare function
|
|
38
|
-
|
|
74
|
+
export declare function autoscaleDomainFromSpans({ stats, quantile, spans, }: {
|
|
75
|
+
stats: ScoreStats;
|
|
76
|
+
quantile: number;
|
|
77
|
+
spans: ScoreSpan[];
|
|
78
|
+
}): [number, number];
|
|
79
|
+
/** `autoscaleDomainFromSpans` over the wiggle packer's datasets. */
|
|
80
|
+
export declare function autoscaleDomainFromStats({ stats, quantile, summaryScoreMode, visibleEntries, }: {
|
|
39
81
|
stats: ScoreStats;
|
|
40
|
-
|
|
82
|
+
quantile: number;
|
|
41
83
|
summaryScoreMode: string;
|
|
42
|
-
numStdDev: number;
|
|
43
|
-
numQuantile?: number;
|
|
44
84
|
visibleEntries: Dataset[];
|
|
45
85
|
}): [number, number];
|
|
46
86
|
/**
|
|
47
87
|
* #api
|
|
48
|
-
*
|
|
49
|
-
* `
|
|
88
|
+
* The score domain of the visible feature arrays, following `quantile` as
|
|
89
|
+
* `scales.y.domainQuantile` says.
|
|
50
90
|
*/
|
|
51
|
-
export declare function computeAutoscaleDomain(
|
|
91
|
+
export declare function computeAutoscaleDomain(quantile: number, summaryScoreMode: string, visibleEntries: {
|
|
52
92
|
data: FeatureArrays;
|
|
53
93
|
visStart: number;
|
|
54
94
|
visEnd: number;
|
|
55
|
-
}[]
|
|
95
|
+
}[]): [number, number] | undefined;
|