Skip to content

Commit 6bf9478

Browse files
Merge branch 'develop' into feature/costum_grid_litpop
2 parents ce30fa4 + af793bc commit 6bf9478

File tree

6 files changed

+134
-32
lines changed

6 files changed

+134
-32
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,24 @@ Removed:
1515
- `pandas-datareader`
1616

1717
### Added
18+
- Added optional parameter to `geo_im_from_array`, `plot_from_gdf`, `plot_rp_imp`, `plot_rp_intensity`,
19+
`plot_intensity`, `plot_fraction`, `_event_plot` to mask plotting when regions are too far from data points [#1047](https://github.com/CLIMADA-project/climada_python/pull/1047). To recreate previous plots (no masking), the parameter can be set to None.
1820
- Added instructions to install Climada petals on Euler cluster in `doc.guide.Guide_Euler.ipynb` [#1029](https://github.com/CLIMADA-project/climada_python/pull/1029)
1921

2022
### Changed
23+
2124
- `Hazard.local_exceedance_intensity`, `Hazard.local_return_period` and `Impact.local_exceedance_impact`, `Impact.local_return_period`, using the `climada.util.interpolation` module: New default (no binning), binning on decimals, and faster implementation [#1012](https://github.com/CLIMADA-project/climada_python/pull/1012)
2225
- World Bank indicator data is now downloaded directly from their API via the function `download_world_bank_indicator`, instead of relying on the `pandas-datareader` package [#1033](https://github.com/CLIMADA-project/climada_python/pull/1033)
26+
- `Exposures.write_hdf5` pickles geometry data in WKB format, which is faster and more sustainable. [#1051](https://github.com/CLIMADA-project/climada_python/pull/1051)
2327

2428
### Fixed
29+
2530
- NaN plotting issues in `geo_im_from_array`[#1038](https://github.com/CLIMADA-project/climada_python/pull/1038)
2631

2732
### Deprecated
2833

2934
### Removed
35+
3036
- `climada.util.interpolation.round_to_sig_digits` [#1012](https://github.com/CLIMADA-project/climada_python/pull/1012)
3137

3238
## 6.0.1

climada/engine/impact.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,6 +1178,7 @@ def plot_rp_imp(
11781178
return_periods=(25, 50, 100, 250),
11791179
log10_scale=True,
11801180
axis=None,
1181+
mask_distance=0.01,
11811182
kwargs_local_exceedance_impact=None,
11821183
**kwargs,
11831184
):
@@ -1194,6 +1195,11 @@ def plot_rp_imp(
11941195
plot impact as log10(impact). Default: True
11951196
smooth : bool, optional
11961197
smooth plot to plot.RESOLUTIONxplot.RESOLUTION. Default: True
1198+
mask_distance: float, optional
1199+
Only regions are plotted that are closer to any of the data points than this distance,
1200+
relative to overall plot size. For instance, to only plot values
1201+
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
1202+
Default is 0.01.
11971203
kwargs_local_exceedance_impact: dict
11981204
Dictionary of keyword arguments for the method impact.local_exceedance_impact.
11991205
kwargs : dict, optional
@@ -1242,7 +1248,12 @@ def plot_rp_imp(
12421248
)
12431249

12441250
axis = u_plot.plot_from_gdf(
1245-
impacts_stats, title, column_labels, axis=axis, **kwargs
1251+
impacts_stats,
1252+
title,
1253+
column_labels,
1254+
axis=axis,
1255+
mask_distance=mask_distance,
1256+
**kwargs,
12461257
)
12471258
return axis, impacts_stats_vals
12481259

climada/entity/exposures/base.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import cartopy.crs as ccrs
3131
import contextily as ctx
32+
import geopandas as gpd
3233
import matplotlib.pyplot as plt
3334
import numpy as np
3435
import pandas as pd
@@ -1131,10 +1132,8 @@ def write_hdf5(self, file_name):
11311132
"""
11321133
LOGGER.info("Writing %s", file_name)
11331134
store = pd.HDFStore(file_name, mode="w")
1134-
pandas_df = pd.DataFrame(self.gdf)
1135-
for col in pandas_df.columns:
1136-
if str(pandas_df[col].dtype) == "geometry":
1137-
pandas_df[col] = np.asarray(self.gdf[col])
1135+
geocols = self.data.columns[self.data.dtypes == "geometry"].to_list()
1136+
pandas_df = self.data.to_wkb()
11381137

11391138
# Avoid pandas PerformanceWarning when writing HDF5 data
11401139
with warnings.catch_warnings():
@@ -1146,6 +1145,7 @@ def write_hdf5(self, file_name):
11461145
for var in type(self)._metadata:
11471146
var_meta[var] = getattr(self, var)
11481147
var_meta["crs"] = self.crs
1148+
var_meta["wkb_columns"] = geocols
11491149
store.get_storer("exposures").attrs.metadata = var_meta
11501150

11511151
store.close()
@@ -1184,7 +1184,15 @@ def from_hdf5(cls, file_name):
11841184
crs = metadata.get("crs", metadata.get("_crs"))
11851185
if crs is None and metadata.get("meta"):
11861186
crs = metadata["meta"].get("crs")
1187-
exp = cls(store["exposures"], crs=crs)
1187+
data = pd.DataFrame(store["exposures"])
1188+
1189+
wkb_columns = (
1190+
metadata.pop("wkb_columns") if "wkb_columns" in metadata else []
1191+
)
1192+
for col in wkb_columns:
1193+
data[col] = gpd.GeoSeries.from_wkb(data[col])
1194+
1195+
exp = cls(data, crs=crs)
11881196
for key, val in metadata.items():
11891197
if key in type(exp)._metadata: # pylint: disable=protected-access
11901198
setattr(exp, key, val)

climada/entity/exposures/test/test_base.py

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -378,11 +378,14 @@ def test_read_template_pass(self):
378378

379379
def test_io_hdf5_pass(self):
380380
"""write and read hdf5"""
381-
exp_df = Exposures(pd.read_excel(ENT_TEMPLATE_XLS), crs="epsg:32632")
382-
exp_df.check()
381+
exp = Exposures(pd.read_excel(ENT_TEMPLATE_XLS), crs="epsg:32632")
382+
383383
# set metadata
384-
exp_df.ref_year = 2020
385-
exp_df.value_unit = "XSD"
384+
exp.ref_year = 2020
385+
exp.value_unit = "XSD"
386+
387+
# add another geometry column
388+
exp.data["geocol2"] = exp.data.geometry.copy(deep=True)
386389

387390
file_name = DATA_DIR.joinpath("test_hdf5_exp.h5")
388391

@@ -392,46 +395,51 @@ def test_io_hdf5_pass(self):
392395

393396
with warnings.catch_warnings():
394397
warnings.simplefilter("error", category=pd.errors.PerformanceWarning)
395-
exp_df.write_hdf5(file_name)
398+
exp.write_hdf5(file_name=file_name)
396399

397400
exp_read = Exposures.from_hdf5(file_name)
398401

399-
self.assertEqual(exp_df.ref_year, exp_read.ref_year)
400-
self.assertEqual(exp_df.value_unit, exp_read.value_unit)
401-
self.assertEqual(exp_df.description, exp_read.description)
402-
np.testing.assert_array_equal(exp_df.latitude, exp_read.latitude)
403-
np.testing.assert_array_equal(exp_df.longitude, exp_read.longitude)
404-
np.testing.assert_array_equal(exp_df.value, exp_read.value)
402+
self.assertEqual(exp.ref_year, exp_read.ref_year)
403+
self.assertEqual(exp.value_unit, exp_read.value_unit)
404+
self.assertEqual(exp.description, exp_read.description)
405+
np.testing.assert_array_equal(exp.latitude, exp_read.latitude)
406+
np.testing.assert_array_equal(exp.longitude, exp_read.longitude)
407+
np.testing.assert_array_equal(exp.value, exp_read.value)
405408
np.testing.assert_array_equal(
406-
exp_df.data["deductible"].values, exp_read.data["deductible"].values
409+
exp.data["deductible"].values, exp_read.data["deductible"].values
407410
)
408411
np.testing.assert_array_equal(
409-
exp_df.data["cover"].values, exp_read.data["cover"].values
412+
exp.data["cover"].values, exp_read.data["cover"].values
410413
)
411414
np.testing.assert_array_equal(
412-
exp_df.data["region_id"].values, exp_read.data["region_id"].values
415+
exp.data["region_id"].values, exp_read.data["region_id"].values
413416
)
414417
np.testing.assert_array_equal(
415-
exp_df.data["category_id"].values, exp_read.data["category_id"].values
418+
exp.data["category_id"].values, exp_read.data["category_id"].values
416419
)
417420
np.testing.assert_array_equal(
418-
exp_df.data["impf_TC"].values, exp_read.data["impf_TC"].values
421+
exp.data["impf_TC"].values, exp_read.data["impf_TC"].values
419422
)
420423
np.testing.assert_array_equal(
421-
exp_df.data["centr_TC"].values, exp_read.data["centr_TC"].values
424+
exp.data["centr_TC"].values, exp_read.data["centr_TC"].values
422425
)
423426
np.testing.assert_array_equal(
424-
exp_df.data["impf_FL"].values, exp_read.data["impf_FL"].values
427+
exp.data["impf_FL"].values, exp_read.data["impf_FL"].values
425428
)
426429
np.testing.assert_array_equal(
427-
exp_df.data["centr_FL"].values, exp_read.data["centr_FL"].values
430+
exp.data["centr_FL"].values, exp_read.data["centr_FL"].values
428431
)
429432

430433
self.assertTrue(
431-
u_coord.equal_crs(exp_df.crs, exp_read.crs),
432-
f"{exp_df.crs} and {exp_read.crs} are different",
434+
u_coord.equal_crs(exp.crs, exp_read.crs),
435+
f"{exp.crs} and {exp_read.crs} are different",
436+
)
437+
self.assertTrue(u_coord.equal_crs(exp.data.crs, exp_read.data.crs))
438+
439+
self.assertTrue(exp_read.data["geocol2"].dtype == "geometry")
440+
np.testing.assert_array_equal(
441+
exp.data["geocol2"].geometry, exp_read.data["geocol2"].values
433442
)
434-
self.assertTrue(u_coord.equal_crs(exp_df.gdf.crs, exp_read.gdf.crs))
435443

436444

437445
class TestAddSea(unittest.TestCase):

climada/hazard/plot.py

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def plot_rp_intensity(
4040
self,
4141
return_periods=(25, 50, 100, 250),
4242
axis=None,
43+
mask_distance=0.01,
4344
kwargs_local_exceedance_intensity=None,
4445
**kwargs,
4546
):
@@ -56,6 +57,11 @@ def plot_rp_intensity(
5657
axis to use
5758
kwargs_local_exceedance_intensity: dict
5859
Dictionary of keyword arguments for the method hazard.local_exceedance_intensity.
60+
mask_distance: float, optional
61+
Only regions are plotted that are closer to any of the data points than this distance,
62+
relative to overall plot size. For instance, to only plot values
63+
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
64+
Default is 0.01.
5965
kwargs: optional
6066
arguments for pcolormesh matplotlib function used in event plots
6167
@@ -89,7 +95,12 @@ def plot_rp_intensity(
8995
)
9096

9197
axis = u_plot.plot_from_gdf(
92-
inten_stats, title, column_labels, axis=axis, **kwargs
98+
inten_stats,
99+
title,
100+
column_labels,
101+
axis=axis,
102+
mask_distance=mask_distance,
103+
**kwargs,
93104
)
94105
return axis, inten_stats.values[:, 1:].T.astype(float)
95106

@@ -100,6 +111,7 @@ def plot_intensity(
100111
smooth=True,
101112
axis=None,
102113
adapt_fontsize=True,
114+
mask_distance=0.01,
103115
**kwargs,
104116
):
105117
"""Plot intensity values for a selected event or centroid.
@@ -123,6 +135,11 @@ def plot_intensity(
123135
in module `climada.util.plot`)
124136
axis: matplotlib.axes._subplots.AxesSubplot, optional
125137
axis to use
138+
mask_distance: float, optional
139+
Only regions are plotted that are closer to any of the data points than this distance,
140+
relative to overall plot size. For instance, to only plot values
141+
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
142+
Default is 0.01.
126143
kwargs: optional
127144
arguments for pcolormesh matplotlib function
128145
used in event plots or for plot function used in centroids plots
@@ -148,6 +165,7 @@ def plot_intensity(
148165
crs_epsg,
149166
axis,
150167
adapt_fontsize=adapt_fontsize,
168+
mask_distance=mask_distance,
151169
**kwargs,
152170
)
153171
if centr is not None:
@@ -157,7 +175,15 @@ def plot_intensity(
157175

158176
raise ValueError("Provide one event id or one centroid id.")
159177

160-
def plot_fraction(self, event=None, centr=None, smooth=True, axis=None, **kwargs):
178+
def plot_fraction(
179+
self,
180+
event=None,
181+
centr=None,
182+
smooth=True,
183+
axis=None,
184+
mask_distance=0.01,
185+
**kwargs,
186+
):
161187
"""Plot fraction values for a selected event or centroid.
162188
163189
Parameters
@@ -179,6 +205,11 @@ def plot_fraction(self, event=None, centr=None, smooth=True, axis=None, **kwargs
179205
in module `climada.util.plot`)
180206
axis: matplotlib.axes._subplots.AxesSubplot, optional
181207
axis to use
208+
mask_distance: float, optional
209+
Relative distance (with respect to maximal map extent in longitude or latitude) to data
210+
points above which plot should not display values. For instance, to only plot values
211+
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
212+
Default is None.
182213
kwargs: optional
183214
arguments for pcolormesh matplotlib function
184215
used in event plots or for plot function used in centroids plots
@@ -196,7 +227,13 @@ def plot_fraction(self, event=None, centr=None, smooth=True, axis=None, **kwargs
196227
if isinstance(event, str):
197228
event = self.get_event_id(event)
198229
return self._event_plot(
199-
event, self.fraction, col_label, smooth, axis, **kwargs
230+
event,
231+
self.fraction,
232+
col_label,
233+
smooth,
234+
axis,
235+
mask_distance=mask_distance,
236+
**kwargs,
200237
)
201238
if centr is not None:
202239
if isinstance(centr, tuple):
@@ -215,6 +252,7 @@ def _event_plot(
215252
axis=None,
216253
figsize=(9, 13),
217254
adapt_fontsize=True,
255+
mask_distance=0.01,
218256
**kwargs,
219257
):
220258
"""Plot an event of the input matrix.
@@ -236,6 +274,11 @@ def _event_plot(
236274
axis to use
237275
figsize: tuple, optional
238276
figure size for plt.subplots
277+
mask_distance: float, optional
278+
Only regions are plotted that are closer to any of the data points than this distance,
279+
relative to overall plot size. For instance, to only plot values
280+
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
281+
Default is None.
239282
kwargs: optional
240283
arguments for pcolormesh matplotlib function
241284
@@ -283,6 +326,7 @@ def _event_plot(
283326
figsize=figsize,
284327
proj=crs_espg,
285328
adapt_fontsize=adapt_fontsize,
329+
mask_distance=mask_distance,
286330
**kwargs,
287331
)
288332

0 commit comments

Comments
 (0)