[原创][开源] 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、求出实际间隔
1 2 | 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之间的数。
1 2 3 4 5 6 | double exponent = Math.Log10(differ_gap) - 1; int _exponent = ( int )exponent; if (exponent < 0 && Math.Abs(exponent) > 1e-8) //处理负指数 { _exponent--; } |
3、得到10-100之间的数
很简单,就一行代码。
1 | int step = ( int )(differ_gap / Math.Pow(10, _exponent)); |
到这一步,假如原来的间隔是0.065,那step就是65了。但65还不是我们想要的,我们想要的是跟它接近的50。
4、转到标准间隔
标准间隔就是我们上面提到的10,20,25,50,100,下面的代码进行转化:
1 2 3 4 5 6 7 8 9 10 | 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。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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; |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现