@jbrowse/wiggle-core 5.0.0-beta.8 → 5.0.0-beta.9
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 +49 -83
- package/esm/ScoreAxisMixin.d.ts +99 -0
- package/esm/ScoreAxisMixin.js +150 -0
- package/esm/ScoreFieldConfigMixin.d.ts +60 -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 +65 -99
- package/esm/ScoreScaleMixin.js +78 -141
- package/esm/SetScoreRulesDialog.d.ts +14 -0
- package/esm/SetScoreRulesDialog.js +45 -0
- package/esm/WiggleScoreConfigMixin.d.ts +89 -0
- package/esm/WiggleScoreConfigMixin.js +69 -0
- package/esm/autoscale.d.ts +45 -5
- package/esm/autoscale.js +99 -67
- package/esm/chrome.d.ts +4 -0
- package/esm/chrome.js +7 -0
- package/esm/computeYTicks.d.ts +1 -1
- package/esm/computeYTicks.js +4 -2
- package/esm/dataTypes.d.ts +2 -6
- package/esm/gapBreak.d.ts +2 -3
- package/esm/gapBreak.js +2 -3
- package/esm/index.d.ts +20 -16
- package/esm/index.js +17 -13
- package/esm/normalize.d.ts +1 -26
- package/esm/normalize.js +1 -86
- package/esm/pointSizeMenu.d.ts +13 -0
- package/esm/pointSizeMenu.js +21 -3
- package/esm/renderingBackendTypes.d.ts +12 -3
- package/esm/renderingBackendTypes.js +4 -1
- package/esm/scale.d.ts +1 -1
- package/esm/scoreFieldConfigSchemaFields.d.ts +10 -0
- package/esm/scoreFieldConfigSchemaFields.js +11 -0
- package/esm/scoreMenuItems.d.ts +19 -7
- package/esm/scoreMenuItems.js +64 -29
- package/esm/scoreRuleMarks.d.ts +13 -37
- package/esm/scoreRuleMarks.js +12 -45
- package/esm/transferables.js +3 -8
- package/esm/valueScaleConfigSchema.d.ts +211 -0
- package/esm/valueScaleConfigSchema.js +240 -0
- package/esm/wiggleRenderModes.generated.d.ts +1 -2
- package/esm/wiggleRenderModes.generated.js +1 -2
- package/package.json +12 -8
- package/esm/scoreAxisConfigSchemaFields.d.ts +0 -44
- package/esm/scoreAxisConfigSchemaFields.js +0 -54
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,6 +9,19 @@ 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
|
+
Already-computed stats to the displayed domain, for the `local` / `localsd` /
|
|
15
|
+
`localpercentile` autoscale modes. `localpercentile` re-walks the spans to build
|
|
16
|
+
its histogram; the other modes read the stats alone.
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
// type signature
|
|
20
|
+
({…}: { stats: ScoreStats; autoscaleType: string | undefined; numStdDev: number; numQuantile?: number | undefined; spans: ScoreSpan[]; }) => [number, number]
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
24
|
+
|
|
11
25
|
### computeAutoscaleDomain
|
|
12
26
|
|
|
13
27
|
Computes a score domain from the visible feature arrays for the `local` /
|
|
@@ -15,7 +29,7 @@ Computes a score domain from the visible feature arrays for the `local` /
|
|
|
15
29
|
|
|
16
30
|
```js
|
|
17
31
|
// type signature
|
|
18
|
-
(autoscaleType: string, summaryScoreMode: string, numStdDev: number, visibleEntries: {…}[], numQuantile?: number) => [...] | undefined
|
|
32
|
+
(autoscaleType: string | undefined, summaryScoreMode: string, numStdDev: number, visibleEntries: {…}[], numQuantile?: number) => [...] | undefined
|
|
19
33
|
```
|
|
20
34
|
|
|
21
35
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
@@ -53,11 +67,12 @@ exactly what it always got.
|
|
|
53
67
|
### domainFromStats
|
|
54
68
|
|
|
55
69
|
Converts score stats into a `[min, max]` domain, applying std-dev expansion for
|
|
56
|
-
the `localsd` autoscale type.
|
|
70
|
+
the `localsd` autoscale type. An `undefined` mode is a display whose scale
|
|
71
|
+
declares none, and takes the plain extremes.
|
|
57
72
|
|
|
58
73
|
```js
|
|
59
74
|
// type signature
|
|
60
|
-
(stats: ScoreStats, autoscaleType: string, numStdDev: number) => [number, number]
|
|
75
|
+
(stats: ScoreStats, autoscaleType: string | undefined, numStdDev: number) => [number, number]
|
|
61
76
|
```
|
|
62
77
|
|
|
63
78
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
@@ -69,12 +84,12 @@ may be before the span between them counts as a hole rather than a segment to
|
|
|
69
84
|
draw. Returns `Infinity` when there is nothing to decide, so a caller can always
|
|
70
85
|
compare against it unguarded.
|
|
71
86
|
|
|
72
|
-
The limit is a multiple of the series'
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
The limit is a multiple of the series' _mean_ spacing rather than an absolute
|
|
88
|
+
distance, so one number works across zoom levels and data types: reduced BigWig
|
|
89
|
+
bins get wider as you zoom out, so any fixed bp threshold would be either
|
|
90
|
+
useless at one end or destructive at the other. It also lets the same rule serve
|
|
91
|
+
a bp axis (wiggle's linecenter) and a px one — the caller picks the space, this
|
|
92
|
+
only cares that the units are consistent.
|
|
78
93
|
|
|
79
94
|
Mean, not median: it is O(1) from the endpoints, and it errs the safe way. A
|
|
80
95
|
series' holes inflate their own mean, which raises the limit and so breaks
|
|
@@ -145,41 +160,6 @@ unless `nice: false` says it is already the one being drawn with.
|
|
|
145
160
|
|
|
146
161
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scale.ts)
|
|
147
162
|
|
|
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
163
|
### resolveSymlogConstant
|
|
184
164
|
|
|
185
165
|
The symlog constant actually used for a domain. `0` (the config default) means
|
|
@@ -200,30 +180,6 @@ rather than hard-coded.
|
|
|
200
180
|
|
|
201
181
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/normalize.ts)
|
|
202
182
|
|
|
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
183
|
### scoreRuleMarks
|
|
228
184
|
|
|
229
185
|
Screen y for each rule that falls inside the plotted domain, dropping the rest.
|
|
@@ -240,17 +196,28 @@ because the axis need not be linear: on a log or symlog track, placing a rule at
|
|
|
240
196
|
read against is not.
|
|
241
197
|
|
|
242
198
|
`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
|
-
|
|
199
|
+
display's ticks were built with (a `YScaleTicks` satisfies it). A box recomputed
|
|
200
|
+
here would place rules off the ticks of any band that lays its axis out
|
|
245
201
|
differently, and the alignments coverage band does.
|
|
246
202
|
|
|
247
203
|
```js
|
|
248
204
|
// type signature
|
|
249
|
-
({…}: { rules: readonly
|
|
205
|
+
({…}: { rules: readonly ValueScaleRule[]; domain: [number, number] | undefined; box: { yTop: number; yBottom: number; }; normalize: (score: number) => number; }) => ScoreRuleMark[]
|
|
250
206
|
```
|
|
251
207
|
|
|
252
208
|
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/scoreRuleMarks.ts)
|
|
253
209
|
|
|
210
|
+
### ScoreSpan
|
|
211
|
+
|
|
212
|
+
One block's worth of values to fold into a domain, whatever packed them: a
|
|
213
|
+
wiggle source's interleaved `featurePositions` and its three summary arrays, or
|
|
214
|
+
a mark layer's separate `x`/`x2` and its one `y` lane. `starts[i * stride]` and
|
|
215
|
+
`ends[i * stride + endOffset]` give instance `i`'s span; `low`, `high` and `avg`
|
|
216
|
+
give the two ends of its value and the one the mean is taken over, which are the
|
|
217
|
+
same array wherever the packer ships a single scalar.
|
|
218
|
+
|
|
219
|
+
[Source code](https://github.com/GMOD/jbrowse-components/blob/main/packages/wiggle-core/src/autoscale.ts)
|
|
220
|
+
|
|
254
221
|
### visibleStatsDomain
|
|
255
222
|
|
|
256
223
|
The visible score domain four displays derive identically: walk the settled
|
|
@@ -270,17 +237,16 @@ initialized — which every caller distinguishes from a domain.
|
|
|
270
237
|
|
|
271
238
|
Widens an autoscaled range so every configured rule stays on the axis.
|
|
272
239
|
|
|
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.
|
|
240
|
+
Without this a rule is dropped from the plot in the views where it is most
|
|
241
|
+
useful. Autoscale follows the visible data, so over a homozygous deletion a
|
|
242
|
+
coverage domain collapses to about `[0, 1]` and a rule at the diploid depth
|
|
243
|
+
falls outside it, though the rule's position above the data is the most
|
|
244
|
+
informative mark in that view, and a rule that vanishes leaves nothing behind to
|
|
245
|
+
notice.
|
|
246
|
+
|
|
247
|
+
Applied to the raw range, before `getNiceDomain` takes the `scales.y` domain
|
|
248
|
+
bounds. Those still win: a rule outside an explicitly bounded axis is one the
|
|
249
|
+
config asked not to be shown, and it drops as before.
|
|
284
250
|
|
|
285
251
|
```js
|
|
286
252
|
// type signature
|
|
@@ -0,0 +1,99 @@
|
|
|
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: the lower bound the config really pins, `undefined`
|
|
32
|
+
* where nothing does.
|
|
33
|
+
*/
|
|
34
|
+
readonly manualMinScore: number | undefined;
|
|
35
|
+
/**
|
|
36
|
+
* #getter
|
|
37
|
+
* Overridable: the upper bound the config really pins.
|
|
38
|
+
*/
|
|
39
|
+
readonly manualMaxScore: number | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* #getter
|
|
42
|
+
* Overridable hook: what each end of the domain falls back to where the
|
|
43
|
+
* config leaves its bound unset. `[undefined, undefined]` — the default —
|
|
44
|
+
* means autoscale both ends, which is right for a track whose scores have
|
|
45
|
+
* no absolute meaning (a bigwig's units are its own).
|
|
46
|
+
*
|
|
47
|
+
* A display whose scores are bounded *by construction* overrides it, so
|
|
48
|
+
* the axis stops being a function of what happens to be on screen: GC
|
|
49
|
+
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
50
|
+
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
51
|
+
* heights depending on where the user had panned, and the track could not
|
|
52
|
+
* be read across loci.
|
|
53
|
+
*
|
|
54
|
+
* A hook rather than a config default because the answer can depend on
|
|
55
|
+
* display state — GC's does, on `gcMode` — and rather than each display
|
|
56
|
+
* re-resolving the sentinels, which is the one thing that must not be
|
|
57
|
+
* duplicated: config bounds still win, precisely because they are checked
|
|
58
|
+
* before this is consulted.
|
|
59
|
+
*/
|
|
60
|
+
readonly defaultScoreDomain: [number | undefined, number | undefined];
|
|
61
|
+
/**
|
|
62
|
+
* #getter
|
|
63
|
+
* Overridable hook (default none): the scales this display draws its y
|
|
64
|
+
* through. A display that answers it gets an axis per band of each,
|
|
65
|
+
* with its cross-hatches, placed by `DisplayChrome` and
|
|
66
|
+
* `renderDisplaySvg`, and the ticks derived below.
|
|
67
|
+
*/
|
|
68
|
+
readonly valueScales: ValueScale[];
|
|
69
|
+
} & {
|
|
70
|
+
/**
|
|
71
|
+
* #getter
|
|
72
|
+
* Resolved lower bound; `undefined` means autoscale this end.
|
|
73
|
+
*/
|
|
74
|
+
readonly minScoreBound: number | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* #getter
|
|
77
|
+
* Resolved upper bound; `undefined` means autoscale this end.
|
|
78
|
+
*/
|
|
79
|
+
readonly maxScoreBound: number | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* #getter
|
|
82
|
+
* Whether the user has pinned either end, which is a different question
|
|
83
|
+
* from whether either end resolved to a number: `defaultScoreDomain` fills
|
|
84
|
+
* the unset ends in, so a GC content track answers yes to the second with
|
|
85
|
+
* nothing configured. The score menu asks this one — it gates the "Clear
|
|
86
|
+
* manual min/max" row, and a Clear that writes the nothing already there
|
|
87
|
+
* is a row that does nothing and never goes away.
|
|
88
|
+
*/
|
|
89
|
+
readonly hasManualScoreBounds: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* #getter
|
|
92
|
+
* The axes, one per declared scale whose domain resolved: where each
|
|
93
|
+
* tick lands in the band's own pixel space, through `computeYTicks`
|
|
94
|
+
* unless the scale brought its own ladder, and where each of the
|
|
95
|
+
* scale's `rules` inside the domain lands in that same box, through the
|
|
96
|
+
* scale type the renderer places its values by.
|
|
97
|
+
*/
|
|
98
|
+
readonly axes: YAxis[];
|
|
99
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { types } from '@jbrowse/mobx-state-tree';
|
|
2
|
+
import { scaleTypeCode } from '@jbrowse/render-core/scoreScale';
|
|
3
|
+
import { computeYTicks } from './computeYTicks.js';
|
|
4
|
+
import { makeScoreNormalizer, resolveSymlogConstant } from './normalize.js';
|
|
5
|
+
import { scoreRuleMarks } from './scoreRuleMarks.js';
|
|
6
|
+
/**
|
|
7
|
+
* #stateModel ScoreAxisMixin
|
|
8
|
+
* #category display
|
|
9
|
+
* Not a cross-cutting mixin any more: {@link ScoreScaleMixin} is its one
|
|
10
|
+
* composer, and a display takes the axis by taking that. The two stay apart
|
|
11
|
+
* because the halves answer different questions — this one derives, the other
|
|
12
|
+
* says where the answer is written.
|
|
13
|
+
*
|
|
14
|
+
* The axis contract apart from where it is written down. `scaleType`,
|
|
15
|
+
* `manualMinScore` and `manualMaxScore` are declared here with neutral answers
|
|
16
|
+
* and a composing display overrides them, so the bounds, the "is anything
|
|
17
|
+
* pinned" question, the ticks and the cross-hatches derive the same way
|
|
18
|
+
* wherever the declaration lives. {@link ScoreScaleMixin} is the one composer
|
|
19
|
+
* in the tree, backing them with the `scales.y` object every quantitative
|
|
20
|
+
* display declares; the split stays because the derived half is what a display
|
|
21
|
+
* writing its scale down somewhere else would answer.
|
|
22
|
+
*
|
|
23
|
+
* The setters are not here. A display cannot set what it has not said where to
|
|
24
|
+
* put, so `setScaleType`/`setMinScore`/`setMaxScore` belong to whichever
|
|
25
|
+
* composer owns the declaration — one owner, whichever it is.
|
|
26
|
+
*/
|
|
27
|
+
export function ScoreAxisMixin() {
|
|
28
|
+
return types
|
|
29
|
+
.model('ScoreAxisMixin', {})
|
|
30
|
+
.views(() => ({
|
|
31
|
+
/**
|
|
32
|
+
* #getter
|
|
33
|
+
* Overridable: where this display's scale type is written down.
|
|
34
|
+
*/
|
|
35
|
+
get scaleType() {
|
|
36
|
+
return 'linear';
|
|
37
|
+
},
|
|
38
|
+
/**
|
|
39
|
+
* #getter
|
|
40
|
+
* Overridable: the lower bound the config really pins, `undefined`
|
|
41
|
+
* where nothing does.
|
|
42
|
+
*/
|
|
43
|
+
get manualMinScore() {
|
|
44
|
+
return undefined;
|
|
45
|
+
},
|
|
46
|
+
/**
|
|
47
|
+
* #getter
|
|
48
|
+
* Overridable: the upper bound the config really pins.
|
|
49
|
+
*/
|
|
50
|
+
get manualMaxScore() {
|
|
51
|
+
return undefined;
|
|
52
|
+
},
|
|
53
|
+
/**
|
|
54
|
+
* #getter
|
|
55
|
+
* Overridable hook: what each end of the domain falls back to where the
|
|
56
|
+
* config leaves its bound unset. `[undefined, undefined]` — the default —
|
|
57
|
+
* means autoscale both ends, which is right for a track whose scores have
|
|
58
|
+
* no absolute meaning (a bigwig's units are its own).
|
|
59
|
+
*
|
|
60
|
+
* A display whose scores are bounded *by construction* overrides it, so
|
|
61
|
+
* the axis stops being a function of what happens to be on screen: GC
|
|
62
|
+
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
63
|
+
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
64
|
+
* heights depending on where the user had panned, and the track could not
|
|
65
|
+
* be read across loci.
|
|
66
|
+
*
|
|
67
|
+
* A hook rather than a config default because the answer can depend on
|
|
68
|
+
* display state — GC's does, on `gcMode` — and rather than each display
|
|
69
|
+
* re-resolving the sentinels, which is the one thing that must not be
|
|
70
|
+
* duplicated: config bounds still win, precisely because they are checked
|
|
71
|
+
* before this is consulted.
|
|
72
|
+
*/
|
|
73
|
+
get defaultScoreDomain() {
|
|
74
|
+
return [undefined, undefined];
|
|
75
|
+
},
|
|
76
|
+
/**
|
|
77
|
+
* #getter
|
|
78
|
+
* Overridable hook (default none): the scales this display draws its y
|
|
79
|
+
* through. A display that answers it gets an axis per band of each,
|
|
80
|
+
* with its cross-hatches, placed by `DisplayChrome` and
|
|
81
|
+
* `renderDisplaySvg`, and the ticks derived below.
|
|
82
|
+
*/
|
|
83
|
+
get valueScales() {
|
|
84
|
+
return [];
|
|
85
|
+
},
|
|
86
|
+
}))
|
|
87
|
+
.views(self => ({
|
|
88
|
+
/**
|
|
89
|
+
* #getter
|
|
90
|
+
* Resolved lower bound; `undefined` means autoscale this end.
|
|
91
|
+
*/
|
|
92
|
+
get minScoreBound() {
|
|
93
|
+
return self.manualMinScore ?? self.defaultScoreDomain[0];
|
|
94
|
+
},
|
|
95
|
+
/**
|
|
96
|
+
* #getter
|
|
97
|
+
* Resolved upper bound; `undefined` means autoscale this end.
|
|
98
|
+
*/
|
|
99
|
+
get maxScoreBound() {
|
|
100
|
+
return self.manualMaxScore ?? self.defaultScoreDomain[1];
|
|
101
|
+
},
|
|
102
|
+
/**
|
|
103
|
+
* #getter
|
|
104
|
+
* Whether the user has pinned either end, which is a different question
|
|
105
|
+
* from whether either end resolved to a number: `defaultScoreDomain` fills
|
|
106
|
+
* the unset ends in, so a GC content track answers yes to the second with
|
|
107
|
+
* nothing configured. The score menu asks this one — it gates the "Clear
|
|
108
|
+
* manual min/max" row, and a Clear that writes the nothing already there
|
|
109
|
+
* is a row that does nothing and never goes away.
|
|
110
|
+
*/
|
|
111
|
+
get hasManualScoreBounds() {
|
|
112
|
+
return (self.manualMinScore !== undefined || self.manualMaxScore !== undefined);
|
|
113
|
+
},
|
|
114
|
+
/**
|
|
115
|
+
* #getter
|
|
116
|
+
* The axes, one per declared scale whose domain resolved: where each
|
|
117
|
+
* tick lands in the band's own pixel space, through `computeYTicks`
|
|
118
|
+
* unless the scale brought its own ladder, and where each of the
|
|
119
|
+
* scale's `rules` inside the domain lands in that same box, through the
|
|
120
|
+
* scale type the renderer places its values by.
|
|
121
|
+
*/
|
|
122
|
+
get axes() {
|
|
123
|
+
return self.valueScales.flatMap(scale => {
|
|
124
|
+
const { domain, rules = [] } = scale;
|
|
125
|
+
const ticks = scale.ticks ??
|
|
126
|
+
computeYTicks({
|
|
127
|
+
height: scale.height,
|
|
128
|
+
offset: scale.offset,
|
|
129
|
+
domain,
|
|
130
|
+
scaleType: scale.scaleType,
|
|
131
|
+
minimalTicks: scale.minimalTicks ?? false,
|
|
132
|
+
symlogConstant: scale.symlogConstant,
|
|
133
|
+
});
|
|
134
|
+
if (!domain || !ticks) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
const [min, max] = domain;
|
|
138
|
+
const ruleMarks = rules.length > 0
|
|
139
|
+
? scoreRuleMarks({
|
|
140
|
+
rules,
|
|
141
|
+
domain,
|
|
142
|
+
box: ticks,
|
|
143
|
+
normalize: makeScoreNormalizer(min, max, scaleTypeCode(scale.scaleType), resolveSymlogConstant(min, max, scale.symlogConstant ?? 0)),
|
|
144
|
+
})
|
|
145
|
+
: [];
|
|
146
|
+
return [{ ...scale, domain, ticks, ruleMarks }];
|
|
147
|
+
});
|
|
148
|
+
},
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { ScoreFieldConfigModel } from './scoreFieldConfigSchemaFields.ts';
|
|
2
|
+
export interface ScoreFieldConfigHost {
|
|
3
|
+
configuration: ScoreFieldConfigModel;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* #stateModel ScoreFieldConfigMixin
|
|
7
|
+
* #category display
|
|
8
|
+
*
|
|
9
|
+
* `WiggleScoreConfigMixin` plus `scoreField`, for a display that plots one
|
|
10
|
+
* configured feature field and so declares `scoreFieldConfigSchemaFields`:
|
|
11
|
+
* both wiggle displays and the Manhattan plot. `LinearMarkDisplay` names a
|
|
12
|
+
* field per mark and composes the base instead.
|
|
13
|
+
*/
|
|
14
|
+
export declare function ScoreFieldConfigMixin(): import("@jbrowse/mobx-state-tree").IModelType<Omit<{}, never>, {
|
|
15
|
+
readonly scaleType: string;
|
|
16
|
+
readonly manualMinScore: number | undefined;
|
|
17
|
+
readonly manualMaxScore: number | undefined;
|
|
18
|
+
readonly defaultScoreDomain: [number | undefined, number | undefined];
|
|
19
|
+
readonly valueScales: import("@jbrowse/display-ui").ValueScale[];
|
|
20
|
+
} & {
|
|
21
|
+
readonly minScoreBound: number | undefined;
|
|
22
|
+
readonly maxScoreBound: number | undefined;
|
|
23
|
+
readonly hasManualScoreBounds: boolean;
|
|
24
|
+
readonly axes: import("@jbrowse/display-ui").YAxis[];
|
|
25
|
+
} & {
|
|
26
|
+
readonly scaleType: string;
|
|
27
|
+
readonly scaleTypeChoices: string[];
|
|
28
|
+
readonly autoscaleType: string | undefined;
|
|
29
|
+
readonly numStdDev: number;
|
|
30
|
+
readonly numQuantile: number;
|
|
31
|
+
readonly symlogConstant: number;
|
|
32
|
+
readonly manualMinScore: number | undefined;
|
|
33
|
+
readonly manualMaxScore: number | undefined;
|
|
34
|
+
readonly scaleTitle: string | undefined;
|
|
35
|
+
readonly scoreRulesDrawn: boolean;
|
|
36
|
+
readonly scoreRules: import("@jbrowse/display-ui").ValueScaleRule[];
|
|
37
|
+
} & {
|
|
38
|
+
setScaleType(scaleType: string): void;
|
|
39
|
+
setAutoscale(val?: string): void;
|
|
40
|
+
setMinScore(val?: number): void;
|
|
41
|
+
setMaxScore(val?: number): void;
|
|
42
|
+
setScoreRules(rules: (number | import("@jbrowse/display-ui").ValueScaleRule)[]): void;
|
|
43
|
+
} & {
|
|
44
|
+
readonly scatterPointSize: number;
|
|
45
|
+
readonly displayCrossHatches: boolean;
|
|
46
|
+
readonly isDensityMode: boolean;
|
|
47
|
+
} & {
|
|
48
|
+
toggleCrossHatches(): void;
|
|
49
|
+
setScatterPointSize(val?: number): void;
|
|
50
|
+
} & {
|
|
51
|
+
readonly showCrossHatches: boolean;
|
|
52
|
+
} & {
|
|
53
|
+
/**
|
|
54
|
+
* #getter
|
|
55
|
+
* The feature field the worker plots on the score axis, `score` by
|
|
56
|
+
* default. A fetch input: every composing display carries it in its
|
|
57
|
+
* `rpcProps()`, since the field is read where the features are.
|
|
58
|
+
*/
|
|
59
|
+
readonly scoreField: string;
|
|
60
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { getConf } from '@jbrowse/core/configuration';
|
|
2
|
+
import { WiggleScoreConfigMixin } from './WiggleScoreConfigMixin.js';
|
|
3
|
+
const confNode = (self) => self;
|
|
4
|
+
/**
|
|
5
|
+
* #stateModel ScoreFieldConfigMixin
|
|
6
|
+
* #category display
|
|
7
|
+
*
|
|
8
|
+
* `WiggleScoreConfigMixin` plus `scoreField`, for a display that plots one
|
|
9
|
+
* configured feature field and so declares `scoreFieldConfigSchemaFields`:
|
|
10
|
+
* both wiggle displays and the Manhattan plot. `LinearMarkDisplay` names a
|
|
11
|
+
* field per mark and composes the base instead.
|
|
12
|
+
*/
|
|
13
|
+
export function ScoreFieldConfigMixin() {
|
|
14
|
+
return WiggleScoreConfigMixin().views(self => ({
|
|
15
|
+
/**
|
|
16
|
+
* #getter
|
|
17
|
+
* The feature field the worker plots on the score axis, `score` by
|
|
18
|
+
* default. A fetch input: every composing display carries it in its
|
|
19
|
+
* `rpcProps()`, since the field is read where the features are.
|
|
20
|
+
*/
|
|
21
|
+
get scoreField() {
|
|
22
|
+
return getConf(confNode(self), 'scoreField');
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ContextMenuAnchor, MenuItem, MouseState } from '@jbrowse/core/ui';
|
|
2
|
+
import type { ChromeModel } from '@jbrowse/display-kit/DisplayChrome';
|
|
3
|
+
import type { Mark } from '@jbrowse/render-core/marks';
|
|
4
|
+
import type { PerRegionRenderingBackend } from '@jbrowse/render-core/perRegionRenderingBackend';
|
|
5
|
+
import type { FrameDimensions } from '@jbrowse/render-core/renderingBackendBase';
|
|
6
|
+
import type { RenderLifecycleModel } from '@jbrowse/render-core/useRenderingBackend';
|
|
7
|
+
import type { ReactNode } from 'react';
|
|
8
|
+
interface PlotBox {
|
|
9
|
+
yTop: number;
|
|
10
|
+
plotHeight: number;
|
|
11
|
+
}
|
|
12
|
+
interface ContextMenuView {
|
|
13
|
+
contextMenuInfo?: ContextMenuAnchor;
|
|
14
|
+
contextMenuItems: () => MenuItem[];
|
|
15
|
+
closeContextMenu: () => void;
|
|
16
|
+
}
|
|
17
|
+
export interface ScorePlotContextMenuHost<Hit> extends ContextMenuView {
|
|
18
|
+
openContextMenu: (info: ContextMenuAnchor & {
|
|
19
|
+
hit: Hit;
|
|
20
|
+
}) => void;
|
|
21
|
+
clearHoveredFeature: () => void;
|
|
22
|
+
}
|
|
23
|
+
export type ScorePlotChromeModel<Hit, TRegion, TState extends FrameDimensions> = ChromeModel & RenderLifecycleModel<PerRegionRenderingBackend<TRegion, TState>> & {
|
|
24
|
+
canvasWidthPx: number;
|
|
25
|
+
setHoveredFeature: (hit?: Hit) => void;
|
|
26
|
+
selectFeature: (hit: Hit) => void;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* The on-screen chrome of a display drawing a mark list on a score axis: the
|
|
30
|
+
* canvas in the axis plot box, hover and click resolved through `findHit`, the
|
|
31
|
+
* pointer-following `tooltip`, and the right-click menu where `contextMenu`
|
|
32
|
+
* names the model that owns it. `findHit` takes y from the plot's own top.
|
|
33
|
+
*/
|
|
34
|
+
export declare const ScorePlotChrome: <Hit, TRegion, TState extends FrameDimensions>({ model, marks, testid, plotGeometry, findHit, tooltip, overlay, indicators, contextMenu, }: {
|
|
35
|
+
model: ScorePlotChromeModel<Hit, TRegion, TState>;
|
|
36
|
+
marks: readonly Mark<TRegion, TState>[];
|
|
37
|
+
testid: string;
|
|
38
|
+
plotGeometry?: PlotBox;
|
|
39
|
+
findHit: (x: number, y: number) => Hit | undefined;
|
|
40
|
+
tooltip: (mouseState: MouseState | undefined) => ReactNode;
|
|
41
|
+
overlay?: (plotGeometry: PlotBox) => ReactNode;
|
|
42
|
+
indicators?: () => ReactNode;
|
|
43
|
+
contextMenu?: ScorePlotContextMenuHost<Hit>;
|
|
44
|
+
}) => import("react").JSX.Element;
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import { eventPoint } from '@jbrowse/core/util/eventPoint';
|
|
4
|
+
import BottomRightIndicators from '@jbrowse/display-kit/BottomRightIndicators';
|
|
5
|
+
import DisplayChrome from '@jbrowse/display-kit/DisplayChrome';
|
|
6
|
+
import { DisplayContextMenu, openContextMenuFromEvent, } from '@jbrowse/display-kit/DisplayContextMenu';
|
|
7
|
+
import { PointerLayer, axisPlotBox } from '@jbrowse/display-ui';
|
|
8
|
+
import { createMarkBackend } from '@jbrowse/render-core/marks/backend';
|
|
9
|
+
import { observer } from 'mobx-react';
|
|
10
|
+
/**
|
|
11
|
+
* The on-screen chrome of a display drawing a mark list on a score axis: the
|
|
12
|
+
* canvas in the axis plot box, hover and click resolved through `findHit`, the
|
|
13
|
+
* pointer-following `tooltip`, and the right-click menu where `contextMenu`
|
|
14
|
+
* names the model that owns it. `findHit` takes y from the plot's own top.
|
|
15
|
+
*/
|
|
16
|
+
export const ScorePlotChrome = observer(function ScorePlotChrome({ model, marks, testid, plotGeometry, findHit, tooltip, overlay, indicators, contextMenu, }) {
|
|
17
|
+
const { height, canvasWidthPx: width } = model;
|
|
18
|
+
const box = plotGeometry ?? axisPlotBox(height);
|
|
19
|
+
const factory = useMemo(() => (canvas) => createMarkBackend(canvas, marks), [marks]);
|
|
20
|
+
const hitAt = (x, y) => findHit(x, y - box.yTop);
|
|
21
|
+
return (_jsx(DisplayChrome, { model: model, factory: factory, testid: testid, style: { width, height, whiteSpace: 'nowrap', textAlign: 'left' }, onPointerPosition: state => {
|
|
22
|
+
model.setHoveredFeature(state ? hitAt(state.x, state.y) : undefined);
|
|
23
|
+
}, onClick: event => {
|
|
24
|
+
const { x, y } = eventPoint(event);
|
|
25
|
+
const hit = hitAt(x, y);
|
|
26
|
+
if (hit) {
|
|
27
|
+
model.selectFeature(hit);
|
|
28
|
+
}
|
|
29
|
+
}, onContextMenu: contextMenu
|
|
30
|
+
? event => {
|
|
31
|
+
const { x, y } = eventPoint(event);
|
|
32
|
+
const hit = hitAt(x, y);
|
|
33
|
+
openContextMenuFromEvent(contextMenu, event, hit
|
|
34
|
+
? { clientX: event.clientX, clientY: event.clientY, hit }
|
|
35
|
+
: undefined);
|
|
36
|
+
}
|
|
37
|
+
: undefined, children: ({ canvasRef, mouseTracker }) => (_jsx(ScorePlotBody, { canvasRef: canvasRef, mouseTracker: mouseTracker, width: width, plotGeometry: box, tooltip: tooltip, overlay: overlay, indicators: indicators, contextMenu: contextMenu })) }));
|
|
38
|
+
});
|
|
39
|
+
const ScorePlotBody = observer(function ScorePlotBody({ canvasRef, mouseTracker, width, plotGeometry, tooltip, overlay, indicators, contextMenu, }) {
|
|
40
|
+
return (_jsxs(_Fragment, { children: [_jsx("canvas", { ref: canvasRef, style: {
|
|
41
|
+
width,
|
|
42
|
+
height: plotGeometry.plotHeight,
|
|
43
|
+
position: 'absolute',
|
|
44
|
+
left: 0,
|
|
45
|
+
top: plotGeometry.yTop,
|
|
46
|
+
} }), overlay?.(plotGeometry), _jsx(PointerLayer, { mouseTracker: mouseTracker, children: tooltip }), indicators ? (_jsx(BottomRightIndicators, { children: indicators() })) : null, contextMenu ? _jsx(DisplayContextMenu, { model: contextMenu }) : null] }));
|
|
47
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { SvgExportable } from '@jbrowse/core/svg/svgReady';
|
|
2
|
+
import type { LgvSvgBodyProps } from '@jbrowse/display-kit/renderDisplaySvg';
|
|
3
|
+
import type { Mark, MarkFrame } from '@jbrowse/render-core/marks';
|
|
4
|
+
import type React from 'react';
|
|
5
|
+
export interface ScorePlotSvgModel extends SvgExportable {
|
|
6
|
+
id: string;
|
|
7
|
+
height: number;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The SVG-export body of a display with a score axis, mounted through
|
|
11
|
+
* `renderDisplaySvg`, which draws the axis and cross-hatches. Paints `marks`
|
|
12
|
+
* over `regions` inside the plot box, at the export's width and the box's
|
|
13
|
+
* height — the two fields of `renderState` the on-screen canvas sizes
|
|
14
|
+
* differently. `plotGeometry` defaults to the single-plot box `ScorePlotChrome`
|
|
15
|
+
* draws in; multi-wiggle stacks its rows over the full height instead.
|
|
16
|
+
* `children` draw over the plot, in the same untranslated space as the axis.
|
|
17
|
+
*/
|
|
18
|
+
export declare function ScorePlotSvgFrame<TRegion, TState extends MarkFrame>({ height, canvasWidth, renderBlocks, opts, plotGeometry, marks, regions, renderState, children, }: LgvSvgBodyProps<ScorePlotSvgModel> & {
|
|
19
|
+
plotGeometry?: {
|
|
20
|
+
yTop: number;
|
|
21
|
+
plotHeight: number;
|
|
22
|
+
};
|
|
23
|
+
marks: readonly Mark<TRegion, TState>[];
|
|
24
|
+
regions: ReadonlyMap<number, TRegion>;
|
|
25
|
+
renderState: TState;
|
|
26
|
+
children?: React.ReactNode;
|
|
27
|
+
}): React.JSX.Element;
|