您现在的位置是:网站首页 > 平行坐标系(Parallel)实现文章详情
平行坐标系(Parallel)实现
陈川
【
ECharts
】
42249人已围观
6630字
平行坐标系(Parallel)实现
平行坐标系是ECharts中用于展示高维数据的强大工具。它通过多个平行轴将多维数据映射到二维平面,每个轴代表一个维度,数据点在各轴上对应位置用折线连接,形成直观可视化效果。
基本配置
平行坐标系的核心配置项是parallel
和parallelAxis
。以下是最简配置示例:
option = {
parallelAxis: [
{ dim: 0, name: 'Price' },
{ dim: 1, name: 'Weight' },
{ dim: 2, name: 'Rating' }
],
series: {
type: 'parallel',
data: [
[12, 56, 3.6],
[23, 89, 4.2],
[31, 47, 5.0]
]
}
};
坐标轴配置
平行坐标系的每个轴都可以单独配置:
parallelAxis: [
{
dim: 0,
name: '温度(℃)',
type: 'value',
min: -10,
max: 40,
axisLine: { lineStyle: { color: '#FF4500' } }
},
{
dim: 1,
name: '湿度(%)',
inverse: true,
nameLocation: 'end',
nameTextStyle: { fontWeight: 'bold' }
}
]
数据映射与样式
数据系列支持丰富的样式配置:
series: {
type: 'parallel',
lineStyle: {
width: 2,
opacity: 0.7,
color: function(params) {
const colorList = ['#c23531','#2f4554','#61a0a8'];
return colorList[params.dataIndex % 3];
}
},
emphasis: {
lineStyle: {
width: 4,
opacity: 1
}
},
data: [
{ value: [12, 5.4, 32], name: '产品A' },
{ value: [18, 6.2, 45], name: '产品B' }
]
}
交互功能
平行坐标系支持多种交互:
parallel: {
parallelAxisDefault: {
axisLabel: { interval: 'auto' },
tooltip: { show: true },
realtime: true // 拖动轴时实时更新
},
axisExpandable: true,
axisExpandCenter: 2,
axisExpandCount: 5,
axisExpandWidth: 50
}
大数据量优化
处理大量数据时的性能优化方案:
series: {
type: 'parallel',
progressive: 500, // 增量渲染阈值
smooth: true, // 平滑曲线
dimensions: ['date', 'value1', 'value2'],
data: largeDataSet,
itemStyle: {
opacity: 0.05 // 半透明处理重叠线
}
}
与其它图表联动
实现平行坐标系与散点图的联动:
option = {
grid: [
{ left: '5%', width: '45%', bottom: '55%' },
{ left: '55%', width: '45%', bottom: '55%' }
],
xAxis: [{ gridIndex: 0 }, { gridIndex: 1 }],
yAxis: [{ gridIndex: 0 }, { gridIndex: 1 }],
parallel: {
top: '60%',
height: '35%'
},
series: [
{
type: 'scatter',
xAxisIndex: 0,
yAxisIndex: 0,
data: scatterData1
},
{
type: 'parallel',
data: parallelData,
selectedMode: 'multiple',
brushSelect: true
}
]
};
自定义视觉映射
通过visualMap实现数据到视觉通道的映射:
visualMap: {
type: 'continuous',
dimension: 2, // 基于第三个维度映射
seriesIndex: 0,
min: 0,
max: 100,
inRange: {
color: ['#313695', '#4575b4', '#74add1', '#abd9e9', '#e0f3f8', '#ffffbf', '#fee090', '#fdae61', '#f46d43', '#d73027', '#a50026']
}
}
真实案例:汽车数据可视化
完整的多维汽车数据可视化示例:
option = {
dataset: {
source: [
['Model', 'MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight', 'Acceleration', 'Year'],
['Chevrolet', 18, 8, 307, 130, 3504, 12, 70],
['Buick', 15, 8, 350, 165, 3693, 11.5, 70]
]
},
parallelAxis: [
{ dim: 1, name: 'MPG' },
{ dim: 2, name: 'Cylinders', type: 'category' },
{ dim: 3, name: 'Displacement' },
{ dim: 4, name: 'Horsepower' },
{ dim: 5, name: 'Weight' },
{ dim: 6, name: 'Acceleration' },
{ dim: 7, name: 'Year', type: 'category' }
],
series: {
type: 'parallel',
datasetIndex: 0,
lineStyle: {
width: 1
},
emphasis: {
lineStyle: {
width: 3
}
},
tooltip: {
formatter: function(params) {
return params.seriesName + '<br>' +
params.marker + params.data[0] + '<br>' +
params.value.map((val, idx) => {
return option.parallelAxis[idx].name + ': ' + val;
}).join('<br>');
}
}
}
};
高级交互:轴缩放与过滤
实现基于轴范围的动态数据过滤:
option = {
parallel: {
axisExpandable: true,
axisExpandCenter: 3,
axisExpandCount: 6,
axisExpandWidth: 30,
parallelAxisDefault: {
tooltip: { show: true },
type: 'value',
nameLocation: 'end',
nameGap: 20,
nameTextStyle: { fontSize: 12 }
}
},
brush: {
parallelIndex: 0,
inBrush: { opacity: 1 },
outOfBrush: { opacity: 0.2 },
throttleType: 'debounce',
throttleDelay: 300
}
};
性能优化技巧
处理超大规模数据集时的实用技巧:
// 数据采样策略
function downSample(data, factor) {
return data.filter((_, index) => index % factor === 0);
}
// Web Worker处理
const worker = new Worker('parallelWorker.js');
worker.postMessage({ action: 'process', data: rawData });
worker.onmessage = function(e) {
myChart.setOption({
series: [{ type: 'parallel', data: e.data }]
});
};
// 分块渲染
function chunkRender(data, chunkSize = 1000) {
let rendered = 0;
const timer = setInterval(() => {
const chunk = data.slice(rendered, rendered + chunkSize);
myChart.appendData({ seriesIndex: 0, data: chunk });
rendered += chunkSize;
if (rendered >= data.length) clearInterval(timer);
}, 200);
}
动态更新与动画
实现数据的动态更新效果:
let currentData = initialData;
setInterval(() => {
currentData = currentData.map(item => {
return item.map(val => val * (0.9 + Math.random() * 0.2));
});
myChart.setOption({
series: [{
type: 'parallel',
data: currentData,
animationDurationUpdate: 1000,
animationEasingUpdate: 'cubicInOut'
}]
});
}, 2000);
多系列对比
在同一坐标系中展示多个数据系列:
series: [
{
type: 'parallel',
name: '2022年',
data: data2022,
lineStyle: { color: '#FFA500' }
},
{
type: 'parallel',
name: '2023年',
data: data2023,
lineStyle: { color: '#1E90FF' }
}
],
legend: {
data: ['2022年', '2023年'],
selected: {
'2022年': true,
'2023年': false
}
}
坐标轴个性化
为不同坐标轴应用不同样式:
parallelAxis: [
{
dim: 0,
name: '温度',
axisLine: {
lineStyle: {
color: '#FF6347',
width: 3
}
},
axisLabel: {
formatter: '{value} °C'
}
},
{
dim: 1,
name: '压力',
axisTick: {
inside: true
},
splitArea: {
show: true,
areaStyle: {
color: ['rgba(255,255,255,0.3)','rgba(200,200,200,0.3)']
}
}
}
]
响应式设计
适应不同屏幕尺寸的配置方案:
function resizeParallel() {
const width = window.innerWidth;
const option = {
parallel: {
left: width < 768 ? '5%' : '15%',
right: width < 768 ? '5%' : '15%',
top: width < 768 ? '20%' : '15%',
bottom: width < 768 ? '15%' : '10%',
parallelAxisDefault: {
nameTextStyle: {
fontSize: width < 768 ? 10 : 12
}
}
}
};
myChart.setOption(option);
}
window.addEventListener('resize', resizeParallel);
上一篇: 桑基图(Sankey)实现
下一篇: 自定义图表实现方法