Repository: UXARRAY/uxarray

Issue:
`_slice_from_grid` may need to use coords from a sliced dataarray
### Version

v2024.08.2

### How did you install UXarray?

Conda

### What happened?

`_slice_from_grid` in UxDataArray create a new subset dataarray using coordinates info from the original dataarray as shown in the lines below:
https://github.com/UXARRAY/uxarray/blob/f71e11bef0fabe3ac74767767ad0509cef5cf504/uxarray/core/dataarray.py#L1099-L1106

This does not cause an issue when the original dataarray does not have coordinates that are sliced, but the constructor fails otherwise with a conflicting size for dimension. Probably a better or a right approach is creating a new sliced dataarray with coordinates from the sliced `d_var` not from the original `self`.

### What did you expect to happen?

A new sliced (subset) dataarray needs to be created with a correctly sliced coordinate variables, not from the original unsliced coordinate variables.

### Can you provide a MCVE to repoduce the bug?

_No response_

Discussion:
philipc2: > Looks good. I tested the change and tried to replicate the issue I had #818 with the uxarray.UxDataArray.Indexes disappearing but had no problems.
> 
> However, given this fix, I can think of two other places a similar change might be needed:
> 
> https://github.com/UXARRAY/uxarray/blob/ec5cc8f279ae7026e5f42ab0570105cd6861ced7/uxarray/remap/nearest_neighbor.py#L110
> 
> and
> 
> https://github.com/UXARRAY/uxarray/blob/ec5cc8f279ae7026e5f42ab0570105cd6861ced7/uxarray/remap/inverse_distance_weighted.py#L151

Good catches, I'll update these also. 
philipc2: @ahijevyc 

When remapping, should the coordinates from the original data array be dropped? It wouldn't make much sense to preserve them (unless I'm understanding it wrong)
philipc2: > The _spatial_ coordinates should not be transferred, but if there are _non-spatial_ coordinates like `time`, `ensemble_member`, or `forecast_hour`, then those should be transferred to the destination. I think that's why I originally thought the `coords` argument was necessary.

That makes sense! I wasn't considering the non-spatial cases. 
review-notebook-app[bot]: Check out this pull request on&nbsp; <a href="https://app.reviewnb.com/UXARRAY/uxarray/pull/1003"><img align="absmiddle"  alt="ReviewNB" height="28" class="BotMessageButtonImage" src="https://raw.githubusercontent.com/ReviewNB/support/master/images/button_reviewnb.png"/></a> 

 See visual diffs & provide feedback on Jupyter Notebooks. 

---

 <i>Powered by <a href='https://www.reviewnb.com/?utm_source=gh'>ReviewNB</a></i>

Patch:
diff --git a/docs/user-guide/subset.ipynb b/docs/user-guide/subset.ipynb
index e220a880..07df1e82 100644
--- a/docs/user-guide/subset.ipynb
+++ b/docs/user-guide/subset.ipynb
@@ -16,10 +16,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:36:46.872906Z",
-     "start_time": "2024-06-07T22:36:34.761168Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -72,10 +68,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:36:46.917137Z",
-     "start_time": "2024-06-07T22:36:46.873648Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -95,10 +87,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:36:53.691169Z",
-     "start_time": "2024-06-07T22:36:46.918225Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -113,10 +101,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:36:53.701638Z",
-     "start_time": "2024-06-07T22:36:53.692509Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -131,10 +115,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:36:53.707801Z",
-     "start_time": "2024-06-07T22:36:53.706375Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -165,10 +145,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:36:59.545160Z",
-     "start_time": "2024-06-07T22:36:53.709243Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -176,8 +152,8 @@
    },
    "outputs": [],
    "source": [
-    "uxds[\"relhum_200hPa\"][0].plot.rasterize(\n",
-    "    method=\"polygon\", exclude_antimeridian=True, title=\"Global Grid\", **plot_opts\n",
+    "uxds[\"relhum_200hPa\"][0].plot(\n",
+    "    rasterize=True, periodic_elements=\"exclude\", title=\"Global Grid\", **plot_opts\n",
     ") * features"
    ]
   },
@@ -227,10 +203,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:38:21.645685Z",
-     "start_time": "2024-06-07T22:38:21.641552Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -245,10 +217,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:38:23.218966Z",
-     "start_time": "2024-06-07T22:38:23.172443Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -277,10 +245,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:38:37.739473Z",
-     "start_time": "2024-06-07T22:38:37.697998Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -310,10 +274,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:39:14.680397Z",
-     "start_time": "2024-06-07T22:39:12.596281Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -325,9 +285,9 @@
     "    lon_bounds, lat_bounds, element=\"nodes\"\n",
     ")\n",
     "\n",
-    "bbox_subset_nodes.plot.rasterize(\n",
-    "    method=\"polygon\",\n",
-    "    exclude_antimeridian=True,\n",
+    "bbox_subset_nodes.plot(\n",
+    "    rasterize=True,\n",
+    "    periodic_elements=\"exclude\",\n",
     "    clim=clim,\n",
     "    title=\"Bounding Box Subset (Corner Node Query)\",\n",
     "    **plot_opts,\n",
