Пример #1
0
def test_resampling_argument_value():
    arg = (
        (ts_as_data_frame, "Q", "mean"),
        (ts_as_series, "D", "median"),
        (ts_as_data_frame.tz_localize("UTC").tz_convert("US/Pacific"), "W", "sum"),
    )
    for a in arg:
        with pytest.raises(ValueError):
            resample_time_series(a[0], a[1], agg=a[2])
Пример #2
0
def test_daily_resampling_incomplete_and_time_shift_mean():
    start = pd.Timestamp(2016, 1, 1, 18)
    end = pd.Timestamp(2016, 1, 31, 18)
    arg = (
        ts_as_data_frame[start:end].tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series[start:end].tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "D", agg="mean")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first day (2016/01/01) and last day (2016/01/31) are incomplete.
            # 31 days are available in January 2016 when resampling using mean.
            assert len(ts_resampled) == 31
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-01", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-01-31", tz="ETC/GMT+8")
            )
        else:
            # first day (2016/01/02) and last day (2016/02/01) are incomplete.
            # 30 days are available in January 2016 and 1 day available in February 2016
            assert len(ts_resampled) == 31
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-02", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-02-01", tz="ETC/GMT-8")
            )
Пример #3
0
def test_weekly_resampling_incomplete_and_time_shift_mean():
    start = pd.Timestamp(2016, 1, 1, 18)
    end = pd.Timestamp(2016, 1, 31, 18)
    arg = (
        ts_as_data_frame[start:end].tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series[start:end].tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W", agg="mean")
        assert len(a) != len(ts_resampled)
        assert len(ts_resampled) == 6
        if i == 0:
            # first week (2015/12/27) and last week (2016/01/31) are incomplete.
            # 1 week is available in 2015 and 5 weeks are available in 2016 when
            # resampling using mean.
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2015-12-27", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-01-31", tz="ETC/GMT+8")
            )
        else:
            # first week (2015/12/27) and last week (2016/01/31) are incomplete.
            # 1 week is available in 2015 and 5 weeks are available in 2016 when
            # resampling using mean.
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2015-12-27", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-01-31", tz="ETC/GMT-8")
            )
Пример #4
0
def test_daily_resampling_time_shift_mean():
    arg = (
        ts_as_data_frame.tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series.tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "D", agg="mean")
        assert len(a) != len(ts_resampled)
        assert len(ts_resampled) == 367
        if i == 0:
            # first day (2015/12/31) and last day (2016/12/31) are incomplete.
            # 1 day is available in 2015 and 366 days are available in 2016
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2015-12-31", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-31", tz="ETC/GMT+8")
            )
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            # first day (2016/01/01) and last day (2017/01/01) are incomplete.
            # 366 days are available in 2016 and 1 day is available in 2017
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-01", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2017-01-01", tz="ETC/GMT-8")
            )
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #5
0
def test_monthly_resampling_time_shift_mean():
    arg = (
        ts_as_data_frame.tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series.tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "M", agg="mean")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first month (2015/12) and last month (2016/12) are incomplete.
            # 1 month is available in 2015 and 12 months are available in 2016 after
            # resampling using mean
            assert len(ts_resampled) == 13
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2015-12-01", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-01", tz="ETC/GMT+8")
            )
        else:
            # first month (2016/01) and last month (2017/01) are incomplete.
            # 12 months are available in 2016 and 1 month available in 2017 after
            # resampling using mean
            assert len(ts_resampled) == 13
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-01", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2017-01-01", tz="ETC/GMT-8")
            )
Пример #6
0
def test_weekly_resampling_incomplete_and_time_shift_sum():
    start = pd.Timestamp(2016, 1, 1, 18)
    end = pd.Timestamp(2016, 1, 31, 18)
    arg = (
        ts_as_data_frame[start:end].tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series[start:end].tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first week (2015/12/27) and last week (2016/01/31) are incomplete.
            # 4 full weeks are available in 2016 after resampling using sum.
            assert len(ts_resampled) == 4
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-03", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-01-24", tz="ETC/GMT+8")
            )
        else:
            # first week (2015/12/27) and last week (2016/01/31) are incomplete.
            # 4 full weeks are available in 2016 after resampling using sum.
            assert len(ts_resampled) == 4
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-03", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-01-24", tz="ETC/GMT-8")
            )
