走势图解海报(trend-poster)
把一组时间序列数据,做成一张能自证结论的中文财经长图:顶部标题 → 走势柱状图 → 历年明细表 → 关键数字卡片 → 历史对标 → 结论条。
核心不是"画个图",而是用数据讲一个关于走势的故事:什么时候见顶、跌了多少、现在相当于历史上的哪一年、按当前趋势会走到哪。
一、触发场景
- "把 XX 的走势做成一张图"
- "很喜欢这个图的样式,用来分析 XX 的走势"
- "一图看懂 XX 这几年"
- "做个复盘图 / 财经长图 / 数据海报"
- 日报、周报里需要一张能直接发微信/星球的传播图
二、工作流(必须按顺序走)
第 1 步:先确认三件事,再动手
数据是这张图的全部价值。动手前先把这三项跟用户对齐(用户已在提问里说清的,就不要重复问):
| 项 | 说明 | 例 |
|---|---|---|
| 标的与口径 | 到底统计的是什么范围 | "全国国有土地使用权出让收入",不是"土地成交价款" |
| 时间跨度与粒度 | 从哪年到哪年,年/季/月 | 2005-2026 |
| 单位 | 必须显式写给读者看 | 万亿元 |
> ⚠️ 口径不写清楚,图就是废的。 口径必须出现在标题下方的 meta 里。
第 2 步:采数据
- 有 MCP / 数据接口(通达信、东财、星耀数智、企查查等)→ 直接取
- 没有 → WebSearch 检索官方口径(统计局、财政部、央行、行业协会年报)
- 每个数字都要能说清来源。取不到的年份就留空,不要补
已装好的金融数据接口(本机可直接用,省一次调研)
akshare(1.19.1)已装在 default venv。只读公开数据,不需要 token。常用的市场估值接口:
import akshare as ak
ak.stock_market_pe_lg(symbol="上证") # 沪市A股平均市盈率,月度,1999年至今(上交所口径)
ak.stock_market_pe_lg(symbol="深证") # 深市A股平均市盈率
ak.stock_market_pe_lg(symbol="创业板")
ak.stock_a_ttm_lyr() # 全部A股 PE(TTM) 月度:中位数/等权平均 + 历史分位
ak.stock_a_all_pb() # 全部A股 PB 月度 + 历史分位
ak.stock_index_pe_lg(symbol="上证50") # 指数 PE(等权/整体、静态/滚动)
月度序列要按年聚合再画图(df.groupby(year).mean())。注意:同一张图里
「年度均值」和「区间极值」是两个口径,卡片里必须分别写明,不要混用。
其他任务的数据出口:A股行情/K线走 tdx-connector 或 ad-api(星耀数智),
企业工商信息走 qcc-company,历史宏观数据走 WebSearch 找官方口径。
第 3 步:写 JSON 配置
复制 assets/example_land_supply.json 当骨架,按需改。字段全集见 references/schema.md(含每个字段的含义、默认值、常见排版坑)。
最小可用骨架:
{
"title": { "l1": "中国土地出让金:", "l2": "2005-2026 走势" },
"meta": [{ "label": "口径", "text": "..." }, { "label": "单位", "text": "万亿元" }],
"blocks": [
{ "type": "chart", "heading": "2005-2026年土地出让金收入", "sec_unit": "万亿元",
"bars": [ { "x": "2005", "y": 0.55, "tone": "gray2" } ],
"legend": [ { "text": "2017-2020年", "tone": "blue" } ] },
{ "type": "table", "heading": "历年数据(万亿元)", "labels": ["年份","出让金"],
"per_row": [11,12], "highlight_keys": ["2021"],
"records": [ { "key": "2005", "values": ["0.55"] } ] },
{ "type": "stats", "heading": "关键数据一览", "items": [
{ "no": "1", "name": "峰值", "value": "8.71", "unit": "万亿元", "tone": "red", "icon": "chart" } ] },
{ "type": "compare", "heading": "现在相当于历史上哪一年?",
"left": { "lbl": "2025年", "op": "≈", "val": "2013年", "sub": "(4.13万亿元)" },
"right": { "lines": ["约回到 **2010-2012年** 水平"] } }
],
"footer": { "lines": ["一句话结论;", "第二句结论 **关键词高亮**。"] },
"credit": "@你的署名"
}
第 4 步:渲染
"C:\Users\Administrator\.workbuddy\binaries\python\envs\default\Scripts\python.exe" \
"C:\Users\Administrator\.workbuddy\skills\trend-poster\scripts\render_poster.py" \
"你的配置.json"
- 默认在 JSON 同目录产出同名
.html+.png(2 倍图) - 指定输出:
--png D:/海报/xxx.png --html D:/海报/xxx.html - 只要 HTML 调细节:
--no-png;只要图:--no-html - 换宽度/清晰度:
--width 1200 --scale 3 - 渲染约 3-10 秒(要起一次 Chromium)。首次运行若明显变慢属正常
- 脚本已处理 Playwright 关闭阻塞问题(清理放守护线程 + 超时 + 强制退出),若仍卡住不返回,直接重跑即可,图通常已生成
> output.scale 默认 2(1080×2 = 2160px 宽)。发微信/星球足够清晰;要印刷级用 3。
第 5 步:自检 + 交付
打开 PNG 逐项核对(详见第五节),然后把 PNG 和 HTML 一起 交给用户。
三、内容设计规则(这张图好不好,全看这一步)
版式是壳,下面这些"叙事零件"才是壳里装的东西。做任何走势图都套这几个:
1. 先分段,再上色
不要一柱一色。按阶段分色,图例去解释阶段含义:
| 阶段 | 建议 tone | 含义 |
|---|---|---|
| 早期基线 | gray2 / gray |
久远年份,仅作参照 |
| 上行期 | blue |
明确增长阶段 |
| 峰值 | red |
唯一的最高点,全图视觉焦点 |
| 回落期 | lblue |
见顶后的下滑 |
| 当年未完成 | purple |
只有 N 个月的数据,必须标"年内数据" |
| 外推/预测 | ghost(虚线) |
必须标"非官方外推" |
2. 峰值一定要单独强调
只有一根柱是红的 + 柱顶挂红色 峰值 8.71 标签。读者的眼睛必须先落到这里。
3. 当年数据要"翻译"成可比口径
只统计到 7 月的数据不能直接跟全年比。做法:
- 柱状图里用 purple 画 1-7 月实际值,紧邻一根 ghost 虚线画全年外推
- 用 callout 右上角批注框写明外推依据("若按前7个月趋势粗略外推,约回到 2010-2012 年区间")
- 折年倍数、同比、降幅各占一张卡片
4. 关键数字卡片:6 张,覆盖 4 类
| 卡片类型 | 例 |
|---|---|
| 峰值 | 峰值(2021年)8.71 万亿元 |
| 最新完整年 | 2025年 4.15 万亿元 |
| 变化幅度 | 较峰值下降 52.3% |
| 历史对标 | 2025年收入水平 ≈2013年 |
| 同比 | 2025年1-7月同比 -30.8% |
| 外推 | 2026年粗略外推 ≈2.87 万亿元(较峰值约 -67.0%) |
5. 「现在相当于历史上哪一年」是这类图最抓人的一块
用一个等式把最新的数字映射回历史:2025年 ≈ 2013年(4.13万亿元)。右边框补一句外推结论。没有把握做对标时,这一块可以整块删掉,不要硬编。
6. 结论条只写 2 句
第一句陈述已发生的事实,第二句给趋势判断。关键词用 **...** 高亮成金色。这是全图的落点,不要写成免责声明。
四、错误与红线
| 红线 | 说明 |
|---|---|
| 不编数据 | 任何数字必须有来源。查不到就留空或注明"数据缺失" |
| 不混口径 | 同一根柱子里不能一半是"出让收入"一半是"成交价款" |
| 外推必须显式标注 | 凡是推算/预测值:用虚线柱 + 图例注明"非官方外推" |
| 未完成年份必须标注 | "2026年1-7月(年内数据)",不能让读者误以为是全年 |
| 导出参数不硬编码 | 账号、Token、Cookie 一概不要写进 JSON 或脚本 |
| 红涨绿跌 | 中国A股惯例:涨用红、跌用绿。只有在这类"数值规模"图里才按语义分色(峰值红) |
| 署名不自创 | credit 用用户给的署名;用户没给就留空 |
五、交付前自检清单
渲染完逐项看 PNG:
- [ ] 数字对得上 — 柱高、柱顶标签、表格里的数字、卡片里的数字,四处一致
- [ ] 口径和单位出现在标题下方,读者不用猜
- [ ] 峰值柱是唯一红色,红色标签没被柱顶标签重叠
- [ ] 右上角
callout没有压住任何柱子或数字 - [ ] 横轴标签没被压扁、没换行错位(尤其
2026\n1-7月这种两行标签) - [ ] 卡片里的数值没有折行、没有超出卡片边界
- [ ] 高亮
**...**的地方在图上确实是金色 - [ ] 表格列数对齐,
highlight_keys的列是红的 - [ ] 结论条 2 句以内,没有空话
- [ ] 整图没有溢出画布(上下左右都不该出现被裁切的内容)
- [ ] 缩放看:把 PNG 缩到手机宽度,标题和关键数字仍然一眼可读
六、微调指引
| 想改什么 | 怎么改 |
|---|---|
| 某根柱颜色 | 改该 bars 项的 tone |
| 纵轴刻度太密/太疏 | ticks(默认 5);刻度上界不对就显式给 y_max |
| 图整体偏高/偏矮 | plot_height(默认 330) |
| 柱子超过 20 根,标签挤 | width 提到 1200 + x_label_size:12 + value_label_size:12 + bar_gap:3 |
| 配色换主题 | 顶层 theme 覆盖 CSS 变量,如 {"--cyan":"#2ee6a8","--blue":"#0f9d6e"} |
| 一张表放两个口径 | table.labels 写多项、records[].values 对应多个值(如沪市/深市两行) |
| 改版式结构 | 直接改 assets/poster_template.html 里的 CSS(所有样式集中在此文件) |
| 加一种新配色 | 在模板 CSS 的 tone 区加 .t-xxx{...} 和 .c-xxx{--c:...;--c2:...} |
| 加一种新图标 | 在 scripts/render_poster.py 的 ICONS 字典里加一条 SVG |
七、文件结构
trend-poster/
├── SKILL.md ← 本文件
├── assets/
│ ├── poster_template.html ← 版式模板(全部 CSS 在这里,改样式只改它)
│ └── example_land_supply.json ← 完整示例配置(中国土地出让金 2005-2026)
├── references/
│ └── schema.md ← JSON 字段全说明 + 常见排版坑
└── scripts/
└── render_poster.py ← 渲染器:JSON → HTML → PNG
技术栈:Python + Playwright(Chromium)截图。全离线,字体走系统字体(SimHei / 微软雅黑 / Noto Sans SC),无任何外部请求。