Skip to content

Commit

Permalink
Feature/init hazard centroids (#563)
Browse files Browse the repository at this point in the history
* update init in centr.py

* updated test and hazard files

* update init centroids

* update test_base

* bugfix test_methods

* bugfix test_vec_ras.py

* Format Centroids.__init__ and its docstring

Co-authored-by: Raphael Portmann <[email protected]>
Co-authored-by: Lukas Riedel <[email protected]>
  • Loading branch information
3 people authored Oct 28, 2022
1 parent 0a7caf9 commit 4cb13dc
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 104 deletions.
4 changes: 2 additions & 2 deletions climada/entity/exposures/test/test_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,12 @@ def test_assign_raster_pass(self):
haz = Hazard('FL')

# explicit, easy-to-understand raster centroids for hazard
haz.centroids = Centroids()
haz.centroids.meta = {
meta = {
'count': 1, 'crs': DEF_CRS,
'width': 20, 'height': 10,
'transform': rasterio.Affine(1.5, 0.0, -20, 0.0, -1.4, 8)
}
haz.centroids = Centroids(meta=meta)

# explicit points with known results (see `expected_result` for details)
exp = Exposures(crs=DEF_CRS)
Expand Down
3 changes: 1 addition & 2 deletions climada/hazard/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1064,8 +1064,7 @@ def vector_to_raster(self, scheduler=None):
scheduler=scheduler)
self.intensity = sparse.csr_matrix(raster[:self.size, :, :].reshape(self.size, -1))
self.fraction = sparse.csr_matrix(raster[self.size:, :, :].reshape(self.size, -1))
self.centroids = Centroids()
self.centroids.meta = meta
self.centroids = Centroids(meta=meta)
self.check()

def read_mat(self, *args, **kwargs):
Expand Down
111 changes: 73 additions & 38 deletions climada/hazard/centroids/centr.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import copy
import logging
from pathlib import Path
from typing import Optional, Dict, Any

import cartopy.crs as ccrs
import geopandas as gpd
Expand Down Expand Up @@ -104,17 +105,55 @@ class Centroids():
'on_land', 'region_id', 'elevation'}
"""Variables whose size will be checked"""

def __init__(self):
"""Initialize to None raster and vector. Default crs=DEF_CRS"""
self.meta = dict()
self.geometry = gpd.GeoSeries(crs=DEF_CRS)
self.lat = np.array([])
self.lon = np.array([])
self.area_pixel = np.array([])
self.dist_coast = np.array([])
self.on_land = np.array([])
self.region_id = np.array([])
self.elevation = np.array([])
def __init__(
self,
lat: Optional[np.ndarray] = None,
lon: Optional[np.ndarray] = None,
geometry: Optional[gpd.GeoSeries] = None,
meta: Optional[Dict[Any, Any]] = None,
area_pixel: Optional[np.ndarray] = None,
on_land: Optional[np.ndarray] = None,
region_id: Optional[np.ndarray] = None,
elevation: Optional[np.ndarray] = None,
dist_coast: Optional[np.ndarray] = None
):
"""Initialization
Parameters
----------
lat : np.array, optional
latitude of size size. Defaults to empty array
lon : np.array, optional
longitude of size size. Defaults to empty array
geometry : gpd.GeoSeries, optional
contains lat and lon crs. Might contain geometry points for lat and lon.
Defaults to empty gpd.Geoseries with crs=DEF_CRS
meta : dict, optional
rasterio meta dictionary containing raster properties: width, height, crs and
transform must be present at least. The affine ransformation needs to be
shearless (only stretching) and have positive x- and negative y-orientation.
Defaults to empty dict()
area_pixel : np.array, optional
area of size size. Defaults to empty array
on_land : np.array, optional
on land (True) and on sea (False) of size size. Defaults to empty array
region_id : np.array, optional
country region code of size size, Defaults to empty array
elevation : np.array, optional
elevation of size size. Defaults to empty array
dist_coast : np.array, optional
distance to coast of size size. Defaults to empty array
"""

self.lat = lat if lat is not None else np.array([])
self.lon = lon if lon is not None else np.array([])
self.geometry = geometry if geometry is not None else gpd.GeoSeries(crs=DEF_CRS)
self.meta = meta if meta is not None else dict()
self.area_pixel = area_pixel if area_pixel is not None else np.array([])
self.on_land = on_land if on_land is not None else np.array([])
self.region_id = region_id if region_id is not None else np.array([])
self.elevation = elevation if elevation is not None else np.array([])
self.dist_coast = dist_coast if dist_coast is not None else np.array([])

def check(self):
"""Check integrity of stored information.
Expand Down Expand Up @@ -235,11 +274,10 @@ def from_geodataframe(cls, gdf, geometry_alias='geom'):
centr : Centroids
Centroids with data from given GeoDataFrame
"""
centroids = cls()

centroids.geometry = gdf.geometry
centroids.lat = gdf.geometry.y.to_numpy(copy=True)
centroids.lon = gdf.geometry.x.to_numpy(copy=True)
geometry = gdf.geometry
lat = gdf.geometry.y.to_numpy(copy=True)
lon = gdf.geometry.x.to_numpy(copy=True)
centroids = cls(lat=lat, lon=lon, geometry=geometry)

