Commit 345c9ca9 authored by Daniel Scheffler's avatar Daniel Scheffler

Revised GeoArray.get_subset(). Added bandnames deleter. Renamed some test...

Revised GeoArray.get_subset(). Added bandnames deleter. Renamed some test functions. Added test___getitem__() and test_get_subset().
parent 35497735
Pipeline #1589 passed with stages
in 1 minute and 2 seconds
......@@ -149,7 +149,7 @@ class GeoArray(object):
if self._bandnames and len(self._bandnames) == self.bands:
return self._bandnames
else:
self._bandnames = OrderedDict(('B%s' % band, i) for i, band in enumerate(range(1, self.bands + 1)))
del self.bandnames # runs deleter which sets it to default values
return self._bandnames
@bandnames.setter
......@@ -164,11 +164,23 @@ class GeoArray(object):
assert len(list(set([type(b) for b in list_bandnames]))) == 1 and type(list_bandnames[0] == 'str'), \
"'bandnames must be a set of strings. Got other datetypes in there.'"
bN_dict = OrderedDict((band, i) for i, band in enumerate(list_bandnames))
assert len(
bN_dict) == self.bands, 'Bands must not have the same name. Received band list: %s' % list_bandnames
assert len(bN_dict) == self.bands, \
'Bands must not have the same name. Received band list: %s' % list_bandnames
self._bandnames = bN_dict
# update bandnames in metadata
if self._metadata is not None:
self.metadata.loc['band_name', :] = list_bandnames
else:
del self.bandnames
@bandnames.deleter
def bandnames(self):
self._bandnames = OrderedDict(('B%s' % band, i) for i, band in enumerate(range(1, self.bands + 1)))
if self._metadata is not None:
self.metadata.loc['band_name', :] = list(self._bandnames.keys())
@property
def is_inmem(self):
"""Check if associated image array is completely loaded into memory."""
......@@ -1397,7 +1409,7 @@ class GeoArray(object):
progress=progress)
return sub_arr, sub_gt, sub_prj
def get_subset(self, xslice=None, yslice=None, zslice=None, return_GeoArray=True):
def get_subset(self, xslice=None, yslice=None, zslice=None, return_GeoArray=True, reset_bandnames=False):
# type: (slice, slice, slice, bool) -> GeoArray
"""Returns a new instatnce of GeoArray representing a subset of the initial one wit respect to given array position.
......@@ -1411,13 +1423,26 @@ class GeoArray(object):
sub_arr = self[yslice if yslice else slice(None), # row
xslice if xslice else slice(None), # col
zslice if zslice else slice(None)] # band
sub_ulXY = imXY2mapXY((xslice.start, yslice.start), self.gt)
if sub_arr is None:
raise ValueError('Unable to return an array for the given slice parameters.')
sub_ulXY = imXY2mapXY((xslice.start or 0, yslice.start or 0), self.gt)
sub_gt = (sub_ulXY[0], self.gt[1], self.gt[2], sub_ulXY[1], self.gt[4], self.gt[5])
# apply zslice to bandnames and metadata
bNs_out = list(np.array(list(self.bandnames))[zslice])
meta_out = None if self._metadata is None else self.meta[list(np.array(range(self.bands))[zslice])]
# get output GeoArray and copy some properties from the input GeoArray
sub_gA = GeoArray(sub_arr, sub_gt, self.prj,
bandnames=list(self.bandnames.keys()), nodata=self.nodata, progress=self.progress, q=self.q)
sub_gA.meta = self.meta
bandnames=bNs_out, nodata=self.nodata, progress=self.progress, q=self.q)
sub_gA.meta = meta_out
sub_gA.filePath = self.filePath
if reset_bandnames:
del self.bandnames # also updates the respective row in self.meta
return sub_gA if return_GeoArray else (sub_arr, sub_gt, self.prj)
# import copy # TODO implement that in order to include all previously set attribute values
......
......@@ -183,7 +183,7 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
reason="The variable committed to the 'GeoArray'-class is neither a path nor a numpy.ndarray."
"All tests of the Test Case 'Test_GeoarrayAppliedOnTiffPath' will be skipped!")
def test_Bandnames(self):
def test_bandnames(self):
"""
Testing the function: bandnames.
Test, if the default (for k=0) and set (for k=1) band names respectively were correctly assigned.
......@@ -191,7 +191,7 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
self.assertEqual(self.testtiff.bandnames, self.expected_bandnames,
msg="The bandnames of the Tiff-file are different than ['B1', 'B2'] (format: OrderedDict)")
def test_ShapeOfTiffArray(self):
def test_shape(self):
"""
Testing the functions: shape - ndim - rows - columns - bands,
indirect testing of the function: set_gdalDataset_meta(!),
......@@ -216,7 +216,7 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
self.skipTest("The shape of the array behind the 'Geoarray'-object is not as expected! "
"The test 'test_ShapeOfTiffArray' will be skipped.")
def test_DtypeOfTiffArray(self):
def test_dtype(self):
"""
Testing the function: dtype,
indirect testing of the function: set_gdalDataset_meta(!).
......@@ -226,7 +226,7 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
self.assertEqual(self.testtiff.dtype, self.expected_dtype,
msg='The dtype of the corresponding array is not as expected!')
def test_GeotransformTiff(self):
def test_geotransform(self):
"""
Testing the functions: geotransform - xgsd - ygsd - xygrid_specs,
indirect testing of the function: set_gdalDataset_meta(!),
......@@ -254,7 +254,7 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
self.skipTest("The geotransform-tuple of the array behind the 'GeoArray'-object is not as expected! "
"The test 'test_GeotransformTiff' will be skipped.")
def test_ProjectionTiff(self):
def test_projection(self):
"""
Testing the functions: projection - epsg,
indirect testing of the function: set_gdalDataset_meta(!),
......@@ -283,7 +283,7 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
self.skipTest("The projections of the 'GeoArray'-object is not as expected! "
"The test 'test_ProjectionTiff' will be skipped.")
def test_NoDataValueOfTiff(self):
def test_nodata(self):
"""
Testing the function: nodata,
indirect testing of the functions: find_noDataVal(), set_gdalDataset_meta(!).
......@@ -301,6 +301,30 @@ class Test_GeoarrayAppliedOnPathArray(unittest.TestCase):
msg="The nodata-value of the tested Tiff-file (%s) is not as expected (%s)!"
% (self.testtiff.nodata, self.given_nodata))
def test___getitem__(self):
def validate(array, exp_shape):
self.assertIsInstance(array, np.ndarray)
self.assertEqual(array.shape, exp_shape)
R, C, B = self.testtiff.shape # (10, 11, 2)
# test full array
validate(self.testtiff[:], (R, C, B))
# test row/col subset
validate(self.testtiff[2:5, :3], (3, 3, B)) # third dimension is not given
validate(self.testtiff[2:5, :3, :], (3, 3, B))
# test band subset
validate(self.testtiff[:, :, 0:1], (R, C, 1)) # band slice # FIXME returns 3D array
validate(self.testtiff[1], (R, C)) # only band is given # FIXME returns 2D
validate(self.testtiff['B1'], (R, C)) # only bandname is given
# test wrong inputs
self.assertRaises(ValueError, self.testtiff.__getitem__, 'B01')
# TODO: add further tests
###################################
# Test case: Test_GeoarrayFunctions
......@@ -357,14 +381,13 @@ class Test_GeoarrayFunctions(unittest.TestCase):
def tearDownClass(cls):
# Removing the "../tests/data/output"-directory with all files. If test case 2 is not executed, the files
# will be removed at the end of this script in the "if __name__ == '__main__'"-code segment.
data_dir = os.path.join(tests_path, "tests", "data", "output")
data_dir_list = os.listdir(data_dir)
out_dir = os.path.join(tests_path, "tests", "data", "output")
for files in data_dir_list:
os.remove(path.join(data_dir, files))
os.rmdir(data_dir)
for file in os.listdir(out_dir):
os.remove(path.join(out_dir, file))
os.rmdir(out_dir)
def test_BoxIsInstanceOfBoxObj(self):
def test_box(self):
"""
Testing the function: box.
Test, if the output of the box-function is an instance boxObj (class, defined in geometry.py, py_tools_ds).
......@@ -372,7 +395,7 @@ class Test_GeoarrayFunctions(unittest.TestCase):
self.assertIsInstance(self.testtiff.box, geometry.boxObj)
def test_MaskNodataIsInstanceOfNoDataMask(self):
def test_mask_nodata(self):
# TODO: Consider the dependency of mask_nodata on the calc_mask_nodata-function.
"""
Testing the function: mask_nodata.
......@@ -381,7 +404,7 @@ class Test_GeoarrayFunctions(unittest.TestCase):
self.assertIsInstance(self.testtiff.mask_nodata, masks.NoDataMask)
def test_MaskBaddataOffTiff(self):
def test_mask_baddata(self):
"""
Testing the function: mask_baddata.
Test,
......@@ -399,7 +422,7 @@ class Test_GeoarrayFunctions(unittest.TestCase):
self.testtiff.mask_baddata = bdm
self.assertIsInstance(self.testtiff.mask_baddata, masks.BadDataMask)
def test_FootprintPolyIsInstanceOfShapely(self):
def test_footprint_poly(self):
# TODO: Test the validation of the footprint_poly-function.
# TODO: Consider the dependencies of the footprint_poly-function on mask_nodata, boxObj.
"""
......@@ -409,7 +432,7 @@ class Test_GeoarrayFunctions(unittest.TestCase):
self.assertIsInstance(self.testtiff.footprint_poly, Polygon)
def test_MetadataIsInstanceOfGeodataframe(self):
def test_metadata(self):
# TODO: Create a metadata-file for the tested TIFF-Image.
# TODO: Test, if the metadata-function gives an output
"""
......@@ -426,7 +449,27 @@ class Test_GeoarrayFunctions(unittest.TestCase):
for ((rS, rE), (cS, cE)), tile in tiles:
self.assertTrue(np.array_equal(tile, self.testtiff[rS: rE + 1, cS: cE + 1]))
def test_SaveTiffToDisk(self):
def test_get_subset(self):
# test without reseting band names
sub_gA = self.testtiff.get_subset(xslice=slice(2, 5), yslice=slice(None, 3), zslice=slice(1, 2))
self.assertIsInstance(sub_gA, GeoArray)
self.assertTrue(list(sub_gA.bandnames), list(self.testtiff.bandnames)[1])
# test with reseting band names
sub_gA = self.testtiff.get_subset(xslice=slice(2, 5), yslice=slice(None, 3), zslice=slice(1, 2),
reset_bandnames=True)
self.assertTrue(list(sub_gA.bandnames), ['B1'])
# test not to return GeoArray
out = self.testtiff.get_subset(xslice=slice(2, 5), yslice=slice(None, 3), zslice=slice(1, 2),
return_GeoArray=False)
self.assertIsInstance(out, tuple)
self.assertTrue(len(out), 3)
self.assertIsInstance(out[0], np.ndarray)
self.assertIsInstance(out[1], tuple)
self.assertIsInstance(out[2], str)
def test_save(self):
"""
Testing the function: save,
test with 2 stages.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment