126 lines
6.7 KiB
Markdown
126 lines
6.7 KiB
Markdown
# 前后端分离的可视化数据返回方案(ECharts)
|
||
|
||
## 目标
|
||
- 后端不再生成/传输图片,仅返回图表数据;前端使用 ECharts 渲染。
|
||
- 统一的数据结构,减少前端适配代码;杜绝 NaN/Infinity/不可序列化对象导致的 API 崩溃。
|
||
- 与现有 API 保持兼容(`images` 可留空),逐步迁移到 `charts` 数据模式。
|
||
|
||
## 序列化与清洗规范(必须遵守)
|
||
- **NaN / Infinity / pd.NA**:递归清洗为 `null`(JSON `null`)。不得返回字符串 "NaN"。
|
||
- **时间戳**:统一 ISO8601 字符串(例 `2023-01-01T12:00:00`)。
|
||
- **数组/矩阵**:全部转为原生 Python list,再 JSON 序列化。
|
||
- **DataFrame**:优先 `to_dict(orient="records")` 或组装 dataset 形式(见下)。
|
||
- **数值类型**:numpy 标量转原生 `int/float/bool`;遇到 `nan/inf` 先清洗。
|
||
|
||
> 建议实现一个通用函数 `to_echarts_safe(obj)`,递归处理上述清洗与类型转换,所有响应数据出站前统一走这一层。
|
||
|
||
## 响应骨架(新增 `charts`,旧字段保持)
|
||
```json
|
||
{
|
||
"success": true,
|
||
"meta": { ... },
|
||
"analysis": {
|
||
"zh": {
|
||
"data_description": "...",
|
||
"preprocessing_steps": [ ... ],
|
||
"api_analysis": { ... },
|
||
"steps": [
|
||
{"key": "ts", "title": "Time Series", "summary": "...", "chart": "ts"},
|
||
...
|
||
]
|
||
}
|
||
},
|
||
"charts": {
|
||
"ts": { "type": "line", "dataset": [...], "meta": {...} },
|
||
"acf_pacf": { "type": "bar", "series": [...], "meta": {...} },
|
||
"heatmap": { "type": "heatmap", "data": [...], "xLabels": [...], "yLabels": [...], "meta": {...} },
|
||
...
|
||
},
|
||
"images": {},
|
||
"log": [...]
|
||
}
|
||
```
|
||
- `steps[].chart` 指向 `charts` 的 key,前端可按步骤顺序渲染。
|
||
- `images` 保留但为空,兼容旧前端。
|
||
|
||
## 各图表建议的数据格式(贴合 ECharts)
|
||
- **时间序列(ts)**:`dataset` 形式
|
||
- 二维数组:首行表头,例如 `[ ["timestamp","sales","ad_cost"], ["2023-01-01T00:00:00", 10, 5], ... ]`
|
||
- 前端:`dataset.source = dataset`,`series: [{type:'line', encode:{x:'timestamp', y:'sales'}}, ...]`
|
||
|
||
- **ACF / PACF(acf_pacf)**:
|
||
- `{ series: [{name:'acf', data:[{lag:0, value:1.0}, ...]}, {name:'pacf', data:[...] }], meta:{column:'sales'} }`
|
||
|
||
- **平稳性检验(stationarity)**:
|
||
- `{ adf: {statistic:..., p_value:..., critical_values:{...}}, kpss:{...}, meta:{column:'sales'} }`
|
||
- 前端可渲染 bar/表格。
|
||
|
||
- **正态性检验(normality)**:
|
||
- `{ columns: [{name:'col', shapiro_p:..., jb_p:..., shapiro_stat:..., jb_stat:...}], meta:{} }`
|
||
|
||
- **季节性分解(seasonal)**:
|
||
- `dataset` 形式:`[["timestamp","observed","trend","seasonal","resid"], [...]]`
|
||
|
||
- **频谱分析(spectral)**:
|
||
- `periodogram`: `{ f: [...], psd: [...] }`(可截断前 N 点)
|
||
- `spectrogram`: `{ f: [...], t: [...], values: [[i,j,val], ...] }`(可只返回 log10 后再压缩)
|
||
|
||
- **相关性热力图(heatmap)**:
|
||
- `{ data: [[i,j,value], ...], xLabels:[...], yLabels:[...], meta:{} }`(后端提前 flatten N×N 矩阵)
|
||
|
||
- **PCA 碎石图(pca_scree)**:
|
||
- `dataset`: `[["component","explained","cumulative"], [1,0.4,0.4], ...]`
|
||
|
||
- **PCA 散点(pca_scatter)**:
|
||
- `records`: `[{pc1:..., pc2:..., timestamp:"..."}, ...]`
|
||
|
||
- **特征重要性(feature_importance)**:
|
||
- `records`: `[{feature:"...", importance:0.12}, ...]`
|
||
|
||
- **聚类(cluster)**:
|
||
- `records`: `[{timestamp:"...", cluster:0, x:<可选>, y:<可选>}...]`
|
||
|
||
- **因子分析(factor)**:
|
||
- 类似聚类:`[{timestamp:"...", factor1:..., factor2:...}]`
|
||
|
||
- **协整检验(cointegration)**:
|
||
- `{ trace_stat:[...], crit_95:[...], eigen_vals:[...], meta:{} }`
|
||
|
||
- **VAR 预测(var_forecast)**:
|
||
- `dataset`: `[["step","var1_forecast","var2_forecast"], [1, ...], ...]`
|
||
|
||
> 原则:能用 `dataset` 就用 `dataset`,多条线在前端通过 `encode` 指定;需要矩阵的提前 flatten;其余用 records。
|
||
|
||
## 样式与主题
|
||
- 后端不返回颜色、线型等视觉样式;仅返回语义字段(series 名称、指标含义)。前端根据主题决定配色与风格。
|
||
|
||
## 实施步骤(建议)
|
||
1) 增加 `to_echarts_safe` 清洗函数,统一处理 NaN/Infinity/Timestamp/DataFrame -> JSON-safe。
|
||
2) 在各分析函数里:保留计算逻辑,改为组装 chart data(dataset/records/flatten),不再生成 PNG;`generate_plots` 逻辑可留作开关,但默认 False。
|
||
3) `run_analysis` 汇总时,将各 step 的数据填入 `charts`,在 `steps` 内写入 `chart` key(引用图表)。
|
||
4) 路由层返回 `charts` 字段,`images` 留空,`steps` 仍返回。
|
||
5) 前端按 `charts` 协议接入 ECharts,去掉对 `images` 的依赖。
|
||
|
||
## 兼容与回退
|
||
- 旧前端:仍可拿到 `analysis.steps` 及 `images`(为空)。
|
||
- 新前端:使用 `charts`。如果某一步失败,返回 `{error:"..."}` 和简短 summary,避免 500。
|
||
|
||
## 性能注意
|
||
- 后端不画图,CPU/IO 显著下降;如需进一步优化,可让前端传 `methods` 列表决定执行哪些步骤。
|
||
|
||
## 算法是否需要改动?
|
||
- 核心统计/时序算法(ADF/KPSS、ACF/PACF、PCA、VAR、季节分解、相关矩阵、聚类等)保持不变,改动集中在“结果封装”层。
|
||
- 需要调整的只是输出包装:
|
||
- 将现有用于绘图的中间结果(DataFrame/ndarray/statsmodels 结果)转换为 ECharts 友好的 JSON 结构,统一经过 `to_echarts_safe` 清洗(NaN/Inf/Timestamp)。
|
||
- 矩阵类结果(如相关性)在后端提前 flatten 成 `[i,j,value]` 列表;dataset 形式优先用于多系列折线/柱状。
|
||
- 可按需做截断/摘要以控体积(如 periodogram 取前 N 点,spectrogram 取均值或下采样)。
|
||
- 补充元信息(列名/单位/变量名),方便前端生成 legend/tooltip。
|
||
- 不需改动的部分:
|
||
- 预处理、标准化流程、算法的数学实现与参数选择(滞后阶、分解周期、PCA 组件数等)保持现状。
|
||
- 如后续发现数据量过大或性能瓶颈,可再对个别步骤做抽样/截断,但不影响算法正确性。
|
||
|
||
## 追加约定(仍然不改算法,只改结果包装)
|
||
- **直方图分箱**:正态性/分布分析中,后端负责 binning(`np.histogram`),返回 `[["range_start","range_end","count"], ...]`。前端不做分箱。
|
||
- **to_echarts_safe 扩展**:除 NaN/Inf/Timestamp 外,显式处理 numpy 各数值类型、Decimal,必要时加“已访问集合”防循环引用。统一输出 JSON-safe、ECharts-friendly 结构。
|
||
- **矩阵/多系列格式**:矩阵类(相关性等)继续 flatten `[i,j,value]`;多系列/多列数据优先用 dataset+encode,保证对齐。
|