昨天看到有读者问,这种 X 轴如何用 pyecharts 实现?
看到后,第一反应是 ECharts 默认不支持,第二反应是也许能想办法拼凑出来,但是得想想思路……
另外就是,这种拼凑,估计还得直接用 ECharts,pyecharts 是定制起来怕是不够灵活……
午休的时候,突然冒出来一个点子,就是把多个一样的 X 轴叠在一起,于是就有了这个:
不够完善的第一版
实现方法
思路如下:
思路有了,那就开始干吧,先准备下数据:
ECharts 官网的表格工具,可以方便地准备样例数据
然后写了一个数据转换函数,主要用于计算分组标签的位置
srcData = [
{group: 'Letters', subGroup: 'lowercase', name: 'a', value: 11},
{group: 'Letters', subGroup: 'lowercase', name: 'b', value: 41},
{group: 'Letters', subGroup: 'uppercase', name: 'C', value: 16},
{group: 'Letters', subGroup: 'uppercase', name: 'D', value: 32},
{group: 'Letters', subGroup: 'uppercase', name: 'E', value: 34},
{group: 'Numbers', subGroup: 'Integer', name: 1, value: 12},
{group: 'Numbers', subGroup: 'Integer', name: 2, value: 35},
{group: 'Numbers', subGroup: 'Integer', name: 3, value: 23},
{group: 'Numbers', subGroup: 'Decimal', name: 2.3, value: 16},
{group: 'Numbers', subGroup: 'Decimal', name: 4.5, value: 12}
];
covertData = function(src) {
var nameList = []; // X 轴数据
var valueList = []; // Y 轴数据
var groupLocationList = []; // 分组位置数据,存入[1.5, 5]这种
var subGroupLocationList = []; // 二级分组位置列表
var groupTickList = [0]; // 分组位置刻度位置数据,整数列表
var subGroupTickList = [0]; // 二级分组刻度位置数据
// 用于记录上次遍历到的分组/二级分组名称,以及该名称出现过的次数
var groupTmp = {
name: '',
count: 0
};
var subGroupTmp = {
name: '',
count: 0
};
// 遍历源数据,生成所需的图表数据、分组轴标签、分组轴刻度数据
for (var i = 0; i < src.length; i++) {
nameList.push(src[i].name);
valueList.push(src[i].value);
// 当一个分组/二次分组名称遍历完成时,计算出该分组的标签、刻度位置
// 然后重新开始计数,这里分别用了两种写法,三元表达式和 if-else 语句
i === src.length - 1 || groupTmp.name !== '' && groupTmp.name !== src[i + 1].group ?
(groupLocationList.push(i - groupTmp.count / 2),
groupTmp.name = '',
groupTmp.count = 0,
groupTickList.push(i + 1)) :
(groupTmp.name = src[i].group,
groupTmp.count++);
if (i === src.length - 1 || subGroupTmp.name !== '' && subGroupTmp.name !== src[i + 1].subGroup) {
subGroupLocationList.push(i - subGroupTmp.count / 2);
subGroupTmp.name = '';
subGroupTmp.count = 0;
subGroupTickList.push(i + 1);
} else {
subGroupTmp.name = src[i].subGroup;
subGroupTmp.count++;
}
}
return {
nameList: nameList,
valueList: valueList,
groupLocationList: groupLocationList,
subGroupLocationList: subGroupLocationList,
groupTickList: groupTickList,
subGroupTickList: subGroupTickList
};
};
dstData = covertData(srcData);
console.log(dstData);
数据转换的结果
准备配置项 option,叠放直角坐标系和自定义分组标签、刻度。代码如下,关键的地方都加了注释:
option = {
// 准备 3 个同一位置叠放的 grid (直角坐标系)
grid: [{
bottom: '20%'
}, {
bottom: '20%'
}, {
bottom: '20%'
}],
// 准备 3 个 X 轴,第一个放数据,后两个放分组标签、刻度
xAxis: [{
gridIndex: 0,
type: 'category',
data: dstData.nameList,
axisTick: {
length: 20
}
}, {
gridIndex: 1,
type: 'category',
data: dstData.nameList,
axisLabel: {
margin: 100,
formatter: function(value, index) {
// 使用回调函数定义分组标签显示的内容及位置
// 当位置为整数时放中间,在两个整数之间时加点空格
// 逻辑控制使用三元表达式嵌套
var retVal = dstData.groupLocationList.indexOf(index) != -1 ?
srcData[index].group :
dstData.groupLocationList.indexOf(index + 0.5) != -1 ?
' ' + srcData[index].group :
'';
return retVal;
}
},
axisTick: {
length: 100, // 刻度长度
// 用回调函数定义刻度的显示/隐藏
interval: (index) => dstData.groupTickList.indexOf(index) != -1
}
}, {
gridIndex: 2,
type: 'category',
data: dstData.nameList,
axisLabel: {
margin: 50,
formatter: function(value, index) {
// 使用回调函数定义二级分组标签显示的内容及位置
// 当位置为整数时放中间,在两个整数之间时加点空格
// 逻辑控制用的 if 语句结合 return
if (dstData.subGroupLocationList.indexOf(index) != -1) {
return srcData[index].subGroup;
}
if (dstData.subGroupLocationList.indexOf(index + 0.5) != -1) {
return ' ' + srcData[index].subGroup;
}
}
},
axisTick: {
length: 50,
interval: (index) => dstData.subGroupTickList.indexOf(index) != -1
}
}],
yAxis: [{
gridIndex: 0,
}, {
gridIndex: 1,
}, {
gridIndex: 2,
}],
series: [{
type: 'bar',
name: 'test',
label: {
show: true,
position: 'top'
},
data: dstData.valueList
}]
};
注意:如果轴标签显示不全,可以通过把 axisLabel.interval 设置为 0,强制显示所有标签。
这个版本还有一个不完善的地方:如果分组内个数是偶数,分组标签就无法真正居中……晚上的时候想到了一个办法,做了个第二版,咱们下回公布~
另外感兴趣的读者也可以想一下、尝试一下,看看有什么好的办法?
本文分享自 ZXand618的ECharts之旅 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!