@jbrowse/wiggle-core 4.3.0 → 5.0.0-beta.10

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 (73) hide show
  1. package/README.md +76 -107
  2. package/esm/AutoscaleGroupDialog.d.ts +7 -0
  3. package/esm/AutoscaleGroupDialog.js +26 -0
  4. package/esm/ScoreAxisMixin.d.ts +134 -0
  5. package/esm/ScoreAxisMixin.js +213 -0
  6. package/esm/ScoreFieldConfigMixin.d.ts +72 -0
  7. package/esm/ScoreFieldConfigMixin.js +25 -0
  8. package/esm/ScorePlotChrome.d.ts +45 -0
  9. package/esm/ScorePlotChrome.js +47 -0
  10. package/esm/ScorePlotSvgFrame.d.ts +27 -0
  11. package/esm/ScorePlotSvgFrame.js +23 -0
  12. package/esm/ScoreScaleMixin.d.ts +113 -50
  13. package/esm/ScoreScaleMixin.js +148 -70
  14. package/esm/SetMinMaxDialog.d.ts +3 -2
  15. package/esm/SetMinMaxDialog.js +20 -6
  16. package/esm/SetScoreRulesDialog.d.ts +14 -0
  17. package/esm/SetScoreRulesDialog.js +45 -0
  18. package/esm/WiggleScoreConfigMixin.d.ts +89 -0
  19. package/esm/WiggleScoreConfigMixin.js +54 -0
  20. package/esm/autoscale.d.ts +54 -14
  21. package/esm/autoscale.js +105 -180
  22. package/esm/autoscaleGroup.d.ts +30 -0
  23. package/esm/autoscaleGroup.js +97 -0
  24. package/esm/chrome.d.ts +5 -0
  25. package/esm/chrome.js +7 -0
  26. package/esm/computeYTicks.d.ts +1 -1
  27. package/esm/computeYTicks.js +4 -3
  28. package/esm/constants.d.ts +1 -2
  29. package/esm/constants.js +1 -10
  30. package/esm/dataTypes.d.ts +4 -6
  31. package/esm/displayModel.d.ts +1 -2
  32. package/esm/gapBreak.d.ts +2 -3
  33. package/esm/gapBreak.js +2 -3
  34. package/esm/index.d.ts +24 -25
  35. package/esm/index.js +20 -18
  36. package/esm/normalize.d.ts +1 -26
  37. package/esm/normalize.js +1 -86
  38. package/esm/pointMarker.d.ts +7 -2
  39. package/esm/pointMarker.js +14 -18
  40. package/esm/pointSizeMenu.d.ts +30 -11
  41. package/esm/pointSizeMenu.js +42 -19
  42. package/esm/renderingBackendTypes.d.ts +13 -4
  43. package/esm/renderingBackendTypes.js +4 -1
  44. package/esm/rowLabelOffset.d.ts +8 -0
  45. package/esm/rowLabelOffset.js +16 -0
  46. package/esm/scale.d.ts +12 -8
  47. package/esm/scale.js +27 -14
  48. package/esm/scoreFieldConfigSchemaFields.d.ts +10 -0
  49. package/esm/scoreFieldConfigSchemaFields.js +8 -0
  50. package/esm/scoreMenuItems.d.ts +35 -16
  51. package/esm/scoreMenuItems.js +95 -62
  52. package/esm/scoreRuleMarks.d.ts +14 -39
  53. package/esm/scoreRuleMarks.js +12 -45
  54. package/esm/transferables.js +4 -9
  55. package/esm/valueScaleConfigSchema.d.ts +253 -0
  56. package/esm/valueScaleConfigSchema.js +270 -0
  57. package/esm/visibleStatsDomain.d.ts +20 -8
  58. package/esm/visibleStatsDomain.js +32 -27
  59. package/esm/wiggleRenderModes.generated.d.ts +1 -2
  60. package/esm/wiggleRenderModes.generated.js +1 -2
  61. package/package.json +14 -9
  62. package/esm/CrossHatches.d.ts +0 -11
  63. package/esm/CrossHatches.js +0 -32
  64. package/esm/ScoreRules.d.ts +0 -11
  65. package/esm/ScoreRules.js +0 -37
  66. package/esm/YScaleBar.d.ts +0 -6
  67. package/esm/YScaleBar.js +0 -46
  68. package/esm/YScaleBarOverlay.d.ts +0 -6
  69. package/esm/YScaleBarOverlay.js +0 -24
  70. package/esm/scoreAxisConfigSchemaFields.d.ts +0 -44
  71. package/esm/scoreAxisConfigSchemaFields.js +0 -54
  72. package/esm/yScaleTicks.d.ts +0 -59
  73. package/esm/yScaleTicks.js +0 -59
