@jbrowse/wiggle-core 5.0.0-beta.7 → 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.
Files changed (47) hide show
  1. package/README.md +49 -83
  2. package/esm/ScoreAxisMixin.d.ts +99 -0
  3. package/esm/ScoreAxisMixin.js +150 -0
  4. package/esm/ScoreFieldConfigMixin.d.ts +60 -0
  5. package/esm/ScoreFieldConfigMixin.js +25 -0
  6. package/esm/ScorePlotChrome.d.ts +45 -0
  7. package/esm/ScorePlotChrome.js +47 -0
  8. package/esm/ScorePlotSvgFrame.d.ts +27 -0
  9. package/esm/ScorePlotSvgFrame.js +23 -0
  10. package/esm/ScoreScaleMixin.d.ts +65 -99
  11. package/esm/ScoreScaleMixin.js +78 -141
  12. package/esm/SetScoreRulesDialog.d.ts +14 -0
  13. package/esm/SetScoreRulesDialog.js +45 -0
  14. package/esm/WiggleScoreConfigMixin.d.ts +89 -0
  15. package/esm/WiggleScoreConfigMixin.js +69 -0
  16. package/esm/autoscale.d.ts +45 -5
  17. package/esm/autoscale.js +99 -67
  18. package/esm/chrome.d.ts +4 -0
  19. package/esm/chrome.js +7 -0
  20. package/esm/computeYTicks.d.ts +1 -1
  21. package/esm/computeYTicks.js +4 -2
  22. package/esm/dataTypes.d.ts +2 -6
  23. package/esm/gapBreak.d.ts +2 -3
  24. package/esm/gapBreak.js +2 -3
  25. package/esm/index.d.ts +20 -16
  26. package/esm/index.js +17 -13
  27. package/esm/normalize.d.ts +1 -26
  28. package/esm/normalize.js +1 -86
  29. package/esm/pointSizeMenu.d.ts +13 -0
  30. package/esm/pointSizeMenu.js +21 -3
  31. package/esm/renderingBackendTypes.d.ts +12 -3
  32. package/esm/renderingBackendTypes.js +4 -1
  33. package/esm/scale.d.ts +1 -1
  34. package/esm/scoreFieldConfigSchemaFields.d.ts +10 -0
  35. package/esm/scoreFieldConfigSchemaFields.js +11 -0
  36. package/esm/scoreMenuItems.d.ts +19 -7
  37. package/esm/scoreMenuItems.js +64 -29
  38. package/esm/scoreRuleMarks.d.ts +13 -37
  39. package/esm/scoreRuleMarks.js +12 -45
  40. package/esm/transferables.js +3 -8
  41. package/esm/valueScaleConfigSchema.d.ts +211 -0
  42. package/esm/valueScaleConfigSchema.js +240 -0
  43. package/esm/wiggleRenderModes.generated.d.ts +1 -2
  44. package/esm/wiggleRenderModes.generated.js +1 -2
  45. package/package.json +12 -8
  46. package/esm/scoreAxisConfigSchemaFields.d.ts +0 -44
  47. package/esm/scoreAxisConfigSchemaFields.js +0 -54
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # @jbrowse/wiggle-core
2
2
 
3
- Shared scale and autoscale utilities for wiggle and coverage displays
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' own _mean_ spacing rather than an
73
- absolute distance, which is what makes one number work across zoom levels and
74
- data types: reduced BigWig bins get wider as you zoom out, so any fixed bp
75
- threshold would be either useless at one end or destructive at the other. It
76
- also lets the same rule serve a bp axis (wiggle's linecenter) and a px one — the
77
- caller picks the space, this only cares that the units are consistent.
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). Recomputing a
244
- box here would silently disagree with any band that lays its axis out
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 ScoreRule[]; domain: [number, number] | undefined; box: { yTop: number; yBottom: number; }; normalize: (score: number) => number; }) => ScoreRuleMark[]
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 silently disappears in exactly the window that makes it
274
- worth having. Autoscale follows the visible data, so over a homozygous deletion
275
- a coverage domain collapses to about `[0, 1]` and a rule at the diploid depth
276
- falls outside it — and "2 copies would be up there" is the most informative
277
- thing that view can say. The reader has no menu to check either: `scoreRules` is
278
- set by whoever wrote the config, so a rule that vanishes leaves nothing behind
279
- to notice.
280
-
281
- Applied to the raw range, before `getNiceDomain` takes the `minScore` /
282
- `maxScore` bounds. Those still win: a rule outside an explicitly bounded axis is
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;