Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix hardcoded text elements in the plots of the forecast class #769

Merged
merged 8 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ Removed:
- `util.lines_polys_handler` solve polygon disaggregation issue in metre-based projection [#666](https://github.com/CLIMADA-project/climada_python/pull/666)
- Problem with `pyproj.CRS` as `Impact` attribute, [#706](https://github.com/CLIMADA-project/climada_python/issues/706). Now CRS is always stored as `str` in WKT format.
- Correctly handle assertion errors in `Centroids.values_from_vector_files` and fix the associated test [#768](https://github.com/CLIMADA-project/climada_python/pull/768/)
- Text in `Forecast` class plots can now be adjusted [#769](https://github.com/CLIMADA-project/climada_python/issues/769)

### Deprecated

Expand Down
43 changes: 29 additions & 14 deletions climada/engine/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,9 +310,10 @@
self._impact[ind_i] = ImpactCalc(self.exposure, self.vulnerability, haz_i)\
.impact(save_mat=True, assign_centroids=False)

def plot_imp_map(

Check warning on line 313 in climada/engine/forecast.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-arguments

LOW: Too many arguments (10/7)
Raw output
Used when a function or method takes too many arguments.

Check warning on line 313 in climada/engine/forecast.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-locals

LOW: Too many local variables (17/15)
Raw output
Used when a function or method has too many local variables.
self,
run_datetime=None,
explain_str=None,
save_fig=True,
close_fig=False,
polygon_file=None,
Expand All @@ -321,13 +322,17 @@
figsize=(9, 13),
adapt_fontsize=True,
):
"""plot a map of the impacts
""" plot a map of the impacts

Parameters
----------
run_datetime : datetime.datetime, optional
Select the used hazard by the run_datetime,
default is first element of attribute run_datetime.
explain_str : str, optional
Short str which explains type of impact, explain_str is included
in the title of the figure.
default is 'mean building damage caused by wind'
save_fig : bool, optional
Figure is saved if True, folder is within your configurable
save_dir and filename is derived from the method summary_str()
Expand Down Expand Up @@ -372,7 +377,7 @@
"run_start": (
run_datetime.strftime("%d.%m.%Y %HUTC +") + lead_time_str + "d"
),
"explain_text": ("mean building damage caused by wind"),
"explain_text": "mean building damage caused by wind" if explain_str is None else explain_str,

Check warning on line 380 in climada/engine/forecast.py

View check run for this annotation

Jenkins - WCR / Pylint

line-too-long

LOW: Line too long (106/100)
Raw output
Used when a line is longer than a given number of characters.
"model_text": "CLIMADA IMPACT",
}
fig, axes = self._plot_imp_map(
Expand Down Expand Up @@ -525,16 +530,25 @@
fig.subplots_adjust(top=0.8)
return fig, axis_sub

def plot_hist(

Check warning on line 533 in climada/engine/forecast.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-locals

LOW: Too many local variables (27/15)
Raw output
Used when a function or method has too many local variables.
self, run_datetime=None, save_fig=True, close_fig=False, figsize=(9, 8)
self,
run_datetime=None,
explain_str=None,
save_fig=True,
close_fig=False,
figsize=(9, 8),
):
"""plot histogram of the forecasted impacts all ensemble members
""" plot histogram of the forecasted impacts all ensemble members

Parameters
----------
run_datetime : datetime.datetime, optional
Select the used hazard by the run_datetime,
default is first element of attribute run_datetime.
explain_str : str, optional
Short str which explains type of impact, explain_str is included
in the title of the figure.
default is 'total building damage'
save_fig : bool, optional
Figure is saved if True, folder is within your configurable
save_dir and filename is derived from the method summary_str()
Expand Down Expand Up @@ -603,7 +617,7 @@
axes.xaxis.set_ticks(x_ticks)
axes.xaxis.set_ticklabels(x_ticklabels)
plt.xticks(rotation=15, horizontalalignment="right")
plt.xlim([(10**-0.25) * bins[0], (10**0.25) * bins[-1]])
plt.xlim([(10 ** -0.25) * bins[0], (10 ** 0.25) * bins[-1]])

lead_time_str = "{:.0f}".format(
self.lead_time(run_datetime).days
Expand All @@ -614,7 +628,7 @@
"run_start": (
run_datetime.strftime("%d.%m.%Y %HUTC +") + lead_time_str + "d"
),
"explain_text": ("total building damage"),
"explain_text": ("total building damage") if explain_str is None else explain_str,
"model_text": "CLIMADA IMPACT",
}
title_position = {
Expand Down Expand Up @@ -656,8 +670,9 @@
plt.text(
0.75,
0.85,
"mean damage:\nCHF "
+ self._number_to_str(self._impact[haz_ind].at_event.mean()),
"mean impact:\n "
+ self._number_to_str(self._impact[haz_ind].at_event.mean())
+ ' ' + self._impact[haz_ind].unit,
horizontalalignment="center",
verticalalignment="center",
transform=axes.transAxes,
Expand Down Expand Up @@ -740,7 +755,7 @@
The default is (9, 13)
adapt_fontsize : bool, optional
If set to true, the size of the fonts will be adapted to the size of the figure.
Otherwise the default matplotlib font size is used. Default is True.
Otherwise, the default matplotlib font size is used. Default is True.

Returns
-------
Expand All @@ -750,10 +765,10 @@
if run_datetime is None:
run_datetime = self.run_datetime[0]
haz_ind = np.argwhere(np.isin(self.run_datetime, run_datetime))[0][0]
wind_map_file_name = (
exceedence_map_file_name = (
self.summary_str(run_datetime) + "_exceed_" + str(threshold) + "_map.jpeg"
)
wind_map_file_name_full = FORECAST_PLOT_DIR / wind_map_file_name
exceedence_map_file_name_full = FORECAST_PLOT_DIR / exceedence_map_file_name
lead_time_str = "{:.0f}".format(
self.lead_time(run_datetime).days
+ self.lead_time(run_datetime).seconds / 60 / 60 / 24
Expand Down Expand Up @@ -783,7 +798,7 @@
adapt_fontsize=adapt_fontsize,
)
if save_fig:
plt.savefig(wind_map_file_name_full)
plt.savefig(exceedence_map_file_name_full)
if close_fig:
plt.clf()
plt.close(fig)
Expand Down Expand Up @@ -974,7 +989,7 @@
Figure is not drawn if True. The default is False.
adapt_fontsize : bool, optional
If set to true, the size of the fonts will be adapted to the size of the figure.
Otherwise the default matplotlib font size is used. Default is True.
Otherwise, the default matplotlib font size is used. Default is True.

Returns
-------
Expand Down Expand Up @@ -1086,7 +1101,7 @@
decision_dict_functions[aggregation] = np.mean
else:
raise ValueError(
"Parameter area_aggregation of "
"Parameter " + aggregation + " of "
+ "Forecast.plot_warn_map() must eiter be "
+ "a float between [0..1], which "
+ "specifys a quantile. or 'sum' or 'mean'."
Expand Down
61 changes: 47 additions & 14 deletions climada/engine/test/test_forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class TestPlot(unittest.TestCase):

def test_Forecast_plot(self):
"""Test cplotting functions from the Forecast class"""
#hazard
## given a forecast based on hazard exposure and vulnerability
#hazard
haz1 = StormEurope.from_cosmoe_file(
HAZ_DIR.joinpath('storm_europe_cosmoe_forecast_vmax_testfile.nc'),
run_datetime=dt.datetime(2018,1,1),
Expand Down Expand Up @@ -149,21 +150,41 @@ def test_Forecast_plot(self):
for f in source:
if f['properties']['adm0_a3'] == 'CHE':
sink.write(f)
#test plotting functions
## test plotting functions
# should save plot without failing
forecast.plot_imp_map(run_datetime=dt.datetime(2017,12,31),
explain_str='test text',
polygon_file=str(cantons_file),
save_fig=True, close_fig=True)
map_file_name = (forecast.summary_str(dt.datetime(2017,12,31)) +
'_impact_map' +
'.jpeg')
map_file_name_full = Path(FORECAST_PLOT_DIR) / map_file_name
map_file_name_full.absolute().unlink(missing_ok=False)
forecast.plot_hist(run_datetime=dt.datetime(2017,12,31),
save_fig=False, close_fig=True)
forecast.plot_exceedence_prob(run_datetime=dt.datetime(2017,12,31),
threshold=5000, save_fig=False, close_fig=True)


#should contain title strings
ax = forecast.plot_hist(run_datetime=dt.datetime(2017,12,31),
explain_str='test text',
save_fig=False, close_fig=False)
title_artists = ax.get_figure().get_children()
title_texts = [x.get_text() for x in title_artists if isinstance(x, plt.Text)]
self.assertIn('test text', title_texts)
self.assertIn('Wed 03 Jan 2018 00-24UTC', title_texts)
self.assertIn('31.12.2017 00UTC +3d', title_texts)
#should contain average impact in axes
artists = ax.get_children()
texts = [x.get_text() for x in artists if type(x) == plt.Text]
self.assertIn('mean impact:\n 26 USD', texts)
ax.get_figure().clf()
#should contain title strings
ax = forecast.plot_exceedence_prob(run_datetime=dt.datetime(2017,12,31),
threshold=5000, explain_str='test text exceedence',
save_fig=False, close_fig=False)[0][0]
title_artists = ax.get_figure().get_children()
title_texts = [x.get_text() for x in title_artists if isinstance(x, plt.Text)]
self.assertIn('test text exceedence', title_texts)
self.assertIn('Wed 03 Jan 2018 00-24UTC', title_texts)
self.assertIn('31.12.2017 00UTC +3d', title_texts)
ax.get_figure().clf()
forecast.plot_warn_map(str(cantons_file),
decision_level = 'polygon',
thresholds=[100000,500000,
Expand All @@ -187,36 +208,48 @@ def test_Forecast_plot(self):
close_fig=True)
forecast.plot_hexbin_ei_exposure()
plt.close()
with self.assertRaises(ValueError):
# should fail because of invalid decision_level
with self.assertRaises(ValueError) as cm:
forecast.plot_warn_map(str(cantons_file),
decision_level = 'test_fail',
decision_level='test_fail',
probability_aggregation=0.2,
area_aggregation=0.2,
title="Building damage warning",
explain_text="warn level based on aggregated damages",
save_fig=False,
close_fig=True)
plt.close()
with self.assertRaises(ValueError):
self.assertIn(
"Parameter decision_level", str(cm.exception)
)
# should fail because of invalid probability_aggregation
with self.assertRaises(ValueError) as cm:
forecast.plot_warn_map(str(cantons_file),
decision_level = 'exposure_point',
decision_level='exposure_point',
probability_aggregation='test_fail',
area_aggregation=0.2,
title="Building damage warning",
explain_text="warn level based on aggregated damages",
save_fig=False,
close_fig=True)
plt.close()
with self.assertRaises(ValueError):
self.assertIn(
"Parameter probability_aggregation", str(cm.exception)
)
# should fail because of invalid area_aggregation
with self.assertRaises(ValueError) as cm:
forecast.plot_warn_map(str(cantons_file),
decision_level = 'exposure_point',
decision_level='exposure_point',
probability_aggregation=0.2,
area_aggregation='test_fail',
title="Building damage warning",
explain_text="warn level based on aggregated damages",
save_fig=False,
close_fig=True)
plt.close()
self.assertIn(
"Parameter area_aggregation", str(cm.exception)
)


# Execute Tests
Expand Down