@@ -1,110 +1,159 @@
1
- import { getConf, setConf } from '@jbrowse/core/configuration';
2
- import { types } from '@jbrowse/mobx-state-tree';
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
- // field table beside it rather than `AnyConfigurationModel`, which is what keeps
6
- // the slot names below checked.
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 Score axis. Nothing — the config slots. Brings `scaleType` / `autoscaleType` / `minScore` / `maxScore` / `*Bound` / `numStdDev` and their setters, i.e. the whole `ScoreScaleModel` interface the shared score menu and `SetMinMaxDialog` consume
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 score axis every quantitative display shares: which scale, how to
14
- * autoscale it, and the manual min/max bounds. This is the runtime half of
15
- * {@link ScoreScaleModel} in `scoreMenuItems.ts` — that interface is what the
16
- * shared Score menu, the autoscale/scale submenus and `SetMinMaxDialog` consume,
17
- * and it was already the canonical contract while two displays hand-wrote
18
- * identical implementations of it (`WiggleScoreConfigMixin`, and the alignments
19
- * coverage band). Composing this is now how a display satisfies it, so a new
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 axis. Colors, `resolution`, cross-hatches and the
23
- * autoscale *computation* stay in `WiggleScoreConfigMixin` / `WiggleCommonMixin`
24
- * — the alignments coverage band shares this axis but none of the rest.
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 types
34
- .model('ScoreScaleMixin', {})
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), 'scaleType');
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 autoscaleType() {
46
- return getConf(confNode(self), 'autoscale');
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 numStdDev() {
52
- return getConf(confNode(self), 'numStdDev');
79
+ get manualMinScore() {
80
+ return getConf(confNode(self), ['scales', 'y', 'domainMin']);
53
81
  },
54
82
  /**
55
83
  * #getter
56
- * Raw slot value, sentinel intact — see the class comment.
84
+ * The upper bound the config pins, `undefined` where it pins none.
57
85
  */
58
- get minScore() {
59
- return getConf(confNode(self), 'minScore');
86
+ get manualMaxScore() {
87
+ return getConf(confNode(self), ['scales', 'y', 'domainMax']);
60
88
  },
61
89
  /**
62
90
  * #getter
63
- * Raw slot value, sentinel intact — see the class comment.
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 maxScore() {
66
- return getConf(confNode(self), 'maxScore');
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
- * Overridable hook: what each end of the domain falls back to where the
71
- * config leaves its bound unset. `[undefined, undefined]` — the default —
72
- * means autoscale both ends, which is right for a track whose scores have
73
- * no absolute meaning (a bigwig's units are its own).
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
- * Resolved lower bound; `undefined` means autoscale this end.
112
+ * `scales.y.title`, `''` while unset
94
113
  */
95
- get minScoreBound() {
96
- return this.minScore === Number.MIN_VALUE
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
- * Resolved upper bound; `undefined` means autoscale this end.
119
+ * `scales.y.grid`
103
120
  */
104
- get maxScoreBound() {
105
- return this.maxScore === Number.MAX_VALUE
106
- ? this.defaultScoreDomain[1]
107
- : this.maxScore;
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), 'scaleType', scaleType);
164
+ setConf(confNode(self), ['scales', 'y', 'type'], scaleType);
116
165
  },
117
166
  /**
118
167
  * #action
119
168
  */
120
- setAutoscale(val) {
121
- setConf(confNode(self), 'autoscale', val);
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), 'minScore', val);
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), 'maxScore', val);
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
  }
@@ -1,11 +1,12 @@
1
1
  declare const _default: (props: {
2
2
  model: {
3
- minScore: number;
4
- maxScore: number;
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;
@@ -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 { minScore, maxScore, scaleType } = model;
9
- const [min, setMin] = useState(minScore === Number.MIN_VALUE ? undefined : minScore);
10
- const [max, setMax] = useState(maxScore === Number.MAX_VALUE ? undefined : maxScore);
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: " }), !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" }), _jsx(NumberTextField, { defaultValue: max, onValueChange: setMax, placeholder: "Enter 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
+ }
@@ -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
- * Converts score stats into a `[min, max]` domain, applying std-dev
35
- * expansion for the `localsd` autoscale type.
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 domainFromStats(stats: ScoreStats, autoscaleType: string, numStdDev: number): [number, number];
38
- export declare function autoscaleDomainFromStats({ stats, autoscaleType, summaryScoreMode, numStdDev, numQuantile, visibleEntries, }: {
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
- autoscaleType: string;
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
- * Computes a score domain from the visible feature arrays for the `local` /
49
- * `localsd` / `localpercentile` autoscale types.
88
+ * The score domain of the visible feature arrays, following `quantile` as
89
+ * `scales.y.domainQuantile` says.
50
90
  */
51
- export declare function computeAutoscaleDomain(autoscaleType: string, summaryScoreMode: string, numStdDev: number, visibleEntries: {
91
+ export declare function computeAutoscaleDomain(quantile: number, summaryScoreMode: string, visibleEntries: {
52
92
  data: FeatureArrays;
53
93
  visStart: number;
54
94
  visEnd: number;
55
- }[], numQuantile?: number): [number, number] | undefined;
95
+ }[]): [number, number] | undefined;