PCM_Report/tablecreate.py

209 lines
6.3 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
实验流程表格生成脚本
- 读取传入的 experimentProcess JSON
- 将数据转换为包含合并信息的脚本表格描述
- 输出格式与应用中的 scriptTable 占位符兼容
- 额外生成脚本图表scriptChartX需要的数据便于测试
可通过环境变量定制行为:
- TABLE_TOKEN目标占位符默认 scriptTable1
- TABLE_START_ROW相对占位符的起始行偏移整数默认 2
- TABLE_START_COL相对占位符的起始列偏移整数默认 0
- TABLE_INCLUDE_HEADERS为 true/1/yes 时输出 headers 行
- CHART_TOKEN_PREFIX脚本图表占位符前缀默认 scriptChart
"""
import json
import os
import sys
from typing import Any, Dict, List, Tuple
def _read_all_stdin() -> str:
try:
if sys.stdin and not sys.stdin.closed and not sys.stdin.isatty():
return sys.stdin.read()
except Exception:
pass
return ""
def _load_payload() -> Dict[str, Any]:
raw = _read_all_stdin().strip()
if not raw and len(sys.argv) > 1:
arg = sys.argv[1]
if os.path.exists(arg) and os.path.isfile(arg):
with open(arg, "r", encoding="utf-8") as fh:
raw = fh.read()
else:
raw = arg
if not raw:
raw = os.environ.get("EXPERIMENT_JSON", "").strip()
if not raw:
raw = "{}"
data = json.loads(raw)
if not isinstance(data, dict):
raise ValueError("experiment JSON must be a dict")
return data
def _include_headers() -> bool:
flag = os.environ.get("TABLE_INCLUDE_HEADERS", "").strip().lower()
return flag in {"1", "true", "yes", "on"}
def _parse_float(value: Any) -> float:
try:
if isinstance(value, (int, float)):
return float(value)
if isinstance(value, str):
cleaned = value.replace("%", "").replace("°C", "").replace("RPM", "").strip()
return float(cleaned)
except Exception:
pass
return float("nan")
def build_table_spec(exp: Dict[str, Any]) -> Dict[str, Any]:
# 目标占位符,可通过环境变量覆盖,默认写入 {scriptTable1}
token = os.environ.get("TABLE_TOKEN", "scriptTable1")
# 当模板中的占位符位于表头时,默认向下偏移两行再开始写入
row_offset = int(os.environ.get("TABLE_START_ROW", "2") or 2)
col_offset = int(os.environ.get("TABLE_START_COL", "0") or 0)
headers: List[Any] = exp.get("headers") or []
rows: List[List[Any]] = exp.get("rows") or []
cells: List[Dict[str, Any]] = []
cursor_row = 0
if headers and _include_headers():
# 需要表头时,把 headers 行写成首行单元格
for ci, title in enumerate(headers):
cells.append({"row": cursor_row, "col": ci, "value": title})
cursor_row += 1
idx = 0
while idx < len(rows):
row = rows[idx] if isinstance(rows[idx], list) else [rows[idx]]
label = str(row[0]) if row else ""
span = 1
while idx + span < len(rows):
nxt = rows[idx + span]
if not isinstance(nxt, list):
break
if (len(nxt) > 0 and nxt[0] == label) and label != "":
# 连续多行的首列内容相同时,记录合并行数
span += 1
else:
break
cells.append({
"row": cursor_row,
"col": 0,
"value": label,
"rowspan": span,
})
for offset in range(span):
values = rows[idx + offset]
if not isinstance(values, list):
values = [values]
# 从第二列开始依次写入实际数据,不需要列合并
for col_idx, val in enumerate(values[1:], start=1):
cells.append({
"row": cursor_row + offset,
"col": col_idx,
"value": val,
})
cursor_row += span
idx += span
return {
"token": token,
"startRow": row_offset,
"startCol": col_offset,
# cells 是最终交给应用的单元格描述列表
"cells": cells,
}
def build_chart_specs(exp: Dict[str, Any]) -> List[Dict[str, Any]]:
"""Return a fixed set of mock charts for testing.
This ignores the experiment payload and always returns data for
scriptChart1/2/3 so the template can render charts during development.
"""
prefix = os.environ.get("CHART_TOKEN_PREFIX", "scriptChart")
# Simple step axis
steps = [1, 2, 3, 4, 5, 6]
charts: List[Dict[str, Any]] = [
{
"token": f"{prefix}1",
"title": "转速趋势(测试)",
"xLabel": "步骤",
"yLabel": "转速 (RPM)",
"kind": "line",
"grid": True,
"series": [
{"label": "输入转速", "x": steps, "y": [900, 1200, 1500, 1800, 2000, 2200]},
{"label": "曲轴转速", "x": steps, "y": [150, 200, 260, 300, 330, 360]},
],
},
{
"token": f"{prefix}2",
"title": "流量分布(测试)",
"xLabel": "步骤",
"yLabel": "流量 (LPM)",
"kind": "bar",
"grid": True,
"series": [
{"label": "流量", "x": steps, "y": [120, 140, 160, 180, 200, 220]},
],
},
{
"token": f"{prefix}3",
"title": "压力曲线(测试)",
"xLabel": "步骤",
"yLabel": "压力 (MPa)",
"kind": "line",
"grid": True,
"series": [
{"label": "压力", "x": steps, "y": [8.0, 9.5, 10.2, 10.8, 11.3, 11.8]},
],
},
]
return charts
def main() -> int:
try:
try:
sys.stdout.reconfigure(encoding="utf-8") # type: ignore[attr-defined]
except Exception:
pass
payload = _load_payload()
table_spec = build_table_spec(payload)
chart_specs = build_chart_specs(payload)
result = {"tables": [table_spec]}
if chart_specs:
result["charts"] = chart_specs
print(json.dumps(result, ensure_ascii=False))
return 0
except Exception as exc:
print(f"error: {exc}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())