Skip to content

Commit e2fd678

Browse files
committed
Refactoring continued (Also now includes the new files)
- Fixes aai per group in static - components -> contributions - privatisation of some funs
1 parent 2bf7768 commit e2fd678

File tree

6 files changed

+532
-198
lines changed

6 files changed

+532
-198
lines changed

climada/trajectories/risk_trajectory.py renamed to climada/trajectories/interpolated_trajectory.py

Lines changed: 52 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
from climada.trajectories.riskperiod import (
3737
AllLinearStrategy,
3838
CalcRiskMetricsPeriod,
39-
ImpactCalcComputation,
4039
ImpactComputationStrategy,
4140
)
4241
from climada.trajectories.snapshot import Snapshot
@@ -61,7 +60,7 @@ class InterpolatedRiskTrajectory(RiskTrajectory):
6160
"eai",
6261
"aai",
6362
"return_periods",
64-
"risk_components",
63+
"risk_contributions",
6564
"aai_per_group",
6665
]
6766
DEFAULT_RP = [50, 100, 500]
@@ -270,13 +269,13 @@ def aai_metrics(self, npv: bool = True, **kwargs) -> pd.DataFrame:
270269
)
271270

272271
def return_periods_metrics(
273-
self, return_periods, npv: bool = True, **kwargs
272+
self, return_periods=None, npv: bool = True, **kwargs
274273
) -> pd.DataFrame:
275274
return self._compute_metrics(
276275
npv=npv,
277276
metric_name="return_periods",
278277
metric_meth="calc_return_periods_metric",
279-
return_periods=return_periods,
278+
return_periods=return_periods if return_periods else self.default_rp,
280279
**kwargs,
281280
)
282281

@@ -300,10 +299,10 @@ def aai_per_group_metrics(self, npv: bool = True, **kwargs) -> pd.DataFrame:
300299
**kwargs,
301300
)
302301

303-
def risk_components_metrics(self, npv: bool = True, **kwargs) -> pd.DataFrame:
304-
"""Return the "components" of change in future risk (Exposure and Hazard)
302+
def risk_contributions_metrics(self, npv: bool = True, **kwargs) -> pd.DataFrame:
303+
"""Return the "contributions" of change in future risk (Exposure and Hazard)
305304
306-
This method returns the components of the change in risk at each date:
305+
This method returns the contributions of the change in risk at each date:
307306
308307
- The 'base risk', i.e., the risk without change in hazard or exposure, compared to trajectory's earliest date.
309308
- The 'exposure contribution', i.e., the additional risks due to change in exposure (only)
@@ -321,13 +320,13 @@ def risk_components_metrics(self, npv: bool = True, **kwargs) -> pd.DataFrame:
321320

322321
tmp = self._compute_metrics(
323322
npv=npv,
324-
metric_name="risk_components",
325-
metric_meth="calc_risk_components_metric",
323+
metric_name="risk_contributions",
324+
metric_meth="calc_risk_contributions_metric",
326325
**kwargs,
327326
)
328327

329328
# If there is more than one Snapshot, we need to update the
330-
# components from previous periods for for continuity
329+
# contributions from previous periods for for continuity
331330
# and to set the base risk from the first period
332331
if len(self._snapshots) > 2:
333332
tmp.set_index(["group", "date", "measure", "metric"], inplace=True)
@@ -446,7 +445,7 @@ def _get_risk_periods(
446445
]
447446

448447
@staticmethod
449-
def identify_continuous_periods(group, time_unit):
448+
def _identify_continuous_periods(group, time_unit):
450449
# Calculate the difference between consecutive dates
451450
if time_unit == "year":
452451
group["date_diff"] = group["date"].dt.year.diff()
@@ -489,7 +488,7 @@ def conditional_agg(group):
489488
# Apply the function to identify continuous periods
490489
df_periods = df_sorted.groupby(
491490
grouper, dropna=False, group_keys=False, observed=True
492-
).apply(cls.identify_continuous_periods, time_unit)
491+
).apply(cls._identify_continuous_periods, time_unit)
493492

