应用场景(以Echarts柱状图为例):
现有一组数据:最小的数是 50000(5万)
,最大的数是 3000000000(30亿)
。
如果按照Echarts正常的画法,我们只需提取出来这些数据然后交给Echarts显示即可。
- 但是这样做面临的问题就很明显——由于数值差距过大,且Echarts本身Y轴的数值是均匀分布的,所以在图里造成的结果是这样的:
在图中,y 轴的数值均匀分布,最高的柱子在x轴 第五
值为30亿,但是x轴 第一
值为5万的柱子,根本看不见,因为差距太大了,包括x轴 第二
值为500万的轴,我们也是只能看到一点点红色。
为了要显示出来小一点的值,我们期望的 y 轴排列应该是这样的:
0 10万 100万 1千万 1亿 10亿 20亿 30亿
这样的数值分布规则就完美符合我们的要求。
所以,我们要做的就是打破 y 轴均匀显示的规则(本质上并没有)。
打破规则
思想
针对这种数值大的数据,我们不免会怀念小数值的好处:
- 比如把上面的数据都更换成小于等于100的数,那么显示起来就毫无问题了,即便数值只有10,但是在最大值是100的图里,也能正常显示。
所以,打破规则用到的思想就是缩小数据体量
:
- 上图中,Echarts本身处理的数据间隔是 5亿,这样分跟我们
x轴
的设置也有关系,x 轴一共 5 个分部,给的数值里最大30亿,所以分布在y 轴
上以 5亿 为间隔刚刚好。 - 如果最大值是 100,那么就会以20为间隔。
那么,我们能不能把上面数据里上亿的数值按照一定的规则让其变成 很小的数据来在图里展示呢?
答案是可以的。
方法
这里可以算是对我在Echarts Gallery 上发布的一个不均匀数据轴图表代码的讲解了。
直达连接:投资计划——不均匀数据轴(y)
首先我们看一组数据:
// 数据源
const sourceData = [{
date: '2020-01-01',
amount: 1000000
},
{
date: '2020-02-01',
amount: 100000
},
{
date: '2020-03-01',
amount: 200000
},
{
date: '2020-04-01',
amount: 50000 // 很小的数值
},
{
date: '2020-05-01',
amount: 20000000
},
{
date: '2020-06-01',
amount: 300000000
},
{
date: '2020-07-01',
amount: 400000
},
{
date: '2020-08-01',
amount: 3000000000 // 很大的数值
},
{
date: '2020-09-01',
amount: 550000
},
];
这一组数据里,最大值是 30亿 最小值是 5万。我们怎么处理数据呢?
-
第一步:设置数据间隔。
// 间隔(0——30亿) // 0 10万 100万 1千万 1亿 10亿 20亿 30亿 const dataInterval = [0, 100000, 1000000, 10000000, 100000000, 1000000000, 2000000000, 3000000000];
可以理解为我们以自己的想法对 0 到 30亿 的数据 划分了显示的间隔。
-
第二步:按照间隔处理数据。
const investAmount = sourceData.map(item => { const amount = item.amount; // 寻找在数据间隔里小于amount的最大值 const min_v = Math.max(...dataInterval.filter(v => v <= amount)); // 寻找在数据间隔里大于amount的最小值 const max_v = Math.min(...dataInterval.filter(v => v > amount)); // 寻找 min_v 所在的下标 const index = dataInterval.findIndex(v => v === min_v); // 计算该amount在y轴上应该展示的位置 const y_value = (((amount - min_v) / (max_v - min_v)) * 10) + index * 10; return { value: y_value, realValue: amount, date: item.date }; }).filter(x => x);
代码解释:
-
首先遍历数据源,取出
amount
(数据)。 -
然后去定义的数据间隔里找
amount
处在间隔的哪两个数据之间。min_v
:在定义的间隔里找到 所有小于 amount 数值 中的 最大值。max_v
:在定义的间隔里找到 所有大于 amount 数值中的 最小值。如果上面说的不是很明白,我换一种说法:
把 amount 放到定义的 数据间隔 里进行排序,然后 min_v 和 max_v 就数据间隔里是 amount 左右两侧的值。
当然代码里是没有真的排序找,而是用了其他的方法而已。
-
接着需要寻找 min_v 所在的值的下标 i ,然后让其 乘以10 得到一个 index。
-
最后利用
amount 和 min_v 的差
除以max_v 和 min_v 的差
乘以10
加上index
即可。 -
这是我们就得到了一个按照一定规则缩小的数值。
-
图例:
-
上图中得到的结果是:
31.111...
,看了这个图应该就明白了,按照上面我讲的,如果把每一个数据都按照这个公式带入算一遍,那么我们就可以把上亿的数转换成几十,而此时得到的Echarts图,将会是一个介于 0 — 70 之间的图,这样就可以把很小的数值也显示出来。
-
-
第三步:渲染数据
这一步最主要的地方是当用户鼠标放到图上时我们肯定不能显示我们处理过后的数,所以要 formatter 一下:
tooltip: { show: true, trigger: 'axis', axisPointer: { type: 'shadow' }, formatter: (v) => { const date = v[0].data.date; // 前面处理数据时,构造的数组里包含了未处理过的原始值,所以这里直接用即可 const value = v[0].data.realValue; return `<div> <span>日期:${date}</span><br> <span>金额:${value / 10000}(万)</span> </div>` } }
现在你可能就明白了,为什么我前面说 本质上并没有打破均匀显示规则
表面上看确实改变了,但实际y轴依然是均匀分布的数值,不过我们改变了表象,转换了数据而已。
OK, 关于怎么构造一个不均匀数据轴图表我已经介绍完了。大家可以直接去看发布的图表。前面已经提供了链接。
完结·撒花