摘自:http://www.cnblogs.com/pengcl/p/3278388.html
由于工作原因,需要画图表,但在图表的该度的取值上就出现了问题,但现在关于图表的控件已经很多了,那应该也有成熟的算法了,经过在网上努力寻找前人们是足迹,算给我找到了这编文章,问题总算解决了!!!---故记。
(1)步长规范化是关键
一般地,我们在标定坐标轴时,给出的参数是:起点、终点和刻度数,因为我们程序设计人员对在一个多大的区域面积内绘制多少个刻度比较美观有直观感觉,相反,而对多大步长则印象较浅。当然,知道刻度数和起点与终点值求步长是很容易的,如下式:
CorStep=(CorMax-CorMin)/CorNumber
式中,CorMax、CorMin、CorNumber分别对应起点、终点和刻度数。步长求出后。我们只要将步长求以lO为底的对数,即可获得步长的数量级,见下式:
Temp=Log(corStep)/Log(10)
或者
Temp=Log(CorStep)/Log(10)+1
式中,Log代表自然对数。至于取哪个公式,需要根据CorStep是否是lO的整数次幂而定。
进而将步长其规范化到0到1的范围内,方法如下:
NewCopStep=CorStep/(10^Temp)
式中,符号“^”代表取幂的意思。
然后根据新的步长取值范围,将新的取值定位在:0.1、O.2、0.25、0.5、1几个常规步长上,称为StardardStep.最后,再根据数量级将规范的步长恢复到本来的数量级上,见下式:
FinalStep=StardardStp*Temp
(2)起点的规范化
一般说来.我们的起点应该是小于等于原来的起点,同时,起点坐标是步长的整数倍比较符合人们的习惯。这一点容易做到,见下式:
NewCorMin=(Int(CorMin/FinalStep))*FinalStep
其中,Int是取整函数。
(3)终点的规范化
按惯例,我们的终点应该是大于等于原来的终点,同样,终点坐标是步长的整数倍比较符合人们的习惯,见下式:
NewCorMax=(Int(CorMax/FinalStep)+1)+FinalStep
其中,Int是取整函数。
(4)最后的修正我们按上面的公式确定完参数后,新确定的步长、起点、终点值有可能使得刻度数与原来刻度数不等。这里是否需要调整呢?如果需要,我们应该如何调整呢?笔者认为,如果新算得的刻度数大于等于原来设定的刻度数,就不应该调整了。如果新算得的刻度数小于原来设定的刻度数,就应该将其调整为原来的刻度数。同时,在步长不动的情况下,分别将起点与终点进行再次修正。
下面是对应的程序:
注:源文为VB代码,由于工作需要,转为javascript代码。
function standard(cormax,cormin,cornumber){
var tmpmax,tmpmin, corstep,tmpstep,tmpnumber,temp,extranumber;
if(cormax<=cormin)
return ;
corstep=(cormax-cormin)/cornumber;
if(Math.pow(10,parseInt(Math.log(corstep)/Math.log(10)))==corstep){
temp = Math.pow(10,parseInt(Math.log(corstep)/Math.log(10)));
}else{
temp = Math.pow(10,(parseInt(Math.log(corstep)/Math.log(10))+1));
}
tmpstep = (corstep/temp).toFixed(6);
//选取规范步长
if(tmpstep>=0&&tmpstep<=0.1){
tmpstep = 0.1;
}else if(tmpstep>=0.100001&&tmpstep<=0.2){
tmpstep = 0.2;
}else if(tmpstep>=0.200001&&tmpstep<=0.25){
tmpstep = 0.25;
}else if(tmpstep>=0.250001&&tmpstep<=0.5){
tmpstep = 0.5
}else{
tmpstep = 1;
}
tmpstep = tmpstep * temp;
if(parseInt(cormin/tmpstep)!=(cormin/tmpstep)){
if(cormin<0){
cormin = (-1) * Math.ceil(Math.abs(cormin/tmpstep))*tmpstep;
}else{
cormin = parseInt(Math.abs(cormin/tmpstep))*tmpstep;
}
}
if(parseInt(cormax/tmpstep)!=(cormax/tmpstep)){
cormax = parseInt(cormax/tmpstep+1)*tmpstep;
}
tmpnumber = (cormax-cormin)/tmpstep;
if(tmpnumber<cornumber){
extranumber = cornumber - tmpnumber;
tmpnumber = cornumber;
if(extranumber%2 == 0){
cormax = cormax + tmpstep*parseInt(extranumber/2);
}else{
cormax = cormax + tmpstep*parseInt(extranumber/2+1);
}
cormin = cormin - tmpstep*parseInt(extranumber/2);
}
cornumber = tmpnumber;
return [cormax,cormin,cornumber];
}
---------------文章摘抄于《坐标轴刻度的规范化标定处理》
转自:http://blog.sciencenet.cn/blog-548663-710759.html
数据作图时,纵横坐标轴刻度范围及刻度值的取法,很大程度上取决于数据的分布。对某一组数据,我们很容易就能知道如何选取这些值才能使图画得漂亮。但是要想找到一个通用的算法,用以对任意分布的数据决定这些值,并不是一件容易的事。下面是我在网上找到的一些作法,权作备份。
● 一篇论文,提出了一种稍嫌复杂,但效果很好的方法,并与目前常用的几种方法作了对比。学院派的典型解决模式:
An Extension of Wilkinson’s Algorithm for Positioning Tick Labels on Axes
http://vis.stanford.edu/papers/tick-labels
● 最早或许也是最简单的一种解决方法。工程师的解决模式,源码:
Heckbert算法,Graphics Gems 1
http://tog.acm.org/resources/GraphicsGems/gems/Label.c
● 中国程序员的解决方案:
求算法:图表控件,如何确定坐标轴的范围和刻度?
http://bbs.csdn.net/topics/340165746
http://yun.baidu.com/xcloud/csdn/pan/share/link?shareid=2328597457&uk=1127608729