# 风语 · 生命链可视化规范 v2

> 位置：`/mnt/data/www/algo/_viz/SPEC.md`
> 适用：`/algo/**` 全部算法说明书页（19 页）· `/algo/index.html` · `/life-chain/**` 生命链可视化专区 · `/internal/lifechain/` 工作室侧
> 实现：`/algo/_viz/viz.css` + `/algo/_viz/viz.js`（纯原生 SVG/HTML，**零外部 CDN**）
> 数据：`/algo/_viz/viz-data.js`（19 页图表）· `/algo/_viz/industry-model.js`（行业研判模型）· 生成脚本 `gen_viz.py` `gen_model.py`
> v2 变更：新增第 1 节【研判模型五条】——**可视化不是画一条曲线，是一套研判模型。**

---

## 0. 一句话

**图不是装饰，是证据。** 一张图放进说明书页，是为了让"开店的老板三秒看懂这个算法在干什么"；宁可画得朴素，也不许画得好看但没有出处。

---

## 1. ★ 研判模型五条（写死，任何页面不得违背）

### 第 1 条 · 大曲线 = 行业总势
一条大曲线对应**一个行业**，按天用**真实回传数据**刷新，不是静态图。
- 落库口径：`MySQL lifechain.industry_score_daily.bus_score`，一天一个值。
- 每次生成时**实时读库**，不缓存旧快照。

### 第 2 条 · 大曲线由小曲线决定
该行业下**每一条环节的小生命链曲线**各一条，大曲线是它们的加权和。
- **站点实际落库的环节**（以实际为准，6 条）：

| 环节 | 字段 | 权重 | 权重来源 |
|---|---|---|---|
| 产品链 | `product_chain` | 0.25 | 真实引擎 `/opt/lifechain_standalone/server.py` 的 `WEIGHTS` |
| 销售链 | `sales_chain` | 0.20 | 同上 |
| 客户链 | `customer_chain` | 0.20 | 同上 |
| 运营链 | `operation_chain` | 0.15 | 同上 |
| 推广链 | `promotion_chain` | 0.10 | 同上 |
| 管理链 | `management_chain` | 0.10 | 同上 |

- **关系式**：`大曲线 ≈ Σ(小曲线 × 权重)`。已在全表 **4478 行**上验证：加权和与 `bus_score` 的绝对差**中位 0.054**（= 表字段两位小数的四舍五入残差）。
- 页面**必须**能回答"大曲线的走势是由哪几条小曲线带起来的"：给出**贡献分解** = `权重 × Δ小曲线`，并标出占总变化的比例。
  > 例：营收上行但沉淀下滑 → 大曲线走平。
- ⚠️ 主人给的环节序列（需求 → 产品 → 护城河 → 信任 → 营收 → 沉淀 → 复利）是**同一件事的口语说法**；站点实际落库的是上面这 6 条，**以实际为准**。

### 第 3 条 · 缺什么 / 补什么必须可视
每一环的小曲线要能直接看出 **断了 / 缺数据 / 弱在哪**。三态定义都是**可复算的**：

| 状态 | 判定规则（可复算） | 画法 |
|---|---|---|
| **缺数据** | 该天该链值为 `NULL` | 空心点 + 灰色区 + **折线断开** |
| **断（未回传）** | 该天 6 条链**同时等于各自基准值**（= 当天没有新数据回传，不是走势） | 灰色竖带 + 空心点 + **折线断开** |
| **弱** | 近 7 个有效天 vs 前 7 个有效天，**加权拖累最大**的那一环 | 缺口清单里标「弱」+ 黄底 |

> ★ **铁律：缺的环节绝不许画成平滑好看的曲线** —— 那正好掩盖了问题。缺口必须是断的、空的、灰的。

每一处缺口旁边必须写人话三段：**缺什么 / 谁去补 / 怎么补**。
- 「缺什么」= 从数据算出来的（Δ、权重、拖累分、占总变化几成）。
- 「谁去补」= 环节→角色的固定映射（**模型定义，非实测值**，见下表）。
- 「怎么补」= 指向站内**真实存在**的算法页（**模型定义，非实测值**）。