@@ -350,10 +310,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:38:57.658080Z",
-     "start_time": "2024-06-07T22:38:55.725793Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -365,9 +321,9 @@
     "    lon_bounds, lat_bounds, element=\"face centers\"\n",
     ")\n",
     "\n",
-    "bbox_subset_faces.plot.rasterize(\n",
-    "    method=\"polygon\",\n",
-    "    exclude_antimeridian=True,\n",
+    "bbox_subset_faces.plot(\n",
+    "    rasterize=True,\n",
+    "    periodic_elements=\"exclude\",\n",
     "    clim=clim,\n",
     "    title=\"Bounding Box Subset (Face Center Query)\",\n",
     "    **plot_opts,\n",
@@ -408,10 +364,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:39:43.139200Z",
-     "start_time": "2024-06-07T22:39:43.026055Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -428,10 +380,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:39:46.520147Z",
-     "start_time": "2024-06-07T22:39:44.107409Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -441,9 +389,9 @@
    "source": [
     "bcircle_subset = uxds[\"relhum_200hPa\"][0].subset.bounding_circle(center_coord, r)\n",
     "\n",
-    "bcircle_subset.plot.rasterize(\n",
-    "    method=\"polygon\",\n",
-    "    exclude_antimeridian=True,\n",
+    "bcircle_subset.plot(\n",
+    "    rasterize=True,\n",
+    "    periodic_elements=\"exclude\",\n",
     "    clim=clim,\n",
     "    title=\"Bounding Circle Subset\",\n",
     "    **plot_opts,\n",
@@ -468,10 +416,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:39:53.170082Z",
-     "start_time": "2024-06-07T22:39:53.017349Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -486,10 +430,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:39:56.343421Z",
-     "start_time": "2024-06-07T22:39:54.415082Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -501,9 +441,9 @@
     "    center_coord, k=30, element=\"nodes\"\n",
     ")\n",
     "\n",
-    "nn_subset.plot.rasterize(\n",
-    "    method=\"polygon\",\n",
-    "    exclude_antimeridian=True,\n",
+    "nn_subset.plot(\n",
+    "    rasterize=True,\n",
+    "    periodic_elements=\"exclude\",\n",
     "    clim=clim,\n",
     "    title=\"Nearest Neighbor Subset\",\n",
     "    **plot_opts,\n",
@@ -526,10 +466,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:40:46.514866Z",
-     "start_time": "2024-06-07T22:40:44.152659Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -541,9 +477,9 @@
     "    center_coord, k=120, element=\"face centers\"\n",
     ")\n",
     "\n",
-    "nn_subset_120.plot.rasterize(\n",
-    "    method=\"polygon\",\n",
-    "    exclude_antimeridian=True,\n",
+    "nn_subset_120.plot(\n",
+    "    rasterize=True,\n",
+    "    periodic_elements=\"exclude\",\n",
     "    clim=clim,\n",
     "    title=\"Nearest Neighbor Subset (120 Faces)\",\n",
     "    **plot_opts,\n",
@@ -566,10 +502,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:41:27.554399Z",
-     "start_time": "2024-06-07T22:41:25.616381Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
@@ -581,9 +513,9 @@
     "    center_coord, k=1, element=\"face centers\"\n",
     ")\n",
     "\n",
-    "nn_subset_1.plot.rasterize(\n",
-    "    method=\"polygon\",\n",
-    "    exclude_antimeridian=True,\n",
+    "nn_subset_1.plot(\n",
+    "    rasterize=True,\n",
+    "    periodic_elements=\"exclude\",\n",
     "    clim=clim,\n",
     "    title=\"Nearest Neighbor Subset (Closest Face)\",\n",
     "    **plot_opts,\n",
@@ -610,10 +542,6 @@
    "cell_type": "code",
    "execution_count": null,
    "metadata": {
-    "ExecuteTime": {
-     "end_time": "2024-06-07T22:43:24.764492Z",
-     "start_time": "2024-06-07T22:43:24.759423Z"
-    },
     "collapsed": false,
     "jupyter": {
      "outputs_hidden": false
diff --git a/uxarray/core/dataarray.py b/uxarray/core/dataarray.py
index 52a464b5..3d1b41f3 100644
--- a/uxarray/core/dataarray.py
+++ b/uxarray/core/dataarray.py
@@ -1085,20 +1085,18 @@ class UxDataArray(xr.DataArray):
         """Slices a  ``UxDataArray`` from a sliced ``Grid``, using cached
         indices to correctly slice the data variable."""
 
-        from uxarray.core.dataarray import UxDataArray
-
         if self._face_centered():
-            d_var = self.isel(
+            da_sliced = self.isel(
                 n_face=sliced_grid._ds["subgrid_face_indices"], ignore_grid=True
             )
 
         elif self._edge_centered():
-            d_var = self.isel(
+            da_sliced = self.isel(
                 n_edge=sliced_grid._ds["subgrid_edge_indices"], ignore_grid=True
             )
 
         elif self._node_centered():
-            d_var = self.isel(
+            da_sliced = self.isel(
                 n_node=sliced_grid._ds["subgrid_node_indices"], ignore_grid=True
             )
 
@@ -1107,14 +1105,7 @@ class UxDataArray(xr.DataArray):
                 "Data variable must be either node, edge, or face centered."
             )
 
-        return UxDataArray(
-            uxgrid=sliced_grid,
-            data=d_var,
-            name=self.name,
-            coords=self.coords,
-            dims=self.dims,
-            attrs=self.attrs,
-        )
+        return UxDataArray(da_sliced, uxgrid=sliced_grid)
 
     def get_dual(self):
         """Compute the dual mesh for a data array, returns a new data array
diff --git a/uxarray/remap/inverse_distance_weighted.py b/uxarray/remap/inverse_distance_weighted.py
index a4436aa6..1c86d13f 100644
--- a/uxarray/remap/inverse_distance_weighted.py
+++ b/uxarray/remap/inverse_distance_weighted.py
@@ -12,6 +12,8 @@ import uxarray.core.dataset
 from uxarray.grid import Grid
 import warnings
 
+from copy import deepcopy
+
 from uxarray.remap.utils import _remap_grid_parse
 
 
@@ -144,13 +146,19 @@ def _inverse_distance_weighted_remap_uxda(
         power,
         k,
     )
+
+    # preserve only non-spatial coordinates
+    destination_coords = deepcopy(source_uxda.coords)
+    if destination_dim in destination_coords:
+        del destination_coords[destination_dim]
+
     # construct data array for remapping variable
     uxda_remap = uxarray.core.dataarray.UxDataArray(
         data=destination_data,
         name=source_uxda.name,
-        coords=source_uxda.coords,
         dims=destination_dims,
         uxgrid=destination_grid,
+        coords=destination_coords,
     )
 
     # return UxDataArray with remapped variable
diff --git a/uxarray/remap/nearest_neighbor.py b/uxarray/remap/nearest_neighbor.py
index 83a8760c..2100cdbb 100644
--- a/uxarray/remap/nearest_neighbor.py
+++ b/uxarray/remap/nearest_neighbor.py
@@ -13,6 +13,8 @@ import uxarray.core.dataarray
 import uxarray.core.dataset
 from uxarray.grid import Grid
 
+from copy import deepcopy
+
 
 def _nearest_neighbor(
     source_grid: Grid,
@@ -103,15 +105,20 @@ def _nearest_neighbor_uxda(
     destination_data = _nearest_neighbor(
         source_uxda.uxgrid, destination_grid, source_uxda.data, remap_to, coord_type
     )
+
+    # preserve only non-spatial coordinates
+    destination_coords = deepcopy(source_uxda.coords)
+    if destination_dim in destination_coords:
+        del destination_coords[destination_dim]
+
     # construct data array for remapping variable
     uxda_remap = uxarray.core.dataarray.UxDataArray(
         data=destination_data,
         name=source_uxda.name,
-        coords=source_uxda.coords,
         dims=destination_dims,
         uxgrid=destination_grid,
+        coords=destination_coords,
     )
-    # return UxDataArray with remapped variable
     return uxda_remap
 
 


Test patch:
diff --git a/test/test_remap.py b/test/test_remap.py
index 6c3aa037..6fb9b753 100644
--- a/test/test_remap.py
+++ b/test/test_remap.py
@@ -214,6 +214,16 @@ class TestNearestNeighborRemap(TestCase):
                 remap_to="nodes"
             )
 
+    def test_preserve_coordinates(self):
+        # Dataset with 'time' coordinates
+        source_uxds = ux.open_dataset(gridfile_geoflow, dsfile_v1_geoflow)
+        destination_grid = ux.open_grid(mpasfile_QU)
+
+        res = source_uxds.remap.nearest_neighbor(destination_grid=destination_grid)
+
+        assert "time" in res.coords
+
+
 
 class TestInverseDistanceWeightedRemapping(TestCase):
     """Testing for inverse distance weighted remapping."""
diff --git a/test/test_subset.py b/test/test_subset.py
index 5cdded05..a1bfaed7 100644
--- a/test/test_subset.py
+++ b/test/test_subset.py
@@ -102,3 +102,21 @@ def test_grid_bounding_box_subset():
 
             grid_subset_antimeridian = grid.subset.bounding_box(
                 bbox_antimeridian[0], bbox_antimeridian[1], element=element)
+
+
+
+
+def test_uxda_isel():
+    uxds = ux.open_dataset(GRID_PATHS[0], DATA_PATHS[0])
+
+    sub = uxds['bottomDepth'].isel(n_face=[1, 2, 3])
+
+    assert len(sub) == 3
+
+def test_uxda_isel_with_coords():
+    uxds = ux.open_dataset(GRID_PATHS[0], DATA_PATHS[0])
+    uxds = uxds.assign_coords({"lon_face": uxds.uxgrid.face_lon})
+    sub = uxds['bottomDepth'].isel(n_face=[1, 2, 3])
+
+    assert "lon_face" in sub.coords
+    assert len(sub.coords['lon_face']) == 3