zoukankan      html  css  js  c++  java
  • [原创][开源] SunnyUI.Net 开发日志:UIBarChart 坐标轴刻度取值算法

    SunnyUI.Net, 基于 C# .Net WinForm 开源控件库、工具类库、扩展类库、多页面开发框架

    UIBarChart 坐标轴刻度取值算法

        在开发UIBarChart的过程中,需要绘制Y轴的刻度,数据作图时,纵横坐标轴刻度范围及刻度值的取法,很大程度上取决于数据的分布。对某一组数据,我们很容易就能知道如何选取这些值才能使图画得漂亮。但是要想找到一个通用的算法,用以对任意分布的数据决定这些值,并不是一件容易的事。

        在网络上找到几篇算法,选取了其中一篇C#语法的,纪录之。

    坐标轴刻度取值算法

    地址:https://blog.csdn.net/lweiyue/article/details/91869984

    作者:

    下载:https://download.csdn.net/download/lweiyue/11239639

        我们在用代码绘制图表的时候,需要绘制坐标轴,而坐标轴上是有刻度的。假如数据最小值是0.32,最大值是0.65,我们想坐标轴上有11个刻度左右,那是不是每个刻度的间隔就是(0.65-0.32)/10=0.033呢?这样做出来的刻度是这样的:

    0.32 0.353 0.386 0.419 0.452 0.485 0.518 0.551 0.584 0.617 0.65

        Oh my god! 这样的刻度实在太奇怪了。还是这样的刻度比较正常一点呢:

    0.3 0.325 0.35 0.375 0.4 0.425 0.45 0.475 0.5 0.525 0.55 0.575 0.6 0.625 0.65

        我们现在就来看看下面这种刻度是怎么生成的。首先举几个例子:

        0, 10, 15个刻度

    0 0.5 1 1.5 2 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7 7.5 8 8.5 9 9.5 10

        -2.4, -0.023, 15个刻度

    -2.4 -2.2 -2 -1.8 -1.6 -1.4 -1.2 -1 -0.8 -0.6 -0.4 -0.2 0 

        我们这个算法有以下要求:

    (1)输入希望大概有多少个刻度。

    (2)最终的刻度数只是接近期望,不一定相同。

    1、求出实际间隔

    double differ = end - start;
    double differ_gap = differ / (expect_num - 1);
    

    这很简单,differ_gap就是实际的刻度间隔。但一般情况下,我们需要把刻度转成10,20,25,50这样的值才会看起来比较自然。

    2、求出一个转化指数

    我们希望的值(10,20,25,50)都是在10-100之间的,但我们的differ_gap可能是0.2,0.025,5000,我们需要把differ_gap转成step*10^_exponent这样的形式,其中step是10-100之间的数。

    double exponent = Math.Log10(differ_gap) - 1;
    int _exponent = (int)exponent;
    if (exponent < 0 && Math.Abs(exponent) > 1e-8)//处理负指数
    {
        _exponent--;
    }
    

    3、得到10-100之间的数

    很简单,就一行代码。

    int step = (int)(differ_gap / Math.Pow(10, _exponent));
    

    到这一步,假如原来的间隔是0.065,那step就是65了。但65还不是我们想要的,我们想要的是跟它接近的50。

    4、转到标准间隔

    标准间隔就是我们上面提到的10,20,25,50,100,下面的代码进行转化:

    int[] fix_steps = new int[] { 10, 20, 25, 50, 100 };
    int fix_step = 10;
    for (int i = fix_steps.Length - 1; i >= 1; i--)
    {
        if (step > (fix_steps[i] + fix_steps[i - 1]) / 2)
        {
            fix_step = fix_steps[i];
            break;
        }
    }
    

    我们这里求出的是一个最接近的间隔,例如16,介于10跟20之间,跟20最接近,就用20。也因为这个原因,最终的刻度数只是接近期望的刻度数。

    5、求出实际的刻度

    也很简单,就一行代码。

    degree_gap = fix_step * Math.Pow(10, _exponent);

    假如最初的间隔是0.065,那现在的degree_gap就变成了我们想要的0.05了。

    6、求出新的最小值和最大值

    一般情况下,最小值最大值都是刻度的整数倍,而且最小值小于或等于原来的最小值,最大值大于或等于原来的最大值。通过下面的代码,我们得到了新的最小值degree_start和新的最大值degree_end。

    double start1 = start / degree_gap;
    int start2 = (int)start1;
    if (start1 < 0 && Math.Abs(start1 - start2) > 1e-8)
    {
        start2--;
    }
    degree_start = start2;
     
    double end1 = end / degree_gap;
    int end2 = (int)end1;
    if (end1 >= 0 && Math.Abs(end1 - end2) > 1e-8)
    {
        end2++;
    }
    degree_end = end2;
    

    完整代码下载

    原创文章,转载请保留链接 Sunny's blog

  • 相关阅读:
    nginx-1.8.1的安装
    ElasticSearch 在3节点集群的启动
    The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files
    sqoop导入导出对mysql再带数据库test能跑通用户自己建立的数据库则不行
    LeetCode 501. Find Mode in Binary Search Tree (找到二叉搜索树的众数)
    LeetCode 437. Path Sum III (路径之和之三)
    LeetCode 404. Sum of Left Leaves (左子叶之和)
    LeetCode 257. Binary Tree Paths (二叉树路径)
    LeetCode Questions List (LeetCode 问题列表)- Java Solutions
    LeetCode 561. Array Partition I (数组分隔之一)
  • 原文地址:https://www.cnblogs.com/yhuse/p/13121869.html
Copyright © 2011-2022 走看看