| 环节 | 谁去补（模型定义） | 怎么补（指向真实工具） |
|---|---|---|
| 产品链 | 管产品和供应链的人 | `/algo/value-assessment.html` 真需求价值评估 |
| 销售链 | 管成交的人 | `/algo/funnel-evaluate.html` 5层靶心漏斗评估 |
| 客户链 | 管获客和留存的人 | `/algo/demand-verify.html` 需求验证6题 |
| 运营链 | 管日常运转的人 | `/algo/four-dim-landing.html` 四维度落地评估 |
| 推广链 | 管投放和传播的人 | `/algo/traffic-target.html` 流量靶心评估V2 |
| 管理链 | 管人和账的人 | `/algo/water-pool.html` 水池理论 |

### 第 4 条 · 大曲线右侧那段【虚线】= 未来研判
从当前点向右延伸的虚线段，必须标注 **方向 + 依据 + 置信度**。
- **起始点** = 最后一个**有效天**（未回传的天不做起点）。
- **长度** = 固定 **7 天**。
- **依据** = 对有效天做**最小二乘拟合**，**多窗口**（7 / 14 / 21 / 29 有效天）各算一次，报出**斜率与 R²**；再用**逐日环比**做交叉验证。依据必须能追到真实数据或算法输出。
- **置信度** = 规则判定，不靠感觉：
  - 所有窗口斜率**符号一致** 且 **最高 R² ≥ 0.5** → **高**
  - 符号一致 且 **最高 R² ≥ 0.2** → **中**
  - 其余（含窗口符号不一致）→ **低**
- **不确定带** = 各窗口外推的**逐点 min/max** 画成灰色带。**窗口分歧越大带越宽** —— 不许收窄成一条假装确定的线。
- 最后一天未回传时：**剔除**并把置信度写清原因。

### 第 5 条 · 可下钻
- 点大曲线上**某个时点** → 展开那一刻**各环节小曲线**（值 / 环比 / 状态）。
- 点**某一环** → 高亮该环对应的缺口条目。
- 实现：事件委托，元素带 `data-lc-day` / `data-lc-chain`，容器带 `data-model`（指向 `window.VIZ_DATA` 的 key）。

### 落地节奏（不要一次铺满）
先在 **1 个行业**做完整样例 → 验证无误 → 再推广。
- 当前样例：**便利店**（`industry-便利店`，35 天真实数据）。
- 推广到其它行业 = 改 `gen_model.py` 里的 `INDUSTRY` 跑一遍，页面加一个 `data-viz` 容器。**不许在没有真数据的行业上强上。**

---

## 2. 五种图，各有各的适用面

| 类型 | `kind` | 什么时候用 | 反面（别用） |
|---|---|---|---|
| **趋势线** | `line` | 同一件事按时间或按轮次变 | 只有 1 个点；维度之间没有先后顺序 |
| **雷达 / 维度条** | `radar` / `bars` | 一件事被拆成 3–9 个固定角度各打一次分 | 维度超过 9 个（雷达会糊，改 `bars`） |
| **漏斗 / 台阶** | `funnel` / `ladder` | 一层一层往下掉的比例 · 一档一档往上走的位置 | 层级之间没有递进关系 |
| **占比堆叠** | `stack` | 同一批对象按天被分成几类，看占比怎么挪 | 类别超过 6 种 |
| **研判模型** | `research` | 行业总势 + 环节小曲线 + 缺口 + 未来虚线 + 下钻 | 没有真回传数据的行业 |

> **为什么没有热力图**：地域 × 行业的热力在 390 手机上必然要靠缩放或横向滚动，违反"手机不溢出"。这一类改用 `bars` 排序条表达。**这是本规范主动放弃的一类图，不是没做完。**

## 3. 统一元素（所有页面共用，不许各页自改）

