diff --git a/config/config.kpi.yaml b/config/config.kpi.yaml index bfc44d901..59bc3f8f2 100644 --- a/config/config.kpi.yaml +++ b/config/config.kpi.yaml @@ -3,6 +3,7 @@ # SPDX-License-Identifier: CC0-1.0 kpi: + enable_latex: True filter_scheme: # Create your own custom filtering schemes during the filter_and_rename() section. # The naming convention must be in nice names. diff --git a/rules/postprocess.smk b/rules/postprocess.smk index ca749b7a1..114f90af5 100644 --- a/rules/postprocess.smk +++ b/rules/postprocess.smk @@ -26,6 +26,7 @@ if config["foresight"] != "perfect": rule plot_power_network: params: plotting=config_provider("plotting"), + kpi=config_provider("kpi"), input: network=RESULTS + "postnetworks/base_s_{clusters}_l{ll}_{opts}_{sector_opts}_{planning_horizons}.nc", diff --git a/scripts/plot_KPIs.py b/scripts/plot_KPIs.py index db862b5ce..738c8c628 100644 --- a/scripts/plot_KPIs.py +++ b/scripts/plot_KPIs.py @@ -22,18 +22,15 @@ import pandas as pd import pypsa from matplotlib import rc -from plot_power_network import load_projection +from plot_power_network import load_projection, test_and_enable_latex from matplotlib.colors import Normalize from plot_summary import preferred_order -from pypsa.statistics import get_bus_and_carrier_and_bus_carrier, get_country_and_carrier from plot_validation_cross_border_flows import sort_one_country, color_country import country_converter as coco + cc = coco.CountryConverter() -# activate latex text rendering -rc('text', usetex=True) -rc('font', **{'family': 'serif', 'serif': ['Computer Modern Roman'], 'sans-serif': ['Computer Modern Sans serif']}) rc('axes', **{'edgecolor': 'None', 'titlesize': 18,'titleweight': 'bold', "labelsize": 14}) rc('figure', **{'edgecolor': 'None'}) rc('patch', **{'edgecolor': 'None'}) @@ -88,7 +85,7 @@ def plot_curtailment(network, regions, path, show_fig=True, focus_de=True, legen # curtailment = n.statistics.curtailment(groupby=n.statistics.groupers.get_bus_and_carrier).droplevel(0).loc[regions.index,:,:] elec_generation = n.generators.carrier.replace(pretty_gen).to_frame().query("not carrier.str.contains('solar thermal')").carrier.unique() - curtailment = n.statistics.curtailment(groupby=n.statistics.groupers.get_bus_and_carrier).droplevel(0) + curtailment = n.statistics.curtailment(groupby=["bus", "carrier"]).droplevel(0) elec_i = pd.Index(set(curtailment.index.get_level_values(1)).intersection(elec_generation)) curtailment_elec = curtailment.loc[:, elec_i, :].reset_index() curtailment_elec = curtailment_elec.rename(index=curtailment_elec.bus.map(n.buses.location)) @@ -213,7 +210,7 @@ def plot_storage_map(network, regions, path=None, focus_de=True, legend_circles= storage_cap = ( n.statistics.optimal_capacity( bus_carrier=["AC", "low voltage"], - groupby=n.statistics.groupers.get_bus_and_carrier, + groupby=["bus", "carrier"], nice_names=False ).div(1e3) # GW .sort_values(ascending=False) @@ -225,7 +222,7 @@ def plot_storage_map(network, regions, path=None, focus_de=True, legend_circles= vres_cap = ( n.statistics.optimal_capacity( bus_carrier=["AC", "low voltage"], - groupby=n.statistics.groupers.get_bus_and_carrier, + groupby=["bus", "carrier"], nice_names=False ).div(1e3) # GW .sort_values(ascending=False) @@ -508,7 +505,7 @@ def plot_energy_trade(network, countries, path): plot_by_country(df_new, plot_kw, path) def prepare_energy_balance(n): - df = n.statistics.energy_balance(groupby=get_bus_and_carrier_and_bus_carrier, aggregate_time=False) + df = n.statistics.energy_balance(groupby=["bus", "carrier", "bus_carrier"], aggregate_time=False) df = df.rename(index=n.buses.country, level="bus") return df @@ -821,14 +818,14 @@ def calculate_capacity(network, countries, kpi_param): storage = kpi_param.get("storage",None) if stats == "install": - df = pd.DataFrame(n.statistics.installed_capacity(groupby=get_country_and_carrier, storage = storage)) + df = pd.DataFrame(n.statistics.installed_capacity(groupby=["country", "carrier"], storage = storage)) elif stats == "optimal": - df = pd.DataFrame(n.statistics.optimal_capacity(groupby=get_country_and_carrier, storage = storage)) + df = pd.DataFrame(n.statistics.optimal_capacity(groupby=["country", "carrier"], storage = storage)) elif stats == "expand": if storage == True: - df = pd.DataFrame(n.statistics.optimal_capacity(groupby=get_country_and_carrier, storage = True)).subtract(pd.DataFrame(n.statistics.installed_capacity(groupby=get_country_and_carrier, storage = True)), fill_value=0) + df = pd.DataFrame(n.statistics.optimal_capacity(groupby=["country", "carrier"], storage = True)).subtract(pd.DataFrame(n.statistics.installed_capacity(groupby=["country", "carrier"], storage = True)), fill_value=0) else: - df = pd.DataFrame(n.statistics.expanded_capacity(groupby=get_country_and_carrier)) + df = pd.DataFrame(n.statistics.expanded_capacity(groupby=["country", "carrier"])) df = df.reset_index(["country","component"]) # convert links power gen techs capacity from MWth to MWel by multiplying by efficiency @@ -850,7 +847,7 @@ def calculate_capacity(network, countries, kpi_param): def calculate_generation(network, countries): n = network.copy() - df = pd.DataFrame(n.statistics.energy_balance(groupby=get_country_and_carrier)) + df = pd.DataFrame(n.statistics.energy_balance(groupby=["country", "carrier"])) df = df.reset_index(["country","component"]) df.loc[~df.country.isin(countries),"country"] = "EU" @@ -877,7 +874,7 @@ def filter_and_rename(network, df, filter_scheme = {}, carrier_filter = None, gr df = df.set_index("nice_name") # Create your own filter - stats = pd.DataFrame(n.statistics.energy_balance(groupby=get_bus_and_carrier_and_bus_carrier)) + stats = pd.DataFrame(n.statistics.energy_balance(groupby=["bus", "carrier", "bus_carrier"])) if carrier_filter == "electricity": carrier = stats[stats.index.get_level_values("bus_carrier").isin(["AC"])].index.get_level_values("carrier").unique() @@ -1327,6 +1324,10 @@ def extract_durations(n, carrier="li-ion battery"): co2_emissions = n.stores_t.e.filter(like="co2 atmosphere", axis=1).iloc[-1].div(1e6)[0] # in MtCO2 logger.info(f"Total annual CO2 emissions of {co2_emissions} MtCO2.") + # test run latex compilation + config_kpi = snakemake.params.kpi + if config_kpi.get("enable_latex", False): test_and_enable_latex() + plot_line_loading(n, regions, path=snakemake.output.line_loading_map, focus_de=True, value="mean", show_fig=False) # extract all the nessesary statistics @@ -1337,7 +1338,7 @@ def extract_durations(n, carrier="li-ion battery"): df_storages_aggregated_durations = ( n.statistics.optimal_capacity( bus_carrier=["AC", "low voltage"], - groupby=n.statistics.groupers.get_country_and_carrier, + groupby=["country", "carrier"], nice_names=False ).div(1e3) # GW .sort_values(ascending=False) @@ -1373,7 +1374,7 @@ def extract_durations(n, carrier="li-ion battery"): df_storages = ( n.statistics.optimal_capacity( bus_carrier=["AC", "low voltage"], - groupby=n.statistics.groupers.get_country_and_carrier, + groupby=["country", "carrier"], ).div(1e3) # GW .sort_values(ascending=False) .to_frame(name="p_nom_opt") @@ -1392,7 +1393,6 @@ def extract_durations(n, carrier="li-ion battery"): df_co2 = calculate_emission(n, countries) df_eql = prepare_energy_balance(n) - config_kpi = snakemake.params.kpi filter_scheme = config_kpi.get("filter_scheme",{}) if config_kpi.get("custom_plots"): for fn, kpi_param in config_kpi["custom_plots"].items(): diff --git a/scripts/plot_power_network.py b/scripts/plot_power_network.py index f91491c07..b9c9b8d5b 100644 --- a/scripts/plot_power_network.py +++ b/scripts/plot_power_network.py @@ -16,11 +16,8 @@ from _helpers import configure_logging, rename_techs, retry, set_scenario_config from plot_summary import preferred_order from pypsa.plot import add_legend_circles, add_legend_lines, add_legend_patches - from matplotlib import rc -# activate latex text rendering -rc('text', usetex=True) -rc('font', **{'family': 'serif', 'serif': ['Computer Modern Roman'], 'sans-serif': ['Computer Modern Sans serif']}) + rc('axes', **{'edgecolor': 'None', 'titlesize': 18,'titleweight': 'bold', "labelsize": 14}) rc('figure', **{'edgecolor': 'None'}) rc('patch', **{'edgecolor': 'None'}) @@ -31,6 +28,34 @@ logger = logging.getLogger(__name__) +def test_and_enable_latex(): + import shutil + import os + + if not shutil.which('latex'): + logger.warning("Latex is not installed, disabling latex text") + + return + + path = "test_and_enable_latex.pdf" + + try: + # add the changes here if latex is enabled + logger.info("Test run latex compilation") + rc('text', usetex=True) + rc('font', **{'family': 'serif', 'serif': ['Computer Modern Roman'], 'sans-serif': ['Computer Modern Sans serif']}) + + # test if latex can render + fig, ax = plt.subplots(figsize=(7, 6)) + pd.Series([1, 2, 3, 3]).plot(kind='hist', ax=ax,title="My plot") + fig.savefig(path, bbox_inches="tight") + + os.remove(path) + + except: + logger.warning("Latex text compilation failed, disabling it now") + rc('text', usetex=False) + rc('font', **{'family': 'serif', 'serif': ['DejaVu Serif'], 'sans-serif': ['DejaVu Sans']}) def rename_techs_tyndp(tech): tech = rename_techs(tech) @@ -282,4 +307,8 @@ def plot_map( proj = load_projection(snakemake.params.plotting) + # test run latex compilation + config_kpi = snakemake.params.kpi + if config_kpi.get("enable_latex", False): test_and_enable_latex() + plot_map(n)