[原創][開源] 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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章