Пример #7
0
def test_daily_resampling_time_shift_sum():
    arg = (
        ts_as_data_frame.tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series.tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "D")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first day (2015/12/31) and last day (2016/12/31) are incomplete.
            # 365 full days are available in 2016 after resampling using sum.
            assert len(ts_resampled) == 365
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-01", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-30", tz="ETC/GMT+8")
            )
        else:
            # first day (2016/01/01) and last day (2017/01/01) are incomplete.
            # 365 full days are available in 2016 after resampling using sum.
            assert len(ts_resampled) == 365
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-02", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-31", tz="ETC/GMT-8")
            )
Пример #8
0
def test_weekly_resampling_time_shift_mean():
    arg = (
        ts_as_data_frame.tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series.tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W", agg="mean")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first week (2015/12/27) and last week (2016/12/25) are incomplete.
            # 1 week is available in 2015 and 52 weeks are available in 2016
            assert len(ts_resampled) == 53
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2015-12-27", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-25", tz="ETC/GMT+8")
            )

        else:
            # first week (2015/12/27) and last week (2017/01/01) are incomplete.
            # 1 week is available in 2015, 52 weeks are available in 2016 and 1 week
            # is available in 2017
            assert len(ts_resampled) == 54
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2015-12-27", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2017-01-01", tz="ETC/GMT-8")
            )
Пример #9
0
def test_monthly_resampling_incomplete_and_time_shift_mean():
    start = pd.Timestamp(2016, 1, 15, 18)
    end = pd.Timestamp(2016, 6, 30, 18)
    arg = (
        ts_as_data_frame[start:end].tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series[start:end].tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "M", agg="mean")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first month (2016/01) and last month (2016/06) are incomplete.
            # 6 months are available in 2016 after resampling using mean.
            assert len(ts_resampled) == 6
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-01", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-06-01", tz="ETC/GMT+8")
            )
        else:
            # first month (2016/01) and last month (2016/07) are incomplete.
            # 7 months are available in 2016 after resampling using mean.
            assert len(ts_resampled) == 7
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-01", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-07-01", tz="ETC/GMT-8")
            )
Пример #10
0
def test_weekly_resampling_time_shift_sum():
    arg = (
        ts_as_data_frame.tz_localize("UTC").tz_convert("ETC/GMT+8"),
        ts_as_series.tz_localize("UTC").tz_convert("ETC/GMT-8"),
    )
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W")
        assert len(a) != len(ts_resampled)
        if i == 0:
            # first week (2015/12/28) and last week (2016/12/25) are incomplete.
            # 51 full weeks are available in 2016 after resampling using sum.
            assert len(ts_resampled) == 51
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-03", tz="ETC/GMT+8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-18", tz="ETC/GMT+8")
            )
        else:
            # first week (2015/12/28) is incomplete.
            # 52 full weeks are available in 2016 after resampling using sum.
            assert len(ts_resampled) == 52
            assert str(ts_resampled.index[0]) == str(
                pd.Timestamp("2016-01-03", tz="ETC/GMT-8")
            )
            assert str(ts_resampled.index[-1]) == str(
                pd.Timestamp("2016-12-25", tz="ETC/GMT-8")
            )
Пример #11
0
def test_monthly_resampling_sum():
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "M")
        assert len(a) != len(ts_resampled)
        # 12 full monts are available in 2016 when resampling using mean.
        assert len(ts_resampled) == 12
        assert str(ts_resampled.index[1]) == str(pd.Timestamp(2016, 2, 1))
        if i == 0:
            assert a.sum().equals(ts_resampled.sum())
        else:
            assert a.sum() == ts_resampled.sum()
