Repository: holoviz/holoviews

Issue:
In this example, OSM Tiles look great, then disappear!
#### ALL software version info

```
conda list | grep -E "bokeh|geoviews|datashader|hvplot|holovies|panel"

bokeh                     2.4.3            py39hf3d152e_0    conda-forge
bokeh-root-cmd            0.1.2              pyhd8ed1ab_0    conda-forge
datashader                0.14.0             pyh6c4a22f_0    conda-forge
geoviews                  1.9.5              pyhd8ed1ab_0    conda-forge
geoviews-core             1.9.5              pyha770c72_0    conda-forge
hvplot                    0.8.0              pyh6c4a22f_0    conda-forge
jupyter-panel-proxy       0.1.0                      py_0    conda-forge
panel                     0.13.1             pyhd8ed1ab_0    conda-forge
```

#### Description of expected behavior and the observed behavior
 
OSM basemap tiles appear nicely, then disappear.  See 15s movie here: 
https://www.screencast.com/t/JhREGjulrH

#### Complete, minimal, self-contained example code that reproduces the issue

Full reproducible notebook here:
https://nbviewer.org/gist/5818739f4aa65e6ed81b1f1501c1be82





Discussion:
@jbednar thanks for suggesting to raise this as a bug here
Suspect it's the `rasterize` call that is regridding the rgb to cover the full extents of the plot. This should afaik not happen because by default it should not regrid it beyond the extents of the original data. Will transfer to hvPlot for now.

Resolving patch:
diff --git a/holoviews/core/util.py b/holoviews/core/util.py
--- a/holoviews/core/util.py
+++ b/holoviews/core/util.py
@@ -803,6 +803,20 @@ def isnumeric(val):
         return False
 
 
+def isequal(value1, value2):
+    """Compare two values, returning a boolean.
+
+    Will apply the comparison to all elements of an array/dataframe.
+    """
+    try:
+        check = (value1 is value2) or (value1 == value2)
+        if not isinstance(check, bool) and hasattr(check, "all"):
+            check = check.all()
+        return bool(check)
+    except Exception:
+        return False
+
+
 def asarray(arraylike, strict=True):
     """
     Converts arraylike objects to NumPy ndarray types. Errors if
diff --git a/holoviews/operation/datashader.py b/holoviews/operation/datashader.py
--- a/holoviews/operation/datashader.py
+++ b/holoviews/operation/datashader.py
@@ -1374,12 +1374,23 @@ class rasterize(AggregationOperation):
                    (type(None), shade) # To handle parameters of datashade
     ]
 
+    __instance_params = set()
+
+    @bothmethod
+    def instance(self_or_cls, **params):
+        inst = super().instance(**params)
+        inst.__instance_params = set(params)
+        return inst
+
     def _process(self, element, key=None):
         # Potentially needs traverse to find element types first?
         all_allowed_kws = set()
         all_supplied_kws = set()
+        instance_params = {
+            k: getattr(self, k) for k in self.__instance_params
+        }
         for predicate, transform in self._transforms:
-            merged_param_values = dict(self.param.values(), **self.p)
+            merged_param_values = dict(instance_params, **self.p)
 
             # If aggregator or interpolation are 'default', pop parameter so
             # datashader can choose the default aggregator itself


Test patch:
diff --git a/holoviews/tests/operation/test_datashader.py b/holoviews/tests/operation/test_datashader.py
--- a/holoviews/tests/operation/test_datashader.py
+++ b/holoviews/tests/operation/test_datashader.py
@@ -1150,6 +1150,24 @@ def test_rasterize_image_string_aggregator(self):
         expected = Image(([2., 7.], [0.75, 3.25], [[1, 5], [6, 22]]))
         self.assertEqual(regridded, expected)
 
+    def test_rasterize_image_expand_default(self):
+        # Should use expand=False by default
+        assert not regrid.expand
+
+        data = np.arange(100.0).reshape(10, 10)
+        c = np.arange(10.0)
+        da = xr.DataArray(data, coords=dict(x=c, y=c))
+        rast_input = dict(x_range=(-1, 10), y_range=(-1, 10), precompute=True, dynamic=False)
+        img = rasterize(Image(da), **rast_input)
+        output = img.data["z"].to_numpy()
+
+        np.testing.assert_array_equal(output, data.T)
+        assert not np.isnan(output).any()
+
+        # Setting expand=True with the {x,y}_ranges will expand the data with nan's
+        img = rasterize(Image(da), expand=True, **rast_input)
+        output = img.data["z"].to_numpy()
+        assert np.isnan(output).any()
 
 class DatashaderSpreadTests(ComparisonTestCase):