From 51a3a7852e64bfb722e38b80cf790e75dfde360e Mon Sep 17 00:00:00 2001 From: "Soroosh.Mani" Date: Thu, 24 Aug 2023 16:43:37 -0400 Subject: [PATCH 1/3] Add tests for average filtering with masked rasters --- tests/api/raster.py | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 tests/api/raster.py diff --git a/tests/api/raster.py b/tests/api/raster.py new file mode 100644 index 00000000..ad6f248a --- /dev/null +++ b/tests/api/raster.py @@ -0,0 +1,58 @@ +import shutil +import tempfile +import unittest +from pathlib import Path + +import numpy as np + +import ocsmesh +from ocsmesh.utils import raster_from_numpy + + +class Raster(unittest.TestCase): + def setUp(self): + self.tdir = Path(tempfile.mkdtemp()) + self.rast1 = self.tdir / 'rast_1.tif' + self.rast2 = self.tdir / 'rast_2.tif' + self.rast3 = self.tdir / 'rast_3.tif' + + rast_xy = np.mgrid[-1:1:0.01, -0.7:0.7:0.01] + rast_z_1 = np.ones_like(rast_xy[0]) * 10 + rast_z_2 = np.ma.MaskedArray( + np.ones_like(rast_xy[0]) * 10, + mask=np.random.random(size=rast_xy[0].shape) < 0.2, + fill_value=np.nan + ) + rast_z_3 = np.ma.MaskedArray( + np.ones_like(rast_xy[0]) * 10, + mask=np.random.random(size=rast_xy[0].shape) < 0.2, + fill_value=-1e+15 + ) + + raster_from_numpy(self.rast1, rast_z_1, rast_xy, 4326) + raster_from_numpy(self.rast2, rast_z_2, rast_xy, 4326) + raster_from_numpy(self.rast3, rast_z_3, rast_xy, 4326) + + + def tearDown(self): + shutil.rmtree(self.tdir) + + + def test_avg_filter_nomask(self): + rast = ocsmesh.Raster(self.rast1) + rast.average_filter(size=17) + self.assertTrue(np.all(rast.get_values() == 10)) + + + def test_avg_filter_masked_nanfill(self): + rast = ocsmesh.Raster(self.rast2) + rast.average_filter(size=17) + self.assertTrue( + np.all(rast.values[~np.isnan(rast.values)] == 10)) + + + def test_avg_filter_masked_nonnanfill(self): + rast = ocsmesh.Raster(self.rast3) + rast.average_filter(size=17) + self.assertTrue( + np.all(rast.values[rast.values != rast.nodata] == 10)) From 17321c4cc10606d00705801f287e19ad77c84459 Mon Sep 17 00:00:00 2001 From: "Soroosh.Mani" Date: Thu, 24 Aug 2023 15:58:58 -0400 Subject: [PATCH 2/3] Set the fill value for masked array after average filtering --- ocsmesh/raster.py | 1 + 1 file changed, 1 insertion(+) diff --git a/ocsmesh/raster.py b/ocsmesh/raster.py index 06fa5f9a..bdcc359c 100644 --- a/ocsmesh/raster.py +++ b/ocsmesh/raster.py @@ -978,6 +978,7 @@ def average_filter( outband_new[mask] = dst.nodatavals[bnd_idx] outband_ma = ma.masked_array(outband_new, mask=mask) + ma.set_fill_value(outband_ma, dst.nodatavals[bnd_idx]) dst.write_band(i, outband_ma) From ab591eaab6d843b5a433ec33b419726eb174a903 Mon Sep 17 00:00:00 2001 From: "Soroosh.Mani" Date: Thu, 24 Aug 2023 16:46:24 -0400 Subject: [PATCH 3/3] Fix for avg filtering non-nan masked raster --- ocsmesh/raster.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ocsmesh/raster.py b/ocsmesh/raster.py index bdcc359c..16d6a439 100644 --- a/ocsmesh/raster.py +++ b/ocsmesh/raster.py @@ -965,8 +965,13 @@ def average_filter( mask_below = ma.getdata(outband) < drop_below outband[mask_below] = np.nan + # Since the nbmean checks for isnan, other fill values + # will be treated as normal numbers outband_new = generic_filter( - outband, LowLevelCallable(nbmean.ctypes), size=size) + outband.filled(np.nan), + LowLevelCallable(nbmean.ctypes), + size=size + ) # Mask raster based on result of filter? if drop_above is not None: