Repository: dlr-eoc/ukis-pysat

Issue:
Nodata values not available when creating dataset from array
Creating an `Image.dataset` from a numpy array produces a rasterio dataset with the following metadata:

```
meta = {
    "driver": "GTiff",
    "dtype": self.__arr.dtype,
    "nodata": nodata,
    "height": self.__arr.shape[-2],
    "width": self.__arr.shape[-1],
    "count": self.__arr.shape[0],
    "crs": crs,
    "transform": transform,
}
```

The instance `nodata` is given as an argument of the method: `__update_dataset(self, crs, transform, nodata=None)`. However, `nodata` is not handed upon function call `self.__update_dataset(crs, transform)` which leaves the new dataset with no nodata value.

Suggest to introduce a nodata value when creating datasets from arrays such as `self.__update_dataset(crs, transform, nodata=nodata)`. This requires handing the nodata value to the instantiation of the Image class `__init__(self, data, dimorder="first", crs=None, transform=None, nodata=None)` if usage is desired.

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

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

```diff
@@            Coverage Diff             @@
##           master      #83      +/-   ##
==========================================
+ Coverage   93.55%   93.59%   +0.04%     
==========================================
  Files           8        8              
  Lines         776      781       +5     
==========================================
+ Hits          726      731       +5     
  Misses         50       50              
```

| Flag | Coverage Δ | |
|---|---|---|
| #unittests | `93.59% <100.00%> (+0.04%)` | :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/83?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [tests/test\_raster.py](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/83/diff?src=pr&el=tree#diff-dGVzdHMvdGVzdF9yYXN0ZXIucHk=) | `99.38% <100.00%> (+0.01%)` | :arrow_up: |
| [ukis\_pysat/raster.py](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/83/diff?src=pr&el=tree#diff-dWtpc19weXNhdC9yYXN0ZXIucHk=) | `92.98% <100.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/83?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/83?src=pr&el=footer). Last update [e8e6b22...0de82f3](https://codecov.io/gh/dlr-eoc/ukis-pysat/pull/83?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 a614feb..c3055ce 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -16,9 +16,13 @@ something was changed
 [master]  (2020-**-**)
 ----------------------
 
+[0.6.1]  (2020-08-31)
+----------------------
+
 Added
 *****
 - ``file``: added to_ESA_date() function #80
+- ``raster``: added nodata value upon dataset creation with numpy arrays #82
 
 
 [0.6.0]  (2020-08-28)
diff --git a/ukis_pysat/__init__.py b/ukis_pysat/__init__.py
index b5d7c28..98eb676 100644
--- a/ukis_pysat/__init__.py
+++ b/ukis_pysat/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "0.6.0"
+__version__ = "0.6.1"
diff --git a/ukis_pysat/raster.py b/ukis_pysat/raster.py
index 2676c25..4a43303 100644
--- a/ukis_pysat/raster.py
+++ b/ukis_pysat/raster.py
@@ -30,12 +30,14 @@ class Image:
 
     da_arr = None
 
-    def __init__(self, data, dimorder="first", crs=None, transform=None):
+    def __init__(self, data, dimorder="first", crs=None, transform=None, nodata=None):
         """
         :param data: rasterio.io.DatasetReader or path to raster or np.ndarray of shape (bands, rows, columns)
         :param dimorder: Order of channels or bands 'first' or 'last' (default: 'first')
         :param crs: Coordinate reference system used when creating form array. If 'data' is np.ndarray this is required (default: None)
         :param transform: Affine transformation mapping the pixel space to geographic space. If 'data' is np.ndarray this is required (default:None)
+        :param nodata: nodata value used when creating form array, optional (default: None)
+
         """
         if dimorder in ("first", "last"):
             self.dimorder = dimorder
@@ -60,7 +62,7 @@ class Image:
             else:
                 self.__arr = reshape_as_raster(data)
             self.dataset = None
-            self.__update_dataset(crs, transform)
+            self.__update_dataset(crs, transform, nodata=nodata)
         else:
             raise TypeError("dataset must be of type rasterio.io.DatasetReader, str or np.ndarray")
 


Test patch:
diff --git a/tests/test_raster.py b/tests/test_raster.py
index d996f6c..2802070 100644
--- a/tests/test_raster.py
+++ b/tests/test_raster.py
@@ -109,6 +109,13 @@ class DataTest(unittest.TestCase):
         self.assertEqual(img_last.arr.shape, (385, 502, 1))
         img_last.close()
 
+    def test_arr_nodata(self):
+        array = np.ones((3, 385, 502))
+
+        with Image(array, crs=self.img.dataset.crs, transform=self.img.dataset.transform, nodata=0.0) as img_nodata:
+            self.assertEqual(img_nodata.dataset.nodata, 0.0)
+            self.assertEqual(img_nodata.dataset.nodatavals, (0.0, 0.0, 0.0))
+
     def test_set_array(self):
         img = Image(TEST_FILE, dimorder="last")
         img.arr = img.arr + 1