Пример #12
0
def test_weekly_resampling_sum():
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W")
        assert len(a) != len(ts_resampled)
        # first week (2015/12/28) is incomplete.
        # 52 full weeks are available in 2016 after resampling using sum.
        assert len(ts_resampled) == 52
        assert ts_resampled.index.dayofweek[0] == 6  # week starts on Sunday
        if i == 0:
            assert not a.sum().equals(ts_resampled.sum())
        else:
            assert a.sum() != ts_resampled.sum()
Пример #13
0
def test_daily_resampling_mean():
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "D", agg="mean")
        assert len(a) != len(ts_resampled)
        # 366 days are available in 2016
        assert len(ts_resampled) == 366
        assert str(ts_resampled.index[1]) == str(pd.Timestamp(2016, 1, 2))
        if i == 0:
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #14
0
def test_monthly_resampling_mean():
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "M", agg="mean")
        assert len(a) != len(ts_resampled)
        # 12 full months are available in 2016 when resampling using mean.
        assert len(ts_resampled) == 12
        assert str(ts_resampled.index[2]) == str(pd.Timestamp(2016, 3, 1))
        if i == 0:
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #15
0
def test_daily_resampling_sum():
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "D")
        assert len(a) != len(ts_resampled)
        # 366 days are available in 2016
        assert len(ts_resampled) == 366
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2016, 1, 1))
        assert str(ts_resampled.index[-1]) == str(pd.Timestamp(2016, 12, 31))
        if i == 0:
            assert a.sum().equals(ts_resampled.sum())
        else:
            assert a.sum() == ts_resampled.sum()
Пример #16
0
def test_monthly_resampling_incomplete_mean():
    start = pd.Timestamp(2016, 1, 15)
    end = pd.Timestamp(2016, 12, 15)
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a[start:end], "M", agg="mean")
        # first month (01/2016) and last month (2016/12) are incomplete.
        # 12 months are available in 2016 when resampling using mean.
        assert len(ts_resampled) == 12
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2016, 1, 1))
        if i == 0:
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #17
0
def test_monthly_resampling_incomplete_sum():
    start = pd.Timestamp(2016, 1, 15)
    end = pd.Timestamp(2016, 12, 15)
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a[start:end], "M")
        # first month (01/2016) and last month (2016/12) are incomplete.
        # 10 full months are available in 2016 when resampling using sum.
        assert len(a[start:end]) != len(ts_resampled)
        assert len(ts_resampled) == 10  # inncomplete months are clipped
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2016, 2, 1))
        if i == 0:
            assert not a.sum().equals(ts_resampled.sum())
        else:
            assert a.sum() != ts_resampled.sum()
Пример #18
0
def test_weekly_resampling_mean():
    arg = (ts_as_data_frame, ts_as_series)
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W", agg="mean")
        assert len(a) != len(ts_resampled)
        # first week (2015/12/27) is incomplete.
        # 1 week is available in 2015 and 52 weeks are available in 2016
        assert len(ts_resampled) == 53
        assert ts_resampled.index.dayofweek[0] == 6  # week starts on Sunday
        assert ts_resampled.index[0] == pd.Timestamp(2015, 12, 27)
        assert ts_resampled.index[-1] == pd.Timestamp(2016, 12, 25)
        if i == 0:
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #19
0
def test_daily_resampling_incomplete_mean():
    start = pd.Timestamp(2016, 1, 1, 12)
    end = pd.Timestamp(2016, 1, 31, 12)
    arg = (ts_as_data_frame[start:end], ts_as_series[start:end])
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "D", agg="mean")
        # first day (2016/01/01) and last day (2016/01/31) are incomplete.
        # 31 days are available in January 2016 after resampling using mean.
        assert len(ts_resampled) == 31
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2016, 1, 1))
        assert str(ts_resampled.index[-1]) == str(pd.Timestamp(2016, 1, 31))
        if i == 0:
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #20
0
def test_weekly_resampling_incomplete_mean():
    start = pd.Timestamp(2016, 1, 1, 12)
    end = pd.Timestamp(2016, 1, 31, 12)
    arg = (ts_as_data_frame[start:end], ts_as_series[start:end])
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a, "W", agg="mean")
        # first week (2015/12/27) and last week (2016/01/31) are incomplete.
        # 1 week is available in 2015 and 5 weeks are available in 2016 after
        # resampling using mean.
        assert len(ts_resampled) == 6
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2015, 12, 27))
        assert str(ts_resampled.index[-1]) == str(pd.Timestamp(2016, 1, 31))
        if i == 0:
            assert ts_resampled.iloc[0, 0] == ts_resampled.iloc[-1, 0] == 1
            assert ts_resampled.iloc[0, 1] == ts_resampled.iloc[-1, 1] == 2
        else:
            assert ts_resampled.iloc[0] == ts_resampled.iloc[-1] == 1