494493
if isinstance(colname, str):
495494
colname = [colname]
@@ -542,30 +541,30 @@ def _calc_waterfall_plot_data(
542541
"""Compute the required data for the waterfall plot between `start_date` and `end_date`."""
543542
start_date = self.start_date if start_date is None else start_date
544543
end_date = self.end_date if end_date is None else end_date
545-
risk_components = self.risk_components_metrics(npv)
546-
risk_components = risk_components.loc[
547-
(risk_components["date"] >= str(start_date))
548-
& (risk_components["date"] <= str(end_date))
544+
risk_contributions = self.risk_contributions_metrics(npv)
545+
risk_contributions = risk_contributions.loc[
546+
(risk_contributions["date"] >= str(start_date))
547+
& (risk_contributions["date"] <= str(end_date))
549548
]
550-
risk_components = risk_components.set_index(["date", "metric"])[
549+
risk_contributions = risk_contributions.set_index(["date", "metric"])[
551550
"risk"
552551
].unstack()
553-
return risk_components
552+
return risk_contributions
554553

555-
def plot_per_date_waterfall(
554+
def plot_time_waterfall(
556555
self,
557556
ax=None,
558557
start_date: datetime.date | None = None,
559558
end_date: datetime.date | None = None,
560559
figsize=(12, 6),
561560
npv=True,
562561
):
563-
"""Plot a waterfall chart of risk components over a specified date range.
562+
"""Plot a waterfall chart of risk contributions over a specified date range.
564563
565564
This method generates a stacked bar chart to visualize the
566-
risk components between specified start and end dates, for each date in between.
565+
risk contributions between specified start and end dates, for each date in between.
567566
If no dates are provided, it defaults to the start and end dates of the risk trajectory.
568-
See the notes on how risk is attributed to each components.
567+
See the notes on how risk is attributed to each contributions.
569568
570569
Parameters
571570
----------
@@ -588,10 +587,10 @@ def plot_per_date_waterfall(
588587
fig = ax.figure # get parent figure from the axis
589588
start_date = self.start_date if start_date is None else start_date
590589
end_date = self.end_date if end_date is None else end_date
591-
risk_component = self._calc_waterfall_plot_data(
590+
risk_contribution = self._calc_waterfall_plot_data(
592591
start_date=start_date, end_date=end_date, npv=npv
593592
)
594-
risk_component = risk_component[
593+
risk_contribution = risk_contribution[
595594
[
596595
"base risk",
597596
"exposure contribution",
@@ -600,17 +599,17 @@ def plot_per_date_waterfall(
600599
"interaction contribution",
601600
]
602601
]
603-
risk_component["base risk"] = risk_component.iloc[0]["base risk"]
604-
# risk_component.plot(x="date", ax=ax, kind="bar", stacked=True)
602+
risk_contribution["base risk"] = risk_contribution.iloc[0]["base risk"]
603+
# risk_contribution.plot(x="date", ax=ax, kind="bar", stacked=True)
605604
ax.stackplot(
606-
risk_component.index.to_timestamp(),
607-
[risk_component[col] for col in risk_component.columns],
608-
labels=risk_component.columns,
605+
risk_contribution.index.to_timestamp(),
606+
[risk_contribution[col] for col in risk_contribution.columns],
607+
labels=risk_contribution.columns,
609608
)
610609
ax.legend()
611-
# bottom = [0] * len(risk_component)
612-
# for col in risk_component.columns:
613-
# bottom = [b + v for b, v in zip(bottom, risk_component[col])]
610+
# bottom = [0] * len(risk_contribution)
611+
# for col in risk_contribution.columns:
612+
# bottom = [b + v for b, v in zip(bottom, risk_contribution[col])]
614613
# Construct y-axis label and title based on parameters
615614
value_label = "USD"
616615
title_label = f"Risk between {start_date} and {end_date} (Average impact)"
@@ -633,9 +632,9 @@ def plot_waterfall(
633632
end_date: datetime.date | None = None,
634633
npv=True,
635634
):
636-
"""Plot a waterfall chart of risk components between two dates.
635+
"""Plot a waterfall chart of risk contributions between two dates.
637636
638-
This method generates a waterfall plot to visualize the changes in risk components
637+
This method generates a waterfall plot to visualize the changes in risk contributions
639638
between a specified start and end date. If no dates are provided, it defaults to
640639
the start and end dates of the risk trajectory.
641640
@@ -658,14 +657,14 @@ def plot_waterfall(
658657
end_date = self.end_date if end_date is None else end_date
659658
start_date_p = pd.to_datetime(start_date).to_period(self._time_resolution)
660659
end_date_p = pd.to_datetime(end_date).to_period(self._time_resolution)
661-
risk_component = self._calc_waterfall_plot_data(
660+
risk_contribution = self._calc_waterfall_plot_data(
662661
start_date=start_date, end_date=end_date, npv=npv
663662
)
664663
if ax is None:
665664
_, ax = plt.subplots(figsize=(8, 5))
666665

667-
risk_component = risk_component.loc[
668-
(risk_component.index == str(end_date))
666+
risk_contribution = risk_contribution.loc[
667+
(risk_contribution.index == str(end_date))
669668
].squeeze()
670669

671670
labels = [
@@ -677,24 +676,24 @@ def plot_waterfall(
677676
f"Total Risk {end_date_p}",
678677
]
679678
values = [
680-
risk_component["base risk"],
681-
risk_component["exposure contribution"],
682-
risk_component["hazard contribution"],
683-
risk_component["vulnerability contribution"],
684-
risk_component["interaction contribution"],
685-
risk_component.sum(),
679+
risk_contribution["base risk"],
680+
risk_contribution["exposure contribution"],
681+
risk_contribution["hazard contribution"],
682+
risk_contribution["vulnerability contribution"],
683+
risk_contribution["interaction contribution"],
684+
risk_contribution.sum(),
686685
]
687686
bottoms = [
688687
0.0,
689-
risk_component["base risk"],
690-
risk_component["base risk"] + risk_component["exposure contribution"],
691-
risk_component["base risk"]
692-
+ risk_component["exposure contribution"]
693-
+ risk_component["hazard contribution"],
694-
risk_component["base risk"]
695-
+ risk_component["exposure contribution"]
696-
+ risk_component["hazard contribution"]
697-
+ risk_component["vulnerability contribution"],
688+
risk_contribution["base risk"],
689+
risk_contribution["base risk"] + risk_contribution["exposure contribution"],
690+
risk_contribution["base risk"]
691+
+ risk_contribution["exposure contribution"]
692+
+ risk_contribution["hazard contribution"],
693+
risk_contribution["base risk"]
694+
+ risk_contribution["exposure contribution"]
695+
+ risk_contribution["hazard contribution"]
696+
+ risk_contribution["vulnerability contribution"],
698697
0.0,
699698
]
700699

@@ -724,7 +723,7 @@ def plot_waterfall(
724723

725724
# Construct y-axis label and title based on parameters
726725
value_label = "USD"
727-
title_label = f"Evolution of the components of risk between {start_date_p} and {end_date_p} (Average impact)"
726+
title_label = f"Evolution of the contributions of risk between {start_date_p} and {end_date_p} (Average impact)"
728727
ax.yaxis.set_major_formatter(ticker.EngFormatter())
729728
ax.set_title(title_label)
730729
ax.set_ylabel(value_label)

climada/trajectories/riskperiod.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,14 @@ def calc_eai_gdf(self) -> pd.DataFrame:
144144
id_vars="date", var_name="coord_id", value_name="risk"
145145
)
146146
eai_gdf = pd.concat(
147-
[snap.exposure.gdf[["group_id"]] for snap in self.snapshots]
147+
[
148+
snap.exposure.gdf.reset_index(names=["coord_id"]).assign(
149+
date=pd.to_datetime(snap.date)
150+
)[["date", "coord_id", "group_id"]]
151+
for snap in self.snapshots
152+
]
148153
)
149-
eai_gdf["coord_id"] = eai_gdf.index
150-
eai_gdf = eai_gdf.merge(df, on="coord_id")
154+
eai_gdf = eai_gdf.merge(df, on=["date", "coord_id"])
151155
eai_gdf = eai_gdf.rename(columns={"group_id": "group"})
152156
eai_gdf["group"] = pd.Categorical(eai_gdf["group"], categories=self._groups_id)
153157
eai_gdf["metric"] = "eai"
@@ -837,8 +841,8 @@ def calc_return_periods_metric(self, return_periods: list[int]) -> pd.DataFrame:
837841
rp_df["measure"] = self.measure.name if self.measure else "no_measure"
838842
return rp_df
839843

840-
def calc_risk_components_metric(self) -> pd.DataFrame:
841-
"""Compute a DataFrame of the individual components of risk (impact), at each dates of the risk period (including changes in exposure, hazard and vulnerability)."""
844+
def calc_risk_contributions_metric(self) -> pd.DataFrame:
845+
"""Compute a DataFrame of the individual contributions of risk (impact), at each dates of the risk period (including changes in exposure, hazard and vulnerability)."""
842846
per_date_aai_V0 = self.interpolation_strategy.interp_over_hazard_dim(
843847
self.per_date_aai_H0V0, self.per_date_aai_H1V0
844848
)

0 commit comments

Comments
 (0)