@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.
- 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
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { PaintLayer } from '@jbrowse/core/util/paintLayer';
|
|
3
|
+
import { axisPlotBox } from '@jbrowse/display-ui';
|
|
4
|
+
import { paintMarkBlocks } from '@jbrowse/render-core/marks';
|
|
5
|
+
/**
|
|
6
|
+
* The SVG-export body of a display with a score axis, mounted through
|
|
7
|
+
* `renderDisplaySvg`, which draws the axis and cross-hatches. Paints `marks`
|
|
8
|
+
* over `regions` inside the plot box, at the export's width and the box's
|
|
9
|
+
* height — the two fields of `renderState` the on-screen canvas sizes
|
|
10
|
+
* differently. `plotGeometry` defaults to the single-plot box `ScorePlotChrome`
|
|
11
|
+
* draws in; multi-wiggle stacks its rows over the full height instead.
|
|
12
|
+
* `children` draw over the plot, in the same untranslated space as the axis.
|
|
13
|
+
*/
|
|
14
|
+
export function ScorePlotSvgFrame({ height, canvasWidth, renderBlocks, opts, plotGeometry = axisPlotBox(height), marks, regions, renderState, children, }) {
|
|
15
|
+
const { yTop, plotHeight } = plotGeometry;
|
|
16
|
+
return (_jsxs(_Fragment, { children: [_jsx("g", { transform: `translate(0,${yTop})`, children: _jsx(PaintLayer, { width: canvasWidth, height: plotHeight, opts: opts, paint: ctx => {
|
|
17
|
+
paintMarkBlocks(ctx, marks, regions, renderBlocks, {
|
|
18
|
+
...renderState,
|
|
19
|
+
canvasWidth,
|
|
20
|
+
canvasHeight: plotHeight,
|
|
21
|
+
});
|
|
22
|
+
} }) }), children] }));
|
|
23
|
+
}
|
package/esm/ScoreScaleMixin.d.ts
CHANGED
|
@@ -1,152 +1,112 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
1
|
+
import type { scalesSchema } from './valueScaleConfigSchema.ts';
|
|
2
|
+
import type { ConfigModelForFields } from '@jbrowse/core/configuration';
|
|
3
|
+
import type { ValueScaleRule } from '@jbrowse/display-ui';
|
|
3
4
|
/**
|
|
4
|
-
* The whole of what `ScoreScaleMixin` needs a composing display to be
|
|
5
|
+
* The whole of what `ScoreScaleMixin` needs a composing display to be: a
|
|
6
|
+
* `scales` object holding the `y` the value-scale factory built. Exported
|
|
5
7
|
* because it is the mixin's contract and `ScoreScaleMixin.test.ts` pins it:
|
|
6
8
|
* widen it and the `@ts-expect-error`s there go unused.
|
|
7
9
|
*/
|
|
8
10
|
export interface ScoreScaleHost {
|
|
9
|
-
configuration:
|
|
11
|
+
configuration: ConfigModelForFields<{
|
|
12
|
+
scales: ReturnType<typeof scalesSchema>;
|
|
13
|
+
}>;
|
|
10
14
|
}
|
|
11
15
|
/**
|
|
12
16
|
* #stateModel ScoreScaleMixin
|
|
13
17
|
* #category display
|
|
14
|
-
* #crossCuttingMixin
|
|
18
|
+
* #crossCuttingMixin Value scale, written in `scales.y`. `valueScaleSchema` / `scalesSchema`. Brings `ScoreAxisMixin` plus `scaleType` / `scaleTypeChoices` / `autoscaleType` / `numStdDev` / `numQuantile` / `symlogConstant` / `manual*` and their setters, i.e. the whole `ScoreScaleModel` interface the shared score menu and `SetMinMaxDialog` consume
|
|
15
19
|
*
|
|
16
|
-
* The
|
|
17
|
-
*
|
|
18
|
-
* {@link
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* score display cannot satisfy it *partially*.
|
|
20
|
+
* The value scale of every quantitative display: wiggle, the multi-wiggle,
|
|
21
|
+
* Manhattan, the alignments coverage band and the mark display each declare
|
|
22
|
+
* `scales.y` through {@link valueScaleSchema} and compose this. It backs
|
|
23
|
+
* {@link ScoreAxisMixin}'s three overridable members off that object and adds
|
|
24
|
+
* the setters that write it, so composing this is how a display satisfies
|
|
25
|
+
* {@link ScoreScaleModel} in `scoreMenuItems.ts` — the interface the shared
|
|
26
|
+
* Score menu, the scale and autoscale submenus and `SetMinMaxDialog` consume.
|
|
24
27
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
* `Number.MIN_VALUE`/`Number.MAX_VALUE` "unset" sentinels intact, and nothing
|
|
31
|
-
* outside this file should want them: `manualMinScore`/`manualMaxScore` are the
|
|
32
|
-
* same answer with the sentinel resolved to `undefined`, which is what the
|
|
33
|
-
* dialog round-trips and what the menu captions itself with;
|
|
34
|
-
* `minScoreBound`/`maxScoreBound` are the resolved bounds, where `undefined`
|
|
35
|
-
* means "autoscale this end". Every consumer that computes a domain reads the
|
|
36
|
-
* `*Bound` pair.
|
|
28
|
+
* What a display's scale offers follows what it draws, so the members below
|
|
29
|
+
* answer `undefined` where its factory call left them out: `autoscaleType` on
|
|
30
|
+
* Manhattan, whose domain is plain min/max, and `symlogConstant` wherever
|
|
31
|
+
* `symlog` is not among the scale types. `scaleTypeChoices` reads the declared
|
|
32
|
+
* enum back, which is what the scale-type radio offers.
|
|
37
33
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* Its setters are the display's to override so the edit lands on the same
|
|
42
|
-
* declaration — one owner, whichever it is.
|
|
43
|
-
*
|
|
44
|
-
* Whether a bound is *configured* is a third question, and `hasManualScoreBounds`
|
|
45
|
-
* is the only getter that answers it — the resolved pair cannot, since
|
|
46
|
-
* `defaultScoreDomain` is exactly the hook that turns an unset end into a number.
|
|
34
|
+
* Deliberately just the scale. Colors, `resolution`, cross-hatches and the
|
|
35
|
+
* autoscale *computation* stay in `WiggleScoreConfigMixin` / `WiggleCommonMixin`
|
|
36
|
+
* — the alignments coverage band shares this scale but none of the rest.
|
|
47
37
|
*/
|
|
48
38
|
export declare function ScoreScaleMixin(): import("@jbrowse/mobx-state-tree").IModelType<{}, {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
readonly
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
} | undefined;
|
|
39
|
+
readonly scaleType: string;
|
|
40
|
+
readonly manualMinScore: number | undefined;
|
|
41
|
+
readonly manualMaxScore: number | undefined;
|
|
42
|
+
readonly defaultScoreDomain: [number | undefined, number | undefined];
|
|
43
|
+
readonly valueScales: import("@jbrowse/display-ui").ValueScale[];
|
|
44
|
+
} & {
|
|
45
|
+
readonly minScoreBound: number | undefined;
|
|
46
|
+
readonly maxScoreBound: number | undefined;
|
|
47
|
+
readonly hasManualScoreBounds: boolean;
|
|
48
|
+
readonly axes: import("@jbrowse/display-ui").YAxis[];
|
|
49
|
+
} & {
|
|
61
50
|
/**
|
|
62
51
|
* #getter
|
|
63
52
|
*/
|
|
64
53
|
readonly scaleType: string;
|
|
65
54
|
/**
|
|
66
55
|
* #getter
|
|
56
|
+
* The scale types this display's own enum admits, which is what the
|
|
57
|
+
* scale-type radio offers; a display with one draws no radio.
|
|
67
58
|
*/
|
|
68
|
-
readonly
|
|
59
|
+
readonly scaleTypeChoices: string[];
|
|
69
60
|
/**
|
|
70
61
|
* #getter
|
|
62
|
+
* `undefined` on a display whose domain consults no autoscale mode.
|
|
71
63
|
*/
|
|
72
|
-
readonly
|
|
64
|
+
readonly autoscaleType: string | undefined;
|
|
73
65
|
/**
|
|
74
66
|
* #getter
|
|
75
|
-
* Raw slot value, sentinel intact — see the class comment.
|
|
76
67
|
*/
|
|
77
|
-
readonly
|
|
68
|
+
readonly numStdDev: number;
|
|
78
69
|
/**
|
|
79
70
|
* #getter
|
|
80
|
-
* Raw slot value, sentinel intact — see the class comment.
|
|
81
71
|
*/
|
|
82
|
-
readonly
|
|
72
|
+
readonly numQuantile: number;
|
|
83
73
|
/**
|
|
84
74
|
* #getter
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
* means autoscale both ends, which is right for a track whose scores have
|
|
88
|
-
* no absolute meaning (a bigwig's units are its own).
|
|
89
|
-
*
|
|
90
|
-
* A display whose scores are bounded *by construction* overrides it, so
|
|
91
|
-
* the axis stops being a function of what happens to be on screen: GC
|
|
92
|
-
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
93
|
-
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
94
|
-
* heights depending on where the user had panned, and the track could not
|
|
95
|
-
* be read across loci.
|
|
96
|
-
*
|
|
97
|
-
* A hook rather than a config default because the answer can depend on
|
|
98
|
-
* display state — GC's does, on `gcMode` — and rather than each display
|
|
99
|
-
* re-resolving the sentinels below, which is the one thing that must not
|
|
100
|
-
* be duplicated: config bounds still win, precisely because they are
|
|
101
|
-
* checked before this is consulted.
|
|
75
|
+
* Raw slot; `0` means "derive from the domain". Resolve it with
|
|
76
|
+
* `resolveSymlogConstant` once the domain is known.
|
|
102
77
|
*/
|
|
103
|
-
readonly
|
|
78
|
+
readonly symlogConstant: number;
|
|
104
79
|
/**
|
|
105
80
|
* #getter
|
|
106
|
-
* The lower bound the config
|
|
81
|
+
* The lower bound the config pins, `undefined` where it pins none.
|
|
107
82
|
*/
|
|
108
83
|
readonly manualMinScore: number | undefined;
|
|
109
84
|
/**
|
|
110
85
|
* #getter
|
|
111
|
-
* The upper bound the config
|
|
86
|
+
* The upper bound the config pins, `undefined` where it pins none.
|
|
112
87
|
*/
|
|
113
88
|
readonly manualMaxScore: number | undefined;
|
|
114
89
|
/**
|
|
115
90
|
* #getter
|
|
116
|
-
*
|
|
117
|
-
|
|
118
|
-
readonly minScoreBound: number | undefined;
|
|
119
|
-
/**
|
|
120
|
-
* #getter
|
|
121
|
-
* Resolved upper bound; `undefined` means autoscale this end.
|
|
122
|
-
*/
|
|
123
|
-
readonly maxScoreBound: number | undefined;
|
|
124
|
-
/**
|
|
125
|
-
* #getter
|
|
126
|
-
* Whether the user has pinned either end, which is a different question
|
|
127
|
-
* from whether either end resolved to a number: `defaultScoreDomain` fills
|
|
128
|
-
* the sentinels in, so a GC content track answers yes to the second with
|
|
129
|
-
* nothing configured. The score menu asks this one — it gates the "Clear
|
|
130
|
-
* manual min/max" row, and a Clear that writes the sentinels already
|
|
131
|
-
* there is a row that does nothing and never goes away.
|
|
91
|
+
* `scales.y.title` as written, `undefined` while unset or on a display
|
|
92
|
+
* whose scale declares no title.
|
|
132
93
|
*/
|
|
133
|
-
readonly
|
|
94
|
+
readonly scaleTitle: string | undefined;
|
|
134
95
|
/**
|
|
135
96
|
* #getter
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
97
|
+
* Whether this display draws `scales.y.rules`, which is whether the
|
|
98
|
+
* score menu offers the reference lines: its scale declares them, and
|
|
99
|
+
* a scale it places y through rules a band for them to cross, which a
|
|
100
|
+
* density plot's colour-mapped rows and a colour ramp do not.
|
|
140
101
|
*/
|
|
141
|
-
readonly
|
|
142
|
-
} & {
|
|
102
|
+
readonly scoreRulesDrawn: boolean;
|
|
143
103
|
/**
|
|
144
104
|
* #getter
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
105
|
+
* `scales.y.rules`, read off the live nodes: a snapshot strips a slot at
|
|
106
|
+
* its default, and a rule at 0 is one. Empty on a display whose scale
|
|
107
|
+
* declares no rules.
|
|
148
108
|
*/
|
|
149
|
-
readonly
|
|
109
|
+
readonly scoreRules: ValueScaleRule[];
|
|
150
110
|
} & {
|
|
151
111
|
/**
|
|
152
112
|
* #action
|
|
@@ -164,4 +124,10 @@ export declare function ScoreScaleMixin(): import("@jbrowse/mobx-state-tree").IM
|
|
|
164
124
|
* #action
|
|
165
125
|
*/
|
|
166
126
|
setMaxScore(val?: number): void;
|
|
127
|
+
/**
|
|
128
|
+
* #action
|
|
129
|
+
* Replaces `scales.y.rules` whole, each entry in a form the config
|
|
130
|
+
* takes: a number, or `{ value, color, label }`.
|
|
131
|
+
*/
|
|
132
|
+
setScoreRules(rules: (number | ValueScaleRule)[]): void;
|
|
167
133
|
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
package/esm/ScoreScaleMixin.js
CHANGED
|
@@ -1,198 +1,127 @@
|
|
|
1
|
-
import { getConf, setConf } from '@jbrowse/core/configuration';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { getConf, getSlotDefinition, readConfObject, setConf, slotChoices, } from '@jbrowse/core/configuration';
|
|
2
|
+
import { rulesABand } from '@jbrowse/display-ui/axisPlacement';
|
|
3
|
+
import { ScoreAxisMixin } from './ScoreAxisMixin.js';
|
|
4
4
|
// The mixin composes onto a display that declares this, not the other way
|
|
5
5
|
// round, so its own `self` isn't typed with it. Cast once, narrowed to the
|
|
6
|
-
//
|
|
7
|
-
//
|
|
6
|
+
// factory's schema rather than `AnyConfigurationModel`, which is what keeps the
|
|
7
|
+
// member names below checked.
|
|
8
8
|
const confNode = (self) => self;
|
|
9
9
|
/**
|
|
10
10
|
* #stateModel ScoreScaleMixin
|
|
11
11
|
* #category display
|
|
12
|
-
* #crossCuttingMixin
|
|
12
|
+
* #crossCuttingMixin Value scale, written in `scales.y`. `valueScaleSchema` / `scalesSchema`. Brings `ScoreAxisMixin` plus `scaleType` / `scaleTypeChoices` / `autoscaleType` / `numStdDev` / `numQuantile` / `symlogConstant` / `manual*` and their setters, i.e. the whole `ScoreScaleModel` interface the shared score menu and `SetMinMaxDialog` consume
|
|
13
13
|
*
|
|
14
|
-
* The
|
|
15
|
-
*
|
|
16
|
-
* {@link
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* score display cannot satisfy it *partially*.
|
|
14
|
+
* The value scale of every quantitative display: wiggle, the multi-wiggle,
|
|
15
|
+
* Manhattan, the alignments coverage band and the mark display each declare
|
|
16
|
+
* `scales.y` through {@link valueScaleSchema} and compose this. It backs
|
|
17
|
+
* {@link ScoreAxisMixin}'s three overridable members off that object and adds
|
|
18
|
+
* the setters that write it, so composing this is how a display satisfies
|
|
19
|
+
* {@link ScoreScaleModel} in `scoreMenuItems.ts` — the interface the shared
|
|
20
|
+
* Score menu, the scale and autoscale submenus and `SetMinMaxDialog` consume.
|
|
22
21
|
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* `Number.MIN_VALUE`/`Number.MAX_VALUE` "unset" sentinels intact, and nothing
|
|
29
|
-
* outside this file should want them: `manualMinScore`/`manualMaxScore` are the
|
|
30
|
-
* same answer with the sentinel resolved to `undefined`, which is what the
|
|
31
|
-
* dialog round-trips and what the menu captions itself with;
|
|
32
|
-
* `minScoreBound`/`maxScoreBound` are the resolved bounds, where `undefined`
|
|
33
|
-
* means "autoscale this end". Every consumer that computes a domain reads the
|
|
34
|
-
* `*Bound` pair.
|
|
35
|
-
*
|
|
36
|
-
* A display that declares its value scale elsewhere answers
|
|
37
|
-
* `declaredValueScale`, and then the scale type and the pinned bounds come
|
|
38
|
-
* from the declaration rather than from `scaleType`/`minScore`/`maxScore`.
|
|
39
|
-
* Its setters are the display's to override so the edit lands on the same
|
|
40
|
-
* declaration — one owner, whichever it is.
|
|
22
|
+
* What a display's scale offers follows what it draws, so the members below
|
|
23
|
+
* answer `undefined` where its factory call left them out: `autoscaleType` on
|
|
24
|
+
* Manhattan, whose domain is plain min/max, and `symlogConstant` wherever
|
|
25
|
+
* `symlog` is not among the scale types. `scaleTypeChoices` reads the declared
|
|
26
|
+
* enum back, which is what the scale-type radio offers.
|
|
41
27
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
28
|
+
* Deliberately just the scale. Colors, `resolution`, cross-hatches and the
|
|
29
|
+
* autoscale *computation* stay in `WiggleScoreConfigMixin` / `WiggleCommonMixin`
|
|
30
|
+
* — the alignments coverage band shares this scale but none of the rest.
|
|
45
31
|
*/
|
|
46
32
|
export function ScoreScaleMixin() {
|
|
47
|
-
return
|
|
48
|
-
.model('ScoreScaleMixin', {})
|
|
33
|
+
return ScoreAxisMixin()
|
|
49
34
|
.views(self => ({
|
|
50
35
|
/**
|
|
51
36
|
* #getter
|
|
52
|
-
* Overridable hook: a value scale the display declares somewhere other
|
|
53
|
-
* than these slots — the mark display's `encoding.y`. Where it answers,
|
|
54
|
-
* it is the owner and the slots below stand in only for the ends it
|
|
55
|
-
* leaves open, so a scale is read from one place whichever place that
|
|
56
|
-
* is. Default none, which is every display whose axis IS these slots.
|
|
57
37
|
*/
|
|
58
|
-
get
|
|
59
|
-
return
|
|
38
|
+
get scaleType() {
|
|
39
|
+
return getConf(confNode(self), ['scales', 'y', 'type']);
|
|
60
40
|
},
|
|
61
41
|
/**
|
|
62
42
|
* #getter
|
|
43
|
+
* The scale types this display's own enum admits, which is what the
|
|
44
|
+
* scale-type radio offers; a display with one draws no radio.
|
|
63
45
|
*/
|
|
64
|
-
get
|
|
65
|
-
return (
|
|
66
|
-
getConf(confNode(self), 'scaleType'));
|
|
46
|
+
get scaleTypeChoices() {
|
|
47
|
+
return (slotChoices(getSlotDefinition(confNode(self).configuration.scales.y, 'type')) ?? []);
|
|
67
48
|
},
|
|
68
49
|
/**
|
|
69
50
|
* #getter
|
|
51
|
+
* `undefined` on a display whose domain consults no autoscale mode.
|
|
70
52
|
*/
|
|
71
53
|
get autoscaleType() {
|
|
72
|
-
return getConf(confNode(self), 'autoscale');
|
|
54
|
+
return getConf(confNode(self), ['scales', 'y', 'autoscale']);
|
|
73
55
|
},
|
|
74
56
|
/**
|
|
75
57
|
* #getter
|
|
76
58
|
*/
|
|
77
59
|
get numStdDev() {
|
|
78
|
-
return getConf(confNode(self), 'numStdDev');
|
|
60
|
+
return getConf(confNode(self), ['scales', 'y', 'numStdDev']);
|
|
79
61
|
},
|
|
80
62
|
/**
|
|
81
63
|
* #getter
|
|
82
|
-
* Raw slot value, sentinel intact — see the class comment.
|
|
83
64
|
*/
|
|
84
|
-
get
|
|
85
|
-
return getConf(confNode(self), '
|
|
65
|
+
get numQuantile() {
|
|
66
|
+
return getConf(confNode(self), ['scales', 'y', 'numQuantile']);
|
|
86
67
|
},
|
|
87
68
|
/**
|
|
88
69
|
* #getter
|
|
89
|
-
* Raw slot
|
|
70
|
+
* Raw slot; `0` means "derive from the domain". Resolve it with
|
|
71
|
+
* `resolveSymlogConstant` once the domain is known.
|
|
90
72
|
*/
|
|
91
|
-
get
|
|
92
|
-
return getConf(confNode(self), '
|
|
73
|
+
get symlogConstant() {
|
|
74
|
+
return getConf(confNode(self), ['scales', 'y', 'symlogConstant']);
|
|
93
75
|
},
|
|
94
76
|
/**
|
|
95
77
|
* #getter
|
|
96
|
-
*
|
|
97
|
-
* config leaves its bound unset. `[undefined, undefined]` — the default —
|
|
98
|
-
* means autoscale both ends, which is right for a track whose scores have
|
|
99
|
-
* no absolute meaning (a bigwig's units are its own).
|
|
100
|
-
*
|
|
101
|
-
* A display whose scores are bounded *by construction* overrides it, so
|
|
102
|
-
* the axis stops being a function of what happens to be on screen: GC
|
|
103
|
-
* content is a fraction, so 0 and 1 are its real limits and mean the same
|
|
104
|
-
* thing at every locus. Autoscaled, the same GC value drew at different
|
|
105
|
-
* heights depending on where the user had panned, and the track could not
|
|
106
|
-
* be read across loci.
|
|
107
|
-
*
|
|
108
|
-
* A hook rather than a config default because the answer can depend on
|
|
109
|
-
* display state — GC's does, on `gcMode` — and rather than each display
|
|
110
|
-
* re-resolving the sentinels below, which is the one thing that must not
|
|
111
|
-
* be duplicated: config bounds still win, precisely because they are
|
|
112
|
-
* checked before this is consulted.
|
|
113
|
-
*/
|
|
114
|
-
get defaultScoreDomain() {
|
|
115
|
-
return [undefined, undefined];
|
|
116
|
-
},
|
|
117
|
-
/**
|
|
118
|
-
* #getter
|
|
119
|
-
* The lower bound the config really sets, `undefined` at the sentinel.
|
|
78
|
+
* The lower bound the config pins, `undefined` where it pins none.
|
|
120
79
|
*/
|
|
121
80
|
get manualMinScore() {
|
|
122
|
-
|
|
123
|
-
if (declared !== undefined) {
|
|
124
|
-
return declared;
|
|
125
|
-
}
|
|
126
|
-
return this.minScore === Number.MIN_VALUE ? undefined : this.minScore;
|
|
81
|
+
return getConf(confNode(self), ['scales', 'y', 'domainMin']);
|
|
127
82
|
},
|
|
128
83
|
/**
|
|
129
84
|
* #getter
|
|
130
|
-
* The upper bound the config
|
|
85
|
+
* The upper bound the config pins, `undefined` where it pins none.
|
|
131
86
|
*/
|
|
132
87
|
get manualMaxScore() {
|
|
133
|
-
|
|
134
|
-
if (declared !== undefined) {
|
|
135
|
-
return declared;
|
|
136
|
-
}
|
|
137
|
-
return this.maxScore === Number.MAX_VALUE ? undefined : this.maxScore;
|
|
88
|
+
return getConf(confNode(self), ['scales', 'y', 'domainMax']);
|
|
138
89
|
},
|
|
139
90
|
/**
|
|
140
91
|
* #getter
|
|
141
|
-
*
|
|
92
|
+
* `scales.y.title` as written, `undefined` while unset or on a display
|
|
93
|
+
* whose scale declares no title.
|
|
142
94
|
*/
|
|
143
|
-
get
|
|
144
|
-
return
|
|
95
|
+
get scaleTitle() {
|
|
96
|
+
return getConf(confNode(self), ['scales', 'y', 'title']);
|
|
145
97
|
},
|
|
146
98
|
/**
|
|
147
99
|
* #getter
|
|
148
|
-
*
|
|
100
|
+
* Whether this display draws `scales.y.rules`, which is whether the
|
|
101
|
+
* score menu offers the reference lines: its scale declares them, and
|
|
102
|
+
* a scale it places y through rules a band for them to cross, which a
|
|
103
|
+
* density plot's colour-mapped rows and a colour ramp do not.
|
|
149
104
|
*/
|
|
150
|
-
get
|
|
151
|
-
return
|
|
105
|
+
get scoreRulesDrawn() {
|
|
106
|
+
return (confNode(self).configuration.scales.y.rules !== undefined &&
|
|
107
|
+
self.valueScales.some(rulesABand));
|
|
152
108
|
},
|
|
153
109
|
/**
|
|
154
110
|
* #getter
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
* with its cross-hatches, placed by `DisplayChrome` and
|
|
170
|
-
* `renderDisplaySvg`, and the ticks derived below.
|
|
171
|
-
*/
|
|
172
|
-
get valueScales() {
|
|
173
|
-
return [];
|
|
174
|
-
},
|
|
175
|
-
}))
|
|
176
|
-
.views(self => ({
|
|
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.
|
|
182
|
-
*/
|
|
183
|
-
get axes() {
|
|
184
|
-
return self.valueScales.flatMap(scale => {
|
|
185
|
-
const { domain } = scale;
|
|
186
|
-
const ticks = scale.ticks ??
|
|
187
|
-
computeYTicks({
|
|
188
|
-
height: scale.height,
|
|
189
|
-
offset: scale.offset,
|
|
190
|
-
domain,
|
|
191
|
-
scaleType: scale.scaleType,
|
|
192
|
-
minimalTicks: scale.minimalTicks ?? false,
|
|
193
|
-
symlogConstant: scale.symlogConstant,
|
|
194
|
-
});
|
|
195
|
-
return domain && ticks ? [{ ...scale, domain, ticks }] : [];
|
|
111
|
+
* `scales.y.rules`, read off the live nodes: a snapshot strips a slot at
|
|
112
|
+
* its default, and a rule at 0 is one. Empty on a display whose scale
|
|
113
|
+
* declares no rules.
|
|
114
|
+
*/
|
|
115
|
+
get scoreRules() {
|
|
116
|
+
const { rules = [] } = confNode(self).configuration.scales.y;
|
|
117
|
+
return rules.map((rule) => {
|
|
118
|
+
const label = readConfObject(rule, 'label');
|
|
119
|
+
const color = readConfObject(rule, 'color');
|
|
120
|
+
return {
|
|
121
|
+
value: readConfObject(rule, 'value'),
|
|
122
|
+
...(color ? { color } : {}),
|
|
123
|
+
...(label ? { label } : {}),
|
|
124
|
+
};
|
|
196
125
|
});
|
|
197
126
|
},
|
|
198
127
|
}))
|
|
@@ -201,25 +130,33 @@ export function ScoreScaleMixin() {
|
|
|
201
130
|
* #action
|
|
202
131
|
*/
|
|
203
132
|
setScaleType(scaleType) {
|
|
204
|
-
setConf(confNode(self), '
|
|
133
|
+
setConf(confNode(self), ['scales', 'y', 'type'], scaleType);
|
|
205
134
|
},
|
|
206
135
|
/**
|
|
207
136
|
* #action
|
|
208
137
|
*/
|
|
209
138
|
setAutoscale(val) {
|
|
210
|
-
setConf(confNode(self), 'autoscale', val);
|
|
139
|
+
setConf(confNode(self), ['scales', 'y', 'autoscale'], val);
|
|
211
140
|
},
|
|
212
141
|
/**
|
|
213
142
|
* #action
|
|
214
143
|
*/
|
|
215
144
|
setMinScore(val) {
|
|
216
|
-
setConf(confNode(self), '
|
|
145
|
+
setConf(confNode(self), ['scales', 'y', 'domainMin'], val);
|
|
217
146
|
},
|
|
218
147
|
/**
|
|
219
148
|
* #action
|
|
220
149
|
*/
|
|
221
150
|
setMaxScore(val) {
|
|
222
|
-
setConf(confNode(self), '
|
|
151
|
+
setConf(confNode(self), ['scales', 'y', 'domainMax'], val);
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* #action
|
|
155
|
+
* Replaces `scales.y.rules` whole, each entry in a form the config
|
|
156
|
+
* takes: a number, or `{ value, color, label }`.
|
|
157
|
+
*/
|
|
158
|
+
setScoreRules(rules) {
|
|
159
|
+
setConf(confNode(self), ['scales', 'y', 'rules'], rules);
|
|
223
160
|
},
|
|
224
161
|
}));
|
|
225
162
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ValueScaleRule } from '@jbrowse/display-ui';
|
|
2
|
+
/**
|
|
3
|
+
* The score menu's editor for `scales.y.rules`: one row per reference line,
|
|
4
|
+
* its value on the plot's own scale, its label and its colour. An empty colour
|
|
5
|
+
* is the display's default, and removing every row removes every line.
|
|
6
|
+
*/
|
|
7
|
+
declare const _default: ({ model, handleClose, }: {
|
|
8
|
+
model: {
|
|
9
|
+
scoreRules: ValueScaleRule[];
|
|
10
|
+
setScoreRules: (rules: ValueScaleRule[]) => void;
|
|
11
|
+
};
|
|
12
|
+
handleClose: () => void;
|
|
13
|
+
}) => import("react").JSX.Element;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { SubmitDialog } from '@jbrowse/core/ui';
|
|
4
|
+
import { isCssColor } from '@jbrowse/core/util/colorBits';
|
|
5
|
+
import DeleteIcon from '@mui/icons-material/Delete';
|
|
6
|
+
import { Button, IconButton, TextField, Typography } from '@mui/material';
|
|
7
|
+
import { observer } from 'mobx-react';
|
|
8
|
+
function rowOf({ value, label = '', color = '' }) {
|
|
9
|
+
return { value: String(value), label, color };
|
|
10
|
+
}
|
|
11
|
+
function valueOk({ value }) {
|
|
12
|
+
return value.trim() !== '' && Number.isFinite(Number(value));
|
|
13
|
+
}
|
|
14
|
+
function colorOk({ color }) {
|
|
15
|
+
return color.trim() === '' || isCssColor(color);
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The score menu's editor for `scales.y.rules`: one row per reference line,
|
|
19
|
+
* its value on the plot's own scale, its label and its colour. An empty colour
|
|
20
|
+
* is the display's default, and removing every row removes every line.
|
|
21
|
+
*/
|
|
22
|
+
export default observer(function SetScoreRulesDialog({ model, handleClose, }) {
|
|
23
|
+
const [rows, setRows] = useState(() => model.scoreRules.map(rowOf));
|
|
24
|
+
const setRow = (index, patch) => {
|
|
25
|
+
setRows(rows.map((row, i) => (i === index ? { ...row, ...patch } : row)));
|
|
26
|
+
};
|
|
27
|
+
return (_jsxs(SubmitDialog, { open: true, title: "Reference lines", submitDisabled: !rows.every(row => valueOk(row) && colorOk(row)), onCancel: handleClose, onSubmit: () => {
|
|
28
|
+
model.setScoreRules(rows.map(row => ({
|
|
29
|
+
value: Number(row.value),
|
|
30
|
+
...(row.label ? { label: row.label } : {}),
|
|
31
|
+
...(row.color.trim() ? { color: row.color.trim() } : {}),
|
|
32
|
+
})));
|
|
33
|
+
handleClose();
|
|
34
|
+
}, children: [_jsx(Typography, { children: "A horizontal line at each value, on the same scale as the plot" }), rows.map((row, index) => (_jsxs("div", { style: { display: 'flex', gap: 8, marginTop: 8 }, children: [_jsx(TextField, { label: "Value", value: row.value, error: !valueOk(row), onChange: event => {
|
|
35
|
+
setRow(index, { value: event.target.value });
|
|
36
|
+
} }), _jsx(TextField, { label: "Label", value: row.label, onChange: event => {
|
|
37
|
+
setRow(index, { label: event.target.value });
|
|
38
|
+
} }), _jsx(TextField, { label: "Color", value: row.color, error: !colorOk(row), onChange: event => {
|
|
39
|
+
setRow(index, { color: event.target.value });
|
|
40
|
+
} }), _jsx(IconButton, { "aria-label": "remove line", onClick: () => {
|
|
41
|
+
setRows(rows.filter((_, i) => i !== index));
|
|
42
|
+
}, children: _jsx(DeleteIcon, {}) })] }, index))), _jsx(Button, { onClick: () => {
|
|
43
|
+
setRows([...rows, { value: '', label: '', color: '' }]);
|
|
44
|
+
}, children: "Add line" })] }));
|
|
45
|
+
});
|