Пример #21
0
def test_daily_resampling_incomplete_sum():
    start = pd.Timestamp(2016, 1, 1, 12)
    end = pd.Timestamp(2016, 1, 31, 12)
    arg = (ts_as_data_frame[start:end], ts_as_series[start:end])
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a[start:end], "D")
        assert len(a) != len(ts_resampled)
        # first day (2016/01/01) and last day (2016/01/31) are incomplete.
        # 29 days are available in Jamuary 2016 after resampling using sum.
        assert len(ts_resampled) == 29
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2016, 1, 2))
        if i == 0:
            assert ts_resampled.sum().equals(
                pd.Series([float(29 * 24), float(29 * 2 * 24)], index=["A", "B"])
            )
        else:
            assert ts_resampled.sum() == 29 * 24
Пример #22
0
def test_weekly_resampling_incomplete_sum():
    start = pd.Timestamp(2016, 1, 1, 12)
    end = pd.Timestamp(2016, 1, 31, 12)
    arg = (ts_as_data_frame[start:end], ts_as_series[start:end])
    for i, a in enumerate(arg):
        ts_resampled = resample_time_series(a[start:end], "W")
        assert len(a) != len(ts_resampled)
        # first week (2015/12/28) and last week (2016/01/31) are incomplete.
        # 4 full weeks are available in 2016 after resampling using sum.
        assert len(ts_resampled) == 4
        assert str(ts_resampled.index[0]) == str(pd.Timestamp(2016, 1, 3))
        assert str(ts_resampled.index[-1]) == str(pd.Timestamp(2016, 1, 24))
        if i == 0:
            assert ts_resampled.sum().equals(
                pd.Series([float(4 * 7 * 24), float(4 * 7 * 2 * 24)], index=["A", "B"])
            )
        else:
            assert ts_resampled.sum() == 4 * 7 * 24
