# -*- coding: utf-8 -*- # SPDX-FileCopyrightText: : 2017-2023 The PyPSA-Eur Authors # # SPDX-License-Identifier: MIT """ Plots energy and cost summaries for solved networks. Relevant Settings ----------------- Inputs ------ Outputs ------- Description ----------- """ import logging import os import matplotlib.pyplot as plt import pandas as pd from _helpers import configure_logging logger = logging.getLogger(__name__) def rename_techs(label): if "H2" in label: label = "hydrogen storage" elif label == "solar": label = "solar PV" elif label == "offwind-ac": label = "offshore wind ac" elif label == "offwind-dc": label = "offshore wind dc" elif label == "onwind": label = "onshore wind" elif label == "ror": label = "hydroelectricity" elif label == "hydro": label = "hydroelectricity" elif label == "PHS": label = "hydroelectricity" elif "battery" in label: label = "battery storage" return label preferred_order = pd.Index( [ "transmission lines", "hydroelectricity", "hydro reservoir", "run of river", "pumped hydro storage", "onshore wind", "offshore wind ac", "offshore wind dc", "solar PV", "solar thermal", "OCGT", "hydrogen storage", "battery storage", ] ) def plot_costs(infn, config, fn=None): ## For now ignore the simpl header cost_df = pd.read_csv(infn, index_col=list(range(3)), header=[1, 2, 3]) df = cost_df.groupby(cost_df.index.get_level_values(2)).sum() # convert to billions df = df / 1e9 df = df.groupby(df.index.map(rename_techs)).sum() to_drop = df.index[df.max(axis=1) < config["plotting"]["costs_threshold"]] print("dropping") print(df.loc[to_drop]) df = df.drop(to_drop) print(df.sum()) new_index = (preferred_order.intersection(df.index)).append( df.index.difference(preferred_order) ) new_columns = df.sum().sort_values().index fig, ax = plt.subplots() fig.set_size_inches((12, 8)) df.loc[new_index, new_columns].T.plot( kind="bar", ax=ax, stacked=True, color=[config["plotting"]["tech_colors"][i] for i in new_index], ) handles, labels = ax.get_legend_handles_labels() handles.reverse() labels.reverse() ax.set_ylim([0, config["plotting"]["costs_max"]]) ax.set_ylabel("System Cost [EUR billion per year]") ax.set_xlabel("") ax.grid(axis="y") ax.legend(handles, labels, ncol=4, loc="upper left") fig.tight_layout() if fn is not None: fig.savefig(fn, transparent=True) def plot_energy(infn, config, fn=None): energy_df = pd.read_csv(infn, index_col=list(range(2)), header=[1, 2, 3]) df = energy_df.groupby(energy_df.index.get_level_values(1)).sum() # convert MWh to TWh df = df / 1e6 df = df.groupby(df.index.map(rename_techs)).sum() to_drop = df.index[df.abs().max(axis=1) < config["plotting"]["energy_threshold"]] print("dropping") print(df.loc[to_drop]) df = df.drop(to_drop) print(df.sum()) new_index = (preferred_order.intersection(df.index)).append( df.index.difference(preferred_order) ) new_columns = df.columns.sort_values() fig, ax = plt.subplots() fig.set_size_inches((12, 8)) df.loc[new_index, new_columns].T.plot( kind="bar", ax=ax, stacked=True, color=[config["plotting"]["tech_colors"][i] for i in new_index], ) handles, labels = ax.get_legend_handles_labels() handles.reverse() labels.reverse() ax.set_ylim([config["plotting"]["energy_min"], config["plotting"]["energy_max"]]) ax.set_ylabel("Energy [TWh/a]") ax.set_xlabel("") ax.grid(axis="y") ax.legend(handles, labels, ncol=4, loc="upper left") fig.tight_layout() if fn is not None: fig.savefig(fn, transparent=True) if __name__ == "__main__": if "snakemake" not in globals(): from _helpers import mock_snakemake snakemake = mock_snakemake( "plot_summary", summary="energy", simpl="", clusters=5, ll="copt", opts="Co2L-24H", attr="", ext="png", country="all", ) configure_logging(snakemake) config = snakemake.config summary = snakemake.wildcards.summary try: func = globals()[f"plot_{summary}"] except KeyError: raise RuntimeError(f"plotting function for {summary} has not been defined") func( os.path.join(snakemake.input[0], f"{summary}.csv"), config, snakemake.output[0] )