@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.
- 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 +20 -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 +14 -9
- 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/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# @jbrowse/wiggle-core
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Score-axis scale, autoscale, config mixins and plot chrome shared by wiggle,
|
|
4
|
+
Manhattan, mark and coverage displays
|
|
4
5
|
|
|
5
6
|
<!-- API_DOCS_START -->
|
|
6
7
|
|
|
@@ -8,14 +9,29 @@ Shared scale and autoscale utilities for wiggle and coverage displays
|
|
|
8
9
|
|
|
9
10
|
Auto-generated from `#api` JSDoc tags in this package. Do not edit by hand.
|
|
10
11
|
|
|
12
|
+
### autoscaleDomainFromSpans
|
|
13
|
+
|
|
14
|
+
The domain the visible instances autoscale to: at a `quantile` of 1 their
|
|
15
|
+
extremes, `stats`; below it `quantileExtent`'s ends, the bottom read off the
|
|
16
|
+
`low`s and the top off the `high`s less the zeros where any is positive, so
|
|
17
|
+
whiskers open to their spread, a sparse window's empty bins lower no top, and a
|
|
18
|
+
window of nothing above 0 keeps the top it has.
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
// type signature
|
|
22
|
+
({ stats, quantile, spans, }: { stats: ScoreStats; quantile: number; spans: ScoreSpan[]; }) => [number, number]
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
26
|
+
|
|
11
27
|
### computeAutoscaleDomain
|
|
12
28
|
|
|
13
|
-
|
|
14
|
-
`
|
|
29
|
+
The score domain of the visible feature arrays, following `quantile` as
|
|
30
|
+
`scales.y.domainQuantile` says.
|
|
15
31
|
|
|
16
32
|
```js
|
|
17
33
|
// type signature
|
|
18
|
-
(
|
|
34
|
+
(quantile: number, summaryScoreMode: string, visibleEntries: { data: FeatureArrays; visStart: number; visEnd: number; }[]) => [number, number] | undefined
|
|
19
35
|
```
|
|
20
36
|
|
|
21
37
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
@@ -50,18 +66,6 @@ exactly what it always got.
|
|
|
50
66
|
|
|
51
67
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/gapBreak.ts)
|
|
52
68
|
|
|
53
|
-
### domainFromStats
|
|
54
|
-
|
|
55
|
-
Converts score stats into a `[min, max]` domain, applying std-dev expansion for
|
|
56
|
-
the `localsd` autoscale type.
|
|
57
|
-
|
|
58
|
-
```js
|
|
59
|
-
// type signature
|
|
60
|
-
(stats: ScoreStats, autoscaleType: string, numStdDev: number) => [number, number]
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
64
|
-
|
|
65
69
|
### gapBreakLimit
|
|
66
70
|
|
|
67
71
|
How far apart two consecutive points of an interpolated (point-to-point) line
|
|
@@ -69,12 +73,12 @@ may be before the span between them counts as a hole rather than a segment to
|
|
|
69
73
|
draw. Returns `Infinity` when there is nothing to decide, so a caller can always
|
|
70
74
|
compare against it unguarded.
|
|
71
75
|
|
|
72
|
-
The limit is a multiple of the series'
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
The limit is a multiple of the series' _mean_ spacing rather than an absolute
|
|
77
|
+
distance, so one number works across zoom levels and data types: reduced BigWig
|
|
78
|
+
bins get wider as you zoom out, so any fixed bp threshold would be either
|
|
79
|
+
useless at one end or destructive at the other. It also lets the same rule serve
|
|
80
|
+
a bp axis (wiggle's linecenter) and a px one — the caller picks the space, this
|
|
81
|
+
only cares that the units are consistent.
|
|
78
82
|
|
|
79
83
|
Mean, not median: it is O(1) from the endpoints, and it errs the safe way. A
|
|
80
84
|
series' holes inflate their own mean, which raises the limit and so breaks
|
|
@@ -107,16 +111,19 @@ Per-feature scalar score array for a summary mode: the min/max summary array for
|
|
|
107
111
|
|
|
108
112
|
### getNiceDomain
|
|
109
113
|
|
|
110
|
-
Rounds a domain to "nice" endpoints
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
Rounds a domain to "nice" endpoints. `zero` reaches a linear or symlog domain to
|
|
115
|
+
0 (`scales.y.zero`, ADR-182); a log domain has no 0 and floors at 1 instead. An
|
|
116
|
+
end given an explicit `bounds` value keeps that value exactly — only an
|
|
117
|
+
autoscaled end is rounded. A log scale's floor still outranks a bound it cannot
|
|
118
|
+
hold.
|
|
113
119
|
|
|
114
|
-
The result never descends: a bound that would put `min`
|
|
115
|
-
other end instead,
|
|
120
|
+
The result never descends and never collapses: a bound that would put `min`
|
|
121
|
+
above `max` widens the other end instead, and one value in view widens away from
|
|
122
|
+
itself, so no consumer has to guess what a backwards or a flat domain means.
|
|
116
123
|
|
|
117
124
|
```js
|
|
118
125
|
// type signature
|
|
119
|
-
({
|
|
126
|
+
({…}: { scaleType: string; domain: readonly [number, number]; bounds: readonly [number | undefined, number | undefined]; zero: boolean; }) => [number, number]
|
|
120
127
|
```
|
|
121
128
|
|
|
122
129
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scale.ts)
|
|
@@ -145,41 +152,6 @@ unless `nice: false` says it is already the one being drawn with.
|
|
|
145
152
|
|
|
146
153
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scale.ts)
|
|
147
154
|
|
|
148
|
-
### makeScoreNormalizer
|
|
149
|
-
|
|
150
|
-
Returns a loop-hoistable function normalizing a score to [0,1].
|
|
151
|
-
|
|
152
|
-
`symlogConstant` is only read for `SCALE_TYPE_SYMLOG`, and is expected to be
|
|
153
|
-
already resolved by resolveSymlogConstant — the shader gets the same resolved
|
|
154
|
-
number as a uniform, so the "auto" rule lives on this side only and the two
|
|
155
|
-
backends compare like for like.
|
|
156
|
-
|
|
157
|
-
A range that is zero **or negative** normalizes everything to 0, which is the
|
|
158
|
-
rule `scoreScale.slang` spells as `range <= 0.0`. Testing `range === 0` here
|
|
159
|
-
instead let a descending domain through to a negative `1 / range`, so every
|
|
160
|
-
score saturated to 1 on this side while the shader flattened them all to 0 — one
|
|
161
|
-
view, opposite plots. `normalizeScoreParity.test.ts` sweeps the two.
|
|
162
|
-
|
|
163
|
-
```js
|
|
164
|
-
// type signature
|
|
165
|
-
(min: number, max: number, scaleType: WiggleScaleType, symlogConstant?: number) => (score: number) => number
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
|
|
169
|
-
|
|
170
|
-
### parseScoreRules
|
|
171
|
-
|
|
172
|
-
Normalizes whatever a `scoreRules` config slot holds into `ScoreRule`s, dropping
|
|
173
|
-
entries that are not usable. Config is user-authored JSON, so a bare number, a
|
|
174
|
-
missing value or a non-numeric one all have to survive being read.
|
|
175
|
-
|
|
176
|
-
```js
|
|
177
|
-
// type signature
|
|
178
|
-
(value: unknown) => ScoreRule[]
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
|
|
182
|
-
|
|
183
155
|
### resolveSymlogConstant
|
|
184
156
|
|
|
185
157
|
The symlog constant actually used for a domain. `0` (the config default) means
|
|
@@ -200,30 +172,6 @@ rather than hard-coded.
|
|
|
200
172
|
|
|
201
173
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
|
|
202
174
|
|
|
203
|
-
### scaleTypeFromString
|
|
204
|
-
|
|
205
|
-
Maps the `'log'`/`'symlog'`/`'linear'` string to the numeric `WiggleScaleType`.
|
|
206
|
-
|
|
207
|
-
```js
|
|
208
|
-
// type signature
|
|
209
|
-
(scaleType: string) => WiggleScaleType
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
|
|
213
|
-
|
|
214
|
-
### ScoreRule
|
|
215
|
-
|
|
216
|
-
One horizontal rule across a score plot, at a score the user chose.
|
|
217
|
-
|
|
218
|
-
`label` is free text and carries no meaning this package assigns. That is
|
|
219
|
-
deliberate: the obvious use is reading a coverage or CNV track against copy
|
|
220
|
-
number, and there is no ploidy JBrowse could assume on the user's behalf. A
|
|
221
|
-
whole-genome triplication is not diploid, plenty of genomes are not diploid to
|
|
222
|
-
begin with, and a cancer sample can be neither — so "2 copies" is a claim only
|
|
223
|
-
the person looking at the track can make.
|
|
224
|
-
|
|
225
|
-
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
|
|
226
|
-
|
|
227
175
|
### scoreRuleMarks
|
|
228
176
|
|
|
229
177
|
Screen y for each rule that falls inside the plotted domain, dropping the rest.
|
|
@@ -240,28 +188,50 @@ because the axis need not be linear: on a log or symlog track, placing a rule at
|
|
|
240
188
|
read against is not.
|
|
241
189
|
|
|
242
190
|
`box` is likewise the caller's own — hand it the same `{yTop, yBottom}` the
|
|
243
|
-
display's ticks were built with (a `YScaleTicks` satisfies it).
|
|
244
|
-
|
|
191
|
+
display's ticks were built with (a `YScaleTicks` satisfies it). A box recomputed
|
|
192
|
+
here would place rules off the ticks of any band that lays its axis out
|
|
245
193
|
differently, and the alignments coverage band does.
|
|
246
194
|
|
|
247
195
|
```js
|
|
248
196
|
// type signature
|
|
249
|
-
({…}: { rules: readonly
|
|
197
|
+
({…}: { rules: readonly ValueScaleRule[]; domain: [number, number] | undefined; box: { yTop: number; yBottom: number; }; normalize: (score: number) => number; }) => ScoreRuleMark[]
|
|
250
198
|
```
|
|
251
199
|
|
|
252
200
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
|
|
253
201
|
|
|
202
|
+
### ScoreSpan
|
|
203
|
+
|
|
204
|
+
One block's worth of values to fold into a domain, whatever packed them: a
|
|
205
|
+
wiggle source's interleaved `featurePositions` and its summary arrays, or a mark
|
|
206
|
+
layer's separate `x`/`x2` and its one `y` lane. `starts[i * stride]` and
|
|
207
|
+
`ends[i * stride + endOffset]` give instance `i`'s span, and `low` and `high`
|
|
208
|
+
the two ends of its value, one array where the packer ships a single scalar.
|
|
209
|
+
|
|
210
|
+
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
211
|
+
|
|
254
212
|
### visibleStatsDomain
|
|
255
213
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
autoscaled range inside the configured bounds. `undefined` while there is
|
|
259
|
-
nothing to scale against — no data, a hidden band, or a view that has not
|
|
260
|
-
initialized — which every caller distinguishes from a domain.
|
|
214
|
+
visibleStatsRange nice-rounded inside the configured bounds: the domain of a
|
|
215
|
+
display whose range is its own alone.
|
|
261
216
|
|
|
262
217
|
```js
|
|
263
218
|
// type signature
|
|
264
|
-
<Payload, Item, Stats>({
|
|
219
|
+
<Payload, Item, Stats>({ bounds, scaleType, zero, ...spec }: VisibleStatsDomainSpec<Payload, Item, Stats>) => [number, number] | undefined
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/visibleStatsDomain.ts)
|
|
223
|
+
|
|
224
|
+
### visibleStatsRange
|
|
225
|
+
|
|
226
|
+
The raw autoscaled range the displays with a value scale derive identically:
|
|
227
|
+
walk the settled blocks, accumulate the stats of what each one shows, and reduce
|
|
228
|
+
them to `[min, max]` before any bound or nice-rounding. `undefined` while there
|
|
229
|
+
is nothing to scale against — no data, a hidden band, or a view that has not
|
|
230
|
+
initialized — which every caller distinguishes from a range.
|
|
231
|
+
|
|
232
|
+
```js
|
|
233
|
+
// type signature
|
|
234
|
+
<Payload, Item, Stats>({ active, view, payloadFor, itemsFor, accumulate, range, }: VisibleStatsRangeSpec<Payload, Item, Stats>) => [number, number] | undefined
|
|
265
235
|
```
|
|
266
236
|
|
|
267
237
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/visibleStatsDomain.ts)
|
|
@@ -270,17 +240,16 @@ initialized — which every caller distinguishes from a domain.
|
|
|
270
240
|
|
|
271
241
|
Widens an autoscaled range so every configured rule stays on the axis.
|
|
272
242
|
|
|
273
|
-
Without this a rule
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
falls outside it
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
one the config asked not to be shown, and it drops as before.
|
|
243
|
+
Without this a rule is dropped from the plot in the views where it is most
|
|
244
|
+
useful. Autoscale follows the visible data, so over a homozygous deletion a
|
|
245
|
+
coverage domain collapses to about `[0, 1]` and a rule at the diploid depth
|
|
246
|
+
falls outside it, though the rule's position above the data is the most
|
|
247
|
+
informative mark in that view, and a rule that vanishes leaves nothing behind to
|
|
248
|
+
notice.
|
|
249
|
+
|
|
250
|
+
Applied to the raw range, before `getNiceDomain` takes the `scales.y` domain
|
|
251
|
+
bounds. Those still win: a rule outside an explicitly bounded axis is one the
|
|
252
|
+
config asked not to be shown, and it drops as before.
|
|
284
253
|
|
|
285
254
|
```js
|
|
286
255
|
// type signature
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AutoscalePeer } from './autoscaleGroup.ts';
|
|
2
|
+
import type { IStateTreeNode } from '@jbrowse/mobx-state-tree';
|
|
3
|
+
declare const _default: ({ model, handleClose, }: {
|
|
4
|
+
model: AutoscalePeer & IStateTreeNode;
|
|
5
|
+
handleClose: () => void;
|
|
6
|
+
}) => import("react").JSX.Element;
|
|
7
|
+
export default _default;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { LabeledCheckbox, SubmitDialog } from '@jbrowse/core/ui';
|
|
4
|
+
import { Typography } from '@mui/material';
|
|
5
|
+
import { observer } from 'mobx-react';
|
|
6
|
+
import { autoscalePeers, autoscaleWith } from './autoscaleGroup.js';
|
|
7
|
+
export default observer(function AutoscaleGroupDialog({ model, handleClose, }) {
|
|
8
|
+
const peers = autoscalePeers(model);
|
|
9
|
+
const group = model.autoscaleGroup;
|
|
10
|
+
const [chosen, setChosen] = useState(() => new Set(group === undefined
|
|
11
|
+
? []
|
|
12
|
+
: peers.map(p => p.display).filter(d => d.autoscaleGroup === group)));
|
|
13
|
+
return (_jsxs(SubmitDialog, { open: true, title: "Autoscale with other tracks", submitText: "Apply", onCancel: handleClose, onSubmit: () => {
|
|
14
|
+
autoscaleWith(model, peers.map(p => p.display), chosen);
|
|
15
|
+
handleClose();
|
|
16
|
+
}, children: [_jsx(Typography, { color: "text.secondary", children: "The tracks ticked here share this track's axis: each end nobody pinned spans all of their data, and follows it as the view moves." }), peers.map(({ display, key, name }) => (_jsx("div", { children: _jsx(LabeledCheckbox, { checked: chosen.has(display), label: name, onChange: checked => {
|
|
17
|
+
const next = new Set(chosen);
|
|
18
|
+
if (checked) {
|
|
19
|
+
next.add(display);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
next.delete(display);
|
|
23
|
+
}
|
|
24
|
+
setChosen(next);
|
|
25
|
+
} }) }, key)))] }));
|
|
26
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { ValueScale, YAxis } from '@jbrowse/display-ui';
|
|
2
|
+
/**
|
|
3
|
+
* #stateModel ScoreAxisMixin
|
|
4
|
+
* #category display
|
|
5
|
+
* Not a cross-cutting mixin any more: {@link ScoreScaleMixin} is its one
|
|
6
|
+
* composer, and a display takes the axis by taking that. The two stay apart
|
|
7
|
+
* because the halves answer different questions — this one derives, the other
|
|
8
|
+
* says where the answer is written.
|
|
9
|
+
*
|
|
10
|
+
* The axis contract apart from where it is written down. `scaleType`,
|
|
11
|
+
* `manualMinScore` and `manualMaxScore` are declared here with neutral answers
|
|
12
|
+
* and a composing display overrides them, so the bounds, the "is anything
|
|
13
|
+
* pinned" question, the ticks and the cross-hatches derive the same way
|
|
14
|
+
* wherever the declaration lives. {@link ScoreScaleMixin} is the one composer
|
|
15
|
+
* in the tree, backing them with the `scales.y` object every quantitative
|
|
16
|
+
* display declares; the split stays because the derived half is what a display
|
|
17
|
+
* writing its scale down somewhere else would answer.
|
|
18
|
+
*
|
|
19
|
+
* The setters are not here. A display cannot set what it has not said where to
|
|
20
|
+
* put, so `setScaleType`/`setMinScore`/`setMaxScore` belong to whichever
|
|
21
|
+
* composer owns the declaration — one owner, whichever it is.
|
|
22
|
+
*/
|
|
23
|
+
export declare function ScoreAxisMixin(): import("@jbrowse/mobx-state-tree").IModelType<{}, {
|
|
24
|
+
/**
|
|
25
|
+
* #getter
|
|
26
|
+
* Overridable: where this display's scale type is written down.
|
|
27
|
+
*/
|
|
28
|
+
readonly scaleType: string;
|
|
29
|
+
/**
|
|
30
|
+
* #getter
|
|
31
|
+
* Overridable: where `scales.y.zero` is written down, whether an
|
|
32
|
+
* autoscaled linear or symlog axis reaches 0.
|
|
33
|
+
*/
|
|
34
|
+
readonly scaleZero: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* #getter
|
|
37
|
+
* Overridable: the lower bound the config really pins, `undefined`
|
|
38
|
+
* where nothing does.
|
|
39
|
+
*/
|
|
40
|
+
readonly manualMinScore: number | undefined;
|
|
41
|
+
/**
|
|
42
|
+
* #getter
|
|
43
|
+
* Overridable: the upper bound the config really pins.
|
|
44
|
+
*/
|
|
45
|
+
readonly manualMaxScore: number | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* #getter
|
|
48
|
+
* Overridable hook: what each end of the domain falls back to where the
|
|
49
|
+
* config leaves its bound unset. `[undefined, undefined]` — the default —
|
|
50
|
+
* means autoscale both ends, which is right for a track whose scores have
|
|
51
|
+
* no absolute meaning (a bigwig's units are its own).
|
|
52
|
+
*
|
|
53
|
+
* A display whose scores are bounded *by construction* overrides it, so
|
|
54
|
+
* the axis stops being a function of what happens to be on screen: GC
|
|
55
|
+
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
56
|
+
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
57
|
+
* heights depending on where the user had panned, and the track could not
|
|
58
|
+
* be read across loci.
|
|
59
|
+
*
|
|
60
|
+
* A hook rather than a config default because the answer can depend on
|
|
61
|
+
* the data — the wiggle display reads the bounds its adapter declares,
|
|
62
|
+
* a GC content track's [0, 1] — and rather than each display
|
|
63
|
+
* re-resolving the sentinels, which is the one thing that must not be
|
|
64
|
+
* duplicated: config bounds still win, precisely because they are checked
|
|
65
|
+
* before this is consulted.
|
|
66
|
+
*/
|
|
67
|
+
readonly defaultScoreDomain: [number | undefined, number | undefined];
|
|
68
|
+
/**
|
|
69
|
+
* #getter
|
|
70
|
+
* Overridable hook (default none): the scales this display draws its y
|
|
71
|
+
* through. A display that answers it gets an axis per band of each,
|
|
72
|
+
* with its cross-hatches, placed by `DisplayChrome` and
|
|
73
|
+
* `renderDisplaySvg`, and the ticks derived below.
|
|
74
|
+
*/
|
|
75
|
+
readonly valueScales: ValueScale[];
|
|
76
|
+
/**
|
|
77
|
+
* #getter
|
|
78
|
+
* Overridable: the group this display's unpinned ends autoscale in,
|
|
79
|
+
* beside every display in its view naming the same one.
|
|
80
|
+
*/
|
|
81
|
+
readonly autoscaleGroup: string | undefined;
|
|
82
|
+
/**
|
|
83
|
+
* #getter
|
|
84
|
+
* Overridable: what this display's own data spans, before any bound,
|
|
85
|
+
* nice-rounding or group widens it; what a group unions.
|
|
86
|
+
*/
|
|
87
|
+
readonly autoscaleRange: [number, number] | undefined;
|
|
88
|
+
} & {
|
|
89
|
+
/**
|
|
90
|
+
* #getter
|
|
91
|
+
* Overridable: whether the autoscaled domain reaches 0, `scaleZero`
|
|
92
|
+
* unless the display maps its score to something with no axis.
|
|
93
|
+
*/
|
|
94
|
+
readonly axisReachesZero: boolean;
|
|
95
|
+
} & {
|
|
96
|
+
/**
|
|
97
|
+
* #getter
|
|
98
|
+
* The domain an autoscaled axis draws: `autoscaleRange`, widened to
|
|
99
|
+
* every range its `autoscaleGroup` holds, nice-rounded inside this
|
|
100
|
+
* display's own bounds. Each member unions the others' own ranges and
|
|
101
|
+
* never their domains, so a pinned end stays the display's that pinned
|
|
102
|
+
* it. `undefined` while this display has nothing of its own to scale.
|
|
103
|
+
*/
|
|
104
|
+
readonly autoscaledDomain: [number, number] | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* #getter
|
|
107
|
+
* Resolved lower bound; `undefined` means autoscale this end.
|
|
108
|
+
*/
|
|
109
|
+
readonly minScoreBound: number | undefined;
|
|
110
|
+
/**
|
|
111
|
+
* #getter
|
|
112
|
+
* Resolved upper bound; `undefined` means autoscale this end.
|
|
113
|
+
*/
|
|
114
|
+
readonly maxScoreBound: number | undefined;
|
|
115
|
+
/**
|
|
116
|
+
* #getter
|
|
117
|
+
* Whether the user has pinned either end, which is a different question
|
|
118
|
+
* from whether either end resolved to a number: `defaultScoreDomain` fills
|
|
119
|
+
* the unset ends in, so a GC content track answers yes to the second with
|
|
120
|
+
* nothing configured. The score menu asks this one — it captions the
|
|
121
|
+
* min/max row with the range in force, and a caption off the resolved
|
|
122
|
+
* pair named a range on every freshly opened GC content track.
|
|
123
|
+
*/
|
|
124
|
+
readonly hasManualScoreBounds: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* #getter
|
|
127
|
+
* The axes, one per declared scale whose domain resolved: where each
|
|
128
|
+
* tick lands in the band's own pixel space, through `computeYTicks`
|
|
129
|
+
* unless the scale brought its own ladder, and where each of the
|
|
130
|
+
* scale's `rules` inside the domain lands in that same box, through the
|
|
131
|
+
* scale type the renderer places its values by.
|
|
132
|
+
*/
|
|
133
|
+
readonly axes: YAxis[];
|
|
134
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { types } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
import { scaleTypeCode } from '@jbrowse/render-core/scoreScale';
|
|
3
|
+
import { autoscaleGroupMembers, unionRanges } from './autoscaleGroup.js';
|
|
4
|
+
import { computeYTicks } from './computeYTicks.js';
|
|
5
|
+
import { makeScoreNormalizer, resolveSymlogConstant } from './normalize.js';
|
|
6
|
+
import { getNiceDomain } from './scale.js';
|
|
7
|
+
import { scoreRuleMarks } from './scoreRuleMarks.js';
|
|
8
|
+
/**
|
|
9
|
+
* #stateModel ScoreAxisMixin
|
|
10
|
+
* #category display
|
|
11
|
+
* Not a cross-cutting mixin any more: {@link ScoreScaleMixin} is its one
|
|
12
|
+
* composer, and a display takes the axis by taking that. The two stay apart
|
|
13
|
+
* because the halves answer different questions — this one derives, the other
|
|
14
|
+
* says where the answer is written.
|
|
15
|
+
*
|
|
16
|
+
* The axis contract apart from where it is written down. `scaleType`,
|
|
17
|
+
* `manualMinScore` and `manualMaxScore` are declared here with neutral answers
|
|
18
|
+
* and a composing display overrides them, so the bounds, the "is anything
|
|
19
|
+
* pinned" question, the ticks and the cross-hatches derive the same way
|
|
20
|
+
* wherever the declaration lives. {@link ScoreScaleMixin} is the one composer
|
|
21
|
+
* in the tree, backing them with the `scales.y` object every quantitative
|
|
22
|
+
* display declares; the split stays because the derived half is what a display
|
|
23
|
+
* writing its scale down somewhere else would answer.
|
|
24
|
+
*
|
|
25
|
+
* The setters are not here. A display cannot set what it has not said where to
|
|
26
|
+
* put, so `setScaleType`/`setMinScore`/`setMaxScore` belong to whichever
|
|
27
|
+
* composer owns the declaration — one owner, whichever it is.
|
|
28
|
+
*/
|
|
29
|
+
export function ScoreAxisMixin() {
|
|
30
|
+
return types
|
|
31
|
+
.model('ScoreAxisMixin', {})
|
|
32
|
+
.views(() => ({
|
|
33
|
+
/**
|
|
34
|
+
* #getter
|
|
35
|
+
* Overridable: where this display's scale type is written down.
|
|
36
|
+
*/
|
|
37
|
+
get scaleType() {
|
|
38
|
+
return 'linear';
|
|
39
|
+
},
|
|
40
|
+
/**
|
|
41
|
+
* #getter
|
|
42
|
+
* Overridable: where `scales.y.zero` is written down, whether an
|
|
43
|
+
* autoscaled linear or symlog axis reaches 0.
|
|
44
|
+
*/
|
|
45
|
+
get scaleZero() {
|
|
46
|
+
return true;
|
|
47
|
+
},
|
|
48
|
+
/**
|
|
49
|
+
* #getter
|
|
50
|
+
* Overridable: the lower bound the config really pins, `undefined`
|
|
51
|
+
* where nothing does.
|
|
52
|
+
*/
|
|
53
|
+
get manualMinScore() {
|
|
54
|
+
return undefined;
|
|
55
|
+
},
|
|
56
|
+
/**
|
|
57
|
+
* #getter
|
|
58
|
+
* Overridable: the upper bound the config really pins.
|
|
59
|
+
*/
|
|
60
|
+
get manualMaxScore() {
|
|
61
|
+
return undefined;
|
|
62
|
+
},
|
|
63
|
+
/**
|
|
64
|
+
* #getter
|
|
65
|
+
* Overridable hook: what each end of the domain falls back to where the
|
|
66
|
+
* config leaves its bound unset. `[undefined, undefined]` — the default —
|
|
67
|
+
* means autoscale both ends, which is right for a track whose scores have
|
|
68
|
+
* no absolute meaning (a bigwig's units are its own).
|
|
69
|
+
*
|
|
70
|
+
* A display whose scores are bounded *by construction* overrides it, so
|
|
71
|
+
* the axis stops being a function of what happens to be on screen: GC
|
|
72
|
+
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
73
|
+
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
74
|
+
* heights depending on where the user had panned, and the track could not
|
|
75
|
+
* be read across loci.
|
|
76
|
+
*
|
|
77
|
+
* A hook rather than a config default because the answer can depend on
|
|
78
|
+
* the data — the wiggle display reads the bounds its adapter declares,
|
|
79
|
+
* a GC content track's [0, 1] — and rather than each display
|
|
80
|
+
* re-resolving the sentinels, which is the one thing that must not be
|
|
81
|
+
* duplicated: config bounds still win, precisely because they are checked
|
|
82
|
+
* before this is consulted.
|
|
83
|
+
*/
|
|
84
|
+
get defaultScoreDomain() {
|
|
85
|
+
return [undefined, undefined];
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* #getter
|
|
89
|
+
* Overridable hook (default none): the scales this display draws its y
|
|
90
|
+
* through. A display that answers it gets an axis per band of each,
|
|
91
|
+
* with its cross-hatches, placed by `DisplayChrome` and
|
|
92
|
+
* `renderDisplaySvg`, and the ticks derived below.
|
|
93
|
+
*/
|
|
94
|
+
get valueScales() {
|
|
95
|
+
return [];
|
|
96
|
+
},
|
|
97
|
+
/**
|
|
98
|
+
* #getter
|
|
99
|
+
* Overridable: the group this display's unpinned ends autoscale in,
|
|
100
|
+
* beside every display in its view naming the same one.
|
|
101
|
+
*/
|
|
102
|
+
get autoscaleGroup() {
|
|
103
|
+
return undefined;
|
|
104
|
+
},
|
|
105
|
+
/**
|
|
106
|
+
* #getter
|
|
107
|
+
* Overridable: what this display's own data spans, before any bound,
|
|
108
|
+
* nice-rounding or group widens it; what a group unions.
|
|
109
|
+
*/
|
|
110
|
+
get autoscaleRange() {
|
|
111
|
+
return undefined;
|
|
112
|
+
},
|
|
113
|
+
}))
|
|
114
|
+
.views(self => ({
|
|
115
|
+
/**
|
|
116
|
+
* #getter
|
|
117
|
+
* Overridable: whether the autoscaled domain reaches 0, `scaleZero`
|
|
118
|
+
* unless the display maps its score to something with no axis.
|
|
119
|
+
*/
|
|
120
|
+
get axisReachesZero() {
|
|
121
|
+
return self.scaleZero;
|
|
122
|
+
},
|
|
123
|
+
}))
|
|
124
|
+
.views(self => ({
|
|
125
|
+
/**
|
|
126
|
+
* #getter
|
|
127
|
+
* The domain an autoscaled axis draws: `autoscaleRange`, widened to
|
|
128
|
+
* every range its `autoscaleGroup` holds, nice-rounded inside this
|
|
129
|
+
* display's own bounds. Each member unions the others' own ranges and
|
|
130
|
+
* never their domains, so a pinned end stays the display's that pinned
|
|
131
|
+
* it. `undefined` while this display has nothing of its own to scale.
|
|
132
|
+
*/
|
|
133
|
+
get autoscaledDomain() {
|
|
134
|
+
const own = self.autoscaleRange;
|
|
135
|
+
const group = self.autoscaleGroup;
|
|
136
|
+
const range = own && group
|
|
137
|
+
? unionRanges([
|
|
138
|
+
own,
|
|
139
|
+
...autoscaleGroupMembers(self, group).map(m => m.autoscaleRange),
|
|
140
|
+
])
|
|
141
|
+
: own;
|
|
142
|
+
return range
|
|
143
|
+
? getNiceDomain({
|
|
144
|
+
domain: range,
|
|
145
|
+
bounds: [this.minScoreBound, this.maxScoreBound],
|
|
146
|
+
scaleType: self.scaleType,
|
|
147
|
+
zero: self.axisReachesZero,
|
|
148
|
+
})
|
|
149
|
+
: undefined;
|
|
150
|
+
},
|
|
151
|
+
/**
|
|
152
|
+
* #getter
|
|
153
|
+
* Resolved lower bound; `undefined` means autoscale this end.
|
|
154
|
+
*/
|
|
155
|
+
get minScoreBound() {
|
|
156
|
+
return self.manualMinScore ?? self.defaultScoreDomain[0];
|
|
157
|
+
},
|
|
158
|
+
/**
|
|
159
|
+
* #getter
|
|
160
|
+
* Resolved upper bound; `undefined` means autoscale this end.
|
|
161
|
+
*/
|
|
162
|
+
get maxScoreBound() {
|
|
163
|
+
return self.manualMaxScore ?? self.defaultScoreDomain[1];
|
|
164
|
+
},
|
|
165
|
+
/**
|
|
166
|
+
* #getter
|
|
167
|
+
* Whether the user has pinned either end, which is a different question
|
|
168
|
+
* from whether either end resolved to a number: `defaultScoreDomain` fills
|
|
169
|
+
* the unset ends in, so a GC content track answers yes to the second with
|
|
170
|
+
* nothing configured. The score menu asks this one — it captions the
|
|
171
|
+
* min/max row with the range in force, and a caption off the resolved
|
|
172
|
+
* pair named a range on every freshly opened GC content track.
|
|
173
|
+
*/
|
|
174
|
+
get hasManualScoreBounds() {
|
|
175
|
+
return (self.manualMinScore !== undefined || self.manualMaxScore !== undefined);
|
|
176
|
+
},
|
|
177
|
+
/**
|
|
178
|
+
* #getter
|
|
179
|
+
* The axes, one per declared scale whose domain resolved: where each
|
|
180
|
+
* tick lands in the band's own pixel space, through `computeYTicks`
|
|
181
|
+
* unless the scale brought its own ladder, and where each of the
|
|
182
|
+
* scale's `rules` inside the domain lands in that same box, through the
|
|
183
|
+
* scale type the renderer places its values by.
|
|
184
|
+
*/
|
|
185
|
+
get axes() {
|
|
186
|
+
return self.valueScales.flatMap(scale => {
|
|
187
|
+
const { domain, rules = [] } = scale;
|
|
188
|
+
const ticks = scale.ticks ??
|
|
189
|
+
computeYTicks({
|
|
190
|
+
height: scale.height,
|
|
191
|
+
offset: scale.offset,
|
|
192
|
+
domain,
|
|
193
|
+
scaleType: scale.scaleType,
|
|
194
|
+
minimalTicks: scale.minimalTicks ?? false,
|
|
195
|
+
symlogConstant: scale.symlogConstant,
|
|
196
|
+
});
|
|
197
|
+
if (!domain || !ticks) {
|
|
198
|
+
return [];
|
|
199
|
+
}
|
|
200
|
+
const [min, max] = domain;
|
|
201
|
+
const ruleMarks = rules.length > 0
|
|
202
|
+
? scoreRuleMarks({
|
|
203
|
+
rules,
|
|
204
|
+
domain,
|
|
205
|
+
box: ticks,
|
|
206
|
+
normalize: makeScoreNormalizer(min, max, scaleTypeCode(scale.scaleType), resolveSymlogConstant(min, max, scale.symlogConstant ?? 0)),
|
|
207
|
+
})
|
|
208
|
+
: [];
|
|
209
|
+
return [{ ...scale, domain, ticks, ruleMarks }];
|
|
210
|
+
});
|
|
211
|
+
},
|
|
212
|
+
}));
|
|
213
|
+
}
|