Highcharts - 使用负值将零保持在 Y 轴中心

问题描述 投票:0回答:7

我有一个带有负值的面积图。与 他们给出的示例 没有什么不同,但有一个变化:我想将零保持在 Y 轴中心。

我知道这可以通过将

yAxis.max
设置为某个值 n 并将
yAxis.min
设置为 −n 来实现,其中 n 代表图表峰值或谷值的绝对值,以更大(如这个小提琴)。然而,我的数据是动态的,所以我不提前知道 n 需要是什么。

我对 Highcharts 比较陌生,所以我可能缺少一种通过配置来完成此操作并让 Highcharts 为我处理的方法,但看起来我需要使用 Javascript 手动调整 y 轴当页面加载时以及新数据进入时我自己。

是否有一种简单的、配置驱动的方法来保持零位于 Y 轴中心?

highcharts
7个回答
24
投票

在深入研究 Highcharts API 后,我最终找到了一种通过配置来实现此目的的方法。每个轴都有一个名为

tickPositioner
的配置选项,您可以为其提供一个返回数组的函数。该数组包含您希望在轴上显示刻度的确切值。这是我的新
tickPositioner
配置,它在 Y 轴上放置了五个刻度,零整齐地位于中间,最大值位于两个极端:

yAxis: {

    tickPositioner: function () {

        var maxDeviation = Math.ceil(Math.max(Math.abs(this.dataMax), Math.abs(this.dataMin)));
        var halfMaxDeviation = Math.ceil(maxDeviation / 2);

        return [-maxDeviation, -halfMaxDeviation, 0, halfMaxDeviation, maxDeviation];
    },

    ...
}

4
投票

我知道这是一篇旧帖子,但我想我无论如何都会发布我的解决方案(这是受到上面接受的答案中建议的一个 macserv 的启发),因为它可能会帮助其他正在寻找类似解决方案的人:

tickPositioner: function (min, max) {
            var maxDeviation = Math.ceil(Math.max(Math.abs(this.dataMax), Math.abs(this.dataMin)));
            return this.getLinearTickPositions(this.tickInterval, -maxDeviation, maxDeviation);
        }

1
投票

您可以使用 getExtremes 和 setExtremes 方法来完成此操作

示例:

http://jsfiddle.net/jlbriggs/j3NTM/1/

var ext = chart.yAxis[0].getExtremes();

1
投票

这是我的解决方案。这样做的好处是您可以保持

tickInterval

  tickPositioner(min, max) {
    let { tickPositions, tickInterval } = this;
    tickPositions = _.map(tickPositions, (tickPos) => Math.abs(tickPos));
    tickPositions = tickPositions.sort((a, b) => (b - a));

    const maxTickPosition = _.first(tickPositions);
    let minTickPosition = maxTickPosition * -1;

    let newTickPositions = [];
    while (minTickPosition <= maxTickPosition) {
      newTickPositions.push(minTickPosition);
      minTickPosition += tickInterval;
    }

    return newTickPositions;
  }

0
投票

以防万一有人正在寻找,

多一个选择。我最终也遇到了类似的情况。按照我的解决方案:

tickPositioner: function () {
    var dataMin,
    dataMax = this.dataMax;
    var positivePositions = [], negativePositions = [];

    if(this.dataMin<0) dataMin = this.dataMin*-1;
    if(this.dataMax<0) dataMax = this.dataMax*-1;

    for (var i = 0; i <= (dataMin)+10; i+=10) {
        negativePositions.push(i*-1)
    }

    negativePositions.reverse().pop();

    for (var i = 0; i <= (dataMax)+10; i+=10) {
        positivePositions.push(i)
    }

    return negativePositions.concat(positivePositions);

},

http://jsfiddle.net/j3NTM/21/


0
投票

这是一个老问题,但最近我遇到了同样的问题,这是我的解决方案,可能会被推广:

const TICK_PRECISION = 2;
const AXIS_MAX_EXPAND_RATE = 1.2;

function setAxisTicks(axis, tickCount) {
    // first you calc the max from the data, then multiply with 1.1 or 1.2 
    // which can expand the max a little, in order to leave some space from the bottom/top to the max value. 
    // toPrecision decide the significant number.
    let maxDeviation = (Math.max(Math.abs(axis.dataMax), Math.abs(axis.dataMin)) * AXIS_MAX_EXPAND_RATE).toPrecision(TICK_PRECISION);

    // in case it is not a whole number
    let wholeMaxDeviation = maxDeviation * 10 ** TICK_PRECISION;

    // halfCount will be the tick counts on each side of 0
    let halfCount = Math.floor(tickCount / 2);

    // look for the nearest larger number which can mod the halfCount
    while (wholeMaxDeviation % halfCount != 0) {
        wholeMaxDeviation++;
    }

    // calc the unit tick amount, remember to divide by the precision
    let unitTick = (wholeMaxDeviation / halfCount) / 10 ** TICK_PRECISION;

    // finally get all ticks
    let tickPositions = [];
    for (let i = -halfCount; i <= halfCount; i++) {
        // there are problems with the precision when multiply a float, make sure no anything like 1.6666666667 in your result
        let tick = parseFloat((unitTick * i).toFixed(TICK_PRECISION));
        tickPositions.push(tick);
    }
    return tickPositions;
}

因此,在您的图表轴刻度定位器中,您可以添加:

tickPositioner: function () {
    return setAxisTicks(this, 7);
},

0
投票

到目前为止,这已经足够了:

yAxis: {
  crossing: 0
}

如果您最终想要像 xy 图表之类的东西并且希望轴对称...受到上面答案的启发,但尽可能利用 highcharts 内部计算(如tickInterval))

xAxis & yAxis: {
  crossing: 0,
  startOnTick: true,
  endOnTick: true,
  tickPositioner: function () {
    // @ts-ignore
    const maxDeviation = Math.ceil(Math.max(Math.abs(this.dataMax), Math.abs(this.dataMin)))
    // @ts-ignore
    return this.getLinearTickPositions(this.tickInterval, -maxDeviation, maxDeviation)
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.