Пример #23
0
def plot_generation_time_series_stack(
    scenario,
    area,
    resources,
    area_type=None,
    time_range=None,
    time_zone="utc",
    time_freq="H",
    show_demand=True,
    show_net_demand=True,
    normalize=False,
    t2c=None,
    t2l=None,
    t2hc=None,
    title=None,
    label_fontsize=20,
    title_fontsize=22,
    tick_fontsize=15,
    legend_fontsize=18,
    save=False,
    filename=None,
    filepath=None,
):
    """Generate time series generation stack plot 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. *'solar_curtailment'*,
        *'wind_curtailment'*, *'wind_offshore_curtailment'* are valid entries together
        with all available generator types in the area. The order of the resources
        determines the stack order in the figure.
    :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 show_net_demand: show net demand line in the plot or not, default is
        True.
    :param bool normalize: normalize the generation based on capacity or not,
        default is False.
    :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 dict t2hc: user specified color of curtailable resource hatches to overwrite
        type2hatchcolor default dict. key: resource type, valid keys are
        *'wind_curtailment'*, *'solar_curtailment'*, *'wind_offshore_curtailment'*,
        value: color code.
    :param str title: user specified title of the figure, default is set to be area.
    :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)

    mi = ModelImmutables(scenario.info["grid_model"])
    type2color = mi.plants["type2color"]
    type2label = mi.plants["type2label"]
    type2hatchcolor = mi.plants["type2hatchcolor"]
    if t2c:
        type2color.update(t2c)
    if t2l:
        type2label.update(t2l)
    if t2hc:
        type2hatchcolor.update(t2hc)

    pg_stack = get_generation_time_series_by_resources(scenario,
                                                       area,
                                                       resources,
                                                       area_type=area_type)
    capacity = get_capacity_by_resources(scenario,
                                         area,
                                         resources,
                                         area_type=area_type)
    demand = get_demand_time_series(scenario, area, area_type=area_type)
    net_demand = get_net_demand_time_series(scenario,
                                            area,
                                            area_type=area_type)
    capacity_ts = pd.Series(capacity.sum(), index=pg_stack.index)

    curtailable_resources = {
        "solar_curtailment",
        "wind_curtailment",
        "wind_offshore_curtailment",
    }
    if curtailable_resources & set(resources):
        curtailment = get_curtailment_time_series(scenario,
                                                  area,
                                                  area_type=area_type)
        for r in curtailable_resources:
            if r in resources and r in curtailment.columns:
                pg_stack[r] = curtailment[r]

    if time_zone != "utc":
        pg_stack = change_time_zone(pg_stack, time_zone)
        demand = change_time_zone(demand, time_zone)
        net_demand = change_time_zone(net_demand, time_zone)
        capacity_ts = change_time_zone(capacity_ts, time_zone)
    if not time_range:
        time_range = (
            pd.Timestamp(scenario.info["start_date"]),
            pd.Timestamp(scenario.info["end_date"]),
        )
    pg_stack = slice_time_series(pg_stack, time_range[0], time_range[1])
    demand = slice_time_series(demand, time_range[0], time_range[1])
    net_demand = slice_time_series(net_demand, time_range[0], time_range[1])
    capacity_ts = slice_time_series(capacity_ts, time_range[0], time_range[1])
    if time_freq != "H":
        pg_stack = resample_time_series(pg_stack, time_freq)
        demand = resample_time_series(demand, time_freq)
        net_demand = resample_time_series(net_demand, time_freq)
        capacity_ts = resample_time_series(capacity_ts, time_freq)

    if "storage" in resources:
        pg_storage = get_storage_time_series(scenario,
                                             area,
                                             area_type=area_type)
        capacity_storage = get_storage_capacity(scenario,
                                                area,
                                                area_type=area_type)
        capacity_storage_ts = pd.Series(capacity_storage,
                                        index=pg_storage.index)

        if time_zone != "utc":
            pg_storage = change_time_zone(pg_storage, time_zone)
            capacity_storage_ts = change_time_zone(capacity_storage_ts,
                                                   time_zone)
        if time_range != ("2016-01-01 00:00:00", "2016-12-31 23:00:00"):
            pg_storage = slice_time_series(pg_storage, time_range[0],
                                           time_range[1])
            capacity_storage_ts = slice_time_series(capacity_storage_ts,
                                                    time_range[0],
                                                    time_range[1])
        if time_freq != "H":
            pg_storage = resample_time_series(pg_storage, time_freq)
            capacity_storage_ts = resample_time_series(capacity_storage_ts,
                                                       time_freq)

        pg_stack["storage"] = pg_storage.clip(lower=0)
        capacity_ts += capacity_storage_ts

        fig, (ax, ax_storage) = plt.subplots(
            2,
            1,
            figsize=(20, 15),
            sharex="row",
            gridspec_kw={
                "height_ratios": [3, 1],
                "hspace": 0.02
            },
        )
        plt.subplots_adjust(wspace=0)
        if normalize:
            pg_storage = pg_storage.divide(capacity_storage_ts, axis="index")
            ax_storage.set_ylabel("Normalized Storage",
                                  fontsize=label_fontsize)
        else:
            ax_storage.set_ylabel("Energy Storage (MW)",
                                  fontsize=label_fontsize)

        ax_storage = pg_storage.plot(color=type2color["storage"],
                                     lw=4,
                                     ax=ax_storage)
        ax_storage.fill_between(
            pg_storage.index.values,
            0,
            pg_storage.values,
            color=type2color["storage"],
            alpha=0.5,
        )

        # Erase year in xticklabels
        xt_with_year = list(ax_storage.__dict__["date_axis_info"][0])
        xt_with_year[-1] = b"%b"
        ax_storage.__dict__["date_axis_info"][0] = tuple(xt_with_year)

        ax_storage.tick_params(axis="both",
                               which="both",
                               labelsize=tick_fontsize)
        ax_storage.set_xlabel("")
        for a in fig.get_axes():
            a.label_outer()
    else:
        fig = plt.figure(figsize=(20, 10))
        ax = fig.gca()

    if normalize:
        pg_stack = pg_stack.divide(capacity_ts, axis="index")
        demand = demand.divide(capacity_ts, axis="index")
        net_demand = net_demand.divide(capacity_ts, axis="index")
        ax.set_ylabel("Normalized Generation", fontsize=label_fontsize)
    else:
        pg_stack = pg_stack.divide(1e6, axis="index")
        demand = demand.divide(1e6, axis="index")
        net_demand = net_demand.divide(1e6, axis="index")
        ax.set_ylabel("Daily Energy TWh", fontsize=label_fontsize)

    available_resources = [r for r in resources if r in pg_stack.columns]
    pg_stack[available_resources].clip(0, None).plot.area(color=type2color,
                                                          linewidth=0,
                                                          alpha=0.7,
                                                          ax=ax,
                                                          sharex="row")

    if show_demand:
        demand.plot(color="red", lw=4, ax=ax)
    if show_net_demand:
        net_demand.plot(color="red", ls="--", lw=2, ax=ax)

    if not title:
        title = area
    ax.set_title("%s" % title, fontsize=title_fontsize)
    ax.grid(color="black", axis="y")

    if "storage" not in resources:
        # Erase year in xticklabels
        xt_with_year = list(ax.__dict__["date_axis_info"][0])
        xt_with_year[-1] = b"%b"
        ax.__dict__["date_axis_info"][0] = tuple(xt_with_year)
        ax.set_xlabel("")

    ax.tick_params(which="both", labelsize=tick_fontsize)
    ax.set_ylim([
        min(0, 1.1 * net_demand.min()),
        max(ax.get_ylim()[1], 1.1 * demand.max()),
    ])

    handles, labels = ax.get_legend_handles_labels()
    if show_demand:
        labels[0] = "Demand"
    if show_net_demand:
        labels[1] = "Net Demand"
    label_offset = show_demand + show_net_demand
    labels = [type2label[l] if l in type2label else l for l in labels]

    # Add hatches
    for r in curtailable_resources:
        if r in available_resources:
            ind = available_resources.index(r)
            ax.fill_between(
                pg_stack[available_resources].index.values,
                pg_stack[available_resources].iloc[:, :ind + 1].sum(axis=1),
                pg_stack[available_resources].iloc[:, :ind].sum(axis=1),
                color="none",
                hatch="//",
                edgecolor=type2hatchcolor[r],
                linewidth=0.0,
            )
            handles[ind + label_offset] = mpatches.Patch(
                facecolor=type2color[r],
                hatch="//",
                edgecolor=type2hatchcolor[r],
                linewidth=0.0,
            )

    ax.legend(
        handles[::-1],
        labels[::-1],
        frameon=2,
        prop={"size": legend_fontsize},
        loc="upper left",
        bbox_to_anchor=(1, 1),
    )

    if save:
        if not filename:
            filename = area
        if not filepath:
            filepath = os.path.join(os.getcwd(), filename)
        plt.savefig(f"{filepath}.pdf", bbox_inches="tight", pad_inches=0)
Пример #24
0
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, grid_model=scenario.info["grid_model"])

    mi = ModelImmutables(scenario.info["grid_model"])
    type2color = mi.plants["type2color"]
    type2label = mi.plants["type2label"]
    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)