Skip to content

Commit

Permalink
feat(axis): Improve log scale to handle 0
Browse files Browse the repository at this point in the history
Replace the use of d3.scaleLog to d3.scaleSymlog to handle 0(zero) in scale values.

Fix #1578
  • Loading branch information
netil committed Aug 1, 2020
1 parent 3631f3b commit ca6cf62
Show file tree
Hide file tree
Showing 8 changed files with 29 additions and 20 deletions.
23 changes: 15 additions & 8 deletions src/ChartInternal/Axis/AxisRendererHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,20 +100,27 @@ export default class AxisRendererHelper {
interval += tickStepSize;
}
} else if (scale.ticks) {
ticks = scale
.ticks(...(this.config.tickArguments || []));
const {tickArguments} = this.config;

// adjust excessive tick count show
if (scale.type === "log") {
const t = scale.ticks();
const [head, tail] = [t[0], t[t.length - 1]];
if (scale.type === "log" && !tickArguments) {
// nicer symlog ticks didn't implemented yet: https://github.com/d3/d3-scale/issues/162
// get ticks values from logScale
const s = getScale("_log")
.domain([start > 0 ? start : 1, end])
.range(scale.range());

ticks = s.ticks();

for (let cnt = end.toFixed().length; ticks.length > 15; cnt--) {
ticks = scale.ticks(cnt);
ticks = s.ticks(cnt);
}

ticks[0] !== head && ticks.unshift(head);
ticks[ticks.length - 1] !== tail && ticks.push(tail);
ticks.splice(0, 1, start);
ticks.splice(ticks.length - 1, 1, end);
} else {
ticks = scale
.ticks(...(this.config.tickArguments || []));
}

ticks = ticks
Expand Down
2 changes: 1 addition & 1 deletion src/ChartInternal/internals/domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export default {
isAllNegative && (padding.top = -yDomainMax);
}

const domain = isLog ? [yDomainMin, yDomainMax].map(v => (v <= 0 ? 1 : v)) :
const domain = isLog ? [yDomainMin, yDomainMax].map(v => (v < 0 ? 0 : v)) :
[yDomainMin - padding.bottom, yDomainMax + padding.top];

return isInverted ? domain.reverse() : domain;
Expand Down
8 changes: 5 additions & 3 deletions src/ChartInternal/internals/scale.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
import {
scaleTime as d3ScaleTime,
scaleLinear as d3ScaleLinear,
scaleLog as d3ScaleLog
scaleLog as d3ScaleLog,
scaleSymlog as d3ScaleSymlog
} from "d3-scale";
import {isString, isValue, parseDate} from "../../module/util";

Expand All @@ -20,12 +21,13 @@ import {isString, isValue, parseDate} from "../../module/util";
export function getScale(type = "linear", min = 0, max = 1): any {
const scale = ({
linear: d3ScaleLinear,
log: d3ScaleLog,
log: d3ScaleSymlog,
_log: d3ScaleLog,
time: d3ScaleTime
})[type]();

scale.type = type;
type === "log" && scale.clamp(true);
/_?log/.test(type) && scale.clamp(true);

return scale.range([min, max]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/config/Options/axis/x.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export default {
* **NOTE:**<br>
* - **log** type:
* - the x values specified by [`data.x`](#.data%25E2%2580%25A4x)(or by any equivalent option), must be exclusively-positive.
* - x axis min value should be > 0, otherwise will be set `1`.
* - x axis min value should be >= 0.
*
* @name axis鈥鈥ype
* @memberof Options
Expand Down
2 changes: 1 addition & 1 deletion src/config/Options/axis/y.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default {
* **NOTE:**<br>
* - **log** type:
* - the bound data values must be exclusively-positive.
* - y axis min value should be > 0, otherwise will be set `1`.
* - y axis min value should be >= 0.
* - [`data.groups`](#.data%25E2%2580%25A4groups)(stacked data) option aren't supported.
*
* @name axis鈥鈥ype
Expand Down
2 changes: 1 addition & 1 deletion src/config/Options/axis/y2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default {
* **NOTE:**<br>
* - **log** type:
* - the bound data values must be exclusively-positive.
* - y2 axis min value should be > 0, otherwise will be set `1`.
* - y2 axis min value should be >= 0.
* - [`data.groups`](#.data%25E2%2580%25A4groups)(stacked data) option aren't supported.
*
* @name axis鈥2鈥ype
Expand Down
2 changes: 1 addition & 1 deletion test/internals/axis-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2521,7 +2521,7 @@ describe("AXIS", function() {
show: true,
type: "log"
}
}
}
}
});

Expand Down
8 changes: 4 additions & 4 deletions types/axis.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ export interface xAxisConfiguration extends AxisConfigurationBase {
* NOTE:
* log type:
* - the x values specified by `data.x`(or by any equivalent option), must be exclusively-positive.
* - x axis min value should be > 0, otherwise will be set `1`.
* - x axis min value should be >= 0.
*/
type?: "timeseries" | "category" | "indexed" | "log";
type?: "category" | "indexed" | "log" | "timeseries";

/**
* Set how to treat the timezone of x values.
Expand Down Expand Up @@ -182,10 +182,10 @@ export interface yAxisConfiguration extends yAxisConfigurationBase {
* NOTE:
* log type:
* - the bound data values must be exclusively-positive.
* - y axis min value should be > 0, otherwise will be set `1`.
* - y axis min value should be >= 0.
* - `data.groups`(stacked data) option aren't supported.
*/
type?: "timeseries" | "category" | "indexed" | "log";
type?: "indexed" | "log" | "timeseries";

/**
* Set clip-path attribute for y axis element.
Expand Down

0 comments on commit ca6cf62

Please sign in to comment.