From 99fb7b844e57fedb0d1d613856a8994f816c01f3 Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Fri, 19 Jun 2026 09:52:45 +0100 Subject: [PATCH 1/9] feat: added scatter summary plot per horizon for all indicators --- rules/cba.smk | 19 +++++ scripts/cba/plot_benchmark_indicators.py | 103 ++++++++++++++++++++++- 2 files changed, 120 insertions(+), 2 deletions(-) diff --git a/rules/cba.smk b/rules/cba.smk index 7baf9ab965..17082188be 100644 --- a/rules/cba.smk +++ b/rules/cba.smk @@ -555,6 +555,18 @@ rule summarize_indicators_per_project: script: "../scripts/cba/summarize_indicators.py" +rule plot_summary_projects_benchmark: + input: + indicators=lambda w: expand( + rules.average_indicators_per_project_and_planning_horizon.output.indicators, + planning_horizons=[w.planning_horizons], + cba_project=cba_projects(w), + run=[w.run], + ), + output: + plot_file=RESULTS + "cba/ensemble_plots/summary_benchmark_{planning_horizons}.png", + script: + "../scripts/cba/plot_benchmark_indicators.py" rule summarize_all_indicators: input: @@ -743,6 +755,13 @@ def cba_ensemble_inputs(w): run=runs, ) ) + inputs.extend( + expand( + rules.plot_summary_projects_benchmark.output.plot_file, + planning_horizons=config["cba"]["planning_horizons"], + run=runs, + ) + ) return inputs diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index b99fe60c82..2d39fc20f0 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -322,6 +322,95 @@ def plot_project_benchmarks( fig.savefig(output_path, dpi=400) plt.close(fig) +def plot_summary_projects_benchmark( + df: pd.DataFrame, + output_path: Path, + planning_horizon: str | None = None, + area_subtitle: str | None = None, +) -> None: + """Plot one summary subplot per indicator for each horizon""" + average_df = df[ + ((df["source"] == "Open-TYNDP") & (df["cyear"] == "weighted-average")) + | (df["source"] == "TYNDP 2024") + ] + if average_df[average_df["source"] == "Open-TYNDP"].empty: + logger.info("No Open-TYNDP weighted-average data to plot") + return + + indicators = sorted( + average_df.loc[average_df["source"] == "Open-TYNDP", "indicator"].dropna().unique() + ) + project_ids = sorted( + average_df.loc[average_df["source"] == "Open-TYNDP", "project_id"].dropna().unique() + ) + + plot_items = {} + for indicator in indicators: + pairs = [] + for project_id in project_ids: + project_df = average_df[average_df["project_id"] == project_id] + model = benchmark_range(project_df, indicator, source="Open-TYNDP") + bench = benchmark_range(project_df, indicator, source="TYNDP 2024") + if model is not None and bench is not None: + pairs.append((bench[1], model[1])) + if pairs: + plot_items[indicator] = pairs + if not plot_items: + logger.info("Incomplete benchmark data to plot") + return + + ncols = min(4, len(plot_items)) + nrows = (len(plot_items) + ncols - 1) // ncols + fig, axes = plt.subplots( + nrows=nrows, + ncols=ncols, + figsize=(3.6 * ncols, 3.3 * nrows), + squeeze=False, + ) + + for ax, (indicator, pairs) in zip(axes.flatten(), plot_items.items()): + xs, ys = zip(*pairs) + ax.scatter( + xs, ys, + s=20, color="tab:blue", alpha=0.6, + edgecolor="white", linewidth=0.5, + ) + ax.axline((0, 0), slope=1, color="black", linestyle="--", linewidth=1, alpha=0.5) + + combined = [abs(v) for v in (*xs, *ys) if v != 0] + if combined: + abs_max = max(combined) + abs_min = min(combined) + if abs_min > 0 and abs_max / abs_min >= 1e3: + linthresh = max(abs_min, 1.0) + ax.set_xscale("symlog", linthresh=linthresh) + ax.set_yscale("symlog", linthresh=linthresh) + + units = average_df.loc[ + (average_df["indicator"] == indicator) & (average_df["source"] == "Open-TYNDP"), "units" + ].dropna() + unit_label = units.iloc[0] if not units.empty else "" + ax.set_title(f"{indicator} ({unit_label})" if unit_label else indicator, fontsize=9) + ax.set_xlabel("TYNDP 2024") + ax.set_ylabel("Open-TYNDP") + ax.axhline(0, color="gray", linewidth=0.5, alpha=0.4) + ax.axvline(0, color="gray", linewidth=0.5, alpha=0.4) + ax.grid(alpha=0.3) + + for ax in axes.flatten()[len(plot_items):]: + ax.axis("off") + + title = "Benchmark of indicators across all projects" + if planning_horizon: + title += f" ({planning_horizon})" + fig.suptitle(title, y=0.995) + if area_subtitle: + fig.text(0.5, 0.965, area_subtitle, ha="center", va="center", fontsize=9) + + fig.tight_layout(rect=[0, 0, 1, 0.94]) + fig.savefig(output_path, dpi=400) + plt.close(fig) + def create_plots(indicators_file, output_path, planning_horizon=None, area=None): """Create benchmark plots from a per-project or collected indicators file.""" @@ -388,6 +477,16 @@ def create_plots(indicators_file, output_path, planning_horizon=None, area=None) set_scenario_config(snakemake) planning_horizon = snakemake.wildcards.get("planning_horizons") - output_target = snakemake.output.get("plot_file") or snakemake.output.plot_dir area = snakemake.config.get("cba", {}).get("area") - create_plots(snakemake.input.indicators, output_target, planning_horizon, area) + + if snakemake.rule == "plot_summary_projects_benchmark": + df = pd.concat(map(pd.read_csv, snakemake.input.indicators), ignore_index=True) + plot_summary_projects_benchmark( + df, + Path(snakemake.output.plot_file), + planning_horizon, + format_area_subtitle(area) + ) + else: + output_target = snakemake.output.get("plot_file") or snakemake.output.plot_dir + create_plots(snakemake.input.indicators, output_target, planning_horizon, area) From d3a8d8c40dd8785a1b0954df4fe57d580ad489fa Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Fri, 19 Jun 2026 10:48:27 +0100 Subject: [PATCH 2/9] refactored main --- scripts/cba/plot_benchmark_indicators.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index 2d39fc20f0..3bc0966248 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -479,14 +479,16 @@ def create_plots(indicators_file, output_path, planning_horizon=None, area=None) planning_horizon = snakemake.wildcards.get("planning_horizons") area = snakemake.config.get("cba", {}).get("area") - if snakemake.rule == "plot_summary_projects_benchmark": + if "cba_project" in snakemake.wildcards.keys(): + output_target = snakemake.output.get("plot_file") or snakemake.output.plot_dir + create_plots(snakemake.input.indicators, output_target, planning_horizon, area) + elif not snakemake.input.indicators: + logger.warning("No indicators input files for summary plot", snakemake.output.plot_file,) + else: df = pd.concat(map(pd.read_csv, snakemake.input.indicators), ignore_index=True) plot_summary_projects_benchmark( df, Path(snakemake.output.plot_file), planning_horizon, format_area_subtitle(area) - ) - else: - output_target = snakemake.output.get("plot_file") or snakemake.output.plot_dir - create_plots(snakemake.input.indicators, output_target, planning_horizon, area) + ) \ No newline at end of file From c32d58f3d2eee1124727aaad40dafb9b607e6951 Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Fri, 19 Jun 2026 11:07:01 +0100 Subject: [PATCH 3/9] fix: b2a societal cost add, with colours --- scripts/cba/plot_benchmark_indicators.py | 32 ++++++++++++++++++------ 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index 3bc0966248..431f15b16b 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -349,10 +349,18 @@ def plot_summary_projects_benchmark( pairs = [] for project_id in project_ids: project_df = average_df[average_df["project_id"] == project_id] - model = benchmark_range(project_df, indicator, source="Open-TYNDP") - bench = benchmark_range(project_df, indicator, source="TYNDP 2024") - if model is not None and bench is not None: - pairs.append((bench[1], model[1])) + if indicator == "B2a_societal_cost_variation": + levels = ["low", "central", "high"] + for level in levels: + model_val = select_value_by_subindex(project_df, indicator, "Open-TYNDP", level) + bench_val = select_value_by_subindex(project_df, indicator, "TYNDP 2024", level) + if model_val is not None and bench_val is not None: + pairs.append((bench_val, model_val, level)) + else: + model = benchmark_range(project_df, indicator, source="Open-TYNDP") + bench = benchmark_range(project_df, indicator, source="TYNDP 2024") + if model is not None and bench is not None: + pairs.append((bench[1], model[1], None)) if pairs: plot_items[indicator] = pairs if not plot_items: @@ -369,10 +377,20 @@ def plot_summary_projects_benchmark( ) for ax, (indicator, pairs) in zip(axes.flatten(), plot_items.items()): - xs, ys = zip(*pairs) + xs = [p[0] for p in pairs] + ys = [p[1] for p in pairs] + if indicator == "B2a_societal_cost_variation": + level_colors = { + "low": "tab:orange", + "central": "tab:green", + "high": "tab:red", + } + colors = [level_colors[level] for _, _, level in pairs] + else: + colors = "tab:blue" ax.scatter( xs, ys, - s=20, color="tab:blue", alpha=0.6, + s=20, color=colors, alpha=0.6, edgecolor="white", linewidth=0.5, ) ax.axline((0, 0), slope=1, color="black", linestyle="--", linewidth=1, alpha=0.5) @@ -483,7 +501,7 @@ def create_plots(indicators_file, output_path, planning_horizon=None, area=None) output_target = snakemake.output.get("plot_file") or snakemake.output.plot_dir create_plots(snakemake.input.indicators, output_target, planning_horizon, area) elif not snakemake.input.indicators: - logger.warning("No indicators input files for summary plot", snakemake.output.plot_file,) + logger.warning("No indicators input files for summary plot: %s", snakemake.output.plot_file) else: df = pd.concat(map(pd.read_csv, snakemake.input.indicators), ignore_index=True) plot_summary_projects_benchmark( From b49d85ba3fe94b1fc36528fa15366da96c8d1d24 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 19 Jun 2026 10:10:16 +0000 Subject: [PATCH 4/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- rules/cba.smk | 5 +- scripts/cba/plot_benchmark_indicators.py | 61 ++++++++++++++++-------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/rules/cba.smk b/rules/cba.smk index 17082188be..e504f711ea 100644 --- a/rules/cba.smk +++ b/rules/cba.smk @@ -555,6 +555,7 @@ rule summarize_indicators_per_project: script: "../scripts/cba/summarize_indicators.py" + rule plot_summary_projects_benchmark: input: indicators=lambda w: expand( @@ -564,10 +565,12 @@ rule plot_summary_projects_benchmark: run=[w.run], ), output: - plot_file=RESULTS + "cba/ensemble_plots/summary_benchmark_{planning_horizons}.png", + plot_file=RESULTS + + "cba/ensemble_plots/summary_benchmark_{planning_horizons}.png", script: "../scripts/cba/plot_benchmark_indicators.py" + rule summarize_all_indicators: input: indicators=lambda w: expand( diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index 431f15b16b..1c59879f29 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -322,11 +322,12 @@ def plot_project_benchmarks( fig.savefig(output_path, dpi=400) plt.close(fig) + def plot_summary_projects_benchmark( - df: pd.DataFrame, - output_path: Path, - planning_horizon: str | None = None, - area_subtitle: str | None = None, + df: pd.DataFrame, + output_path: Path, + planning_horizon: str | None = None, + area_subtitle: str | None = None, ) -> None: """Plot one summary subplot per indicator for each horizon""" average_df = df[ @@ -338,10 +339,14 @@ def plot_summary_projects_benchmark( return indicators = sorted( - average_df.loc[average_df["source"] == "Open-TYNDP", "indicator"].dropna().unique() + average_df.loc[average_df["source"] == "Open-TYNDP", "indicator"] + .dropna() + .unique() ) project_ids = sorted( - average_df.loc[average_df["source"] == "Open-TYNDP", "project_id"].dropna().unique() + average_df.loc[average_df["source"] == "Open-TYNDP", "project_id"] + .dropna() + .unique() ) plot_items = {} @@ -352,11 +357,15 @@ def plot_summary_projects_benchmark( if indicator == "B2a_societal_cost_variation": levels = ["low", "central", "high"] for level in levels: - model_val = select_value_by_subindex(project_df, indicator, "Open-TYNDP", level) - bench_val = select_value_by_subindex(project_df, indicator, "TYNDP 2024", level) + model_val = select_value_by_subindex( + project_df, indicator, "Open-TYNDP", level + ) + bench_val = select_value_by_subindex( + project_df, indicator, "TYNDP 2024", level + ) if model_val is not None and bench_val is not None: pairs.append((bench_val, model_val, level)) - else: + else: model = benchmark_range(project_df, indicator, source="Open-TYNDP") bench = benchmark_range(project_df, indicator, source="TYNDP 2024") if model is not None and bench is not None: @@ -389,11 +398,17 @@ def plot_summary_projects_benchmark( else: colors = "tab:blue" ax.scatter( - xs, ys, - s=20, color=colors, alpha=0.6, - edgecolor="white", linewidth=0.5, + xs, + ys, + s=20, + color=colors, + alpha=0.6, + edgecolor="white", + linewidth=0.5, + ) + ax.axline( + (0, 0), slope=1, color="black", linestyle="--", linewidth=1, alpha=0.5 ) - ax.axline((0, 0), slope=1, color="black", linestyle="--", linewidth=1, alpha=0.5) combined = [abs(v) for v in (*xs, *ys) if v != 0] if combined: @@ -405,17 +420,21 @@ def plot_summary_projects_benchmark( ax.set_yscale("symlog", linthresh=linthresh) units = average_df.loc[ - (average_df["indicator"] == indicator) & (average_df["source"] == "Open-TYNDP"), "units" + (average_df["indicator"] == indicator) + & (average_df["source"] == "Open-TYNDP"), + "units", ].dropna() unit_label = units.iloc[0] if not units.empty else "" - ax.set_title(f"{indicator} ({unit_label})" if unit_label else indicator, fontsize=9) + ax.set_title( + f"{indicator} ({unit_label})" if unit_label else indicator, fontsize=9 + ) ax.set_xlabel("TYNDP 2024") ax.set_ylabel("Open-TYNDP") ax.axhline(0, color="gray", linewidth=0.5, alpha=0.4) ax.axvline(0, color="gray", linewidth=0.5, alpha=0.4) ax.grid(alpha=0.3) - for ax in axes.flatten()[len(plot_items):]: + for ax in axes.flatten()[len(plot_items) :]: ax.axis("off") title = "Benchmark of indicators across all projects" @@ -501,12 +520,14 @@ def create_plots(indicators_file, output_path, planning_horizon=None, area=None) output_target = snakemake.output.get("plot_file") or snakemake.output.plot_dir create_plots(snakemake.input.indicators, output_target, planning_horizon, area) elif not snakemake.input.indicators: - logger.warning("No indicators input files for summary plot: %s", snakemake.output.plot_file) + logger.warning( + "No indicators input files for summary plot: %s", snakemake.output.plot_file + ) else: df = pd.concat(map(pd.read_csv, snakemake.input.indicators), ignore_index=True) plot_summary_projects_benchmark( - df, + df, Path(snakemake.output.plot_file), planning_horizon, - format_area_subtitle(area) - ) \ No newline at end of file + format_area_subtitle(area), + ) From 874b8482da2b905e5745309ece8f837a8aea25a3 Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Fri, 19 Jun 2026 11:15:59 +0100 Subject: [PATCH 5/9] release notes --- doc/release_notes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 05c2ce4933..52e18f3ac7 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -33,6 +33,8 @@ Upcoming Open-TYNDP Release - Add ``include_objective_constant`` and ``assign_all_duals`` to solving config validator. - Add ``gurobi-simplex`` as solver option. +* Add CBA per horizon summary plots for each indicator benchmarking TYNDP and Open-TYNDP (https://github.com/open-energy-transition/open-tyndp/pull/753). + **Bugfixes and Compatibility** **Documentation** From 46b01c80f3bf15e98c57b602ec83ef816cad4a0a Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Tue, 30 Jun 2026 16:04:10 +0100 Subject: [PATCH 6/9] fix: add option for not collection years --- rules/cba.smk | 29 ++++++++++++++++++++---- scripts/cba/plot_benchmark_indicators.py | 16 ++++++++----- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/rules/cba.smk b/rules/cba.smk index e504f711ea..7c09cbb58f 100644 --- a/rules/cba.smk +++ b/rules/cba.smk @@ -556,14 +556,28 @@ rule summarize_indicators_per_project: "../scripts/cba/summarize_indicators.py" -rule plot_summary_projects_benchmark: - input: - indicators=lambda w: expand( +def summary_benchmark_indicators(w): + """ + Returns Indicator CSVs as inputs for the per-horizon summary benchmark plot. + If collection scenarios, returns the weighted-average ensemble indicators CSV as inputs for plotting. + """ + if get_run_name(w) in cba_collection_scenarios(w): + return expand( rules.average_indicators_per_project_and_planning_horizon.output.indicators, planning_horizons=[w.planning_horizons], cba_project=cba_projects(w), run=[w.run], - ), + ) + return expand( + rules.collect_indicators.output.indicators, + planning_horizons=[w.planning_horizons], + run=[w.run], + ) + + +rule plot_summary_projects_benchmark: + input: + indicators=summary_benchmark_indicators, output: plot_file=RESULTS + "cba/ensemble_plots/summary_benchmark_{planning_horizons}.png", @@ -706,6 +720,13 @@ def collect_cba_scenario_inputs(w): run=cba_scenarios(w), ) ) + inputs.extend( + expand( + rules.plot_summary_projects_benchmark.output.plot_file, + planning_horizons=config_provider("cba", "planning_horizons")(w), + run=cba_scenarios(w), + ) + ) run = get_run_name(w) if run in cba_collection_scenarios(w): diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index 1c59879f29..48417fa4b7 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -330,13 +330,17 @@ def plot_summary_projects_benchmark( area_subtitle: str | None = None, ) -> None: """Plot one summary subplot per indicator for each horizon""" - average_df = df[ - ((df["source"] == "Open-TYNDP") & (df["cyear"] == "weighted-average")) - | (df["source"] == "TYNDP 2024") - ] - if average_df[average_df["source"] == "Open-TYNDP"].empty: - logger.info("No Open-TYNDP weighted-average data to plot") + model_df = df[df["source"] == "Open-TYNDP"] + if model_df.empty: + logger.info("No Open-TYNDP data to plot") return + weighted_df = model_df[model_df["cyear"] == "weighted-average"] + if not weighted_df.empty: + model_df = weighted_df + + average_df = pd.concat( + [model_df, df[df["source"] == "TYNDP 2024"]], ignore_index=True + ) indicators = sorted( average_df.loc[average_df["source"] == "Open-TYNDP", "indicator"] From cca9b7677524cbbd73467fadd2601e52e25f77d7 Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Thu, 16 Jul 2026 10:31:48 +0100 Subject: [PATCH 7/9] fix: remove b2a non-central, add stats values box --- scripts/cba/plot_benchmark_indicators.py | 46 +++++++++++++----------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index 48417fa4b7..f5893a4852 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -328,6 +328,7 @@ def plot_summary_projects_benchmark( output_path: Path, planning_horizon: str | None = None, area_subtitle: str | None = None, + eps: float = 1e-6, ) -> None: """Plot one summary subplot per indicator for each horizon""" model_df = df[df["source"] == "Open-TYNDP"] @@ -359,21 +360,19 @@ def plot_summary_projects_benchmark( for project_id in project_ids: project_df = average_df[average_df["project_id"] == project_id] if indicator == "B2a_societal_cost_variation": - levels = ["low", "central", "high"] - for level in levels: - model_val = select_value_by_subindex( - project_df, indicator, "Open-TYNDP", level - ) - bench_val = select_value_by_subindex( - project_df, indicator, "TYNDP 2024", level - ) - if model_val is not None and bench_val is not None: - pairs.append((bench_val, model_val, level)) + model_val = select_value_by_subindex( + project_df, indicator, "Open-TYNDP", "central" + ) + bench_val = select_value_by_subindex( + project_df, indicator, "TYNDP 2024", "central" + ) + if model_val is not None and bench_val is not None: + pairs.append((bench_val, model_val)) else: model = benchmark_range(project_df, indicator, source="Open-TYNDP") bench = benchmark_range(project_df, indicator, source="TYNDP 2024") if model is not None and bench is not None: - pairs.append((bench[1], model[1], None)) + pairs.append((bench[1], model[1])) if pairs: plot_items[indicator] = pairs if not plot_items: @@ -392,15 +391,7 @@ def plot_summary_projects_benchmark( for ax, (indicator, pairs) in zip(axes.flatten(), plot_items.items()): xs = [p[0] for p in pairs] ys = [p[1] for p in pairs] - if indicator == "B2a_societal_cost_variation": - level_colors = { - "low": "tab:orange", - "central": "tab:green", - "high": "tab:red", - } - colors = [level_colors[level] for _, _, level in pairs] - else: - colors = "tab:blue" + colors = "tab:blue" ax.scatter( xs, ys, @@ -438,6 +429,21 @@ def plot_summary_projects_benchmark( ax.axvline(0, color="gray", linewidth=0.5, alpha=0.4) ax.grid(alpha=0.3) + benchmark_df = pd.DataFrame(pairs, columns=["TYNDP 2024", "Open-TYNDP"]) + errors = ( + (benchmark_df["Open-TYNDP"] - benchmark_df["TYNDP 2024"]).abs() + / ((benchmark_df["Open-TYNDP"].abs() + benchmark_df["TYNDP 2024"].abs()) + / 2 + eps) * 100 + ) + values = ( + f"n = {len(pairs)}\n" + f"sMAPE = {errors.mean():.1f}%\n" + f"sMdAPE = {errors.median():.1f}%" + ) + ax.text(0.05, 0.95, values, transform=ax.transAxes, fontsize=6, verticalalignment="top", + bbox=dict(boxstyle="round", facecolor="white", alpha=0.8), + ) + for ax in axes.flatten()[len(plot_items) :]: ax.axis("off") From 69aeffe036fbc62ac3341e21e714ced416f9b038 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 16 Jul 2026 10:03:31 +0000 Subject: [PATCH 8/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- scripts/cba/plot_benchmark_indicators.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/scripts/cba/plot_benchmark_indicators.py b/scripts/cba/plot_benchmark_indicators.py index d7701c1ef6..dc40924ffb 100644 --- a/scripts/cba/plot_benchmark_indicators.py +++ b/scripts/cba/plot_benchmark_indicators.py @@ -461,17 +461,27 @@ def plot_summary_projects_benchmark( benchmark_df = pd.DataFrame(pairs, columns=["TYNDP 2024", "Open-TYNDP"]) errors = ( (benchmark_df["Open-TYNDP"] - benchmark_df["TYNDP 2024"]).abs() - / ((benchmark_df["Open-TYNDP"].abs() + benchmark_df["TYNDP 2024"].abs()) - / 2 + eps) * 100 + / ( + (benchmark_df["Open-TYNDP"].abs() + benchmark_df["TYNDP 2024"].abs()) + / 2 + + eps + ) + * 100 ) values = ( - f"n = {len(pairs)}\n" + f"n = {len(pairs)}\n" f"sMAPE = {errors.mean():.1f}%\n" f"sMdAPE = {errors.median():.1f}%" ) - ax.text(0.05, 0.95, values, transform=ax.transAxes, fontsize=6, verticalalignment="top", - bbox=dict(boxstyle="round", facecolor="white", alpha=0.8), - ) + ax.text( + 0.05, + 0.95, + values, + transform=ax.transAxes, + fontsize=6, + verticalalignment="top", + bbox=dict(boxstyle="round", facecolor="white", alpha=0.8), + ) for ax in axes.flatten()[len(plot_items) :]: ax.axis("off") From f68d2c9ea44560c4acec67c23198698397b9dff1 Mon Sep 17 00:00:00 2001 From: AndreasHD11 Date: Thu, 16 Jul 2026 14:34:37 +0100 Subject: [PATCH 9/9] fix: wildcard was only working if scenarios are enabled --- rules/cba.smk | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/rules/cba.smk b/rules/cba.smk index f257269e54..19f2f67e6b 100644 --- a/rules/cba.smk +++ b/rules/cba.smk @@ -561,17 +561,18 @@ def summary_benchmark_indicators(w): Returns Indicator CSVs as inputs for the per-horizon summary benchmark plot. If collection scenarios, returns the weighted-average ensemble indicators CSV as inputs for plotting. """ - if get_run_name(w) in cba_collection_scenarios(w): + run = get_run_name(w) + if run in cba_collection_scenarios(w): return expand( rules.average_indicators_per_project_and_planning_horizon.output.indicators, planning_horizons=[w.planning_horizons], cba_project=cba_projects(w), - run=[w.run], + run=[run], ) return expand( rules.collect_indicators.output.indicators, planning_horizons=[w.planning_horizons], - run=[w.run], + run=[run], )