# -*- coding: utf-8 -*-
"""ICM 2023 F 配图：24 张 SVG，复用 _svg 基元，输出到 papers/。
视角划分：Paper1 口径构建与全球减缓模型 / Paper2 巴西深析与抵抗分布 / Paper3 稳健性与政策建议。
"""
import os
import math
import xml.dom.minidom
import gen_icm2023f as G

HERE = os.path.dirname(os.path.abspath(__file__))
OUT = os.path.normpath(os.path.join(HERE, "..", "assets", "problems", "papers"))
os.makedirs(OUT, exist_ok=True)

from _svg import (_fig, _save, _bar, _grouped_bar, _line, _scatter, _pie,
                  _heatmap, _network, _flow, _txt, C_RED, C_GREEN, C_ACC, C_CYAN,
                  C_AMB, C_PUR, C_TEAL, C_PINK, C_MUT, C_TXT, C_GRID, PALETTE)

C_BLUE = C_ACC
C_AMBER = C_AMB
C_PURPLE = C_PUR
D = G.gen_icm2023f()
rows = D["rows"]
scen = D["scenarios"]
by_region = D["by_region"]
regions = D["regions"]
corr = D["corr"]
sens = D["sens"]
br = D["brazil"]
worth = D["worth_it"]
PHIS = D["PHIS"]
REGION_CN = D["REGION_CN"]

SHORT = {r["id"]: r["name"].split()[-1].replace(".", "") for r in rows}
NAMES = {r["id"]: r["name"] for r in rows}
REGION_COLOR = {"美洲": C_GREEN, "亚洲": C_RED, "欧洲": C_BLUE, "非洲": C_AMBER,
                "大洋洲": C_TEAL, "中东": C_PURPLE}


def _by_id(i):
    return next(r for r in rows if r["id"] == i)


def _save_check(name, svg):
    xml.dom.minidom.parseString(svg)
    _save(os.path.join(OUT, name), svg)
    return name


# ---------- 自定义：侵蚀/分解柱（GDP 被 D_res/D_env 侵蚀 -> GGDP） ----------
def _erosion(title, items, W=760, H=440, note=""):
    """items: [(code, gdp, d_res, d_env, ggd)]"""
    n = len(items)
    bw = (W - 140) / (n + 1)
    body = ""
    for i, (code, gdp, dr, de, ggd) in enumerate(items):
        x = 60 + (i + 1) * bw
        mx = max(gdp for _, gdp, _, _, _ in items) * 1.05
        if mx <= 0:
            mx = 1
        y0 = H - 100
        full_h = (gdp / mx) * (H - 175)
        ggd_h = (ggd / mx) * (H - 175)
        d_h = full_h - ggd_h
        # 全量轮廓
        body += '<rect x="%g" y="%g" width="%g" height="%g" fill="#eef2ff" stroke="%s" stroke-width="1.5"/>\n' % (x, y0 - full_h, bw, full_h, C_BLUE)
        # GGDP 实填（底部）
        body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" rx="2"/>\n' % (x, y0 - ggd_h, bw, ggd_h, C_BLUE)
        # 被侵蚀段（顶部红）
        body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" opacity="0.85"/>\n' % (x, y0 - full_h, bw, d_h, C_RED)
        body += _txt(x + bw / 2, y0 - full_h - 6, "%.2f" % gdp, 10, C_MUT)
        body += _txt(x + bw / 2, y0 - ggd_h - 6, "%.2f" % ggd, 11, C_BLUE, "middle", "700")
        body += _txt(x + bw / 2, y0 + 16, code, 10, C_TXT)
    body += _txt(120, 57, "■ GGDP(实填)  ■ 自然资本损耗 D_res+D_env(红)", 11, C_TXT, "start")
    if note:
        body += _txt(W / 2, H - 14, note, 11, C_MUT)
    return _fig(title, body, W, H)


