Grafana ECharts插件数据转换失败:绘制动态日期X轴箱线图求助
ECharts箱线图数据适配与动态日期处理
问题背景
我正在用ECharts绘制箱线图,参考官方箱线图示例,现在遇到的问题是无法正确导入数据源数据。现有代码及数据源如下:
现有代码
data.series.map((s) => { if (s.refID === 'DATE_FILTERED') { categories_date = s.fields.find((f) => f.name === 'date').values.buffer || s.fields.find((f) => f.name === 'date').values; } else if (s.refID === 'VH_CTQ') { var_20240102 = s.fields.find((f) => f.name === '2024-01-02').values.buffer || s.fields.find((f) => f.name === '2024-01-02').values; var_20240103 = s.fields.find((f) => f.name === '2024-01-03').values.buffer || s.fields.find((f) => f.name === '2024-01-03').values.buffer; var_20240104 = s.fields.find((f) => f.name === '2024-01-04').values.buffer || s.fields.find((f) => f.name === '2024-01-04').values.buffer; } vh_ctq_data = categories_date.map((id, index) => { return { value: [categories_date[index] , var_20240102[index] , var_20240103[index] , var_20240104[index]] }; }); // return categories_date.map((d, i) => [d, var_20240102[i], var_20240103[i], var_20240104[i]]); });
数据源
表1:VH_CTQ
| 2024-01-02 | 2024-01-03 | 2024-01-04 | 2024-01-05 | 2024-01-06 | 2024-01-07 |
|---|---|---|---|---|---|
| 1.122 | 1.118 | 1.125 | 1.122 | 1.118 | 1.128 |
| 1.115 | 1.125 | 1.122 | 1.128 | 1.126 | 1.122 |
| 1.127 | 1.118 | 1.114 | 1.109 | 1.134 | 1.128 |
| NULL | 1.118 | 1.124 | 1.104 | 1.114 | NULL |
| NULL | 1.115 | 1.111 | 1.126 | 1.119 | NULL |
| NULL | 1.127 | NULL | NULL | 1.118 | NULL |
| NULL | NULL | NULL | NULL | 1.106 | NULL |
表2:DATE_FILTERED
| date |
|---|
| 2024-01-02 |
| 2024-01-03 |
| 2024-01-04 |
| 2024-01-05 |
| 2024-01-06 |
| 2024-01-07 |
疑问
如何绘制以date列为X轴的箱线图?若date列为动态可变的,该如何适配处理?
解决方案
核心问题分析
当前代码存在三个关键问题:
- 硬编码日期字段,无法适配动态新增/删除的日期列
- 数据格式不符合ECharts箱线图要求:箱线图需要每个类别对应一组数据的五数统计值(最小值、下四分位、中位数、上四分位、最大值),而非按行索引取对应值
- 未处理数据源中的
NULL值,会导致统计计算错误
1. 通用统计工具函数
先实现一个计算箱线图五数统计的工具函数,自动过滤无效值:
// 计算一组数据的箱线图五数统计(最小值、下四分位、中位数、上四分位、最大值) function calculateBoxplotStats(dataArr) { // 过滤NULL值并转换为数字类型 const validData = dataArr.filter(val => val !== null && val !== 'NULL').map(Number); if (validData.length === 0) return [null, null, null, null, null]; const sorted = validData.sort((a, b) => a - b); const len = sorted.length; const medianIndex = Math.floor(len / 2); // 计算中位数 const median = len % 2 === 1 ? sorted[medianIndex] : (sorted[medianIndex - 1] + sorted[medianIndex]) / 2; // 计算下四分位 const q1 = calculateMedian(sorted.slice(0, medianIndex)); // 计算上四分位 const q3 = calculateMedian(sorted.slice(medianIndex + (len % 2 === 1 ? 1 : 0))); return [sorted[0], q1, median, q3, sorted[len - 1]]; } // 辅助函数:计算中位数 function calculateMedian(arr) { const len = arr.length; if (len === 0) return null; const mid = Math.floor(len / 2); return len % 2 === 1 ? arr[mid] : (arr[mid - 1] + arr[mid]) / 2; }
2. 动态适配数据源的主逻辑
通过正则匹配自动识别所有日期字段,无需硬编码:
let categoriesDate = []; let vhCtqData = []; // 遍历数据源分离分类和数值数据 data.series.forEach(s => { if (s.refID === 'DATE_FILTERED') { // 获取X轴分类日期列表 const dateField = s.fields.find(f => f.name === 'date'); categoriesDate = dateField.values.buffer || dateField.values; } else if (s.refID === 'VH_CTQ') { // 动态匹配所有YYYY-MM-DD格式的日期字段 const dateFields = s.fields.filter(f => /^\d{4}-\d{2}-\d{2}$/.test(f.name)); // 为每个日期字段计算箱线图统计值 vhCtqData = dateFields.map(field => { const values = field.values.buffer || field.values; return calculateBoxplotStats(values); }); } }); // ECharts配置项 const option = { xAxis: { type: 'category', data: categoriesDate, axisLabel: { rotate: 30 // 旋转标签避免重叠 } }, yAxis: { type: 'value' }, series: [ { name: 'VH_CTQ', type: 'boxplot', data: vhCtqData } ] }; // 初始化并渲染图表 const myChart = echarts.init(document.getElementById('main')); myChart.setOption(option);
关键说明
- 动态日期适配:用正则表达式
/^\d{4}-\d{2}-\d{2}$/自动匹配所有日期格式的字段,无论日期列新增或删除,代码都能自动适配 - NULL值处理:统计函数中过滤掉所有NULL值,确保计算结果准确
- 数据格式匹配:每个日期对应一组五数统计值,完全符合ECharts箱线图的数据要求
- X轴对齐:
DATE_FILTERED的日期列表与VH_CTQ的日期字段一一对应,保证X轴分类和数据精准匹配
内容的提问来源于stack exchange,提问作者TonyMoly312
相关产品推荐
相关产品推荐

