Source code for postreise.plot.plot_curtailment_ts

import os

import matplotlib.pyplot as plt
import pandas as pd
from powersimdata.input.check import _check_resources_and_format
from powersimdata.network.model import ModelImmutables
from powersimdata.scenario.check import _check_scenario_is_in_analyze_state

from postreise.analyze.demand import get_demand_time_series
from postreise.analyze.generation.curtailment import get_curtailment_time_series
from postreise.analyze.generation.summarize import (
    get_generation_time_series_by_resources,
)
from postreise.analyze.time import (
    change_time_zone,
    resample_time_series,
    slice_time_series,
)


[docs]def plot_curtailment_time_series( scenario, area, resources, area_type=None, time_range=None, time_zone="utc", time_freq="H", show_demand=True, percentage=True, t2c=None, t2l=None, title=None, label_fontsize=20, title_fontsize=22, tick_fontsize=15, legend_fontsize=18, save=False, filename=None, filepath=None, ): """Generate time series curtailment plot of each specified resource in a certain area of a scenario. :param powersimdata.scenario.scenario.Scenario scenario: scenario instance :param str area: one of *loadzone*, *state*, *state abbreviation*, *interconnect*, *'all'* :param str/list resources: one or a list of resources. :param str area_type: one of *'loadzone'*, *'state'*, *'state_abbr'*, *'interconnect'* :param tuple time_range: [start_timestamp, end_timestamp] where each time stamp is pandas.Timestamp/numpy.datetime64/datetime.datetime. If None, the entire time range is used for the given scenario. :param str time_zone: new time zone. :param str time_freq: frequency. Either *'D'* (day), *'W'* (week), *'M'* (month). :param bool show_demand: show demand line in the plot or not, default is True. :param bool percentage: plot the curtailment in terms of percentage or not, default is True. :param dict t2c: user specified color of resource type to overwrite type2color default dict. key: resource type, value: color code. :param dict t2l: user specified label of resource type to overwrite type2label default dict. key: resource type, value: label. :param str title: user specified title of the figure. :param float label_fontsize: user specified label fontsize, default is 20. :param float title_fontsize: user specified title fontsize, default is 22. :param float tick_fontsize: user specified ticks of axes fontsize, default is 15. :param float legend_fontsize: user specified legend fontsize, default is 18. :param bool save: save the generated figure or not, default is False. :param str filename: if save is True, user specified filename, use area if None. :param str filepath: if save is True, user specified filepath, use current directory if None. """ _check_scenario_is_in_analyze_state(scenario) resources = _check_resources_and_format( resources, mi=ModelImmutables(scenario.info["grid_model"]) ) mi = ModelImmutables(scenario.info["grid_model"]) type2color = mi.plants["type2color"] type2color.update( {k + "_curtailment": v for k, v in mi.plants["curtailable2color"].items()} ) type2label = mi.plants["type2label"] type2label.update( {k + "_curtailment": v for k, v in mi.plants["curtailable2label"].items()} ) if t2c: type2color.update(t2c) if t2l: type2label.update(t2l) resource_pg = get_generation_time_series_by_resources( scenario, area, resources, area_type=area_type ) demand = get_demand_time_series(scenario, area, area_type=area_type) curtailment = get_curtailment_time_series(scenario, area, area_type=area_type) resource_pg = change_time_zone(resource_pg, time_zone) demand = change_time_zone(demand, time_zone) curtailment = change_time_zone(curtailment, time_zone) if not time_range: time_range = ( pd.Timestamp(scenario.info["start_date"], tz="utc"), pd.Timestamp(scenario.info["end_date"], tz="utc"), ) resource_pg = slice_time_series(resource_pg, time_range[0], time_range[1]) demand = slice_time_series(demand, time_range[0], time_range[1]) curtailment = slice_time_series(curtailment, time_range[0], time_range[1]) if time_freq != "H": resource_pg = resample_time_series(resource_pg, time_freq) demand = resample_time_series(demand, time_freq) curtailment = resample_time_series(curtailment, time_freq) for r in resource_pg.columns: curtailment[r + "_curtailment" + "_mean"] = curtailment[ r + "_curtailment" ].mean() curtailment[r + "_available"] = curtailment[r + "_curtailment"] + resource_pg[r] curtailment[r + "_curtailment" + "_percentage"] = ( curtailment[r + "_curtailment"] / curtailment[r + "_available"] * 100 ) curtailment[r + "_curtailment" + "_percentage" + "_mean"] = curtailment[ r + "_curtailment" + "_percentage" ].mean() for r in resources: if r not in resource_pg.columns: raise ValueError(f"{r} is invalid in {area}!") fig = plt.figure(figsize=(20, 10)) ax = fig.gca() title_text = f"{area} {r.capitalize()}" if not title else title plt.title(title_text, fontsize=title_fontsize) cr = r + "_curtailment" if percentage: key1, key2 = f"{cr}_percentage", f"{cr}_percentage_mean" else: key1, key2 = cr, f"{cr}_mean" curtailment[key1].plot( ax=ax, lw=4, alpha=0.7, color=type2color[cr], label=type2label[cr], ) curtailment[key2].plot( ax=ax, ls="--", lw=4, alpha=0.7, color=type2color[cr], label=type2label[cr] + " Mean", ) ax_twin = ax.twinx() curtailment[r + "_available"].plot( ax=ax_twin, lw=4, alpha=0.7, color=type2color[r], label=f"{type2label[r]} Energy Available", ) if show_demand: demand.plot(ax=ax_twin, lw=4, alpha=0.7, color="red", label="Demand") # Erase year in xticklabels xt_with_year = list(ax_twin.__dict__["date_axis_info"][0]) xt_with_year[-1] = b"%b" ax_twin.__dict__["date_axis_info"][0] = tuple(xt_with_year) ax_twin.set_xlabel("") ax_twin.tick_params(which="both", labelsize=tick_fontsize) ax_twin.yaxis.get_offset_text().set_fontsize(tick_fontsize) ax_twin.set_ylabel("MWh", fontsize=label_fontsize) ax_twin.legend(loc="upper right", prop={"size": legend_fontsize}) ax.tick_params(which="both", labelsize=tick_fontsize) ax.yaxis.get_offset_text().set_fontsize(tick_fontsize) ax.grid(color="black", axis="y") ax.set_xlabel("") if percentage: ax.set_ylabel("Curtailment [%]", fontsize=label_fontsize) else: ax.set_ylabel("Curtailment", fontsize=label_fontsize) ax.legend(loc="upper left", prop={"size": legend_fontsize}) if save: if not filename: filename = f"{area.lower()}_{r}_curtailment" if not filepath: filepath = os.path.join(os.getcwd(), filename) plt.savefig(f"{filepath}.pdf", bbox_inches="tight", pad_inches=0)