Skip to content

Commit 32a0fde

Browse files
update function
1 parent 2581a08 commit 32a0fde

File tree

3 files changed

+64
-19
lines changed

3 files changed

+64
-19
lines changed

climada/hazard/plot.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
import cartopy.crs as ccrs
2525
import cartopy.feature as cfeature
26+
import matplotlib.colors as mcolors
2627
import matplotlib.pyplot as plt
2728
import numpy as np
2829
from deprecation import deprecated
@@ -168,11 +169,13 @@ def plot_track_density(
168169
add_features: dict = None,
169170
title: str = None,
170171
figsize=(12, 6),
172+
div_cmap=False,
173+
cbar=True,
171174
cbar_kwargs: dict = {
172175
"orientation": "horizontal",
173176
"pad": 0.05,
174177
"shrink": 0.8,
175-
"label": "Track Density [n° tracks / km²]",
178+
"label": "n° tracks per 1° x 1° grid cell",
176179
},
177180
**kwargs,
178181
):
@@ -194,6 +197,10 @@ def plot_track_density(
194197
Title of the plot.
195198
figsize: tuple
196199
Figure size when creating a new figure.
200+
div_cmap: bool, default = False
201+
If True, the colormap will be centered to 0.
202+
cbar: bool, Default = True
203+
If True, the color bar is added
197204
cbar_kwargs: dict
198205
dictionary containing keyword arguments passed to cbar
199206
kwargs:
@@ -262,12 +269,23 @@ def plot_track_density(
262269
if add_features.get("lakes", False):
263270
axis.add_feature(cfeature.LAKES, alpha=0.4, edgecolor="black")
264271

265-
# Plot density with contourf
266-
contourf = axis.contourf(lon, lat, hist, transform=ccrs.PlateCarree(), **kwargs)
272+
if div_cmap:
273+
norm = mcolors.TwoSlopeNorm(
274+
vmin=np.nanmin(hist), vcenter=0, vmax=np.nanmax(hist)
275+
)
276+
kwargs["norm"] = norm
277+
278+
# contourf = axis.contourf(lon, lat, hist, transform=ccrs.PlateCarree(), **kwargs)
279+
contourf = axis.imshow(
280+
hist,
281+
extent=[lon.min(), lon.max(), lat.min(), lat.max()],
282+
transform=ccrs.PlateCarree(),
283+
origin="lower",
284+
**kwargs,
285+
)
267286

268-
# Add colorbar
269-
plt.colorbar(contourf, ax=axis, **cbar_kwargs)
270-
# Title setup
287+
if cbar:
288+
plt.colorbar(contourf, ax=axis, **cbar_kwargs)
271289
if title:
272290
axis.set_title(title, fontsize=16)
273291

climada/hazard/tc_tracks.py

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2985,6 +2985,7 @@ def _zlib_from_dataarray(data_var: xr.DataArray) -> bool:
29852985
def compute_track_density(
29862986
tc_track: TCTracks,
29872987
res: int = 5,
2988+
bounds: tuple = None,
29882989
genesis: bool = False,
29892990
norm: str = None,
29902991
filter_tracks: bool = True,
@@ -3005,19 +3006,23 @@ def compute_track_density(
30053006
track object containing a list of all tracks
30063007
res: int (optional), default: 5°
30073008
resolution in degrees of the grid bins in which the density will be computed
3009+
bounds: tuple, dafault: None
3010+
(lat_min,lat_max,lon_min,lon_max) latitude and longitude bounds to compute track density.
30083011
genesis: bool, Default = False
30093012
If true the function computes the track density of only the genesis location of tracks
3010-
norm: bool (optional), default = False
3011-
If False it returns the number of samples in each bin. If True, returns the
3012-
specified normalization function at each bin computed as count_bin / grid_area.
3013+
norm: str (optional), default = None
3014+
If None the function returns the number of samples in each bin. If True, it normalize the
3015+
bin count as specified: if norm = area -> normalize by gird cell area. If norm = sum ->
3016+
normalize by the total sum of each bin.
30133017
filter_tracks: bool (optional) default: True
30143018
If True the track density is computed as the number of different tracks crossing a grid
30153019
cell. If False, the track density takes into account how long the track stayed in each
30163020
grid cell. Hence slower tracks increase the density if the parameter is set to False.
30173021
wind_min: float (optional), default: None
3018-
Minimum wind speed above which to select tracks.
3022+
Minimum wind speed above which to select tracks (inclusive).
30193023
wind_max: float (optional), default: None
3020-
Maximal wind speed below which to select tracks.
3024+
Maximal wind speed below which to select tracks (exclusive if wind_min is also provided,
3025+
otherwise inclusive).
30213026
Returns:
30223027
-------
30233028
hist_count: np.ndarray
@@ -3048,8 +3053,14 @@ def compute_track_density(
30483053
)
30493054

30503055
# define grid resolution and bounds for density computation
3051-
lat_bins: np.ndarray = np.linspace(-90, 90, int(180 / res))
3052-
lon_bins: np.ndarray = np.linspace(-180, 180, int(360 / res))
3056+
if not bounds:
3057+
lat_min, lat_max, lon_min, lon_max = -90, 90, -180, 180
3058+
else:
3059+
lat_min, lat_max, lon_min, lon_max = bounds[0], bounds[1], bounds[2], bounds[3]
3060+
3061+
lat_bins: np.ndarray = np.linspace(lat_min, lat_max, int(180 / res))
3062+
lon_bins: np.ndarray = np.linspace(lon_min, lon_max, int(360 / res))
3063+
30533064
# compute 2D density
30543065
if genesis:
30553066
hist_count = compute_genesis_density(
@@ -3062,7 +3073,7 @@ def compute_track_density(
30623073
# select according to wind speed
30633074
wind_speed = track.max_sustained_wind.values
30643075
if wind_min and wind_max:
3065-
index = np.where((wind_speed >= wind_min) & (wind_speed <= wind_max))[0]
3076+
index = np.where((wind_speed >= wind_min) & (wind_speed < wind_max))[0]
30663077
elif wind_min and not wind_max:
30673078
index = np.where(wind_speed >= wind_min)[0]
30683079
elif wind_max and not wind_min:
@@ -3147,9 +3158,14 @@ def normalize_hist(
31473158
"""
31483159

31493160
if norm == "area":
3150-
grid_area, _ = u_coord.compute_grid_cell_area(res=res)
3161+
grid_area = u_coord.compute_grid_cell_area(res=res)
31513162
norm_hist: np.ndarray = hist_count / grid_area
31523163
elif norm == "sum":
31533164
norm_hist: np.ndarray = hist_count / hist_count.sum()
3165+
else:
3166+
raise ValueError(
3167+
"Invalid value for input parameter 'norm':\n"
3168+
"it should be either 'area' or 'sum'"
3169+
)
31543170

31553171
return norm_hist

climada/util/coordinates.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -528,15 +528,20 @@ def compute_grid_cell_area_validation(res: float) -> tuple[np.ndarray]:
528528

529529

530530
def compute_grid_cell_area(
531-
res: float = 1.0, projection: str = "WGS84", units: str = "km^2"
531+
res: float = None,
532+
bounds: tuple = None,
533+
projection: str = "WGS84",
534+
units: str = "km^2",
532535
) -> np.ndarray:
533536
"""
534537
Compute the area of each grid cell in a latitude-longitude grid.
535538
536539
Parameters:
537540
-----------
538541
res: float
539-
Grid resolution in degrees (default is 1° x 1°)
542+
Grid resolution in degrees
543+
bounds: tuple, dafault: None
544+
(lat_min,lat_max,lon_min,lon_max) latitude and longitude bounds to compute grid cell area
540545
projection: str
541546
Ellipsoid or spherical projection to approximate Earth. To get the complete list of
542547
projections call :py:meth:`pyproj.get_ellps_map()`. Widely used projections:
@@ -556,8 +561,14 @@ def compute_grid_cell_area(
556561
>>> area = compute_grid_areas(res = 1, projection ="sphere", units = "m^2")
557562
"""
558563
geod = Geod(ellps=projection) # Use specified ellipsoid model
559-
lat_edges = np.linspace(-90, 90, int(180 / res)) # Latitude edges
560-
lon_edges = np.linspace(-180, 180, int(360 / res)) # Longitude edges
564+
565+
if not bounds:
566+
lat_min, lat_max, lon_min, lon_max = -90, 90, -180, 180
567+
else:
568+
lat_min, lat_max, lon_min, lon_max = bounds[0], bounds[1], bounds[2], bounds[3]
569+
570+
lat_edges: np.ndarray = np.linspace(lat_min, lat_max, int(180 / res))
571+
lon_edges: np.ndarray = np.linspace(lon_min, lon_max, int(360 / res))
561572

562573
area = np.zeros((len(lat_edges) - 1, len(lon_edges) - 1)) # Create an empty grid
563574

0 commit comments

Comments
 (0)