# ---------- 自定义：敏感性 tornado（水平） ----------
def _tornado(title, sens_list, W=760, H=440):
    body = ""
    n = len(sens_list)
    x0, x1 = 110, W - 60
    vals = [s["base"] for s in sens_list] + [s["low"] for s in sens_list] + [s["high"] for s in sens_list]
    vmin, vmax = min(vals), max(vals)
    lo, hi = vmin * 0.95, vmax * 1.05
    if hi == lo:
        hi = lo + 1
    def SX(v):
        return x0 + (v - lo) / (hi - lo) * (x1 - x0)
    y0 = 90
    rh = (H - 150) / n
    base_x = SX(sens_list[0]["base"])
    for g in range(5):
        gy = y0 + g / 4 * (H - 150 - y0)
        body += '<line x1="%g" y1="%g" x2="%g" y2="%g" stroke="%s" stroke-width="1" stroke-dasharray="3 3"/>\n' % (x0, gy, x1, gy, C_GRID)
        body += _txt(x0 - 6, gy + 4, "%.3f" % (hi - g / 4 * (hi - lo)), 10, C_MUT, "end")
    for i, s in enumerate(sens_list):
        cy = y0 + i * rh + rh / 2
        bx = SX(s["base"])
        lx = SX(s["low"]); hx = SX(s["high"])
        body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" opacity="0.55" rx="2"/>\n' % (min(lx, hx), cy - rh * 0.32, abs(hx - lx), rh * 0.64, C_AMBER)
        body += '<line x1="%g" y1="%g" x2="%g" y2="%g" stroke="%s" stroke-width="2.5"/>\n' % (bx, cy - rh * 0.4, bx, cy + rh * 0.4, C_RED)
        body += _txt(x0 - 8, cy + 4, s["param"], 11, C_TXT, "end")
        body += _txt(x1 + 4, cy + 4, "[%.3f, %.3f]" % (s["low"], s["high"]), 10, C_MUT, "start")
    body += _txt((x0 + x1) / 2, H - 14, "红竖线=基准ΔT；琥珀条=参数±20%区间（°C）", 11, C_MUT)
    return _fig(title, body, W, H)


# ============ Paper 1：口径构建与全球减缓模型 ============
def f1_1():
    picks = ["美国 USA", "中国 China", "巴西 Brazil", "沙特 Saudi", "瑞士 Switzerland", "澳大利亚 Australia"]
    items = []
    for nm in picks:
        r = next(x for x in rows if x["name"] == nm)
        items.append((r["name"].split()[-1].replace(".", ""), r["gdp"], r["d_res"], r["d_env"], r["ggd"]))
    return _erosion("图1 代表国 GGDP 分解：GDP 被自然资本损耗侵蚀为 GGDP", items,
                    note="红段=D_res+D_env（资源耗减+环境退化）；蓝段=GGDP（绿色比 1−res−env）")


def f1_2():
    s = sorted(rows, key=lambda r: r["rank_drop"], reverse=True)
    labels = [SHORT[r["id"]] for r in s]
    vals = [r["rank_drop"] for r in s]
    W, H = 760, 440
    n = len(vals)
    bw = (W - 140) / (n + 1)
    body = ""
    y0 = H - 95
    mx = max(max(vals), abs(min(vals)), 0.1)
    scale = (H - 175) / (2 * mx)
    zero = y0 - (H - 175) / 2
    body += '<line x1="%g" y1="%g" x2="%g" y2="%g" stroke="%s" stroke-width="2"/>\n' % (60, zero, W - 60, zero, "#9ca3af")
    for i, v in enumerate(vals):
        x = 60 + (i + 1) * bw
        h = v * scale
        if v >= 0:
            body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" rx="2"/>\n' % (x, zero - h, bw, h, C_RED)
            body += _txt(x + bw / 2, zero - h - 4, "%.1f" % v, 8, C_MUT)
        else:
            body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" rx="2"/>\n' % (x, zero, bw, -h, C_GREEN)
            body += _txt(x + bw / 2, zero + (-h) + 10, "%.1f" % v, 8, C_MUT)
        body += _txt(x + bw / 2, y0 + 12, labels[i], 8, C_TXT)
    body += _txt(120, 57, "■ 排名下降(红)  ■ 排名上升(绿)", 11, C_TXT, "start")
    body += _txt(W / 2, H - 14, "零线上方=相对地位受损，下方=受益（清洁国小幅上升）", 11, C_MUT)
    return _fig("图2 各国排名变化（GGDP 相对 GDP 的位次变动）", body, W, H)


def f1_3():
    s = sorted(rows, key=lambda r: r["ci"], reverse=True)[:12]
    labels = [SHORT[r["id"]] for r in s]
    vals = [r["ci"] for r in s]
    colors = [REGION_COLOR[r["region"]] for r in s]
    return _bar("图3 碳强度 TOP12（CO2/GDP，Gt/万亿$，按区域着色）", labels, vals, colors, fmt="%.3f")


