Commit 6af15cca authored by Tejesh's avatar Tejesh 🖖

wip: new spec scales code

parent 8eea0369
Pipeline #91171 failed with stage
in 37 seconds
......@@ -16,40 +16,19 @@ Scales are dictionaries with the following keys:
**Scale Types**:
- **Quantitative Scales**
- `linear`
- `log`
- `pow`
- `sqrt`
- `symlog`
- `time`
- `utc`
- `sequential`
- `Linear`
- `Log`
- `Pow`
- `Sqrt`
- `Sequential`
- **Discrete Scales**
- `ordinal`
- `band`
- `point`
- `Ordinal`
- `Band`
- `Point`
- **Discretizing Scales**
- `quantile`
- `quantize`
- `threshold`
- `bin-ordinal`
Usage:
```js
fill: {
metric: 'age',
scheme: 'RdYlGn'
}
// or
fill: {
metric: 'age', // same as function(d) { return d.age }
scale: 'linear',
domain: [0, 50, 100],
range: ['red', 'yellow', 'green'],
}
```
- `Quantile`
- `Quantize`
- `Threshold`
**Notes**:
- *Schemes* is used to describe a discrete color range.
......@@ -97,12 +76,12 @@ var categorical_to_colorscheme = g1.scale({
To map continous data (numericals) to color schemes:
To map continuous data (numericals) to color schemes:
**Notes**:
- Quantile scale divides *total data points* to bins, with each bin containing equal number of data points.
- Quantile scale takes domain as entire dataset. Metric is mandatory and should be continous data. `domain` parameter is ignored even if provided.
- Quantile scale takes domain as entire dataset. Metric is mandatory and should be continuous data. `domain` parameter is ignored even if provided.
```js
var quantile_scale = g1.scale(data, {
......
......@@ -33,77 +33,68 @@ IDEAL SPEC:
export { scale }
function scale(data, config) {
var result, config_scheme, scale, chromatic, d3_scheme
var metricFormula = typeof config.metric == 'function' ? config.metric
: function (d) { return d[config.metric] }
var result, scale, domain, range, d3_scheme
var discrete_scales = ['ordinal', 'band', 'point'],
discretizing_scales = ['quantize', 'quantile', 'threshold']
config_scheme = config.scheme
if (!config.range) {
if (config_scheme && config_scheme in d3) {
// Explicit mention of schemeXXX or interpolateXXX
chromatic = config.count ? d3[config_scheme][config.count] : d3[config_scheme]
} else {
config_scheme = config_scheme.toUpperCase()[0] + config_scheme.slice(1)
// Decide whether schemeXXX or interpolateXXX
if (!config.count && 'interpolate' + config_scheme in d3) {
// interpolate
chromatic = d3['interpolate' + config_scheme]
} else {
// discrete without config.count (provide default count)
d3_scheme = d3['scheme' + config_scheme]
config.count = config.count ? config.count : d3_scheme.length
// for schemeBlues kind of discrete ranges, the k value is [3, 9].
// First 3 values are empty
chromatic = typeof d3_scheme[0] == 'string' ? d3_scheme : d3_scheme[config.count]
}
}
}
var domain = config.domain || d3.extent(data, metricFormula)
continous_scales = ['linear', 'log', 'pow', 'sqrt', 'sequential']
// Scale Resolver
if (config.scale) {
if (config.scale.toLowerCase() == 'quantile') {
domain = data.map(metricFormula)
}
// if domain is not given for ordinal scales, do not use d3.extent two value array as domain.
// One approach (being used now) is to calculate and assign domain to distinct ordinal values (Review?)
// The other approach is to pass empty array as domain
else if (discrete_scales.indexOf(config.scale.toLowerCase()) >= 0) {
if (!config.domain) domain = Object.keys(Object.fromEntries(d3.group(data, metricFormula)))
metricFormula = function (d) { return d }
}
scale = config.scale[0].toUpperCase() + config.scale.slice(1).toLowerCase()
} else if (config_scheme) {
scale = 'Sequential'
} else {
scale = 'Linear'
}
if (config.reverse) {
// Quantize/Quantile/Threshold scales sorts the domain by ascending order
// So, no point in reversing domain. Instead reverse color scheme range
if (discretizing_scales.indexOf(scale.toLowerCase()) >= 0 && config_scheme) {
config.range = (config.range && config.range.slice().reverse()) || chromatic.slice().reverse()
if (scale == 'Sequential') {
scale = 'Linear'
}
// Range Resolver
if (!Array.isArray(config.range)) {
// if Continous scale
if (continous_scales.indexOf(scale) >= 0) {
range = [0, 1]
} else {
domain = domain.slice().reverse()
// discrete without config.count (provide default count)
d3_scheme = d3['scheme' + config.range.scheme]
config.count = config.range.count ? config.range.count : d3_scheme.length
// for schemeBlues kind of discrete ranges, the k value is [3, 9].
// First 3 values are empty
range = typeof d3_scheme[0] == 'string' ? d3_scheme : d3_scheme[config.count]
}
}
if (discretizing_scales.indexOf(scale.toLowerCase()) >= 0 && config_scheme && !config.reverse) {
config.range = config.range || chromatic
// Domain Resolver
if (Array.isArray(config.domain)) {
domain = config.domain
} else {
if (discrete_scales.indexOf(config.scale) >= 0) {
// TODO: figure a better way to find column's distinct values
domain = Object.keys(Object.fromEntries(d3.group(data, (d) => d[config.domain.metric])))
} else if (config.scale.toLowerCase() == 'quantile') {
domain = data.map((d) => d[config.domain.metric])
} else {
domain = d3.extent(data, (d) => d[config.domain.metric])
}
}
// TODO PERF: concat is too slow?
if (discretizing_scales.indexOf(scale.toLowerCase()) < 0 && config_scheme) {
result = d3['scale' + scale](chromatic).domain(domain)
} else if (config.range) {
result = d3['scale' + scale]()
.domain(domain)
.range(config.range)
if (config.reverse) {
// Quantize/Quantile/Threshold scales sorts the domain by ascending order
// So, no point in reversing domain. Instead reverse color scheme range
range = range.slice().revese()
}
result = d3['scale' + scale]()
.domain(domain)
.range(range)
return function (val) {
return result(metricFormula(val))
// console.log('val: ', val, metricFormula, metricFormula(val), result)
if (continous_scales.indexOf(config.scale) >= 0 && !Array.isArray(config.range)) {
return d3['interpolate' + config.scale.scheme](result(val))
}
return result(val)
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment