图表y轴的数据处理方案

问题

笔者最近在作图表需求,遇到一个这样的问题,图表的y轴数据处理得不够好看,以下:javascript

图表的数据为1005,1988,2500,3902,5530,很显然这个处理数据的结果不尽人意。java

方案

既然有这个问题,那么就须要一个新的处理方案,平时咱们在使用Excel等工具制做的折线图,会发现上面的数据实际上是处理过的了,以下: 工具

对比可知,为了让图表的数据规整,须要保证间隔的规整,如50,500等数字的倍数,其次是肯定起点,只要肯定好起点,经过间隔的累加便可。因此,对于这个方案有两个须要处理的,那就是肯定起点min和找间隔interval。

制定需求

对于笔者而言,需求不只包含数据的规整,还有小数位数的格式化,其中涉及到单位的转换,如初始值给了10345,21200,29001,y轴格式化为1.0万,2.0万,3.0万,那么须要对小数位数作处理,使得最后结果为1万,2万,3万。因此对于笔者而言,找出间隔以后,还须要对最终结果的小数位数作去0操做。ui

步骤

1. 初始值

首先,须要找出数据集的最小值min,最大值max,这里笔者给出的数据为min = 47769543,max = 54961473,最多须要保留的小数位数decimal=1。还包含如下须要用到的方法:this

方法名 做用
formatDataByRanges 对数据进行单位转换处理,如47769534作“万”处理则为 4776.9534

2. 计算过程

  1. 肯定起点
    首先计算range = max - min = 7191930,接着对range进行formatDataByRanges处理为719.1930,而后originInterval = range/4 = 179.798,这时候的originInterval就是没有处理过的间距值,接下来就是经过range找出规整的间距interval,首先经过range产生一组规整间距值为1000 500 200 100, 产生的伪代码以下:
export function genIntervalList(originInterval: number) {
    let base = genPowNum(originInterval)
    return [10 * base, 5 * base, 2 * base, base]
}

// 获取数字的十的幂次方的位数
// 如 90 则为 1
 // 如 0.01则为 -2
function getPowBit(number) {
    return Math.floor(Math.log10(data))
}  

/** * 生成十的幂次方 * @param data */
export function genPowNum(data: number) {
    let bit = getPowBit(data)
    return Math.pow(10, bit)
}

复制代码

接着从第二个数开始遍历1000 500 200 100, 当找到大于originInterval的数时则中止,获取当前点的上一个数为咱们所需的interval,如179.798 > 100, 那么interval就为200。而后经过interval对min作处理,固然这里的min也通过处理为4776.9543,处理过程以下:spa

function handleMin(min, interval) {
    if(min < interval) {
        return 0
    } else {
         let baseNum = genPowNum(interval) * 10
       // 去掉最小值不须要比较的位数 
       // 如min为4776.9543 interval为200 那么formatMin = 4000
       // 如min为0.073 interval为0.005 那么formatMin = 0.07
         let formatMin = Math.floor(min / baseNum) * baseNum
         let minRange = min - formatMin
         
          // 找出适合的interval 这里为500
        // 因此最后的min = 4000 + 500 = 4500
         return formatMin + this.findMinInterval(minRange, interval)
    }
}

  function findMinInterval(minRange: number, interval: number) {
        let factorList = genIntervalList(interval)
        for (let i = 1; i < factorList.length; i++) {
            if (minRange >= factorList[i]) {
                return factorList[i]
            }
        }
        return 0
    }
复制代码

通过上述的处理,可得最小值为4500code

  1. 找间距
    因为通过步骤1肯定了min,min已经改变了,因此range须要从新计算,interval也须要从新计算。计算方式参考步骤1的找间距,计算可得interval为500。orm

  2. 最终计算
    通过步骤1,2能够获得min和interval,若是此时min< interval,那么须要令min = 0,而后从新执行步骤2。这样就能够获得最后的min,interval,接着须要计算最后须要保留的小数位数,以下:cdn

function getDecimal(interval, min) {
   if(interval < 1) {
       return  Math.abs(getPowBit(interval))
   } else {
       // 若是间距的range和max相等 则不须要保留小数位数
       // 如interval是1500万 max是4000万 range都为万 不须要保留小数
       if(interval.range = max.range) {
           return 0
       } else {
             // 当range不相等的状况 可知min必定大于formatInterval
             // 如min为121.1万 interval为2000 这时候对2000作range的处理
             // 则可获得最大须要保留的位数
           return Math.abs(getPowBit(formatInterval / formatMinData.range))
       }
   }
}
复制代码
  1. 最后结果
    最后可得y轴的数据为4500万 5000万 5500万 6000万 6500万

总结

对于这个方案,在于肯定min和interval,对于interval而言,则能够本身灵活定义规整的间距,如520取的是550,而不是1000,这样的好处是可让图表的走势更加明显。blog

相关文章
相关标签/搜索