def f1_4():
    phis = PHIS
    dC = [scen[p]["dC_global"] for p in phis]
    dT = [scen[p]["dT"] for p in phis]
    # 双轴：柱=ΔC(左)，折线=ΔT(右)
    W, H = 760, 440
    x0, x1 = 90, W - 60
    y0, y1 = H - 90, 70
    mxC = max(dC) * 1.15
    mxT = max(dT) * 1.4
    bw = 90
    body = ""
    for g in range(5):
        gy = y1 + g / 4 * (y0 - y1)
        body += '<line x1="%g" y1="%g" x2="%g" y2="%g" stroke="%s" stroke-width="1" stroke-dasharray="3 3"/>\n' % (x0, gy, x1, gy, C_GRID)
        body += _txt(x0 - 8, gy + 4, "%.0f" % (mxC - g / 4 * mxC), 10, C_MUT, "end")
    for i, p in enumerate(phis):
        cx = x0 + 120 + i * 180
        hC = (dC[i] / mxC) * (y0 - y1)
        body += '<rect x="%g" y="%g" width="%g" height="%g" fill="%s" rx="3"/>\n' % (cx - bw / 2, y0 - hC, bw, hC, C_BLUE)
        body += _txt(cx, y0 - hC - 6, "%.0f" % dC[i], 11, C_BLUE, "middle", "700")
    # ΔT 折线（右轴）
    poly = []
    for i, p in enumerate(phis):
        cx = x0 + 120 + i * 180
        sy = y1 + (1 - dT[i] / mxT) * (y0 - y1)
        poly.append((cx, sy))
    body += '<polyline points="%s" fill="none" stroke="%s" stroke-width="2.5"/>\n' % (" ".join("%g,%g" % (a, b) for a, b in poly), C_RED)
    for i, (a, b) in enumerate(poly):
        body += '<circle cx="%g" cy="%g" r="4" fill="%s"/>\n' % (a, b, C_RED)
        body += _txt(a, b - 12, "%.3f°C" % dT[i], 10, C_RED, "middle", "700")
    for i, p in enumerate(phis):
        cx = x0 + 120 + i * 180
        body += _txt(cx, y0 + 18, "φ=%.1f" % p, 11, C_TXT)
    body += _txt(120, 57, "■ ΔC 累计避免CO2(Gt,左轴)", 11, C_BLUE, "start")
    body += _txt(320, 57, "● ΔT 增温放缓(°C,右轴)", 11, C_RED, "start")
    body += _txt(W / 2, H - 14, "全球采纳比例越高，气候减缓影响越大（线性可辩护）", 11, C_MUT)
    return _fig("图4 全球减缓影响随采纳比例 φ 的变化（ΔC 与 ΔT）", body, W, H)


def f1_5():
    phis = PHIS
    benefit = [scen[p]["benefit"] / 1e12 for p in phis]
    cost = [scen[p]["cost"] / 1e12 for p in phis]
    net = [scen[p]["net"] / 1e12 for p in phis]
    groups = ["φ=0.3", "φ=0.6", "φ=1.0"]
    cats = ["气候效益", "转轨成本", "净收益"]
    vals = [[benefit[0], cost[0], net[0]], [benefit[1], cost[1], net[1]], [benefit[2], cost[2], net[2]]]
    svg = _grouped_bar("图5 气候效益 vs 转轨成本 vs 净收益（单位：万亿美元）", groups, cats, vals, fmt="%.2f")
    return svg


def f1_6():
    return _tornado("图6 敏感性 tornado：ΔT(φ=1) 对各参数 ±20% 的响应（°C）", sens)


def f1_7():
    return _flow("图7 方法论流程：从口径选择到一页报告", [
        ("选口径", "SEEA式\nGGDP"),
        ("建模型", "减排响应\nr=R·φ·s"),
        ("估全球影响", "ΔC/ΔT/$"),
        ("值得性", "BCR=39"),
        ("国别深析", "巴西"),
        ("一页报告", "致领导人"),
    ])


def f1_8():
    groups = [REGION_CN[r] for r in regions]
    cats = ["均值绿色比", "均值抵抗"]
    vals = [[by_region[r]["mean_green"], by_region[r]["mean_resist"]] for r in regions]
    return _grouped_bar("图8 各区域绿色比（清洁度）与抵抗指数对比", groups, cats, vals, fmt="%.3f")


