- 新增 3.7 地市间对比分析(表 6,8 地市分三梯队,含梯度分析与跨地市验证) - 新增 5.4 实施路线图与风险缓解(表 7 三阶段路线图 + 表 8 六类风险矩阵) - 更新 notebooks/pilot_analysis.md(新增第 9-10 节) - 新增 plots/city_comparison.png + city_comparison.csv + roadmap_data.csv - 更新 processing/validate_data.py(校验扩展至 46 项,全部通过)
122 lines
4.2 KiB
Python
122 lines
4.2 KiB
Python
#!/usr/bin/env python3
|
||
"""生成试点数据分析图表。
|
||
|
||
输出:
|
||
plots/pilot_run_data.png — 各地市预警数据柱状图
|
||
plots/vendor_effort.png — 供应商人天投入饼图
|
||
plots/access_cost.png — 接入链路耗时对比图
|
||
"""
|
||
|
||
import csv
|
||
import os
|
||
import sys
|
||
|
||
import matplotlib
|
||
matplotlib.use("Agg")
|
||
import matplotlib.pyplot as plt
|
||
|
||
PLOT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
|
||
|
||
def load_csv(name):
|
||
path = os.path.join(PLOT_DIR, name)
|
||
with open(path, encoding="utf-8") as f:
|
||
return list(csv.DictReader(f))
|
||
|
||
|
||
def plot_run_data():
|
||
rows = load_csv("pilot_run_data.csv")
|
||
cities = [r["city"] for r in rows]
|
||
alerts = [int(r["alert_count"]) if r["alert_count"] else 0 for r in rows]
|
||
colors = ["#2196F3" if a > 0 else "#BDBDBD" for a in alerts]
|
||
|
||
fig, ax = plt.subplots(figsize=(10, 5))
|
||
bars = ax.bar(cities, alerts, color=colors)
|
||
ax.set_ylabel("累计预警数据(条)")
|
||
ax.set_title("各地市电量突增能力应用预警数据(截至 2026-06-25)")
|
||
for bar, val in zip(bars, alerts):
|
||
if val > 0:
|
||
ax.text(bar.get_x() + bar.get_width() / 2, val + 200,
|
||
f"{val:,}", ha="center", fontsize=9)
|
||
plt.xticks(rotation=30, ha="right")
|
||
plt.tight_layout()
|
||
plt.savefig(os.path.join(PLOT_DIR, "pilot_run_data.png"), dpi=150)
|
||
plt.close()
|
||
|
||
|
||
def plot_vendor_effort():
|
||
rows = load_csv("vendor_effort.csv")
|
||
labels = [r["category"] for r in rows]
|
||
sizes = [int(r["person_days"]) for r in rows]
|
||
|
||
fig, ax = plt.subplots(figsize=(8, 6))
|
||
wedges, texts, autotexts = ax.pie(
|
||
sizes, labels=labels, autopct="%1.0f%%", startangle=140,
|
||
textprops={"fontsize": 9},
|
||
)
|
||
ax.set_title("供应商人天投入结构(合计 100 人天)")
|
||
plt.tight_layout()
|
||
plt.savefig(os.path.join(PLOT_DIR, "vendor_effort.png"), dpi=150)
|
||
plt.close()
|
||
|
||
|
||
def plot_access_cost():
|
||
rows = load_csv("access_cost.csv")
|
||
steps = [r["step"] for r in rows if r["step"] != "端到端合计"]
|
||
ideal = [int(r["ideal_days"]) for r in rows if r["step"] != "端到端合计"]
|
||
actual = [int(r["actual_days"]) for r in rows if r["step"] != "端到端合计"]
|
||
|
||
x = range(len(steps))
|
||
width = 0.35
|
||
fig, ax = plt.subplots(figsize=(10, 5))
|
||
ax.bar([i - width / 2 for i in x], ideal, width, label="理想耗时", color="#4CAF50")
|
||
ax.bar([i + width / 2 for i in x], actual, width, label="实际耗时", color="#FF5722")
|
||
ax.set_ylabel("耗时(工作日)")
|
||
ax.set_title("单地市接入链路耗时:理想 vs 实际")
|
||
ax.set_xticks(x)
|
||
ax.set_xticklabels(steps, rotation=20, ha="right")
|
||
ax.legend()
|
||
plt.tight_layout()
|
||
plt.savefig(os.path.join(PLOT_DIR, "access_cost.png"), dpi=150)
|
||
plt.close()
|
||
|
||
|
||
def plot_city_comparison():
|
||
rows = load_csv("city_comparison.csv")
|
||
cities = [r["city"] for r in rows]
|
||
alerts = [int(r["alert_count"]) for r in rows]
|
||
teams = [r["team"] for r in rows]
|
||
colors = {"第一梯队": "#4CAF50", "第二梯队": "#2196F3", "第三梯队": "#BDBDBD"}
|
||
bar_colors = [colors.get(t, "#999") for t in teams]
|
||
|
||
fig, ax = plt.subplots(figsize=(10, 5))
|
||
bars = ax.bar(cities, alerts, color=bar_colors)
|
||
ax.set_ylabel("累计预警数据(条)")
|
||
ax.set_title("各地市接入阶段与产出对比(截至 2026-06-25)")
|
||
for bar, val, team in zip(bars, alerts, teams):
|
||
if val > 0:
|
||
ax.text(bar.get_x() + bar.get_width() / 2, val + 200,
|
||
f"{val:,}", ha="center", fontsize=9)
|
||
else:
|
||
ax.text(bar.get_x() + bar.get_width() / 2, 200,
|
||
team, ha="center", fontsize=8, color="#666")
|
||
from matplotlib.patches import Patch
|
||
legend = [Patch(facecolor=colors[t], label=t) for t in ["第一梯队", "第二梯队", "第三梯队"]]
|
||
ax.legend(handles=legend, loc="upper right")
|
||
plt.xticks(rotation=30, ha="right")
|
||
plt.tight_layout()
|
||
plt.savefig(os.path.join(PLOT_DIR, "city_comparison.png"), dpi=150)
|
||
plt.close()
|
||
|
||
|
||
def main():
|
||
plot_run_data()
|
||
plot_vendor_effort()
|
||
plot_access_cost()
|
||
plot_city_comparison()
|
||
print("图表已生成:pilot_run_data.png, vendor_effort.png, access_cost.png, city_comparison.png")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|