| 元素 | 规则 |
|---|---|
| **坐标轴单位** | 折线/研判模型纵轴必须写单位或口径（分 / 人 / % / 元）。没有单位的图不许上线。 |
| **时间范围默认值** | 默认**最近 30–35 天**或**本页真跑那一组**；范围写在脚注「口径」里。少于 3 个点的，不画折线，改画条。 |
| **颜色语义（全站唯一）** | **升 `#16a34a` 绿 · 降 `#dc2626` 红 · 平 `#64748b` 灰 · 缺 `#cbd5e1` 浅灰**。行业状态色另有固定映射：上行绿 / 稳健蓝 / 平稳灰 / 低位橙 / 低迷红（取自 `industry_score_daily.status_color` 原值）。**同一颜色在任何页面只许表达同一个意思。** |
| **标注（铁律）** | 每张图**必须**在下方标出：`数据来源` + `生成时间` + `实测/示意` 徽章。缺一个都算没做完。 |
| **图下那句话** | 每张图下面必须有**一句人话**"这张图说明什么"，不许写"如图所示"。 |
| **空数据** | 取不到数时**不画空框**、不留白，渲染成 `这个维度暂时没有可用数据。` 提示块，**不假装有数**。 |
| **手机 390** | 折线/雷达/堆叠/研判模型按容器实际宽度重绘，文字不缩放；条/漏斗/阶梯用 HTML 排版，长中文换行不撑破。**横向不许滚动。** |
| **依赖** | 明确禁止外部 CDN。只许本地文件 + 原生 SVG/HTML/CSS。 |

## 4. ★ 铁律：实测优先，示意必标

1. **每张图必须标【数据来源 + 生成时间】。**
2. **拿不到真数据的，画"结构示意图"，并在图下明确标「示意，非实测」（黄底徽章）。**
3. 真数据来源只写这几种，写全表名/路径/接口，不许写"系统数据"这种含糊话：
   - 本页第 3 节**真跑输出**（页面内原文数字，读者可当场对照）
   - **MySQL 表**：`lifechain.industry_score_daily` / `lifechain.market_trend_daily` / `lifechain.chain_country_industry` 等
   - **真实引擎口径**：`/opt/lifechain_standalone/server.py` 的 `SUBLINE_KEYS` / `WEIGHTS`
   - **落盘文件**：`/mnt/data/www/internal/lifechain/data.json` · `/mnt/data/opt/algorithms/output/geo_industry_grid_baseline.json`
   - **接口**：曲线引擎 `http://127.0.0.1:8923/api/curve/*`
4. **推算必须交代口径**：由实测值做乘法/加权/拟合推出来的，写清公式与参数（例：`N(t+1)=N(t)×K`；最小二乘窗口与 R²）。**不允许把推算说成实测，也不允许把实测降级成示意。**
5. 当前状态：19 页图表**全部实测**；研判模型样例**全部实测**（0 张示意）。

## 5. 与工作室（`/internal/lifechain/`）的一致性

- **同一数据源**：专区页 30 条小链直接读工作室用的同一个文件 `/mnt/data/www/internal/lifechain/data.json`；研判模型两侧都读 `/algo/_viz/industry-model.js`（由 `industry_score_daily` 实时生成）。**不另存第二份快照。**
- **同一颜色语义**：升降平缺四色与第 3 节完全一致。
- **同一画法**：都用 `viz.js` + `viz.css`。

## 6. 页面接入方式（三步）

```html
<link rel="stylesheet" href="/algo/_viz/viz.css">
<div data-viz="industry-便利店"></div>
<script src="/algo/_viz/viz-data.js"></script>
<script src="/algo/_viz/industry-model.js"></script>
<script src="/algo/_viz/viz.js"></script>
```

`viz.js` 自动读 `window.VIZ_DATA[key]` 渲染，页面不用写任何画图代码。新增图 = 在 `gen_viz.py` / `gen_model.py` 里加一条数据 + 页面放一个 `data-viz` 容器。

## 7. 自检清单（每加一张图过一遍）

- [ ] 有 `数据来源` + `生成时间` + `实测/示意` 徽章
- [ ] 有图下"这张图说明什么"一句话
- [ ] 纵轴有单位/口径
- [ ] 颜色没跑出第 3 节语义表
- [ ] 研判模型：大曲线能答"由哪几条小曲线带起来"；缺口**是断的**；虚线带方向/依据/置信度/不确定带；下钻可点
- [ ] 1440 与 390 都不横向溢出
- [ ] 控制台 0 报错
- [ ] 回链到 `/life-chain/`