# ============ Paper 2：巴西深析与抵抗分布 ============
def f2_1():
    items = [(SHORT[br["id"]], br["gdp"], br["d_res"], br["d_env"], br["ggd"])]
    return _erosion("图1 巴西 GGDP 分解：2.00 万亿$ GDP 中 0.42 万亿$ 为自然资本损耗", items,
                    note="绿色比=0.790；D_env=0.240(含森林退减) 高于 D_res=0.180")


def f2_2():
    peers = ["加拿大 Canada", "俄罗斯 Russia", "韩国 S.Korea", "澳大利亚 Australia", "墨西哥 Mexico", "西班牙 Spain", "巴西 Brazil", "意大利 Italy"]
    items = []
    for nm in peers:
        r = next(x for x in rows if x["name"] == nm)
        items.append((r["name"].split()[-1].replace(".", ""), r["gdp"], r["d_res"], r["d_env"], r["ggd"]))
    return _erosion("图2 巴西与同量级经济体绿色比对比（红段越小越清洁）", items,
                    note="巴西红段占比 21%，高于多数同量级国家 → 自然资本依赖高")


def f2_3():
    yrs = list(range(0, 28))
    bau, ggd = [], []
    for t in yrs:
        bau.append((2023 + t, 0.48 * (1.015 ** t)))
        ggd.append((2023 + t, 0.48 - (0.48 - br["baa_emis"]) * (min(t, 12) / 12.0)))
    return _line("图3 巴西排放路径：BAU 缓增 vs GGDP 稳态下降", [
        ("BAU(维持GDP导向)", C_RED, bau),
        ("GGDP导向(稳态0.40 Gt)", C_GREEN, ggd),
    ], xlabel="年份", ylabel="年排放 Gt/yr")


def f2_4():
    s = sorted(rows, key=lambda r: r["resist"], reverse=True)[:12]
    labels = [SHORT[r["id"]] for r in s]
    vals = [r["resist"] for r in s]
    colors = [REGION_COLOR[r["region"]] for r in s]
    return _bar("图4 抵抗指数 TOP12（res+env，越高越倾向抵制转轨）", labels, vals, colors, fmt="%.3f")


def f2_5():
    series = []
    for rg in regions:
        pts = [(r["dev"], r["green"]) for r in rows if r["region"] == rg]
        series.append((REGION_CN[rg], REGION_COLOR[rg], pts))
    return _scatter("图5 发展指数 vs 绿色比（按区域着色，清洁国居上）", series,
                    xlabel="发展指数 dev", ylabel="绿色比 green_ratio")


def f2_6():
    labels = [REGION_CN[r] for r in regions]
    vals = [by_region[r]["avoided_full"] for r in regions]
    colors = [REGION_COLOR[r] for r in regions]
    return _bar("图6 各区域满采纳累计避免 CO2（Gt，亚洲贡献最大）", labels, vals, colors, fmt="%.1f")


def f2_7():
    series = [("抵抗 vs 排名下降", C_PURPLE, [(r["resist"], r["rank_drop"]) for r in rows])]
    return _scatter("图7 抵抗指数 vs 排名下降（相关 0.57，资源国受损更明显）", series,
                    xlabel="抵抗指数 resist", ylabel="排名下降 rank_drop")


def f2_8():
    return _flow("图8 国别深析流程：巴西", [
        ("选巴西", "森林/资源\n依赖高"),
        ("算GGDP", "1.58万亿$"),
        ("排放路径", "BAU vs GGDP"),
        ("成本效益", "净$1.0e11"),
        ("一页报告", "建议采用"),
    ])


