Repository: DHI/mikeio

Issue:
Dataset item assignment
![image](https://user-images.githubusercontent.com/614215/132855983-021049d6-ad62-4bcf-8ff6-e137932fa4e8.png)


Discussion:

Patch:
diff --git a/mikeio/dataset.py b/mikeio/dataset.py
index b447f1c7..39255424 100644
--- a/mikeio/dataset.py
+++ b/mikeio/dataset.py
@@ -162,31 +162,44 @@ class Dataset(TimeSeries):
     def __len__(self):
         return len(self.items)
 
-    def __getitem__(self, x):
+    def __setitem__(self, key, value):
 
-        if isinstance(x, slice):
-            s = self.time.slice_indexer(x.start, x.stop)
+        if isinstance(key, int):
+            self.data[key] = value
+
+        elif isinstance(key, str):
+            item_lookup = {item.name: i for i, item in enumerate(self.items)}
+            key = item_lookup[key]
+            self.data[key] = value
+        else:
+
+            raise ValueError(f"indexing with a {type(key)} is not (yet) supported")
+
+    def __getitem__(self, key):
+
+        if isinstance(key, slice):
+            s = self.time.slice_indexer(key.start, key.stop)
             time_steps = list(range(s.start, s.stop))
             return self.isel(time_steps, axis=0)
 
-        if isinstance(x, int):
-            return self.data[x]
+        if isinstance(key, int):
+            return self.data[key]
 
-        if isinstance(x, str):
+        if isinstance(key, str):
             item_lookup = {item.name: i for i, item in enumerate(self.items)}
-            x = item_lookup[x]
-            return self.data[x]
+            key = item_lookup[key]
+            return self.data[key]
 
-        if isinstance(x, ItemInfo):
-            return self.__getitem__(x.name)
+        if isinstance(key, ItemInfo):
+            return self.__getitem__(key.name)
 
-        if isinstance(x, list):
+        if isinstance(key, list):
             data = []
             items = []
 
             item_lookup = {item.name: i for i, item in enumerate(self.items)}
 
-            for v in x:
+            for v in key:
                 data_item = self.__getitem__(v)
                 if isinstance(v, str):
                     i = item_lookup[v]
@@ -199,7 +212,7 @@ class Dataset(TimeSeries):
 
             return Dataset(data, self.time, items)
 
-        raise ValueError(f"indexing with a {type(x)} is not (yet) supported")
+        raise ValueError(f"indexing with a {type(key)} is not (yet) supported")
 
     def __radd__(self, other):
         return self.__add__(other)
@@ -229,51 +242,61 @@ class Dataset(TimeSeries):
         else:
             return self._multiply_value(other)
 
-    def _add_dataset(self, other, sign=1.0):        
+    def _add_dataset(self, other, sign=1.0):
         self._check_datasets_match(other)
         try:
-            data = [self[x] + sign*other[y] for x, y in zip(self.items, other.items)]
+            data = [self[x] + sign * other[y] for x, y in zip(self.items, other.items)]
         except:
             raise ValueError("Could not add data in Dataset")
         time = self.time.copy()
         items = deepcopy(self.items)
-        return Dataset(data, time, items) 
+        return Dataset(data, time, items)
 
     def _check_datasets_match(self, other):
         if self.n_items != other.n_items:
-            raise ValueError(f"Number of items must match ({self.n_items} and {other.n_items})")
+            raise ValueError(
+                f"Number of items must match ({self.n_items} and {other.n_items})"
+            )
         for j in range(self.n_items):
             if self.items[j].type != other.items[j].type:
-                raise ValueError(f"Item types must match. Item {j}: {self.items[j].type} != {other.items[j].type}")
+                raise ValueError(
+                    f"Item types must match. Item {j}: {self.items[j].type} != {other.items[j].type}"
+                )
             if self.items[j].unit != other.items[j].unit:
-                raise ValueError(f"Item units must match. Item {j}: {self.items[j].unit} != {other.items[j].unit}")            
+                raise ValueError(
+                    f"Item units must match. Item {j}: {self.items[j].unit} != {other.items[j].unit}"
+                )
         if not np.all(self.time == other.time):
             raise ValueError("All timesteps must match")
         if self.shape != other.shape:
-            raise ValueError("shape must match")    
+            raise ValueError("shape must match")
 
     def _add_value(self, value):
         try:
             data = [value + self[x] for x in self.items]
         except:
-            raise ValueError(f"{value} could not be added to Dataset")        
+            raise ValueError(f"{value} could not be added to Dataset")
         items = deepcopy(self.items)
         time = self.time.copy()
         return Dataset(data, time, items)
 
-
     def _multiply_value(self, value):
         try:
             data = [value * self[x] for x in self.items]
         except:
-            raise ValueError(f"{value} could not be multiplied to Dataset")        
+            raise ValueError(f"{value} could not be multiplied to Dataset")
         items = deepcopy(self.items)
         time = self.time.copy()
         return Dataset(data, time, items)
 
     def describe(self, **kwargs):
         """Generate descriptive statistics by wrapping pandas describe()"""
-        all_df = [pd.DataFrame(self.data[j].flatten(), columns=[self.items[j].name]).describe(**kwargs) for j in range(self.n_items)]
+        all_df = [
+            pd.DataFrame(self.data[j].flatten(), columns=[self.items[j].name]).describe(
+                **kwargs
+            )
+            for j in range(self.n_items)
+        ]
         return pd.concat(all_df, axis=1)
 
     def copy(self):


Test patch:
diff --git a/tests/test_dataset.py b/tests/test_dataset.py
index 1191c867..36b453b9 100644
--- a/tests/test_dataset.py
+++ b/tests/test_dataset.py
@@ -11,6 +11,7 @@ from mikeio.eum import EUMType, ItemInfo, EUMUnit
 def _get_time(nt):
     return list(rrule(freq=SECONDLY, count=nt, dtstart=datetime(2000, 1, 1)))
 
+
 @pytest.fixture
 def ds1():
     nt = 10
@@ -24,6 +25,7 @@ def ds1():
     items = [ItemInfo("Foo"), ItemInfo("Bar")]
     return Dataset(data, time, items)
 
+
 @pytest.fixture
 def ds2():
     nt = 10
@@ -37,6 +39,7 @@ def ds2():
     items = [ItemInfo("Foo"), ItemInfo("Bar")]
     return Dataset(data, time, items)
 
+
 def test_get_names():
 
     data = []
@@ -241,8 +244,9 @@ def test_select_subset_isel_multiple_idxs():
 def test_decribe(ds1):
     df = ds1.describe()
     assert df.columns[0] == "Foo"
-    assert df.loc['mean'][1] == pytest.approx(0.2)
-    assert df.loc['max'][0] == pytest.approx(0.1)
+    assert df.loc["mean"][1] == pytest.approx(0.2)
+    assert df.loc["max"][0] == pytest.approx(0.1)
+
 
 def test_create_undefined():
 
@@ -468,6 +472,21 @@ def test_get_data_name():
     assert ds["Foo"].shape == (100, 100, 30)
 
 
+def test_set_data_name():
+
+    nt = 100
+
+    time = _get_time(nt)
+    items = [ItemInfo("Foo")]
+    ds = Dataset([np.zeros((nt, 10))], time, items)
+
+    assert ds["Foo"][0, 0] == 0.0
+
+    ds["Foo"] = np.zeros((nt, 10)) + 1.0
+
+    assert ds["Foo"][0, 0] == 1.0
+
+
 def test_get_bad_name():
     nt = 100
     data = []
@@ -909,29 +928,32 @@ def test_init():
     assert ds.n_elements == n_elements
     assert ds.items[0].name == "Foo"
 
+
 def test_add_scalar(ds1):
     ds2 = ds1 + 10.0
     assert np.all(ds2[0] - ds1[0] == 10.0)
 
     ds3 = 10.0 + ds1
     assert np.all(ds3[0] == ds2[0])
-    assert np.all(ds3[1] == ds2[1])       
-    
+    assert np.all(ds3[1] == ds2[1])
+
+
 def test_sub_scalar(ds1):
     ds2 = ds1 - 10.0
     assert np.all(ds1[0] - ds2[0] == 10.0)
 
     ds3 = 10.0 - ds1
     assert np.all(ds3[0] == 9.9)
-    assert np.all(ds3[1] == 9.8) 
+    assert np.all(ds3[1] == 9.8)
+
 
 def test_mul_scalar(ds1):
     ds2 = ds1 * 2.0
-    assert np.all(ds2[0]*0.5 == ds1[0]) 
+    assert np.all(ds2[0] * 0.5 == ds1[0])
 
     ds3 = 2.0 * ds1
     assert np.all(ds3[0] == ds2[0])
-    assert np.all(ds3[1] == ds2[1])    
+    assert np.all(ds3[1] == ds2[1])
 
 
 def test_add_dataset(ds1, ds2):
@@ -941,7 +963,7 @@ def test_add_dataset(ds1, ds2):
 
     ds4 = ds2 + ds1
     assert np.all(ds3[0] == ds4[0])
-    assert np.all(ds3[1] == ds4[1])    
+    assert np.all(ds3[1] == ds4[1])
 
     ds2b = ds2.copy()
     ds2b.items[0] = ItemInfo(EUMType.Wind_Velocity)
@@ -951,17 +973,19 @@ def test_add_dataset(ds1, ds2):
 
     ds2c = ds2.copy()
     tt = ds2c.time.to_numpy()
-    tt[-1] = tt[-1] + np.timedelta64(1, 's')
+    tt[-1] = tt[-1] + np.timedelta64(1, "s")
     ds2c.time = pd.DatetimeIndex(tt)
     with pytest.raises(ValueError):
         # time does not match
         ds1 + ds2c
 
+
 def test_sub_dataset(ds1, ds2):
     ds3 = ds2 - ds1
     assert np.all(ds3[0] == 0.9)
     assert np.all(ds3[1] == 1.8)
 
+
 def test_non_equidistant():
     nt = 4
     d = np.random.uniform(size=nt)