@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,89 @@
|
|
|
1
|
+
import type { scalesSchema } from './valueScaleConfigSchema.ts';
|
|
2
|
+
import type { ConfigModelForFields } from '@jbrowse/core/configuration';
|
|
3
|
+
/** The slots its composers each declare, with their own defaults. */
|
|
4
|
+
export declare const wiggleScoreConfigExtraSlots: {
|
|
5
|
+
readonly scatterPointSize: {
|
|
6
|
+
readonly type: 'number';
|
|
7
|
+
readonly defaultValue: 2;
|
|
8
|
+
};
|
|
9
|
+
readonly displayCrossHatches: {
|
|
10
|
+
readonly type: 'boolean';
|
|
11
|
+
readonly defaultValue: false;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export interface WiggleScoreConfigHost {
|
|
15
|
+
configuration: ConfigModelForFields<{
|
|
16
|
+
scales: ReturnType<typeof scalesSchema>;
|
|
17
|
+
} & typeof wiggleScoreConfigExtraSlots>;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* #stateModel WiggleScoreConfigMixin
|
|
21
|
+
* #category display
|
|
22
|
+
*
|
|
23
|
+
* The score-plot config every display with a score axis shares: the axis
|
|
24
|
+
* (`ScoreScaleMixin`), the cross-hatch toggle and the scatter point size. A
|
|
25
|
+
* display plotting one configured field composes `ScoreFieldConfigMixin`,
|
|
26
|
+
* which adds `scoreField`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function WiggleScoreConfigMixin(): import("@jbrowse/mobx-state-tree").IModelType<Omit<{}, never>, {
|
|
29
|
+
readonly scaleType: string;
|
|
30
|
+
readonly manualMinScore: number | undefined;
|
|
31
|
+
readonly manualMaxScore: number | undefined;
|
|
32
|
+
readonly defaultScoreDomain: [number | undefined, number | undefined];
|
|
33
|
+
readonly valueScales: import("@jbrowse/display-ui").ValueScale[];
|
|
34
|
+
} & {
|
|
35
|
+
readonly minScoreBound: number | undefined;
|
|
36
|
+
readonly maxScoreBound: number | undefined;
|
|
37
|
+
readonly hasManualScoreBounds: boolean;
|
|
38
|
+
readonly axes: import("@jbrowse/display-ui").YAxis[];
|
|
39
|
+
} & {
|
|
40
|
+
readonly scaleType: string;
|
|
41
|
+
readonly scaleTypeChoices: string[];
|
|
42
|
+
readonly autoscaleType: string | undefined;
|
|
43
|
+
readonly numStdDev: number;
|
|
44
|
+
readonly numQuantile: number;
|
|
45
|
+
readonly symlogConstant: number;
|
|
46
|
+
readonly manualMinScore: number | undefined;
|
|
47
|
+
readonly manualMaxScore: number | undefined;
|
|
48
|
+
readonly scaleTitle: string | undefined;
|
|
49
|
+
readonly scoreRulesDrawn: boolean;
|
|
50
|
+
readonly scoreRules: import("@jbrowse/display-ui").ValueScaleRule[];
|
|
51
|
+
} & {
|
|
52
|
+
setScaleType(scaleType: string): void;
|
|
53
|
+
setAutoscale(val?: string): void;
|
|
54
|
+
setMinScore(val?: number): void;
|
|
55
|
+
setMaxScore(val?: number): void;
|
|
56
|
+
setScoreRules(rules: (number | import("@jbrowse/display-ui").ValueScaleRule)[]): void;
|
|
57
|
+
} & {
|
|
58
|
+
/**
|
|
59
|
+
* #getter
|
|
60
|
+
*/
|
|
61
|
+
readonly scatterPointSize: number;
|
|
62
|
+
/**
|
|
63
|
+
* #getter
|
|
64
|
+
* The configured cross-hatch setting the menu toggles; `showCrossHatches`
|
|
65
|
+
* is what draws.
|
|
66
|
+
*/
|
|
67
|
+
readonly displayCrossHatches: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* #getter
|
|
70
|
+
* Whether score maps to color instead of height; a display overrides it.
|
|
71
|
+
*/
|
|
72
|
+
readonly isDensityMode: boolean;
|
|
73
|
+
} & {
|
|
74
|
+
/**
|
|
75
|
+
* #action
|
|
76
|
+
*/
|
|
77
|
+
toggleCrossHatches(): void;
|
|
78
|
+
/**
|
|
79
|
+
* #action
|
|
80
|
+
*/
|
|
81
|
+
setScatterPointSize(val?: number): void;
|
|
82
|
+
} & {
|
|
83
|
+
/**
|
|
84
|
+
* #getter
|
|
85
|
+
* Whether the score-axis cross hatches draw: never in density mode, which
|
|
86
|
+
* has no height axis to rule and no toggle in its menu.
|
|
87
|
+
*/
|
|
88
|
+
readonly showCrossHatches: boolean;
|
|
89
|
+
}, import("@jbrowse/mobx-state-tree")._NotCustomized, import("@jbrowse/mobx-state-tree")._NotCustomized>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { getConf, setConf } from '@jbrowse/core/configuration';
|
|
2
|
+
import { types } from '@jbrowse/mobx-state-tree';
|
|
3
|
+
import { ScoreScaleMixin } from './ScoreScaleMixin.js';
|
|
4
|
+
/** The slots its composers each declare, with their own defaults. */
|
|
5
|
+
export const wiggleScoreConfigExtraSlots = {
|
|
6
|
+
scatterPointSize: { type: 'number', defaultValue: 2 },
|
|
7
|
+
displayCrossHatches: { type: 'boolean', defaultValue: false },
|
|
8
|
+
};
|
|
9
|
+
const confNode = (self) => self;
|
|
10
|
+
/**
|
|
11
|
+
* #stateModel WiggleScoreConfigMixin
|
|
12
|
+
* #category display
|
|
13
|
+
*
|
|
14
|
+
* The score-plot config every display with a score axis shares: the axis
|
|
15
|
+
* (`ScoreScaleMixin`), the cross-hatch toggle and the scatter point size. A
|
|
16
|
+
* display plotting one configured field composes `ScoreFieldConfigMixin`,
|
|
17
|
+
* which adds `scoreField`.
|
|
18
|
+
*/
|
|
19
|
+
export function WiggleScoreConfigMixin() {
|
|
20
|
+
return types
|
|
21
|
+
.compose('WiggleScoreConfigMixin', ScoreScaleMixin(), types.model({}))
|
|
22
|
+
.views(self => ({
|
|
23
|
+
/**
|
|
24
|
+
* #getter
|
|
25
|
+
*/
|
|
26
|
+
get scatterPointSize() {
|
|
27
|
+
return getConf(confNode(self), 'scatterPointSize');
|
|
28
|
+
},
|
|
29
|
+
/**
|
|
30
|
+
* #getter
|
|
31
|
+
* The configured cross-hatch setting the menu toggles; `showCrossHatches`
|
|
32
|
+
* is what draws.
|
|
33
|
+
*/
|
|
34
|
+
get displayCrossHatches() {
|
|
35
|
+
return getConf(confNode(self), 'displayCrossHatches');
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* #getter
|
|
39
|
+
* Whether score maps to color instead of height; a display overrides it.
|
|
40
|
+
*/
|
|
41
|
+
get isDensityMode() {
|
|
42
|
+
return false;
|
|
43
|
+
},
|
|
44
|
+
}))
|
|
45
|
+
.actions(self => ({
|
|
46
|
+
/**
|
|
47
|
+
* #action
|
|
48
|
+
*/
|
|
49
|
+
toggleCrossHatches() {
|
|
50
|
+
setConf(confNode(self), 'displayCrossHatches', !self.displayCrossHatches);
|
|
51
|
+
},
|
|
52
|
+
/**
|
|
53
|
+
* #action
|
|
54
|
+
*/
|
|
55
|
+
setScatterPointSize(val) {
|
|
56
|
+
setConf(confNode(self), 'scatterPointSize', val);
|
|
57
|
+
},
|
|
58
|
+
}))
|
|
59
|
+
.views(self => ({
|
|
60
|
+
/**
|
|
61
|
+
* #getter
|
|
62
|
+
* Whether the score-axis cross hatches draw: never in density mode, which
|
|
63
|
+
* has no height axis to rule and no toggle in its menu.
|
|
64
|
+
*/
|
|
65
|
+
get showCrossHatches() {
|
|
66
|
+
return self.displayCrossHatches && !self.isDensityMode;
|
|
67
|
+
},
|
|
68
|
+
}));
|
|
69
|
+
}
|
package/esm/autoscale.d.ts
CHANGED
|
@@ -18,6 +18,29 @@ export interface ScoreStats {
|
|
|
18
18
|
scoreMean: number;
|
|
19
19
|
scoreStdDev: number;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* #api
|
|
23
|
+
* One block's worth of values to fold into a domain, whatever packed them: a
|
|
24
|
+
* wiggle source's interleaved `featurePositions` and its three summary arrays,
|
|
25
|
+
* or a mark layer's separate `x`/`x2` and its one `y` lane. `starts[i * stride]`
|
|
26
|
+
* and `ends[i * stride + endOffset]` give instance `i`'s span; `low`, `high` and
|
|
27
|
+
* `avg` give the two ends of its value and the one the mean is taken over, which
|
|
28
|
+
* are the same array wherever the packer ships a single scalar.
|
|
29
|
+
*/
|
|
30
|
+
export interface ScoreSpan {
|
|
31
|
+
count: number;
|
|
32
|
+
starts: Uint32Array;
|
|
33
|
+
ends: Uint32Array;
|
|
34
|
+
stride: number;
|
|
35
|
+
endOffset: number;
|
|
36
|
+
low: Float32Array;
|
|
37
|
+
high: Float32Array;
|
|
38
|
+
avg: Float32Array;
|
|
39
|
+
visStart?: number;
|
|
40
|
+
visEnd?: number;
|
|
41
|
+
}
|
|
42
|
+
/** The wiggle packer's arrays as a span, under a summary mode. */
|
|
43
|
+
export declare function datasetSpan({ data, visStart, visEnd }: Dataset, summaryScoreMode: string): ScoreSpan;
|
|
21
44
|
/**
|
|
22
45
|
* #api
|
|
23
46
|
* Per-feature scalar score array for a summary mode: the min/max summary array
|
|
@@ -28,16 +51,33 @@ export declare function getEffectiveScores(data: {
|
|
|
28
51
|
featureMinScores: Float32Array;
|
|
29
52
|
featureMaxScores: Float32Array;
|
|
30
53
|
}, summaryScoreMode: string): Float32Array<ArrayBufferLike>;
|
|
54
|
+
export declare function computeSpanStats(spans: ScoreSpan[]): ScoreStats | undefined;
|
|
55
|
+
/** `computeSpanStats` over the wiggle packer's datasets. */
|
|
31
56
|
export declare function computeScoreStats(summaryScoreMode: string, datasets: Dataset[]): ScoreStats | undefined;
|
|
32
57
|
/**
|
|
33
58
|
* #api
|
|
34
|
-
* Converts score stats into a `[min, max]` domain, applying std-dev
|
|
35
|
-
*
|
|
59
|
+
* Converts score stats into a `[min, max]` domain, applying std-dev expansion
|
|
60
|
+
* for the `localsd` autoscale type. An `undefined` mode is a display whose
|
|
61
|
+
* scale declares none, and takes the plain extremes.
|
|
36
62
|
*/
|
|
37
|
-
export declare function domainFromStats(stats: ScoreStats, autoscaleType: string, numStdDev: number): [number, number];
|
|
63
|
+
export declare function domainFromStats(stats: ScoreStats, autoscaleType: string | undefined, numStdDev: number): [number, number];
|
|
64
|
+
/**
|
|
65
|
+
* #api
|
|
66
|
+
* Already-computed stats to the displayed domain, for the `local` / `localsd` /
|
|
67
|
+
* `localpercentile` autoscale modes. `localpercentile` re-walks the spans to
|
|
68
|
+
* build its histogram; the other modes read the stats alone.
|
|
69
|
+
*/
|
|
70
|
+
export declare function autoscaleDomainFromSpans({ stats, autoscaleType, numStdDev, numQuantile, spans, }: {
|
|
71
|
+
stats: ScoreStats;
|
|
72
|
+
autoscaleType: string | undefined;
|
|
73
|
+
numStdDev: number;
|
|
74
|
+
numQuantile?: number;
|
|
75
|
+
spans: ScoreSpan[];
|
|
76
|
+
}): [number, number];
|
|
77
|
+
/** `autoscaleDomainFromSpans` over the wiggle packer's datasets. */
|
|
38
78
|
export declare function autoscaleDomainFromStats({ stats, autoscaleType, summaryScoreMode, numStdDev, numQuantile, visibleEntries, }: {
|
|
39
79
|
stats: ScoreStats;
|
|
40
|
-
autoscaleType: string;
|
|
80
|
+
autoscaleType: string | undefined;
|
|
41
81
|
summaryScoreMode: string;
|
|
42
82
|
numStdDev: number;
|
|
43
83
|
numQuantile?: number;
|
|
@@ -48,7 +88,7 @@ export declare function autoscaleDomainFromStats({ stats, autoscaleType, summary
|
|
|
48
88
|
* Computes a score domain from the visible feature arrays for the `local` /
|
|
49
89
|
* `localsd` / `localpercentile` autoscale types.
|
|
50
90
|
*/
|
|
51
|
-
export declare function computeAutoscaleDomain(autoscaleType: string, summaryScoreMode: string, numStdDev: number, visibleEntries: {
|
|
91
|
+
export declare function computeAutoscaleDomain(autoscaleType: string | undefined, summaryScoreMode: string, numStdDev: number, visibleEntries: {
|
|
52
92
|
data: FeatureArrays;
|
|
53
93
|
visStart: number;
|
|
54
94
|
visEnd: number;
|
package/esm/autoscale.js
CHANGED
|
@@ -14,6 +14,22 @@ export const DEFAULT_AUTOSCALE_OPTIONS = [
|
|
|
14
14
|
['localpercentile', 'Local (99th percentile)'],
|
|
15
15
|
['localsd', 'Local ± 3σ'],
|
|
16
16
|
];
|
|
17
|
+
/** The wiggle packer's arrays as a span, under a summary mode. */
|
|
18
|
+
export function datasetSpan({ data, visStart, visEnd }, summaryScoreMode) {
|
|
19
|
+
const { low, high } = boundArrays(summaryScoreMode);
|
|
20
|
+
return {
|
|
21
|
+
count: data.numFeatures,
|
|
22
|
+
starts: data.featurePositions,
|
|
23
|
+
ends: data.featurePositions,
|
|
24
|
+
stride: 2,
|
|
25
|
+
endOffset: 1,
|
|
26
|
+
low: low(data),
|
|
27
|
+
high: high(data),
|
|
28
|
+
avg: data.featureScores,
|
|
29
|
+
visStart,
|
|
30
|
+
visEnd,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
17
33
|
/**
|
|
18
34
|
* #api
|
|
19
35
|
* Per-feature scalar score array for a summary mode: the min/max summary array
|
|
@@ -50,14 +66,15 @@ function boundArrays(summaryScoreMode) {
|
|
|
50
66
|
// resolution on the domain, which is finer than any autoscale needs and keeps
|
|
51
67
|
// the second pass O(n) with a fixed, trivial allocation.
|
|
52
68
|
const NUM_HISTOGRAM_BINS = 1024;
|
|
53
|
-
// First index whose
|
|
54
|
-
//
|
|
55
|
-
function lowerBoundByStart(
|
|
69
|
+
// First index whose instance STARTS at or after `bp`. `starts` is sorted by
|
|
70
|
+
// start — the same property `findFeatureAtBp` binary-searches on.
|
|
71
|
+
function lowerBoundByStart(span, bp) {
|
|
72
|
+
const { starts, stride } = span;
|
|
56
73
|
let lo = 0;
|
|
57
|
-
let hi =
|
|
74
|
+
let hi = span.count;
|
|
58
75
|
while (lo < hi) {
|
|
59
76
|
const mid = (lo + hi) >> 1;
|
|
60
|
-
if (
|
|
77
|
+
if (starts[mid * stride] >= bp) {
|
|
61
78
|
hi = mid;
|
|
62
79
|
}
|
|
63
80
|
else {
|
|
@@ -81,60 +98,62 @@ function lowerBoundByStart(featurePositions, numFeatures, bp) {
|
|
|
81
98
|
* still test `overlaps` per feature inside the range, so a dataset that broke
|
|
82
99
|
* that assumption could only lose a long early feature, never gain one.
|
|
83
100
|
*/
|
|
84
|
-
function visibleIndexRange(
|
|
101
|
+
function visibleIndexRange(span) {
|
|
102
|
+
const { visStart, visEnd, ends, stride, endOffset } = span;
|
|
85
103
|
if (visStart === undefined || visEnd === undefined) {
|
|
86
|
-
return { from: 0, to:
|
|
104
|
+
return { from: 0, to: span.count };
|
|
87
105
|
}
|
|
88
|
-
const to = lowerBoundByStart(
|
|
89
|
-
let from = lowerBoundByStart(
|
|
90
|
-
while (from > 0 &&
|
|
106
|
+
const to = lowerBoundByStart(span, visEnd);
|
|
107
|
+
let from = lowerBoundByStart(span, visStart);
|
|
108
|
+
while (from > 0 && ends[(from - 1) * stride + endOffset] > visStart) {
|
|
91
109
|
from--;
|
|
92
110
|
}
|
|
93
111
|
return { from, to };
|
|
94
112
|
}
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
// Half-open overlap test against the span's own window, for the instances the
|
|
114
|
+
// index range admits.
|
|
115
|
+
function spanOverlaps(span, i) {
|
|
116
|
+
const { visStart, visEnd, starts, ends, stride, endOffset } = span;
|
|
117
|
+
return (visStart === undefined ||
|
|
118
|
+
visEnd === undefined ||
|
|
119
|
+
overlaps(starts[i * stride], ends[i * stride + endOffset], visStart, visEnd));
|
|
120
|
+
}
|
|
121
|
+
// Min/max/mean/stddev of the visible instances, in one pass. Exported (not #api
|
|
122
|
+
// — internal plumbing shared with the quantitative displays) so a caller needing
|
|
123
|
+
// both a domain and the raw extent computes the stats once and feeds them to
|
|
124
|
+
// `autoscaleDomainFromSpans` instead of walking the arrays twice.
|
|
125
|
+
export function computeSpanStats(spans) {
|
|
101
126
|
let min = Infinity;
|
|
102
127
|
let max = -Infinity;
|
|
103
128
|
let sum = 0;
|
|
104
129
|
let sumSq = 0;
|
|
105
130
|
let count = 0;
|
|
106
|
-
for (const
|
|
107
|
-
const {
|
|
108
|
-
|
|
109
|
-
// per-feature loop.
|
|
110
|
-
const minScores = low(data);
|
|
111
|
-
const maxScores = high(data);
|
|
112
|
-
const { from, to } = visibleIndexRange(featurePositions, numFeatures, visStart, visEnd);
|
|
131
|
+
for (const span of spans) {
|
|
132
|
+
const { low, high, avg } = span;
|
|
133
|
+
const { from, to } = visibleIndexRange(span);
|
|
113
134
|
for (let i = from; i < to; i++) {
|
|
114
|
-
if (
|
|
115
|
-
visEnd !== undefined &&
|
|
116
|
-
!overlaps(featurePositions[i * 2], featurePositions[i * 2 + 1], visStart, visEnd)) {
|
|
135
|
+
if (!spanOverlaps(span, i)) {
|
|
117
136
|
continue;
|
|
118
137
|
}
|
|
119
|
-
// Non-finite
|
|
138
|
+
// Non-finite values are skipped rather than folded in: a wig file may
|
|
120
139
|
// carry a NaN, and one of them poisons min/max and mean alike, collapsing
|
|
121
140
|
// the whole domain to the [0, 1] stub the callers fall back to.
|
|
122
|
-
const lo =
|
|
141
|
+
const lo = low[i];
|
|
123
142
|
if (Number.isFinite(lo)) {
|
|
124
143
|
min = Math.min(min, lo);
|
|
125
144
|
}
|
|
126
|
-
const hi =
|
|
145
|
+
const hi = high[i];
|
|
127
146
|
if (Number.isFinite(hi)) {
|
|
128
147
|
max = Math.max(max, hi);
|
|
129
148
|
}
|
|
130
|
-
// Mean/stddev always
|
|
131
|
-
//
|
|
132
|
-
//
|
|
133
|
-
//
|
|
134
|
-
const
|
|
135
|
-
if (Number.isFinite(
|
|
136
|
-
sum +=
|
|
137
|
-
sumSq +=
|
|
149
|
+
// Mean/stddev always come from `avg` — the average score on the wiggle
|
|
150
|
+
// side — while min/max come from the mode-selected pair. Intentional:
|
|
151
|
+
// sd-based autoscale centers on the average-value distribution even in
|
|
152
|
+
// whiskers/min/max summary modes.
|
|
153
|
+
const mid = avg[i];
|
|
154
|
+
if (Number.isFinite(mid)) {
|
|
155
|
+
sum += mid;
|
|
156
|
+
sumSq += mid * mid;
|
|
138
157
|
count++;
|
|
139
158
|
}
|
|
140
159
|
}
|
|
@@ -146,10 +165,15 @@ export function computeScoreStats(summaryScoreMode, datasets) {
|
|
|
146
165
|
const stdDev = Math.sqrt(Math.max(0, sumSq / count - mean * mean));
|
|
147
166
|
return { scoreMin: min, scoreMax: max, scoreMean: mean, scoreStdDev: stdDev };
|
|
148
167
|
}
|
|
168
|
+
/** `computeSpanStats` over the wiggle packer's datasets. */
|
|
169
|
+
export function computeScoreStats(summaryScoreMode, datasets) {
|
|
170
|
+
return computeSpanStats(datasets.map(d => datasetSpan(d, summaryScoreMode)));
|
|
171
|
+
}
|
|
149
172
|
/**
|
|
150
173
|
* #api
|
|
151
|
-
* Converts score stats into a `[min, max]` domain, applying std-dev
|
|
152
|
-
*
|
|
174
|
+
* Converts score stats into a `[min, max]` domain, applying std-dev expansion
|
|
175
|
+
* for the `localsd` autoscale type. An `undefined` mode is a display whose
|
|
176
|
+
* scale declares none, and takes the plain extremes.
|
|
153
177
|
*/
|
|
154
178
|
export function domainFromStats(stats, autoscaleType, numStdDev) {
|
|
155
179
|
if (autoscaleType === 'localsd') {
|
|
@@ -161,31 +185,28 @@ export function domainFromStats(stats, autoscaleType, numStdDev) {
|
|
|
161
185
|
}
|
|
162
186
|
return [stats.scoreMin, stats.scoreMax];
|
|
163
187
|
}
|
|
164
|
-
// The `quantile`-th percentile magnitude of one signed side of the
|
|
165
|
-
// distribution:
|
|
188
|
+
// The `quantile`-th percentile magnitude of one signed side of the value
|
|
189
|
+
// distribution: instances are filtered to a single sign (`positiveSide`), their
|
|
166
190
|
// magnitudes binned over `[0, maxMag]`, and the magnitude below which `quantile`
|
|
167
191
|
// of that side's mass falls is returned — clipping the outermost `1 - quantile`
|
|
168
192
|
// as outliers. Returns 0 when the side is empty. A fixed histogram keeps this an
|
|
169
193
|
// O(n) pass with no sort, approximate to ~1/NUM_HISTOGRAM_BINS of maxMag, far
|
|
170
194
|
// finer than the display needs.
|
|
171
|
-
function sideMagnitudePercentile(
|
|
195
|
+
function sideMagnitudePercentile(spans, valuesFor, positiveSide, maxMag, quantile) {
|
|
172
196
|
if (maxMag <= 0) {
|
|
173
197
|
return 0;
|
|
174
198
|
}
|
|
175
199
|
const bins = new Int32Array(NUM_HISTOGRAM_BINS);
|
|
176
200
|
const scale = NUM_HISTOGRAM_BINS / maxMag;
|
|
177
201
|
let count = 0;
|
|
178
|
-
for (const
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
const { from, to } = visibleIndexRange(featurePositions, numFeatures, visStart, visEnd);
|
|
202
|
+
for (const span of spans) {
|
|
203
|
+
const values = valuesFor(span);
|
|
204
|
+
const { from, to } = visibleIndexRange(span);
|
|
182
205
|
for (let i = from; i < to; i++) {
|
|
183
|
-
if (
|
|
184
|
-
visEnd !== undefined &&
|
|
185
|
-
!overlaps(featurePositions[i * 2], featurePositions[i * 2 + 1], visStart, visEnd)) {
|
|
206
|
+
if (!spanOverlaps(span, i)) {
|
|
186
207
|
continue;
|
|
187
208
|
}
|
|
188
|
-
const mag = positiveSide ?
|
|
209
|
+
const mag = positiveSide ? values[i] : -values[i];
|
|
189
210
|
if (mag > 0) {
|
|
190
211
|
const bin = Math.min(NUM_HISTOGRAM_BINS - 1, Math.floor(mag * scale));
|
|
191
212
|
bins[bin]++;
|
|
@@ -207,10 +228,10 @@ function sideMagnitudePercentile(datasets, scoresFor, positiveSide, maxMag, quan
|
|
|
207
228
|
}
|
|
208
229
|
return maxMag;
|
|
209
230
|
}
|
|
210
|
-
// Builds a `[low, high]` domain by clipping each side of the
|
|
211
|
-
// to its central `quantile` fraction (e.g. 0.99
|
|
231
|
+
// Builds a `[low, high]` domain by clipping each side of the value distribution
|
|
232
|
+
// to its central `quantile` fraction (e.g. 0.99 -> clip the outermost 1% of each
|
|
212
233
|
// sign). Unlike localsd it makes no normality assumption, so it stays robust on
|
|
213
|
-
// the heavily skewed
|
|
234
|
+
// the heavily skewed distributions typical of coverage/wiggle data.
|
|
214
235
|
//
|
|
215
236
|
// The two signs are clipped INDEPENDENTLY, anchored at 0. A single combined
|
|
216
237
|
// percentile spends its whole budget on the dominant side, so on strongly
|
|
@@ -218,46 +239,57 @@ function sideMagnitudePercentile(datasets, scoresFor, positiveSide, maxMag, quan
|
|
|
218
239
|
// sparse, small negative tail) the minority tail's 1st percentile lands at or
|
|
219
240
|
// above 0 and the negative extent collapses to a flat band. Measuring each
|
|
220
241
|
// side's percentile from 0 outward keeps a small-but-real opposite tail visible.
|
|
221
|
-
function
|
|
242
|
+
function percentileDomainFromSpans(stats, quantile, spans) {
|
|
222
243
|
const { scoreMin, scoreMax } = stats;
|
|
223
244
|
if (scoreMax - scoreMin <= 0) {
|
|
224
245
|
return [scoreMin, scoreMax];
|
|
225
246
|
}
|
|
226
|
-
const arrays = boundArrays(summaryScoreMode);
|
|
227
247
|
const high = scoreMax > 0
|
|
228
|
-
? sideMagnitudePercentile(
|
|
248
|
+
? sideMagnitudePercentile(spans, span => span.high, true, scoreMax, quantile)
|
|
229
249
|
: 0;
|
|
230
250
|
const negExtent = scoreMin < 0
|
|
231
|
-
? sideMagnitudePercentile(
|
|
251
|
+
? sideMagnitudePercentile(spans, span => span.low, false, -scoreMin, quantile)
|
|
232
252
|
: 0;
|
|
233
253
|
// Anchor the low bound at 0 for all-positive data (matching localsd's origin
|
|
234
254
|
// convention); otherwise extend it to the negative side's clipped extent.
|
|
235
255
|
return [scoreMin < 0 ? -negExtent : 0, high];
|
|
236
256
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
257
|
+
/**
|
|
258
|
+
* #api
|
|
259
|
+
* Already-computed stats to the displayed domain, for the `local` / `localsd` /
|
|
260
|
+
* `localpercentile` autoscale modes. `localpercentile` re-walks the spans to
|
|
261
|
+
* build its histogram; the other modes read the stats alone.
|
|
262
|
+
*/
|
|
263
|
+
export function autoscaleDomainFromSpans({ stats, autoscaleType, numStdDev, numQuantile = 0.99, spans, }) {
|
|
242
264
|
return autoscaleType === 'localpercentile'
|
|
243
|
-
?
|
|
265
|
+
? percentileDomainFromSpans(stats, numQuantile, spans)
|
|
244
266
|
: domainFromStats(stats, autoscaleType, numStdDev);
|
|
245
267
|
}
|
|
268
|
+
/** `autoscaleDomainFromSpans` over the wiggle packer's datasets. */
|
|
269
|
+
export function autoscaleDomainFromStats({ stats, autoscaleType, summaryScoreMode, numStdDev, numQuantile = 0.99, visibleEntries, }) {
|
|
270
|
+
return autoscaleDomainFromSpans({
|
|
271
|
+
stats,
|
|
272
|
+
autoscaleType,
|
|
273
|
+
numStdDev,
|
|
274
|
+
numQuantile,
|
|
275
|
+
spans: visibleEntries.map(d => datasetSpan(d, summaryScoreMode)),
|
|
276
|
+
});
|
|
277
|
+
}
|
|
246
278
|
/**
|
|
247
279
|
* #api
|
|
248
280
|
* Computes a score domain from the visible feature arrays for the `local` /
|
|
249
281
|
* `localsd` / `localpercentile` autoscale types.
|
|
250
282
|
*/
|
|
251
283
|
export function computeAutoscaleDomain(autoscaleType, summaryScoreMode, numStdDev, visibleEntries, numQuantile = 0.99) {
|
|
252
|
-
const
|
|
284
|
+
const spans = visibleEntries.map(d => datasetSpan(d, summaryScoreMode));
|
|
285
|
+
const stats = computeSpanStats(spans);
|
|
253
286
|
return stats
|
|
254
|
-
?
|
|
287
|
+
? autoscaleDomainFromSpans({
|
|
255
288
|
stats,
|
|
256
289
|
autoscaleType,
|
|
257
|
-
summaryScoreMode,
|
|
258
290
|
numStdDev,
|
|
259
291
|
numQuantile,
|
|
260
|
-
|
|
292
|
+
spans,
|
|
261
293
|
})
|
|
262
294
|
: undefined;
|
|
263
295
|
}
|
package/esm/chrome.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { AxisGutter, CrossHatchLines, CrossHatches, ScoreDomainCaption, ScoreRuleLines, ScoreRules, YScaleBar, YScaleBarOverlay, } from '@jbrowse/display-ui';
|
|
2
|
+
export { makeResolutionSubMenuItem } from './ResolutionStepper.tsx';
|
|
3
|
+
export { makePointSizeSubMenu, makeScatterPointSizeMenuItem, } from './pointSizeMenu.tsx';
|
|
4
|
+
export { default as SetMinMaxDialog } from './SetMinMaxDialog.tsx';
|
package/esm/chrome.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// What draws a score plot, kept out of the package entry so the entry's score
|
|
2
|
+
// math and config mixins stay real in the RPC worker. A display imports these;
|
|
3
|
+
// an adapter or an RPC method never does.
|
|
4
|
+
export { AxisGutter, CrossHatchLines, CrossHatches, ScoreDomainCaption, ScoreRuleLines, ScoreRules, YScaleBar, YScaleBarOverlay, } from '@jbrowse/display-ui';
|
|
5
|
+
export { makeResolutionSubMenuItem } from './ResolutionStepper.js';
|
|
6
|
+
export { makePointSizeSubMenu, makeScatterPointSizeMenuItem, } from './pointSizeMenu.js';
|
|
7
|
+
export { default as SetMinMaxDialog } from './SetMinMaxDialog.js';
|
package/esm/computeYTicks.d.ts
CHANGED
package/esm/computeYTicks.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { YSCALEBAR_LABEL_OFFSET
|
|
1
|
+
import { YSCALEBAR_LABEL_OFFSET } from '@jbrowse/display-ui/yAxisConstants';
|
|
2
|
+
import { axisPlotBox } from '@jbrowse/display-ui/yScaleTicks';
|
|
2
3
|
import { getScale } from './scale.js';
|
|
3
4
|
// Builds Y-axis tick positions for a wiggle-family display: tick values come
|
|
4
5
|
// from d3's scale.ticks(4) at normal heights, or fall back to the domain
|
|
@@ -17,7 +18,8 @@ export function computeYTicks(opts) {
|
|
|
17
18
|
const { yTop, yBottom } = axisPlotBox(height, offset);
|
|
18
19
|
// A window whose scores are all one value (an all-zero coverage stretch) has
|
|
19
20
|
// a domain of no width. d3 answers the midpoint for every input there while
|
|
20
|
-
// `makeScoreNormalizer`
|
|
21
|
+
// `makeScoreNormalizer` puts that value on the baseline, and the renderer is
|
|
22
|
+
// the one to agree with.
|
|
21
23
|
if (domainMin === domainMax) {
|
|
22
24
|
return { items: [{ value: domainMin, y: yBottom }], yTop, yBottom };
|
|
23
25
|
}
|
package/esm/dataTypes.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ZoomRange } from '@jbrowse/core/data_adapters/BaseAdapter/zoomRange';
|
|
1
2
|
export interface SourceInfo {
|
|
2
3
|
name: string;
|
|
3
4
|
color?: string;
|
|
@@ -13,14 +14,9 @@ export interface WiggleFeatureArrays {
|
|
|
13
14
|
featureMaxScores: Float32Array;
|
|
14
15
|
numFeatures: number;
|
|
15
16
|
hasSummaryScores: boolean;
|
|
16
|
-
posFeaturePositions: Uint32Array;
|
|
17
|
-
posFeatureScores: Float32Array;
|
|
18
|
-
posNumFeatures: number;
|
|
19
|
-
negFeaturePositions: Uint32Array;
|
|
20
|
-
negFeatureScores: Float32Array;
|
|
21
|
-
negNumFeatures: number;
|
|
22
17
|
}
|
|
23
18
|
export type WiggleSourceData = SourceInfo & WiggleFeatureArrays;
|
|
24
19
|
export interface WiggleDataResult {
|
|
25
20
|
sources: WiggleSourceData[];
|
|
21
|
+
zoomRange?: ZoomRange;
|
|
26
22
|
}
|
package/esm/gapBreak.d.ts
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* draw. Returns `Infinity` when there is nothing to decide, so a caller can
|
|
6
6
|
* always compare against it unguarded.
|
|
7
7
|
*
|
|
8
|
-
* The limit is a multiple of the series'
|
|
9
|
-
* absolute distance,
|
|
10
|
-
* data types: reduced BigWig bins get wider as you zoom out, so any fixed bp
|
|
8
|
+
* The limit is a multiple of the series' *mean* spacing rather than an
|
|
9
|
+
* absolute distance, so one number works across zoom levels and data types: reduced BigWig bins get wider as you zoom out, so any fixed bp
|
|
11
10
|
* threshold would be either useless at one end or destructive at the other. It
|
|
12
11
|
* also lets the same rule serve a bp axis (wiggle's linecenter) and a px one —
|
|
13
12
|
* the caller picks the space, this only cares that the units are consistent.
|
package/esm/gapBreak.js
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
* draw. Returns `Infinity` when there is nothing to decide, so a caller can
|
|
6
6
|
* always compare against it unguarded.
|
|
7
7
|
*
|
|
8
|
-
* The limit is a multiple of the series'
|
|
9
|
-
* absolute distance,
|
|
10
|
-
* data types: reduced BigWig bins get wider as you zoom out, so any fixed bp
|
|
8
|
+
* The limit is a multiple of the series' *mean* spacing rather than an
|
|
9
|
+
* absolute distance, so one number works across zoom levels and data types: reduced BigWig bins get wider as you zoom out, so any fixed bp
|
|
11
10
|
* threshold would be either useless at one end or destructive at the other. It
|
|
12
11
|
* also lets the same rule serve a bp axis (wiggle's linecenter) and a px one —
|
|
13
12
|
* the caller picks the space, this only cares that the units are consistent.
|