Skip to content

Commit 4265ee4

Browse files
committed
#update code
1 parent ef8be45 commit 4265ee4

12 files changed

+188
-41
lines changed

GeoAnalyze/core.py

+12-4
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,19 @@ def raster_resampling_method(
123123
) -> dict[str, rasterio.enums.Resampling]:
124124

125125
'''
126-
Returns the dictionary of raster resampling method. Supported options are:
127-
- `nearest`: Nearest-neighbor interpolation.
128-
- `bilinear`: Bilinear interpolation.
129-
- `cubic`: Cubic convolution interpolation.
126+
Returns the dictionary of raster resampling methods.
127+
128+
Supported options:
129+
130+
================= ===========================================
131+
Method Description
132+
================= ===========================================
133+
nearest Nearest-neighbor interpolation.
134+
bilinear Bilinear interpolation.
135+
cubic Cubic interpolation.
136+
================= ===========================================
130137
'''
138+
131139
resampling_dictionary = {
132140
'nearest': rasterio.enums.Resampling.nearest,
133141
'bilinear': rasterio.enums.Resampling.bilinear,

GeoAnalyze/data/polygon.cpg

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
UTF-8

GeoAnalyze/data/polygon.dbf

85 Bytes
Binary file not shown.

GeoAnalyze/data/polygon.prj

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
PROJCS["EUREF_FIN_TM35FIN",GEOGCS["GCS_ETRS_1989",DATUM["D_ETRS_1989",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Transverse_Mercator"],PARAMETER["False_Easting",500000.0],PARAMETER["False_Northing",0.0],PARAMETER["Central_Meridian",27.0],PARAMETER["Scale_Factor",0.9996],PARAMETER["Latitude_Of_Origin",0.0],UNIT["Meter",1.0]]

GeoAnalyze/data/polygon.shp

76.8 KB
Binary file not shown.

GeoAnalyze/data/polygon.shx

108 Bytes
Binary file not shown.

GeoAnalyze/packagedata.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import rasterio
3+
import geopandas
34
from .core import Core
45

56

@@ -9,7 +10,6 @@ class PackageData:
910
Provides access to datasets included in the :mod:`GeoAnalyze` package.
1011
'''
1112

12-
# pytest complete
1313
def get_dem(
1414
self,
1515
dem_file: str
@@ -49,3 +49,22 @@ def get_dem(
4949
dem_raster.write(raster_array, 1)
5050

5151
return raster_profile
52+
53+
@property
54+
def get_polygon_gdf(
55+
self,
56+
) -> geopandas.GeoDataFrame:
57+
58+
'''
59+
Retrieves the polygon GeoDataFrame from the test data.
60+
'''
61+
62+
# data file path
63+
data_file = os.path.join(
64+
os.path.dirname(__file__), 'data', 'polygon.shp'
65+
)
66+
67+
# polygon GeoDataFrame
68+
gdf = geopandas.read_file(data_file)
69+
70+
return gdf

GeoAnalyze/raster.py

+44-25
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,13 @@ def resolution_rescaling(
253253

254254
return output_profile
255255

256-
# pytest pending
257256
def resolution_rescaling_with_mask(
258257
self,
259258
input_file: str,
260259
mask_file: str,
261260
resampling_method: str,
262261
output_file: str
263-
) -> list[list[float]]:
262+
) -> rasterio.profiles.Profile:
264263

265264
'''
266265
Rescales the raster array from its existing resolution
@@ -275,10 +274,8 @@ def resolution_rescaling_with_mask(
275274
Path to the mask raster file, defining the spatial extent and resolution.
276275
277276
resampling_method : str
278-
Method used for raster resampling. Supported options are:
279-
- 'nearest': Nearest-neighbor interpolation.
280-
- 'bilinear': Bilinear interpolation.
281-
- 'cubic': Cubic convolution interpolation.
277+
Raster resampling method with supported options from
278+
:attr:`GeoAnalyze.core.Core.raster_resampling_method`.
282279
283280
output_file : str
284281
Path to the output raster file.
@@ -290,18 +287,19 @@ def resolution_rescaling_with_mask(
290287
of the reprojected raster array. Each sublist represents a row of the matrix.
291288
'''
292289

293-
# mapping of resampling methods
294-
resampling_function = {
295-
'nearest': rasterio.enums.Resampling.nearest,
296-
'bilinear': rasterio.enums.Resampling.bilinear,
297-
'cubic': rasterio.enums.Resampling.cubic
298-
}
290+
# check validity of output file path
291+
check_file = Core().is_valid_raster_driver(output_file)
292+
if check_file is True:
293+
pass
294+
else:
295+
raise Exception('Could not retrieve driver from the file path.')
299296

300297
# check resampling method
301-
if resampling_method in resampling_function.keys():
298+
resampling_dict = Core().raster_resampling_method
299+
if resampling_method in resampling_dict.keys():
302300
pass
303301
else:
304-
raise Exception('Input resampling method is not supported.')
302+
raise Exception(f'Input resampling method must be one of {list(resampling_dict.keys())}.')
305303

306304
# rescaling resolution
307305
with rasterio.open(mask_file) as mask_raster:
@@ -333,20 +331,18 @@ def resolution_rescaling_with_mask(
333331
)
334332
# saving output raster
335333
with rasterio.open(output_file, 'w', **mask_profile) as output_raster:
336-
rescaled_raster = rasterio.warp.reproject(
334+
rasterio.warp.reproject(
337335
source=rasterio.band(input_raster, 1),
338336
destination=rasterio.band(output_raster, 1),
339337
src_transform=mask_raster.transform,
340338
src_crs=mask_raster.crs,
341339
dst_transform=output_transform,
342340
dst_crs=mask_raster.crs,
343-
resampling=resampling_function[resampling_method]
341+
resampling=resampling_dict[resampling_method]
344342
)
345-
affine_matrix = [
346-
list(rescaled_raster[1])[i:i + 3] for i in [0, 3, 6]
347-
]
343+
output_profile = output_raster.profile
348344

349-
return affine_matrix
345+
return output_profile
350346

351347
def crs_reprojection(
352348
self,
@@ -432,13 +428,12 @@ def crs_reprojection(
432428

433429
return output_profile
434430

435-
# pytest pending
436431
def nodata_conversion_from_value(
437432
self,
438433
input_file: str,
439434
target_value: list[float],
440-
nodata: float,
441-
output_file: str
435+
output_file: str,
436+
nodata: typing.Optional[float] = None
442437
) -> rasterio.profiles.Profile:
443438

444439
'''
@@ -464,8 +459,17 @@ def nodata_conversion_from_value(
464459
A profile containing metadata about the output raster.
465460
'''
466461

462+
# check validity of output file path
463+
check_file = Core().is_valid_raster_driver(output_file)
464+
if check_file is True:
465+
pass
466+
else:
467+
raise Exception('Could not retrieve driver from the file path.')
468+
469+
# saving raster after converting raster value to NoData
467470
with rasterio.open(input_file) as input_raster:
468471
raster_profile = input_raster.profile
472+
nodata = raster_profile['nodata'] if nodata is None else nodata
469473
input_array = input_raster.read(1)
470474
output_array = numpy.where(
471475
numpy.isin(input_array, target_value),
@@ -479,7 +483,7 @@ def nodata_conversion_from_value(
479483
)
480484
with rasterio.open(output_file, 'w', **raster_profile) as output_raster:
481485
output_raster.write(output_array, 1)
482-
output_profile = dict(output_raster.profile)
486+
output_profile = output_raster.profile
483487

484488
return output_profile
485489

@@ -521,6 +525,7 @@ def nodata_value_change(
521525
else:
522526
raise Exception('Could not retrieve driver from the file path.')
523527

528+
# saving raster after changing NoData value
524529
with rasterio.open(input_file) as input_raster:
525530
raster_profile = input_raster.profile
526531
output_array = numpy.where(
@@ -563,6 +568,14 @@ def clipping_by_shapes(
563568
A profile containing metadata about the output raster.
564569
'''
565570

571+
# check validity of output file path
572+
check_file = Core().is_valid_raster_driver(output_file)
573+
if check_file is True:
574+
pass
575+
else:
576+
raise Exception('Could not retrieve driver from the file path.')
577+
578+
# saving clipped raster
566579
with rasterio.open(input_file) as input_raster:
567580
raster_profile = input_raster.profile.copy()
568581
gdf = geopandas.read_file(shape_file)
@@ -586,7 +599,6 @@ def clipping_by_shapes(
586599

587600
return output_profile
588601

589-
# pytest pending
590602
def array_from_geometries(
591603
self,
592604
shape_file: str,
@@ -627,6 +639,13 @@ def array_from_geometries(
627639
A profile containing metadata about the output raster.
628640
'''
629641

642+
# check validity of output file path
643+
check_file = Core().is_valid_raster_driver(output_file)
644+
if check_file is True:
645+
pass
646+
else:
647+
raise Exception('Could not retrieve driver from the file path.')
648+
630649
# input shapes
631650
gdf = geopandas.read_file(shape_file)
632651

docs/modules.rst

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ API Reference
66
:maxdepth: 2
77

88
GeoAnalyze
9+
submodules

docs/submodules.rst

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Submodules
2+
------------
3+
4+
.. automodule:: GeoAnalyze.core
5+
:members:
6+
:undoc-members:
7+
:show-inheritance:
8+
9+

tests/test_raster.py

+69-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
import tempfile
3+
import geopandas
34
import GeoAnalyze
45
import pytest
56

@@ -39,6 +40,10 @@ def test_count_cells(
3940
dem_file=dem_file
4041
)
4142
assert raster_profile['count'] == 1
43+
# accessing polygon GeoDataFrame
44+
polygon_gdf = packagedata.get_polygon_gdf
45+
assert isinstance(polygon_gdf, geopandas.GeoDataFrame)
46+
polygon_gdf.to_file(os.path.join(tmp_dir, 'polygon.shp'))
4247
# pass test for counting raster data cells
4348
data_cells = raster.count_data_cells(
4449
raster_file=dem_file
@@ -69,6 +74,14 @@ def test_count_cells(
6974
output_file=os.path.join(tmp_dir, 'dem_32m.tif')
7075
)
7176
assert output_profile['width'] == 1856
77+
# pass test for raster resolution rescaling with mask
78+
output_profile = raster.resolution_rescaling_with_mask(
79+
input_file=os.path.join(tmp_dir, 'dem_32m.tif'),
80+
mask_file=os.path.join(tmp_dir, 'dem.tif'),
81+
resampling_method='bilinear',
82+
output_file=os.path.join(tmp_dir, 'dem_16m.tif')
83+
)
84+
assert output_profile['height'] == 3790
7285
# pass test for raster Coordinate Reference System reprojectoion
7386
output_profile = raster.crs_reprojection(
7487
input_file=os.path.join(tmp_dir, 'dem_32m.tif'),
@@ -85,6 +98,13 @@ def test_count_cells(
8598
dtype='float32'
8699
)
87100
assert output_profile['nodata'] == 0
101+
# pass test for raster clipping by shapes
102+
output_profile = raster.clipping_by_shapes(
103+
input_file=os.path.join(tmp_dir, 'dem_32m.tif'),
104+
shape_file=os.path.join(tmp_dir, 'polygon.shp'),
105+
output_file=os.path.join(tmp_dir, 'dem_32m_clipped.tif')
106+
)
107+
assert output_profile['width'] == 979
88108

89109

90110
def test_error_raster_file_driver(
@@ -99,6 +119,13 @@ def test_error_raster_file_driver(
99119
dem_file='dem.tifff',
100120
)
101121
assert exc_info.value.args[0] == message['error_driver']
122+
# error test of invalid file path for raster boundary polygon GeoDataFrame
123+
with pytest.raises(Exception) as exc_info:
124+
raster.boundary_polygon(
125+
raster_file='dem.tif',
126+
shape_file='dem_boundary.sh'
127+
)
128+
assert exc_info.value.args[0] == message['error_driver']
102129
# error test of invalid file path for raster resolution rescaling
103130
with pytest.raises(Exception) as exc_info:
104131
raster.resolution_rescaling(
@@ -108,11 +135,13 @@ def test_error_raster_file_driver(
108135
output_file='dem_32m.tifff'
109136
)
110137
assert exc_info.value.args[0] == message['error_driver']
111-
# error test of invalid file path for raster boundary polygon GeoDataFrame
138+
# error test of invalid file path for raster resolution rescaling with mask
112139
with pytest.raises(Exception) as exc_info:
113-
raster.boundary_polygon(
114-
raster_file='dem.tif',
115-
shape_file='dem_boundary.sh'
140+
raster.resolution_rescaling_with_mask(
141+
input_file='dem_32m.tif',
142+
mask_file='dem.tif',
143+
resampling_method='bilinear',
144+
output_file='dem_16m.tifff'
116145
)
117146
assert exc_info.value.args[0] == message['error_driver']
118147
# error test of invalid file path for raster Coordinate Reference System reprojectoion
@@ -132,6 +161,33 @@ def test_error_raster_file_driver(
132161
output_file='dem_NoData_0.tifff'
133162
)
134163
assert exc_info.value.args[0] == message['error_driver']
164+
# error test of invalid file path for raster array from geometries
165+
with pytest.raises(Exception) as exc_info:
166+
raster.array_from_geometries(
167+
shape_file='stream.shp',
168+
value_column='flw_id',
169+
mask_file='dem.tif',
170+
nodata=-9999,
171+
dtype='int32',
172+
output_file='stream.tifff'
173+
)
174+
assert exc_info.value.args[0] == message['error_driver']
175+
# error test of invalid file path for raster NoData conversion from value
176+
with pytest.raises(Exception) as exc_info:
177+
raster.nodata_conversion_from_value(
178+
input_file='stream.tif',
179+
target_value=[1, 9],
180+
output_file='stream_NoData.tifff',
181+
)
182+
assert exc_info.value.args[0] == message['error_driver']
183+
# error test of invalid file path for raster clipping by shapes
184+
with pytest.raises(Exception) as exc_info:
185+
raster.clipping_by_shapes(
186+
input_file='dem.tif',
187+
shape_file='polygon.shp',
188+
output_file='dem_clipped.tifff'
189+
)
190+
assert exc_info.value.args[0] == message['error_driver']
135191

136192

137193
def test_error_resampling_method(
@@ -148,6 +204,15 @@ def test_error_resampling_method(
148204
output_file='dem_32m.tif'
149205
)
150206
assert exc_info.value.args[0] == message['error_resampling']
207+
# error test of resampling method for raster resolution rescaling with mask
208+
with pytest.raises(Exception) as exc_info:
209+
raster.resolution_rescaling_with_mask(
210+
input_file='dem_32m.tif',
211+
mask_file='dem.tif',
212+
resampling_method='bilinearr',
213+
output_file='dem_16m.tif'
214+
)
215+
assert exc_info.value.args[0] == message['error_resampling']
151216
# error test of resampling method for raster Coordinate Reference System reprojectoion
152217
with pytest.raises(Exception) as exc_info:
153218
raster.crs_reprojection(

0 commit comments

Comments
 (0)