Repository: dlr-eoc/ukis-pysat

Issue:
Create ukis_pysat.raster-Image with 2D array
**Is your feature request related to a problem? Please describe.**

- `ukis_pysat.raster` only treats 3D arrays. Numerous extermal methods work on a 2D basis and using `np.squeeze()` or `np.expand_dims()` adds unnecessary code.

- building an `ukis_pysat.raster.Image()` from a 2D array will fail with a misleading error message:
  > rasterio._err.CPLE_FileIOError: Free disk space available is 68524220416 bytes, whereas 413266544908 are at least necessary.
  
  We could narrow this problem down to the fact, that bringing a 2D array into a 3D method is simply not working.

**Describe the solution you'd like**
Allow initalization of `ukis_pysat.raster.Image` with both 2D or 3D arrays. If I'm not mistaken, rasterio is limited to 3D arrays. @MWieland and @fwfichtner what is your opinion on this?


Discussion:
codecov-commenter: # [Codecov](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=h1) Report
> Merging [#89](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=desc) into [master](https://codecov.io/gh/dlr-eoc/ukis-pysat/commit/a8bbb98b586bc2429a85dbf0084c2619ee437838?el=desc) will **increase** coverage by `0.05%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89/graphs/tree.svg?width=650&height=150&src=pr&token=6LYPGRGMXV)](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master      #89      +/-   ##
==========================================
+ Coverage   93.46%   93.52%   +0.05%     
==========================================
  Files           8        8              
  Lines         796      803       +7     
==========================================
+ Hits          744      751       +7     
  Misses         52       52              
```

| Flag | Coverage Δ | |
|---|---|---|
| #unittests | `93.52% <100.00%> (+0.05%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tests/test\_raster.py](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89/diff?src=pr&el=tree#diff-dGVzdHMvdGVzdF9yYXN0ZXIucHk=) | `99.40% <100.00%> (+0.01%)` | :arrow_up: |
| [ukis\_pysat/raster.py](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89/diff?src=pr&el=tree#diff-dWtpc19weXNhdC9yYXN0ZXIucHk=) | `93.06% <100.00%> (+0.08%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=footer). Last update [a8bbb98...e15f3f6](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/89?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index c04d503..e14adb0 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,12 +16,16 @@ something was changed
 [master]  (2020-**-**)
 ----------------------
 
+Added
+*****
+- ``raster``: possibility to init with 2D array #88
+
 [0.6.3]  (2020-09-02)
 ----------------------
 
 Fixed
 *****
-- ``file`` imported Pattern of module typing
+- ``file``: imported Pattern of module typing
 
 [0.6.2]  (2020-09-02)
 ----------------------
diff --git a/ukis_pysat/raster.py b/ukis_pysat/raster.py
index ea72b1b..9fcceaf 100644
--- a/ukis_pysat/raster.py
+++ b/ukis_pysat/raster.py
@@ -61,6 +61,10 @@ class Image:
                 self.__arr = data
             else:
                 self.__arr = reshape_as_raster(data)
+
+            if self.__arr.ndim == 2:
+                self.__arr = np.expand_dims(self.__arr, 0)  # always return 3D for consistency
+
             self.dataset = None
             self.__update_dataset(crs, transform, nodata=nodata)
         else:


Test patch:
diff --git a/tests/test_raster.py b/tests/test_raster.py
index 28cb8b1..edf8d1e 100644
--- a/tests/test_raster.py
+++ b/tests/test_raster.py
@@ -23,9 +23,8 @@ class DataTest(unittest.TestCase):
         self.img.close()
 
     def test_init(self):
-        img = Image(self.img.dataset)
-        self.assertTrue(np.array_equal(self.img.arr, img.arr))
-        img.close()
+        with Image(self.img.dataset) as img:
+            self.assertTrue(np.array_equal(self.img.arr, img.arr))
 
     def test_context(self):
         with Image(TEST_FILE) as raster_file:
@@ -52,6 +51,12 @@ class DataTest(unittest.TestCase):
         self.assertTrue(np.array_equal(self.img.arr, img.arr))
         img.close()
 
+    def test_init_2dim(self):
+        with Image(np.ones(shape=(385, 502)), crs=self.img.dataset.crs, transform=self.img.dataset.transform) as img:
+            self.assertEqual(img.arr.ndim, 3)
+            self.assertEqual(len(img.arr), 1)
+            self.assertEqual(img.arr.shape, (1, 385, 502))
+
     def test_init_with_arry_fail_missing_crs(self):
         with self.assertRaises(TypeError):
             Image(data=self.img.arr, crs=self.img.dataset.transform)