for col in gdf.columns:
if col in [geometry_alias, 'geometry', 'lat', 'lon']:
Expand Down Expand Up @@ -287,15 +325,15 @@ def from_pix_bounds(cls, xf_lat, xo_lon, d_lat, d_lon, n_lat, n_lon, crs=DEF_CRS
centr : Centroids
Centroids with meta according to given pixel border data.
"""
centr = cls()
centr.meta = {
meta = {
'dtype': 'float32',
'width': n_lon,
'height': n_lat,
'crs': crs,
'transform': rasterio.Affine(d_lon, 0.0, xo_lon, 0.0, d_lat, xf_lat),
}
return centr

return cls(meta=meta)

def set_raster_from_pnt_bounds(self, *args, **kwargs):
"""This function is deprecated, use Centroids.from_pnt_bounds instead."""
Expand Down Expand Up @@ -323,15 +361,14 @@ def from_pnt_bounds(cls, points_bounds, res, crs=DEF_CRS):
centr : Centroids
Centroids with meta according to given points border data.
"""
centr = cls()
rows, cols, ras_trans = u_coord.pts_to_raster_meta(points_bounds, (res, -res))
centr.meta = {
meta = {
'width': cols,
'height': rows,
'crs': crs,
'transform': ras_trans,
}
return centr
return cls(meta=meta)

def set_lat_lon(self, *args, **kwargs):
"""This function is deprecated, use Centroids.from_lat_lon instead."""
Expand All @@ -357,11 +394,10 @@ def from_lat_lon(cls, lat, lon, crs=DEF_CRS):
centr : Centroids
Centroids with points according to given coordinates
"""
centr = cls()
centr.lat = np.asarray(lat)
centr.lon = np.asarray(lon)
centr.geometry = gpd.GeoSeries(crs=crs)
return centr
lat = np.asarray(lat)
lon = np.asarray(lon)
geometry = gpd.GeoSeries(crs=crs)
return cls(lat=lat, lon=lon, geometry=geometry)

def set_raster_file(self, file_name, band=None, **kwargs):
"""This function is deprecated, use Centroids.from_raster_file
Expand Down Expand Up @@ -408,11 +444,10 @@ def from_raster_file(cls, file_name, src_crs=None, window=False,
centr : Centroids
Centroids with meta attribute according to the given raster file
"""
centr = cls()
centr.meta, _ = u_coord.read_raster(
meta, _ = u_coord.read_raster(
file_name, [1], src_crs, window, geometry, dst_crs,
transform, width, height, resampling)
return centr
return cls(meta=meta)

def values_from_raster_files(self, file_names, band=None, src_crs=None, window=False,
geometry=False, dst_crs=False, transform=None, width=None,
Expand Down Expand Up @@ -498,10 +533,9 @@ def from_vector_file(cls, file_name, dst_crs=None):
centr : Centroids
Centroids with points according to the given vector file
"""
centr = cls()
centr.lat, centr.lon, centr.geometry, _ = u_coord.read_vector(
lat, lon, geometry, _ = u_coord.read_vector(
file_name, [], dst_crs=dst_crs)
return centr
return cls(lat=lat, lon=lon, geometry=geometry)

def values_from_vector_files(self, file_names, val_names=None, dst_crs=None):
"""Read intensity or other data from vector files, making sure that geometry is compatible.
Expand Down Expand Up @@ -736,7 +770,6 @@ def union(self, *others):

# create new Centroids object and set concatenated attributes
centroids = Centroids()
centroids.meta = {}
for attr_name, attr_val in vars(cent_list[0]).items():
if isinstance(attr_val, np.ndarray) and attr_val.ndim == 1:
attr_val_list = [getattr(cent, attr_name) for cent in cent_list]
Expand Down Expand Up @@ -1186,13 +1219,15 @@ def _from_hdf5(cls, data):
crs=crs)
else:
centr_meta = data.get('meta')
centr = cls()
centr.meta['crs'] = crs
meta = dict()
meta['crs'] = crs
for key, value in centr_meta.items():
if key != 'transform':
centr.meta[key] = value[0]
meta[key] = value[0]
else:
centr.meta[key] = rasterio.Affine(*value)
meta[key] = rasterio.Affine(*value)
centr = cls(meta=meta)

for centr_name in data.keys():
if centr_name not in ('crs', 'lat', 'lon', 'meta'):
setattr(centr, centr_name, np.array(data.get(centr_name)))
Expand Down
16 changes: 8 additions & 8 deletions climada/hazard/centroids/test/test_centr.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,16 +131,16 @@ def test_write_hdf5(self):
class TestCentroidsMethods(unittest.TestCase):

def test_union(self):
cent1 = Centroids()
cent1.lat, cent1.lon = np.array([0, 1]), np.array([0, -1])
cent1.on_land = np.array([True, True])
lat, lon = np.array([0, 1]), np.array([0, -1])
on_land = np.array([True, True])
cent1 = Centroids(lat=lat, lon=lon, on_land=on_land)

cent2 = Centroids()
cent2.lat, cent2.lon = np.array([2, 3]), np.array([-2, 3])
cent2.on_land = np.array([False, False])
lat2, lon2 = np.array([2, 3]), np.array([-2, 3])
on_land2 = np.array([False, False])
cent2 = Centroids(lat=lat2, lon=lon2, on_land=on_land2)

cent3 = Centroids()
cent3.lat, cent3.lon = np.array([-1, -2]), np.array([1, 2])
lat3, lon3 = np.array([-1, -2]), np.array([1, 2])
cent3 = Centroids(lat=lat3,lon=lon3)

cent = cent1.union(cent2)
np.testing.assert_array_equal(cent.lat, [0, 1, 2, 3])
Expand Down
Loading

0 comments on commit 4cb13dc

Please sign in to comment.