# ============ Paper 3：稳健性与政策建议 ============
def f3_1():
    phis = PHIS
    dT = [scen[p]["dT"] for p in phis]
    base = dT[2]
    lo = [base * 0.8 * (p / 1.0) for p in phis]
    hi = [base * 1.2 * (p / 1.0) for p in phis]
    W, H = 760, 440
    x0, x1 = 90, W - 60
    y0, y1 = H - 90, 70
    mx = max(hi) * 1.15
    if mx <= 0:
        mx = 1
    body = ""
    for g in range(5):
        gy = y1 + g / 4 * (y0 - y1)
        body += '<line x1="%g" y1="%g" x2="%g" y2="%g" stroke="%s" stroke-width="1" stroke-dasharray="3 3"/>\n' % (x0, gy, x1, gy, C_GRID)
        body += _txt(x0 - 8, gy + 4, "%.3f" % (mx - g / 4 * mx), 10, C_MUT, "end")
    xs = [x0 + 120 + i * 180 for i in range(len(phis))]
    # 不确定带
    poly = " ".join("%g,%g" % (xs[i], y1 + (1 - hi[i] / mx) * (y0 - y1)) for i in range(len(phis)))
    poly += " " + " ".join("%g,%g" % (xs[i], y1 + (1 - lo[i] / mx) * (y0 - y1)) for i in range(len(phis) - 1, -1, -1))
    body += '<polygon points="%s" fill="%s" opacity="0.20"/>\n' % (poly, C_AMBER)
    body += '<polyline points="%s" fill="none" stroke="%s" stroke-width="2.5"/>\n' % (" ".join("%g,%g" % (xs[i], y1 + (1 - dT[i] / mx) * (y0 - y1)) for i in range(len(phis))), C_RED)
    for i in range(len(phis)):
        body += '<circle cx="%g" cy="%g" r="4" fill="%s"/>\n' % (xs[i], y1 + (1 - dT[i] / mx) * (y0 - y1), C_RED)
        body += _txt(xs[i], y0 + 18, "φ=%.1f" % phis[i], 11, C_TXT)
        body += _txt(xs[i], y1 + (1 - dT[i] / mx) * (y0 - y1) - 10, "%.3f°C" % dT[i], 10, C_RED, "middle", "700")
    body += _txt(120, 57, "红=基准ΔT；琥珀带=参数±20%不确定区间", 11, C_TXT, "start")
    body += _txt(W / 2, H - 14, "即使参数全面保守(−20%)，ΔT 仍达 0.07°C（正向且显著）", 11, C_MUT)
    return _fig("图1 增温放缓 ΔT 的不确定性带（参数 ±20%）", body, W, H)


def f3_2():
    series = [("碳强度 vs 敏感系数", C_TEAL, [(r["ci"], r["sens"]) for r in rows])]
    return _scatter("图2 碳强度 vs 减排敏感系数（相关 0.67，机制成立）", series,
                    xlabel="碳强度 CO2/GDP", ylabel="敏感系数 s")


def f3_3():
    picks = ["瑞士 Switzerland", "巴西 Brazil", "沙特 Saudi"]
    labels = [next(x for x in rows if x["name"] == nm)["name"].split()[-1].replace(".", "") for nm in picks]
    res = [next(x for x in rows if x["name"] == nm)["res"] for nm in picks]
    env = [next(x for x in rows if x["name"] == nm)["env"] for nm in picks]
    vals = [[res[i], env[i]] for i in range(len(picks))]
    return _grouped_bar("图3 自然资本依赖度对比（res / env 占比，巴西 21%% 居前）", labels, ["资源耗减res", "环境退化env"], vals, fmt="%.3f")


def f3_4():
    labels = ["巴西气候效益", "巴西转轨成本", "巴西净收益"]
    vals = [br["benefit"] / 1e8, br["cost"] / 1e8, br["net"] / 1e8]
    colors = [C_GREEN, C_RED, C_BLUE]
    return _bar("图4 巴西成本效益（单位：亿$）", labels, vals, colors, fmt="%.1f")


