XIAN-FEM-2026June/3D opticsfem-master/ppt_assets/make_timeline_chart.py

107 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""Gantt-style timeline for 3D OpticsFEM (target: late July 2026)."""
from __future__ import annotations
from datetime import date, timedelta
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.patches as mpatches
OUT = Path(__file__).resolve().parent
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "Arial"]
plt.rcParams["axes.unicode_minus"] = False
GREEN = "#75BD42"
GREEN_D = "#4A7C3F"
BLUE = "#4874CB"
ORANGE = "#EE822F"
GRAY = "#CCCCCC"
DARK = "#2C3E50"
WHITE = "#FFFFFF"
# (label, start, end, color, status)
# status: done | doing | plan | stretch
T0 = date(2026, 6, 1)
ITEMS = [
("阶段0 工程基础", date(2026, 6, 1), date(2026, 6, 15), GREEN, "done"),
("阶段2 PEC/ELE", date(2026, 6, 10), date(2026, 6, 20), GREEN, "done"),
("阶段3 PBC 单/双周期", date(2026, 6, 15), date(2026, 6, 25), GREEN, "done"),
("阶段1 本征频率 Run/Post", date(2026, 6, 23), date(2026, 7, 5), ORANGE, "doing"),
("阶段4 BELE/源项边界", date(2026, 6, 28), date(2026, 7, 12), BLUE, "plan"),
("算例验证 & 文档整理", date(2026, 7, 8), date(2026, 7, 18), BLUE, "plan"),
(".em 接口适配(基础)", date(2026, 7, 10), date(2026, 7, 25), BLUE, "plan"),
("阶段5 PML/Port可选", date(2026, 7, 20), date(2026, 8, 10), GRAY, "stretch"),
("阶段6 本征模式/二阶(可选)", date(2026, 8, 1), date(2026, 8, 31), GRAY, "stretch"),
]
MILESTONES = [
(date(2026, 6, 25), "阶段13\n验收"),
(date(2026, 7, 18), "MVP\n内测"),
(date(2026, 7, 31), "7月下旬\n交付"),
]
def main() -> None:
fig, ax = plt.subplots(figsize=(14, 6.2), facecolor=WHITE)
y = len(ITEMS)
for i, (label, start, end, color, status) in enumerate(ITEMS):
yy = y - i
width = (end - start).days + 1
hatch = "" if status != "stretch" else "///"
alpha = 1.0 if status != "stretch" else 0.55
ax.barh(
yy, width, left=mdates.date2num(start), height=0.55,
color=color, edgecolor=DARK, linewidth=0.8,
hatch=hatch, alpha=alpha,
)
mid = start + timedelta(days=width // 2)
ax.text(
mdates.date2num(mid), yy, label,
ha="center", va="center", fontsize=9.5,
color=WHITE if status in ("done", "doing") else DARK,
fontweight="bold" if status == "doing" else "normal",
)
for ms_date, ms_text in MILESTONES:
x = mdates.date2num(ms_date)
ax.axvline(x, color="#C0392B", ls="--", lw=1.2, alpha=0.75, zorder=0)
ax.text(x, y + 0.55, ms_text, ha="center", va="bottom", fontsize=8.5,
color="#C0392B", fontweight="bold")
ax.set_yticks([])
ax.set_ylim(0.3, y + 1.2)
ax.set_xlim(mdates.date2num(date(2026, 5, 28)), mdates.date2num(date(2026, 9, 5)))
ax.xaxis.set_major_locator(mdates.WeekdayLocator(byweekday=mdates.MO, interval=1))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%m/%d"))
ax.xaxis.set_minor_locator(mdates.DayLocator(interval=1))
ax.grid(axis="x", alpha=0.25, ls="--")
ax.spines["top"].set_visible(False)
ax.spines["right"].set_visible(False)
ax.spines["left"].set_visible(False)
ax.set_title(
"OpticsFEM 3D 扩展 — 时间节点规划目标2026年7月下旬交付",
fontsize=14, fontweight="bold", color=DARK, pad=14,
)
legend_items = [
mpatches.Patch(facecolor=GREEN, edgecolor=DARK, label="已完成"),
mpatches.Patch(facecolor=ORANGE, edgecolor=DARK, label="进行中"),
mpatches.Patch(facecolor=BLUE, edgecolor=DARK, label="7月计划"),
mpatches.Patch(facecolor=GRAY, edgecolor=DARK, hatch="///", alpha=0.55, label="8月及以后扩展"),
]
ax.legend(handles=legend_items, loc="lower right", fontsize=9, framealpha=0.95)
out = OUT / "timeline_july2026.png"
fig.savefig(out, dpi=180, bbox_inches="tight", facecolor=WHITE)
plt.close(fig)
print(f"Saved {out}")
if __name__ == "__main__":
main()