美文网首页
图表刻度算法

图表刻度算法

作者: 紫阚 | 来源:发表于2017-02-15 18:23 被阅读158次
    背景

    绘制柱状图、折线图的时候,需要根据数据,动态生成刻度的区间

    需求

    刻度美观、数据最大的柱状图落在顶部的区间,刻度的数量是固定的。

    根据数据渲染刻度
    结果预览

    固定5个刻度区间,数据最大值与刻度之间的偏移对比如下

    输入 每块偏移 第1段 第2段 第3段 第4段 第5段
    4 1 1 2 3 4 5
    27 6 6 12 18 24 30
    174 35 35 70 105 140 175
    13500 3000 3000 6000 9000 12000 15000
    思路

    区间之间的偏移量,为了美观,定义如下

    单位数偏移量1~9,参考图表4、27输入
    两位数开始:偏移量第二位是5的倍数,第二位以后0,如10、15、20...95 ;三位数100、150、200...950,参考图表174、13500输入

    实现算法

    核心就是根据最大值/区间得出偏移量,再循环从美观的偏移量里面找到离该值最近的一个大偏移量。
    代码是基于java,但是对平台的依赖很少,很容易改改就移植到ios、.net上

    
     /**
         * 根据位数创建第一个为1的数字
         * <p>
         * 2700 =>1000
         *
         * @param delta
         * @return
         */
        public static int refreshNumber(double delta) {
            int i = 1;
    
            while (delta >= 10) {
                delta /= 10;
                i *= 10;
            }
            return i;
        }
    
    
        /**
         * 获取刻度的区间
         *
         * @param rangeCount 一共几个刻度从底部0开始算,比如0,20,40,60,80,100算6个,之所以不算5个是为了兼容后续的优化
         * @param maxValue   最大值
         * @return
         */
        public static List<Integer> getChartRange(int rangeCount, double maxValue) {
            int resultDelta = 0;
            boolean isFound = false;
    
            double delta = maxValue / (rangeCount - 1);
            if (delta == 0) delta = 1;
    
            //从1开始,跳过重复计算,比如delta是2700,则shift从1000开始
            int shift = refreshNumber(delta);
    
            while (true) {
                //个位数从1~9
                //从10位开始,从10~95 以此类推100~950
                for (float i = 0; i < 10; i += 0.5f) {
                    //个位数时9.5会强转成9,相当于9计算了两次,因此不会产生浮点刻度的问题
                    resultDelta = (int) (i * shift);
    
                    //找到离自己最大的一个推荐刻度
                    if (delta <= resultDelta) {
                        isFound = true;
                        break;
                    }
                }
                if (isFound) break;
    
                shift *= 10;
            }
            List<Integer> list = new ArrayList<>(rangeCount);
    
            for (int i = 0; i < rangeCount; i++) {
                list.add(i * resultDelta);
            }
            return list;
        }
    

    后续优化

    1. 对浮点型支持,这个很好做,主要是把shift改成0.1f就好了。
    2. 对于差异比较小的大数据进行对比,比如一组数据:331000,331100,331200;这个如果从0开始算的话,视觉上差异很小,这个时候如果换成从331000开始计算,这样对比差异就很直观。方法里我预留了第0个的位置的初衷就是如此。

    相关文章

      网友评论

          本文标题:图表刻度算法

          本文链接:https://www.haomeiwen.com/subject/yiwqwttx.html