def f3_5():
    # 一页非技术报告 flyer（560×760）
    W, H = 560, 760
    body = ""
    body += '<rect x="0" y="0" width="%d" height="%d" fill="#f8fafc"/>\n' % (W, H)
    body += '<rect x="0" y="0" width="%d" height="70" fill="%s"/>\n' % (W, C_GREEN)
    body += _txt(W / 2, 30, "一页非技术报告 · 致巴西领导人", 18, "#ffffff", "middle", "700")
    body += _txt(W / 2, 52, "关于采用绿色 GDP（GGDP）作为国家经济健康主要指标的建议", 11, "#e8f5e9", "middle")
    # 现状
    y = 100
    body += _txt(28, y, "一、现状：今天的 GDP 隐瞒了自然资本的代价", 14, C_TXT, "start", "700"); y += 26
    body += _txt(28, y, "巴西 GDP 约 2.00 万亿$，但其中 0.42 万亿$（21%）来自森林与", 12, C_MUT, "start"); y += 20
    body += _txt(28, y, "资源耗减——这部分在 GDP 里被记为“增长”，实则透支未来。", 12, C_MUT, "start"); y += 30
    # 问题
    body += _txt(28, y, "二、问题：继续以 GDP 为纲的代价", 14, C_TXT, "start", "700"); y += 26
    body += _txt(28, y, "· 森林退减推高短期 GDP，却削弱气候韧性与长期福祉；", 12, C_MUT, "start"); y += 20
    body += _txt(28, y, "· 我们的碳强度（0.24 Gt/万亿$）高于多数同量级国家。", 12, C_MUT, "start"); y += 30
    # 建议
    body += _txt(28, y, "三、建议：采用 GGDP", 14, C_GREEN, "start", "700"); y += 26
    body += _txt(28, y, "· 把森林与资源损耗计入核算，让“保护”成为“增长”；", 12, C_MUT, "start"); y += 20
    body += _txt(28, y, "· 模型显示：满采纳可使巴西年排放降 16%、累计避免 2.1 Gt，", 12, C_MUT, "start"); y += 20
    body += _txt(28, y, "  净收益约 1000 亿美元，远超转轨成本（约 37 亿美元）。", 12, C_MUT, "start"); y += 30
    # 行动
    body += _txt(28, y, "四、三步走行动", 14, C_TXT, "start", "700"); y += 26
    body += _txt(28, y, "1) 建立森林与碳账户的官方 GGDP 卫星账户；", 12, C_MUT, "start"); y += 20
    body += _txt(28, y, "2) 将 GGDP 用于保护区与农业补贴的绩效评估；", 12, C_MUT, "start"); y += 20
    body += _txt(28, y, "3) 在国际谈判中以 GGDP 争取气候资金与公允排名。", 12, C_MUT, "start"); y += 34
    # 结论框
    body += '<rect x="28" y="%g" width="%d" height="60" rx="8" fill="#e8f5e9" stroke="%s" stroke-width="2"/>\n' % (y, W - 56, C_GREEN)
    body += _txt(40, y + 24, "结论：建议巴西支持并率先采用 GGDP，", 13, C_GREEN, "start", "700")
    body += _txt(40, y + 44, "把自然资本变成国家竞争力的新引擎。", 13, C_GREEN, "start", "700")
    body += _txt(W - 28, H - 20, "数据：本站合成演示模型（SEED 2023）", 9, C_MUT, "end")
    return _fig("图5 一页非技术报告（致巴西领导人）", body, W, H)


def f3_6():
    labels = [REGION_CN[r] for r in regions]
    vals = [by_region[r]["avoided_full"] for r in regions]
    colors = [REGION_COLOR[r] for r in regions]
    total = sum(vals)
    pct = [v / total * 100 for v in vals]
    svg = _bar("图6 各区域减缓贡献占比（亚洲主导，占 %.0f%%）" % pct[labels.index("亚洲")],
               labels, vals, colors, fmt="%.1f")
    return svg


def f3_7():
    yrs = list(range(0, 28))
    series = []
    for p in PHIS:
        dCg = scen[p]["dC_global"]
        series.append(("φ=%.1f" % p, C_BLUE if p == 0.3 else (C_AMBER if p == 0.6 else C_RED),
                       [(2023 + t, dCg * (t / 27.0)) for t in yrs]))
    return _line("图7 累计避免 CO2 随时间的情景累积（至 2050）", series, xlabel="年份", ylabel="累计避免 Gt CO2")


def f3_8():
    return _flow("图8 治理闭环：采用—激励—核算—补偿—迭代", [
        ("采用GGDP", "替换头条\n指标"),
        ("激励减排", "压降 D_env"),
        ("监测核算", "卫星账户"),
        ("抵抗补偿", "公正转轨\n基金"),
        ("迭代优化", "灵敏度\n复盘"),
    ])


# ---------------------------------------------------------------------------
JOBS = [f1_1, f1_2, f1_3, f1_4, f1_5, f1_6, f1_7, f1_8,
        f2_1, f2_2, f2_3, f2_4, f2_5, f2_6, f2_7, f2_8,
        f3_1, f3_2, f3_3, f3_4, f3_5, f3_6, f3_7, f3_8]


def main():
    bad = 0
    for i, job in enumerate(JOBS, 1):
        try:
            svg = job()
            name = "icm2023f-%d-fig%d.svg" % ((i - 1) // 8 + 1, (i - 1) % 8 + 1)
            _save_check(name, svg)
        except Exception as e:
            bad += 1
            print("FAIL", i, job.__name__, e)
    print("icm2023f figures: %d generated, %d bad" % (len(JOBS), bad))


if __name__ == "__main__":
    main()
