坐标轴刻度取值算法

您所在的位置:网站首页 坐标值怎么算坐标 坐标轴刻度取值算法

坐标轴刻度取值算法

2024-04-22 06:58| 来源: 网络整理| 查看: 265

本文链接:https://blog.csdn.net/qq_26909801/article/details/96966372数值型坐标轴刻度计算算法前言算法描述上代码代码运行效果结语前言因实习的公司是做大数据的,而我的工作刚好又是需要绘制一些数据图表的。绘制图表有许多现成的组件可以使用,但是要想达到产品所需要的效果,只靠组件内部的一些功能是不太够的。一些细腻的要求必须在掌握组件原理方法的情况下,自己去写算法来完成。例如,本文要说的这个刻度计算算法,开始正文之前,我先描述遇到的问题。echarts自身的刻度计算有时候并不好用,例如有时候你希望让图表只有5条刻度线,即分成4段,echarts提供了一个参数叫splitNumber,把splitNumber设为4可以让图表尽量地分成4段,然而当数据波动较大时,echarts会自动增加分割的段数,即即使大部分数据都能正常分出4段刻度,但仍有少部分数据实际分出的段数可能不止4段。如下面这样:

因此我们得出一个结论,echarts的splitNumber只是预估的分割段数。如果我们需要强制把刻度区间分为4段,则需要我们自己去写算法计算刻度。另外,即使段数正确的情况下,echarts自动计算出的刻度也可能存在区间过大,数据差异不明显的情况,如下面的图片,因为刻度区间太大,导致各个数据看起来像是差不多大的,看不出差异:

另外,echarts自动计算出的刻度也有一些其他的问题,例如当图表在柱状图和堆叠图中切换时,堆叠图可能出现刻度溢出问题。不过堆叠图的刻度计算这里就先不说明了,下面开始正文吧。

算法描述刻度计算的算法之前我之前也写了一版,解决了分割段数的问题,但是仍无法解决刻度区间过大的问题。之前那一版算法的主要思想是取近似值,分别取最大值和最小值的最小近似整值得到刻度,虽然不是最优的算法,但是在构思和调整算法的时候我也学到了不少东西,而这一版的算法是在我们技术老大的点拨下结合网上的一些文章和项目的需求而写出来的,算法如下:

要求: 根据一组数的最大值、最小值来确定刻度值,确定刻度的最大值maxi、最小值mini和刻度间隔interval。当出现异号数据时可选择正负两边刻度是否需要对称,当存在异号数据时要求其中一条刻度分割线必须在0刻度上,可以选择是否允许段数误差。

确定分割段数splitNumber和魔数数组magic = [10,15,20,25,30,40,50,60,70,80,90,100];从目标数组arr中算出最大值max和最小值min,确定初始间隔大小 tempGap = (max-min)/splitNumber;设tempGap除以一个倍数multiple后,刚好处于魔数数组的区间[10,100]中,记录倍数multiple;从魔数数组中取出第一个大于tempGap缩放值的魔数,用 魔数*multiple当做理想刻度间隔(estep)进行第一次计算,计算出max和min的邻近刻度maxi和mini,如果允许分割段数误差,则直接结束运算,取interval=estep;当刻度需要正负两边对称且存在异号数据时,取maxi和mini中绝对值大的一方,将其相反数赋值给另外一方,计算interval=(maxi-mini)/splitNumber,结束运算;当正负刻度不需要对称或不存在异号数据时,判断实际分割段数是否等于splitNumber,如果不相等,则重新取较大的魔数进行运算,当魔数取完或者分割段数相等时结束运算,得出interval=(maxi-mini)/splitNumber.上代码算法采用javascript语言描述,因为图表的绘制在前端完成。

/* 刻度计算算法,基于魔术数组 [10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100]; 解释:魔数数组是理想间隔数组,即我们希望每个刻度的间隔都是魔数数组中某个数的整数倍。(准确的来说是整10倍) */ //新增,解决js的浮点数存在精度问题,在计算出最后结果时可以四舍五入一次,因为刻度太小也没有意义,所以这里忽略设置精度为8位 function fixedNum(num){ if((""+num).indexOf('.')>=0) num = parseFloat(num.toFixed(8)); return num; } //1.初始化 var symmetrical = false;//是否要求正负刻度对称。默认为false,需要时请设置为true var deviation = false;//是否允许误差,即实际分出的段数不等于splitNumber var magic = [10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100];//魔数数组经过扩充,放宽魔数限制避免出现取不到魔数的情况。 var arr = [1230, 320, 20, 304, 102, 234];//测试数据 var max,min,splitNumber; splitNumber = 4;//理想的刻度间隔段数,即希望刻度区间有多少段 max = Math.max.apply(null,arr);//调用js已有函数计算出最大值 min = Math.min.apply(null,arr);//计算出最小值 //2.计算出初始间隔tempGap和缩放比例multiple var tempGap = (max - min) / splitNumber;//初始刻度间隔的大小。 //设tempGap除以multiple后刚刚处于魔数区间内,先求multiple的幂10指数,例如当tempGap为120,想要把tempGap映射到魔数数组(即处理为10到100之间的数),则倍数为10,即10的1次方。 var multiple = Math.floor(Math.log10(tempGap)-1);//这里使用Math.floor的原因是,当Math.log10(tempGap)-1无论是正负数都需要向下取整。不能使用parseInt或其他取整逻辑代替。 multiple = Math.pow(10,multiple);//刚才是求出指数,这里求出multiple的实际值。分开两行代码避免有人看不懂 //3.取出邻近较大的魔数执行第一次计算 var tempStep = tempGap / multiple;//映射后的间隔大小 var estep;//期望得到的间隔 var lastIndex = -1;//记录上一次取到的魔数下标,避免出现死循环 for(var i = 0; i < magic.length;i++){ if(magic[i]>tempStep){ estep = magic[i]*multiple;//取出第一个大于tempStep的魔数,并乘以multiple作为期望得到的最佳间隔 break; } } //4.求出期望的最大刻度和最小刻度,为estep的整数倍 var maxi,mini; function countDegree(estep){ //这里的parseInt是我无意中写出来的,本来我是想对maxi使用Math.floor,对mini使用Math.ceil的。这样能向下取到邻近的一格,不过后面发现用parseInt好像画出来图的比较好看 maxi = parseInt(max/estep+1) * estep;//最终效果是当max/estep属于(-1,Infinity)区间时,向上取1格,否则取2格。 mini = parseInt(min/estep-1) * estep;//当min/estep属于(-Infinity,1)区间时,向下取1格,否则取2格。 //如果max和min刚好在刻度线的话,则按照上面的逻辑会向上或向下多取一格 if(max===0) maxi = 0;//这里进行了一次矫正,优先取到0刻度 if(min===0) mini = 0; if(symmetrical&&maxi*mini0){ outter:do{ //计算模拟的实际分段数 var tempSplitNumber = Math.round((maxi-mini)/estep); //当趋势单调性发生变化时可能出现死循环,需要进行校正 if((i-lastIndex)*(tempSplitNumber-splitNumber)


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3