Skip to content

Add option in raster plot to crop around centroids #1047

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

Merged
merged 8 commits into from
May 16, 2025
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
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Removed:
- `pandas-datareader`

### Added

- Added optional parameter to `geo_im_from_array`, `plot_from_gdf`, `plot_rp_imp`, `plot_rp_intensity`,
`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.
- 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)

### Changed
Expand Down
13 changes: 12 additions & 1 deletion climada/engine/impact.py
Original file line number Diff line number Diff line change
Expand Up @@ -1173,11 +1173,12 @@

return axis

def plot_rp_imp(

Check warning on line 1176 in climada/engine/impact.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-positional-arguments

LOW: Too many positional arguments (6/5)
Raw output
no description found
self,
return_periods=(25, 50, 100, 250),
log10_scale=True,
axis=None,
mask_distance=0.01,
kwargs_local_exceedance_impact=None,
**kwargs,
):
Expand All @@ -1194,6 +1195,11 @@
plot impact as log10(impact). Default: True
smooth : bool, optional
smooth plot to plot.RESOLUTIONxplot.RESOLUTION. Default: True
mask_distance: float, optional
Only regions are plotted that are closer to any of the data points than this distance,
relative to overall plot size. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is 0.01.
kwargs_local_exceedance_impact: dict
Dictionary of keyword arguments for the method impact.local_exceedance_impact.
kwargs : dict, optional
Expand Down Expand Up @@ -1242,7 +1248,12 @@
)

axis = u_plot.plot_from_gdf(
impacts_stats, title, column_labels, axis=axis, **kwargs
impacts_stats,
title,
column_labels,
axis=axis,
mask_distance=mask_distance,
**kwargs,
)
return axis, impacts_stats_vals

Expand Down
50 changes: 47 additions & 3 deletions climada/hazard/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
self,
return_periods=(25, 50, 100, 250),
axis=None,
mask_distance=0.01,
kwargs_local_exceedance_intensity=None,

Check warning on line 44 in climada/hazard/plot.py

View check run for this annotation

Jenkins - WCR / Pylint

invalid-name

LOW: Argument name "kwargs_local_exceedance_intensity" doesn't conform to '(([a-z][a-z0-9_]{2,30})|(_[a-z0-9_]*))$' pattern
Raw output
Used when the name doesn't match the regular expression associated to its type(constant, variable, class...).
**kwargs,
):
"""
Expand All @@ -56,6 +57,11 @@
axis to use
kwargs_local_exceedance_intensity: dict
Dictionary of keyword arguments for the method hazard.local_exceedance_intensity.
mask_distance: float, optional
Only regions are plotted that are closer to any of the data points than this distance,
relative to overall plot size. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is 0.01.
kwargs: optional
arguments for pcolormesh matplotlib function used in event plots

Expand Down Expand Up @@ -89,7 +95,12 @@
)

axis = u_plot.plot_from_gdf(
inten_stats, title, column_labels, axis=axis, **kwargs
inten_stats,
title,
column_labels,
axis=axis,
mask_distance=mask_distance,
**kwargs,
)
return axis, inten_stats.values[:, 1:].T.astype(float)

Expand All @@ -100,6 +111,7 @@
smooth=True,
axis=None,
adapt_fontsize=True,
mask_distance=0.01,
**kwargs,
):
"""Plot intensity values for a selected event or centroid.
Expand All @@ -123,6 +135,11 @@
in module `climada.util.plot`)
axis: matplotlib.axes._subplots.AxesSubplot, optional
axis to use
mask_distance: float, optional
Only regions are plotted that are closer to any of the data points than this distance,
relative to overall plot size. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is 0.01.
kwargs: optional
arguments for pcolormesh matplotlib function
used in event plots or for plot function used in centroids plots
Expand All @@ -148,6 +165,7 @@
crs_epsg,
axis,
adapt_fontsize=adapt_fontsize,
mask_distance=mask_distance,
**kwargs,
)
if centr is not None:
Expand All @@ -157,7 +175,15 @@

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

def plot_fraction(self, event=None, centr=None, smooth=True, axis=None, **kwargs):
def plot_fraction(

Check warning on line 178 in climada/hazard/plot.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-positional-arguments

LOW: Too many positional arguments (6/5)
Raw output
no description found
self,
event=None,
centr=None,
smooth=True,
axis=None,
mask_distance=0.01,
**kwargs,
):
"""Plot fraction values for a selected event or centroid.

Parameters
Expand All @@ -179,6 +205,11 @@
in module `climada.util.plot`)
axis: matplotlib.axes._subplots.AxesSubplot, optional
axis to use
mask_distance: float, optional
Relative distance (with respect to maximal map extent in longitude or latitude) to data
points above which plot should not display values. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is None.
kwargs: optional
arguments for pcolormesh matplotlib function
used in event plots or for plot function used in centroids plots
Expand All @@ -196,7 +227,13 @@
if isinstance(event, str):
event = self.get_event_id(event)
return self._event_plot(
event, self.fraction, col_label, smooth, axis, **kwargs
event,
self.fraction,
col_label,
smooth,
axis,
mask_distance=mask_distance,
**kwargs,
)
if centr is not None:
if isinstance(centr, tuple):
Expand All @@ -215,6 +252,7 @@
axis=None,
figsize=(9, 13),
adapt_fontsize=True,
mask_distance=0.01,
**kwargs,
):
"""Plot an event of the input matrix.
Expand All @@ -236,6 +274,11 @@
axis to use
figsize: tuple, optional
figure size for plt.subplots
mask_distance: float, optional
Only regions are plotted that are closer to any of the data points than this distance,
relative to overall plot size. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is None.
kwargs: optional
arguments for pcolormesh matplotlib function

Expand Down Expand Up @@ -283,6 +326,7 @@
figsize=figsize,
proj=crs_espg,
adapt_fontsize=adapt_fontsize,
mask_distance=mask_distance,
**kwargs,
)

Expand Down
27 changes: 26 additions & 1 deletion climada/util/plot.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
from mpl_toolkits.axes_grid1 import make_axes_locatable
from rasterio.crs import CRS
from scipy.interpolate import griddata
from scipy.spatial import cKDTree
from shapely.geometry import box

import climada.util.coordinates as u_coord
Expand Down Expand Up @@ -337,6 +338,7 @@
axes=None,
figsize=(9, 13),
adapt_fontsize=True,
mask_distance=0.01,
**kwargs,
):
"""Image(s) plot defined in array(s) over input coordinates.
Expand Down Expand Up @@ -368,6 +370,11 @@
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.
mask_distance: float, optional
Only regions are plotted that are closer to any of the data points than this distance,
relative to overall plot size. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is 0.01.
**kwargs
arbitrary keyword arguments for pcolormesh matplotlib function

Expand Down Expand Up @@ -448,6 +455,17 @@
(grid_x, grid_y),
fill_value=min_value,
)
# Compute distance of each grid point to the nearest known point
if mask_distance is not None:
tree = cKDTree(np.array((coord[:, 1], coord[:, 0])).T)
distances, _ = tree.query(
np.c_[grid_x.ravel(), grid_y.ravel()],
p=2, # for plotting squares and not sphere around centroids use p=np.inf
)
threshold = (
max(extent[1] - extent[0], extent[3] - extent[2]) * mask_distance
)
grid_im[(distances.reshape(grid_im.shape) > threshold)] = min_value
else:
grid_x = coord[:, 1].reshape((width, height)).transpose()
grid_y = coord[:, 0].reshape((width, height)).transpose()
Expand Down Expand Up @@ -477,7 +495,7 @@
)
# handle NaNs in griddata
color_nan = "gainsboro"
if np.any(np.isnan(x) for x in grid_im):
if np.isnan(grid_im).any():
Comment on lines -480 to +498
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume, this is the fix for the bug?
When does it occur? (How can it be reproduced?)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the idea was that whenever grid_im has a NaN we want to include a small legend (because we plot nan values in gray). np.any(np.isnan(x) for x in grid_im) from before did not actually output a bool but a generator, such that this if condition was always True

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ValentinGebhart Thanks! You don't happen to have an example that you could point me to?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. This would be an example where we want the legend (see PR #1038):

import numpy as np
from climada.hazard import Hazard
from climada.util import HAZ_DEMO_H5 # CLIMADA's Python file
haz_tc_fl = Hazard.from_hdf5(HAZ_DEMO_H5) # Historic tropical cyclones in Florida from 1990 to 2004
haz_tc_fl.check() # Use always the check() method to see if the hazard has been loaded correctly

centroids_mask = np.array(
[ (i + j > 10) for j in range(50) for i in range(50)]
)
haz_tc_fl.centroids = haz_tc_fl.centroids.select(sel_cen=centroids_mask)
haz_tc_fl.intensity = haz_tc_fl.intensity[:, -2434:]

return_periods, label, column_label = haz_tc_fl.local_return_period([30, 40])

from climada.util.plot import plot_from_gdf
plot_from_gdf(return_periods, colorbar_name=label, title_subplots=column_label)

and here we do not want the legend but in the current develop version it would be printed as well.

haz_tc_fl.plot_intensity(event=0)

no_data_patch = mpatches.Patch(
facecolor=color_nan, edgecolor="black", label="NaN"
)
Expand Down Expand Up @@ -1078,7 +1096,7 @@
ax.legend(bars, data.keys())


def plot_from_gdf(

Check warning on line 1099 in climada/util/plot.py

View check run for this annotation

Jenkins - WCR / Pylint

too-many-positional-arguments

LOW: Too many positional arguments (8/5)
Raw output
no description found
gdf: gpd.GeoDataFrame,
colorbar_name: str = None,
title_subplots: callable = None,
Expand All @@ -1086,6 +1104,7 @@
axis=None,
figsize=(9, 13),
adapt_fontsize=True,
mask_distance=0.01,
**kwargs,
):
"""Plot several subplots from different columns of a GeoDataFrame, e.g., for
Expand All @@ -1108,6 +1127,11 @@
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.
mask_distance: float, optional
Relative distance (with respect to maximal map extent in longitude or latitude) to data
points above which plot should not display values. For instance, to only plot values
at the centroids, use mask_distance=0.01. If None, the plot is not masked.
Default is 0.01.
kwargs: optional
Arguments for pcolormesh matplotlib function used in event plots.

Expand Down Expand Up @@ -1168,6 +1192,7 @@
axes=axis,
figsize=figsize,
adapt_fontsize=adapt_fontsize,
mask_distance=mask_distance,
**kwargs,
)

Expand Down
Loading