@jbrowse/plugin-wiggle 1.5.7 → 1.6.2
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/dist/BigWigAdapter/BigWigAdapter.d.ts +5 -3
- package/dist/LinearWiggleDisplay/components/SetColorDialog.d.ts +4 -2
- package/dist/LinearWiggleDisplay/models/model.d.ts +35 -6
- package/dist/index.d.ts +104 -18
- package/dist/plugin-wiggle.cjs.development.js +176 -106
- package/dist/plugin-wiggle.cjs.development.js.map +1 -1
- package/dist/plugin-wiggle.cjs.production.min.js +1 -1
- package/dist/plugin-wiggle.cjs.production.min.js.map +1 -1
- package/dist/plugin-wiggle.esm.js +178 -108
- package/dist/plugin-wiggle.esm.js.map +1 -1
- package/package.json +2 -2
- package/src/BigWigAdapter/BigWigAdapter.ts +17 -13
- package/src/DensityRenderer/index.ts +3 -4
- package/src/LinearWiggleDisplay/components/SetColorDialog.tsx +84 -45
- package/src/LinearWiggleDisplay/components/WiggleDisplayComponent.tsx +2 -2
- package/src/LinearWiggleDisplay/models/configSchema.ts +1 -0
- package/src/LinearWiggleDisplay/models/model.tsx +34 -18
- package/src/index.ts +10 -5
- package/src/util.ts +1 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-wiggle",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.2",
|
|
4
4
|
"description": "JBrowse 2 wiggle adapters, tracks, etc.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jbrowse",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"publishConfig": {
|
|
61
61
|
"access": "public"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "92455c6021abd69548496a450983d89f8837860d"
|
|
64
64
|
}
|
|
@@ -5,15 +5,15 @@ import {
|
|
|
5
5
|
} from '@jbrowse/core/data_adapters/BaseAdapter'
|
|
6
6
|
import { AugmentedRegion as Region } from '@jbrowse/core/util/types'
|
|
7
7
|
import { openLocation } from '@jbrowse/core/util/io'
|
|
8
|
+
import { updateStatus } from '@jbrowse/core/util'
|
|
8
9
|
import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
9
10
|
import SimpleFeature, { Feature } from '@jbrowse/core/util/simpleFeature'
|
|
10
11
|
import { map, mergeAll } from 'rxjs/operators'
|
|
11
12
|
import { readConfObject } from '@jbrowse/core/configuration'
|
|
12
|
-
import {
|
|
13
|
+
import { AnyConfigurationModel } from '@jbrowse/core/configuration/configurationSchema'
|
|
13
14
|
import { rectifyStats, UnrectifiedFeatureStats } from '@jbrowse/core/util/stats'
|
|
14
15
|
import PluginManager from '@jbrowse/core/PluginManager'
|
|
15
16
|
|
|
16
|
-
import configSchema from './configSchema'
|
|
17
17
|
import { getSubAdapterType } from '@jbrowse/core/data_adapters/dataAdapterCache'
|
|
18
18
|
|
|
19
19
|
interface WiggleOptions extends BaseOptions {
|
|
@@ -30,7 +30,7 @@ export default class BigWigAdapter extends BaseFeatureDataAdapter {
|
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
public constructor(
|
|
33
|
-
config:
|
|
33
|
+
config: AnyConfigurationModel,
|
|
34
34
|
getSubAdapter?: getSubAdapterType,
|
|
35
35
|
pluginManager?: PluginManager,
|
|
36
36
|
) {
|
|
@@ -45,25 +45,24 @@ export default class BigWigAdapter extends BaseFeatureDataAdapter {
|
|
|
45
45
|
|
|
46
46
|
private async setup(opts?: BaseOptions) {
|
|
47
47
|
const { statusCallback = () => {} } = opts || {}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return result
|
|
48
|
+
return updateStatus('Downloading bigwig header', statusCallback, () =>
|
|
49
|
+
this.bigwig.getHeader(opts),
|
|
50
|
+
)
|
|
52
51
|
}
|
|
53
52
|
|
|
54
53
|
public async getRefNames(opts?: BaseOptions) {
|
|
55
|
-
const
|
|
56
|
-
return Object.keys(
|
|
54
|
+
const { refsByName } = await this.setup(opts)
|
|
55
|
+
return Object.keys(refsByName)
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
public async refIdToName(refId: number) {
|
|
60
|
-
const
|
|
61
|
-
return
|
|
59
|
+
const { refsByNumber } = await this.setup()
|
|
60
|
+
return refsByNumber[refId]?.name
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
public async getGlobalStats(opts?: BaseOptions) {
|
|
65
|
-
const
|
|
66
|
-
return rectifyStats(
|
|
64
|
+
const { totalSummary } = await this.setup(opts)
|
|
65
|
+
return rectifyStats(totalSummary as UnrectifiedFeatureStats)
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
public getFeatures(region: Region, opts: WiggleOptions = {}) {
|
|
@@ -92,5 +91,10 @@ export default class BigWigAdapter extends BaseFeatureDataAdapter {
|
|
|
92
91
|
}, signal)
|
|
93
92
|
}
|
|
94
93
|
|
|
94
|
+
// always render bigwig instead of calculating a feature density for it
|
|
95
|
+
async estimateRegionsStats(_regions: Region[]) {
|
|
96
|
+
return { featureDensity: 0 }
|
|
97
|
+
}
|
|
98
|
+
|
|
95
99
|
public freeResources(): void {}
|
|
96
100
|
}
|
|
@@ -24,11 +24,10 @@ export default class DensityRenderer extends WiggleBaseRenderer {
|
|
|
24
24
|
const pivotValue = readConfObject(config, 'bicolorPivotValue')
|
|
25
25
|
const negColor = readConfObject(config, 'negColor')
|
|
26
26
|
const posColor = readConfObject(config, 'posColor')
|
|
27
|
+
const color = readConfObject(config, 'color')
|
|
27
28
|
let colorCallback
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
// default color, use posColor/negColor instead
|
|
31
|
-
colorScale =
|
|
29
|
+
if (color === '#f0f') {
|
|
30
|
+
const colorScale =
|
|
32
31
|
pivot !== 'none'
|
|
33
32
|
? getScale({
|
|
34
33
|
...scaleOpts,
|
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { makeStyles } from '@material-ui/core/styles'
|
|
1
|
+
import React, { useState } from 'react'
|
|
3
2
|
import {
|
|
3
|
+
Button,
|
|
4
4
|
Dialog,
|
|
5
5
|
DialogContent,
|
|
6
|
+
DialogActions,
|
|
6
7
|
DialogTitle,
|
|
7
8
|
IconButton,
|
|
8
|
-
|
|
9
|
+
Typography,
|
|
10
|
+
FormControlLabel,
|
|
11
|
+
Radio,
|
|
12
|
+
makeStyles,
|
|
9
13
|
} from '@material-ui/core'
|
|
10
14
|
import CloseIcon from '@material-ui/icons/Close'
|
|
11
15
|
import { CompactPicker, Color, RGBColor } from 'react-color'
|
|
12
16
|
|
|
13
17
|
const useStyles = makeStyles(theme => ({
|
|
14
|
-
root: {},
|
|
15
18
|
closeButton: {
|
|
16
19
|
position: 'absolute',
|
|
17
20
|
right: theme.spacing(1),
|
|
@@ -22,33 +25,34 @@ const useStyles = makeStyles(theme => ({
|
|
|
22
25
|
|
|
23
26
|
// this is needed because passing a entire color object into the react-color
|
|
24
27
|
// for alpha, can't pass in an rgba string for example
|
|
25
|
-
function
|
|
28
|
+
function serialize(color: Color) {
|
|
26
29
|
if (color instanceof Object) {
|
|
27
|
-
const { r, g, b
|
|
28
|
-
return `rgb(${r},${g},${b}
|
|
30
|
+
const { r, g, b } = color as RGBColor
|
|
31
|
+
return `rgb(${r},${g},${b})`
|
|
29
32
|
}
|
|
30
33
|
return color
|
|
31
34
|
}
|
|
32
35
|
|
|
33
|
-
export default function SetColorDialog(
|
|
36
|
+
export default function SetColorDialog({
|
|
37
|
+
model,
|
|
38
|
+
handleClose,
|
|
39
|
+
}: {
|
|
34
40
|
model: {
|
|
35
41
|
color: number
|
|
36
|
-
setColor:
|
|
42
|
+
setColor: (arg?: string) => void
|
|
43
|
+
setPosColor: (arg?: string) => void
|
|
44
|
+
setNegColor: (arg?: string) => void
|
|
37
45
|
}
|
|
38
46
|
handleClose: () => void
|
|
39
47
|
}) {
|
|
40
48
|
const classes = useStyles()
|
|
41
|
-
const
|
|
49
|
+
const [posneg, setPosNeg] = useState(false)
|
|
42
50
|
|
|
43
51
|
return (
|
|
44
|
-
<Dialog
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
aria-describedby="alert-dialog-description"
|
|
49
|
-
>
|
|
50
|
-
<DialogTitle id="alert-dialog-title">
|
|
51
|
-
Select a color
|
|
52
|
+
<Dialog open onClose={handleClose}>
|
|
53
|
+
<DialogTitle>
|
|
54
|
+
Select either an overall color, or the positive/negative colors. Note
|
|
55
|
+
that density renderers only work properly with positive/negative colors
|
|
52
56
|
<IconButton
|
|
53
57
|
aria-label="close"
|
|
54
58
|
className={classes.closeButton}
|
|
@@ -57,37 +61,72 @@ export default function SetColorDialog(props: {
|
|
|
57
61
|
<CloseIcon />
|
|
58
62
|
</IconButton>
|
|
59
63
|
</DialogTitle>
|
|
60
|
-
<DialogContent
|
|
61
|
-
<
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
64
|
+
<DialogContent>
|
|
65
|
+
<FormControlLabel
|
|
66
|
+
checked={!posneg}
|
|
67
|
+
onClick={() => setPosNeg(false)}
|
|
68
|
+
control={<Radio />}
|
|
69
|
+
label={'Overall color'}
|
|
70
|
+
/>
|
|
71
|
+
<FormControlLabel
|
|
72
|
+
checked={posneg}
|
|
73
|
+
onClick={() => setPosNeg(true)}
|
|
74
|
+
control={<Radio />}
|
|
75
|
+
label={'Positive/negative color'}
|
|
76
|
+
/>
|
|
77
|
+
|
|
78
|
+
{posneg ? (
|
|
79
|
+
<>
|
|
80
|
+
<Typography>Positive color</Typography>
|
|
81
|
+
<CompactPicker
|
|
82
|
+
onChange={event => {
|
|
83
|
+
model.setPosColor(serialize(event.rgb))
|
|
84
|
+
model.setColor(undefined)
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
<Typography>Negative color</Typography>
|
|
88
|
+
<CompactPicker
|
|
89
|
+
onChange={event => {
|
|
90
|
+
model.setNegColor(serialize(event.rgb))
|
|
71
91
|
model.setColor(undefined)
|
|
72
92
|
}}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
</
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
type="submit"
|
|
82
|
-
onClick={() => {
|
|
83
|
-
handleClose()
|
|
93
|
+
/>
|
|
94
|
+
</>
|
|
95
|
+
) : (
|
|
96
|
+
<>
|
|
97
|
+
<Typography>Overall color</Typography>
|
|
98
|
+
<CompactPicker
|
|
99
|
+
onChange={event => {
|
|
100
|
+
model.setColor(serialize(event.rgb))
|
|
84
101
|
}}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
102
|
+
/>
|
|
103
|
+
</>
|
|
104
|
+
)}
|
|
90
105
|
</DialogContent>
|
|
106
|
+
<DialogActions>
|
|
107
|
+
<Button
|
|
108
|
+
onClick={() => {
|
|
109
|
+
model.setPosColor(undefined)
|
|
110
|
+
model.setNegColor(undefined)
|
|
111
|
+
model.setColor(undefined)
|
|
112
|
+
}}
|
|
113
|
+
color="secondary"
|
|
114
|
+
variant="contained"
|
|
115
|
+
>
|
|
116
|
+
Restore default
|
|
117
|
+
</Button>
|
|
118
|
+
|
|
119
|
+
<Button
|
|
120
|
+
variant="contained"
|
|
121
|
+
color="primary"
|
|
122
|
+
type="submit"
|
|
123
|
+
onClick={() => {
|
|
124
|
+
handleClose()
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
Submit
|
|
128
|
+
</Button>
|
|
129
|
+
</DialogActions>
|
|
91
130
|
</Dialog>
|
|
92
131
|
)
|
|
93
132
|
}
|
|
@@ -26,11 +26,11 @@ export const YScaleBar = observer(
|
|
|
26
26
|
|
|
27
27
|
const LinearWiggleDisplay = observer((props: { model: WiggleDisplayModel }) => {
|
|
28
28
|
const { model } = props
|
|
29
|
-
const {
|
|
29
|
+
const { stats, height, needsScalebar } = model
|
|
30
30
|
return (
|
|
31
31
|
<div>
|
|
32
32
|
<BaseLinearDisplayComponent {...props} />
|
|
33
|
-
{
|
|
33
|
+
{stats && needsScalebar ? (
|
|
34
34
|
<svg
|
|
35
35
|
style={{
|
|
36
36
|
position: 'absolute',
|
|
@@ -65,6 +65,8 @@ const stateModelFactory = (
|
|
|
65
65
|
resolution: types.optional(types.number, 1),
|
|
66
66
|
fill: types.maybe(types.boolean),
|
|
67
67
|
color: types.maybe(types.string),
|
|
68
|
+
posColor: types.maybe(types.string),
|
|
69
|
+
negColor: types.maybe(types.string),
|
|
68
70
|
summaryScoreMode: types.maybe(types.string),
|
|
69
71
|
rendererTypeNameState: types.maybe(types.string),
|
|
70
72
|
scale: types.maybe(types.string),
|
|
@@ -80,7 +82,7 @@ const stateModelFactory = (
|
|
|
80
82
|
}),
|
|
81
83
|
)
|
|
82
84
|
.volatile(() => ({
|
|
83
|
-
|
|
85
|
+
statsReady: false,
|
|
84
86
|
message: undefined as undefined | string,
|
|
85
87
|
stats: observable({ scoreMin: 0, scoreMax: 50 }),
|
|
86
88
|
statsFetchInProgress: undefined as undefined | AbortController,
|
|
@@ -89,11 +91,17 @@ const stateModelFactory = (
|
|
|
89
91
|
updateStats(stats: { scoreMin: number; scoreMax: number }) {
|
|
90
92
|
self.stats.scoreMin = stats.scoreMin
|
|
91
93
|
self.stats.scoreMax = stats.scoreMax
|
|
92
|
-
self.
|
|
94
|
+
self.statsReady = true
|
|
93
95
|
},
|
|
94
96
|
setColor(color: string) {
|
|
95
97
|
self.color = color
|
|
96
98
|
},
|
|
99
|
+
setPosColor(color: string) {
|
|
100
|
+
self.posColor = color
|
|
101
|
+
},
|
|
102
|
+
setNegColor(color: string) {
|
|
103
|
+
self.negColor = color
|
|
104
|
+
},
|
|
97
105
|
|
|
98
106
|
setLoading(aborter: AbortController) {
|
|
99
107
|
const { statsFetchInProgress: statsFetch } = self
|
|
@@ -161,7 +169,7 @@ const stateModelFactory = (
|
|
|
161
169
|
},
|
|
162
170
|
}))
|
|
163
171
|
.views(self => ({
|
|
164
|
-
get TooltipComponent()
|
|
172
|
+
get TooltipComponent() {
|
|
165
173
|
return Tooltip as unknown as React.FC
|
|
166
174
|
},
|
|
167
175
|
|
|
@@ -187,11 +195,6 @@ const stateModelFactory = (
|
|
|
187
195
|
get scaleType() {
|
|
188
196
|
return self.scale || getConf(self, 'scaleType')
|
|
189
197
|
},
|
|
190
|
-
get filled() {
|
|
191
|
-
return typeof self.fill !== 'undefined'
|
|
192
|
-
? self.fill
|
|
193
|
-
: readConfObject(this.rendererConfig, 'filled')
|
|
194
|
-
},
|
|
195
198
|
|
|
196
199
|
get maxScore() {
|
|
197
200
|
const { max } = self.constraints
|
|
@@ -202,19 +205,22 @@ const stateModelFactory = (
|
|
|
202
205
|
const { min } = self.constraints
|
|
203
206
|
return min !== undefined ? min : getConf(self, 'minScore')
|
|
204
207
|
},
|
|
205
|
-
|
|
208
|
+
}))
|
|
209
|
+
.views(self => ({
|
|
206
210
|
get rendererConfig() {
|
|
207
211
|
const configBlob =
|
|
208
|
-
getConf(self, ['renderers',
|
|
212
|
+
getConf(self, ['renderers', self.rendererTypeName]) || {}
|
|
209
213
|
|
|
210
214
|
return self.rendererType.configSchema.create(
|
|
211
215
|
{
|
|
212
216
|
...configBlob,
|
|
213
217
|
filled: self.fill,
|
|
214
|
-
scaleType:
|
|
218
|
+
scaleType: self.scaleType,
|
|
215
219
|
displayCrossHatches: self.displayCrossHatches,
|
|
216
220
|
summaryScoreMode: self.summaryScoreMode,
|
|
217
|
-
color: self.color,
|
|
221
|
+
...(self.color ? { color: self.color } : {}),
|
|
222
|
+
...(self.negColor ? { negColor: self.negColor } : {}),
|
|
223
|
+
...(self.posColor ? { posColor: self.posColor } : {}),
|
|
218
224
|
},
|
|
219
225
|
getEnv(self),
|
|
220
226
|
)
|
|
@@ -223,6 +229,11 @@ const stateModelFactory = (
|
|
|
223
229
|
.views(self => {
|
|
224
230
|
let oldDomain: [number, number] = [0, 0]
|
|
225
231
|
return {
|
|
232
|
+
get filled() {
|
|
233
|
+
return typeof self.fill !== 'undefined'
|
|
234
|
+
? self.fill
|
|
235
|
+
: readConfObject(self.rendererConfig, 'filled')
|
|
236
|
+
},
|
|
226
237
|
get summaryScoreModeSetting() {
|
|
227
238
|
return (
|
|
228
239
|
self.summaryScoreMode ||
|
|
@@ -311,9 +322,10 @@ const stateModelFactory = (
|
|
|
311
322
|
const { renderProps: superRenderProps } = self
|
|
312
323
|
return {
|
|
313
324
|
renderProps() {
|
|
325
|
+
const superProps = superRenderProps()
|
|
314
326
|
return {
|
|
315
|
-
...
|
|
316
|
-
notReady: !self.
|
|
327
|
+
...superProps,
|
|
328
|
+
notReady: superProps.notReady || !self.statsReady,
|
|
317
329
|
rpcDriverName: self.rpcDriverName,
|
|
318
330
|
displayModel: self,
|
|
319
331
|
config: self.rendererConfig,
|
|
@@ -481,6 +493,7 @@ const stateModelFactory = (
|
|
|
481
493
|
},
|
|
482
494
|
...opts,
|
|
483
495
|
}
|
|
496
|
+
|
|
484
497
|
if (autoscaleType === 'global' || autoscaleType === 'globalsd') {
|
|
485
498
|
const results: FeatureStats = (await rpcManager.call(
|
|
486
499
|
sessionId,
|
|
@@ -572,17 +585,20 @@ const stateModelFactory = (
|
|
|
572
585
|
return
|
|
573
586
|
}
|
|
574
587
|
|
|
575
|
-
if (
|
|
588
|
+
if (!self.estimatedStatsReady) {
|
|
589
|
+
return
|
|
590
|
+
}
|
|
591
|
+
if (self.regionTooLarge) {
|
|
576
592
|
return
|
|
577
593
|
}
|
|
578
594
|
|
|
579
|
-
const
|
|
595
|
+
const wiggleStats = await getStats({
|
|
580
596
|
signal: aborter.signal,
|
|
581
597
|
filters: self.filters,
|
|
582
598
|
})
|
|
583
599
|
|
|
584
600
|
if (isAlive(self)) {
|
|
585
|
-
self.updateStats(
|
|
601
|
+
self.updateStats(wiggleStats)
|
|
586
602
|
}
|
|
587
603
|
} catch (e) {
|
|
588
604
|
if (!isAbortException(e) && isAlive(self)) {
|
|
@@ -596,7 +612,7 @@ const stateModelFactory = (
|
|
|
596
612
|
)
|
|
597
613
|
},
|
|
598
614
|
async renderSvg(opts: ExportSvgOpts) {
|
|
599
|
-
await when(() => self.
|
|
615
|
+
await when(() => self.statsReady && !!self.regionCannotBeRenderedText)
|
|
600
616
|
const { needsScalebar, stats } = self
|
|
601
617
|
const { offsetPx } = getContainingView(self) as LGV
|
|
602
618
|
return (
|
package/src/index.ts
CHANGED
|
@@ -103,12 +103,17 @@ export default class WigglePlugin extends Plugin {
|
|
|
103
103
|
const regexGuess = /\.(bw|bigwig)$/i
|
|
104
104
|
const adapterName = 'BigWigAdapter'
|
|
105
105
|
const fileName = getFileName(file)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
bigWigLocation: file,
|
|
110
|
-
}
|
|
106
|
+
const obj = {
|
|
107
|
+
type: adapterName,
|
|
108
|
+
bigWigLocation: file,
|
|
111
109
|
}
|
|
110
|
+
|
|
111
|
+
if (regexGuess.test(fileName) && !adapterHint) {
|
|
112
|
+
return obj
|
|
113
|
+
} else if (adapterHint === adapterName) {
|
|
114
|
+
return obj
|
|
115
|
+
}
|
|
116
|
+
|
|
112
117
|
return adapterGuesser(file, index, adapterHint)
|
|
113
118
|
}
|
|
114
119
|
},
|
package/src/util.ts
CHANGED
|
@@ -41,7 +41,6 @@ export function getScale({
|
|
|
41
41
|
throw new Error('undefined scaleType')
|
|
42
42
|
}
|
|
43
43
|
scale.domain(pivotValue !== undefined ? [min, pivotValue, max] : [min, max])
|
|
44
|
-
// console.log('before', scale.domain())
|
|
45
44
|
scale.nice()
|
|
46
45
|
|
|
47
46
|
const [rangeMin, rangeMax] = range
|
|
@@ -49,8 +48,6 @@ export function getScale({
|
|
|
49
48
|
throw new Error('invalid range')
|
|
50
49
|
}
|
|
51
50
|
scale.range(inverted ? range.slice().reverse() : range)
|
|
52
|
-
|
|
53
|
-
// console.log('after', scale.domain())
|
|
54
51
|
return scale
|
|
55
52
|
}
|
|
56
53
|
/**
|
|
@@ -118,7 +115,7 @@ export function getNiceDomain({
|
|
|
118
115
|
}
|
|
119
116
|
}
|
|
120
117
|
if (min === undefined || max === undefined) {
|
|
121
|
-
throw new Error('invalid domain')
|
|
118
|
+
throw new Error('invalid domain supplied to stats function')
|
|
122
119
|
}
|
|
123
120
|
if (minScore !== undefined && minScore !== Number.MIN_VALUE) {
|
|
124
121
|
min = minScore
|