Repository: holoviz/holoviews

Issue:
invert_yaxis causes the image to shift

#### ALL software version info
* holoviews='1.16.2'
* bokeh='3.1.1'
* panel='1.1.1'
* python=3.10
* jupyterlab=3.5.2
* pyviz_comms jupyterlab extension with version 2.3.2

#### Description of expected behavior and the observed behavior

This is basically the same issue as https://github.com/holoviz/holoviews/issues/4668. When I use `invert_yaxis=True` the image shifts down. If the initial image goes from y=0 to 100 I would expect the output axes to go from 100 (on bottom) to 0 (on top), and the image also flipped so that the row corresponding to y=0 would be on top. Instead the row corresponding to y=0 goes to _200_.

#### Complete, minimal, self-contained example code that reproduces the issue

```
import numpy as np
import holoviews as hv
import panel as pn
hv.extension('bokeh')

vector = np.arange(100)
d = np.outer(vector, vector)


img = hv.Image((vector, vector, d)).opts(invert_yaxis=True)

```

#### Stack traceback and/or browser JavaScript console output
N/A

#### Screenshots 

![Screenshot 2023-07-05 at 2 52 48 PM](https://github.com/holoviz/holoviews/assets/109681919/52b1ee5d-25e8-4d56-96c2-0848e8aaffc0)



Discussion:
same issue in #5727

Resolving patch:
diff --git a/holoviews/plotting/bokeh/raster.py b/holoviews/plotting/bokeh/raster.py
--- a/holoviews/plotting/bokeh/raster.py
+++ b/holoviews/plotting/bokeh/raster.py
@@ -12,7 +12,7 @@
 from .element import ColorbarPlot, LegendPlot
 from .selection import BokehOverlaySelectionDisplay
 from .styles import base_properties, fill_properties, line_properties, mpl_to_bokeh
-from .util import colormesh
+from .util import bokeh3, colormesh
 
 
 class RasterPlot(ColorbarPlot):
@@ -102,9 +102,9 @@ def get_data(self, element, ranges, style):
                 l, b, r, t = b, l, t, r
 
         dh, dw = t-b, r-l
-        if self.invert_xaxis:
+        if self.invert_xaxis and not bokeh3:
             l, r = r, l
-        if self.invert_yaxis:
+        if self.invert_yaxis and not bokeh3:
             b, t = t, b
         data = dict(x=[l], y=[b], dw=[dw], dh=[dh])
 
@@ -116,12 +116,11 @@ def get_data(self, element, ranges, style):
                 img = img.astype(np.int8)
             if 0 in img.shape:
                 img = np.array([[np.NaN]])
-            if ((self.invert_axes and type(element) is not Raster) or
-                (not self.invert_axes and type(element) is Raster)):
+            if self.invert_axes ^ (type(element) is Raster):
                 img = img.T
-            if self.invert_xaxis:
+            if self.invert_xaxis and not bokeh3:
                 img = img[:, ::-1]
-            if self.invert_yaxis:
+            if self.invert_yaxis and not bokeh3:
                 img = img[::-1]
             key = 'image' if i == 2 else dimension_sanitizer(vdim.name)
             data[key] = [img]
@@ -205,10 +204,10 @@ def get_data(self, element, ranges, style):
             l, b, r, t = b, l, t, r
 
         dh, dw = t-b, r-l
-        if self.invert_xaxis:
+        if self.invert_xaxis and not bokeh3:
             l, r = r, l
             img = img[:, ::-1]
-        if self.invert_yaxis:
+        if self.invert_yaxis and not bokeh3:
             img = img[::-1]
             b, t = t, b
 


Test patch:
diff --git a/holoviews/tests/plotting/bokeh/test_rasterplot.py b/holoviews/tests/plotting/bokeh/test_rasterplot.py
--- a/holoviews/tests/plotting/bokeh/test_rasterplot.py
+++ b/holoviews/tests/plotting/bokeh/test_rasterplot.py
@@ -1,6 +1,7 @@
 import numpy as np
 
 from holoviews.element import Raster, Image, RGB
+from holoviews.plotting.bokeh.util import bokeh3
 
 from .test_plot import TestBokehPlot, bokeh_renderer
 
@@ -46,11 +47,19 @@ def test_raster_invert_axes(self):
         raster = Raster(arr).opts(invert_axes=True)
         plot = bokeh_renderer.get_plot(raster)
         source = plot.handles['source']
-        self.assertEqual(source.data['image'][0], np.rot90(arr))
-        self.assertEqual(source.data['x'][0], 0)
-        self.assertEqual(source.data['y'][0], 3)
-        self.assertEqual(source.data['dw'][0], 2)
-        self.assertEqual(source.data['dh'][0], 3)
+
+        if bokeh3:
+            self.assertEqual(source.data['image'][0], arr.T)
+            self.assertEqual(source.data['x'][0], 0)
+            self.assertEqual(source.data['y'][0], 0)
+            self.assertEqual(source.data['dw'][0], 2)
+            self.assertEqual(source.data['dh'][0], 3)
+        else:
+            self.assertEqual(source.data['image'][0], np.rot90(arr))
+            self.assertEqual(source.data['x'][0], 0)
+            self.assertEqual(source.data['y'][0], 3)
+            self.assertEqual(source.data['dw'][0], 2)
+            self.assertEqual(source.data['dh'][0], 3)
 
     def test_image_invert_axes(self):
         arr = np.array([[0, 1, 2], [3, 4,  5]])
@@ -71,11 +80,16 @@ def test_image_invert_xaxis(self):
         self.assertEqual(x_range.start, 0.5)
         self.assertEqual(x_range.end, -0.5)
         cdata = plot.handles['source'].data
-        self.assertEqual(cdata['x'], [0.5])
         self.assertEqual(cdata['y'], [-0.5])
         self.assertEqual(cdata['dh'], [1.0])
         self.assertEqual(cdata['dw'], [1.0])
-        self.assertEqual(cdata['image'][0], arr[::-1, ::-1])
+
+        if bokeh3:
+            self.assertEqual(cdata['x'], [-0.5])
+            self.assertEqual(cdata['image'][0], arr[::-1])
+        else:
+            self.assertEqual(cdata['x'], [0.5])
+            self.assertEqual(cdata['image'][0], arr[::-1, ::-1])
 
     def test_image_invert_yaxis(self):
         arr = np.random.rand(10, 10)
@@ -86,10 +100,15 @@ def test_image_invert_yaxis(self):
         self.assertEqual(y_range.end, -0.5)
         cdata = plot.handles['source'].data
         self.assertEqual(cdata['x'], [-0.5])
-        self.assertEqual(cdata['y'], [0.5])
         self.assertEqual(cdata['dh'], [1.0])
         self.assertEqual(cdata['dw'], [1.0])
-        self.assertEqual(cdata['image'][0], arr)
+
+        if bokeh3:
+            self.assertEqual(cdata['y'], [-0.5])
+            self.assertEqual(cdata['image'][0], arr[::-1])
+        else:
+            self.assertEqual(cdata['y'], [0.5])
+            self.assertEqual(cdata['image'][0], arr)
 
     def test_rgb_invert_xaxis(self):
         rgb = RGB(np.random.rand(10, 10, 3)).opts(invert_xaxis=True)
@@ -98,11 +117,15 @@ def test_rgb_invert_xaxis(self):
         self.assertEqual(x_range.start, 0.5)
         self.assertEqual(x_range.end, -0.5)
         cdata = plot.handles['source'].data
-        self.assertEqual(cdata['x'], [0.5])
         self.assertEqual(cdata['y'], [-0.5])
         self.assertEqual(cdata['dh'], [1.0])
         self.assertEqual(cdata['dw'], [1.0])
 
+        if bokeh3:
+            self.assertEqual(cdata['x'], [-0.5])
+        else:
+            self.assertEqual(cdata['x'], [0.5])
+
     def test_rgb_invert_yaxis(self):
         rgb = RGB(np.random.rand(10, 10, 3)).opts(invert_yaxis=True)
         plot = bokeh_renderer.get_plot(rgb)
@@ -111,6 +134,10 @@ def test_rgb_invert_yaxis(self):
         self.assertEqual(y_range.end, -0.5)
         cdata = plot.handles['source'].data
         self.assertEqual(cdata['x'], [-0.5])
-        self.assertEqual(cdata['y'], [0.5])
         self.assertEqual(cdata['dh'], [1.0])
         self.assertEqual(cdata['dw'], [1.0])
+
+        if bokeh3:
+            self.assertEqual(cdata['y'], [-0.5])
+        else:
+            self.assertEqual(cdata['y'], [0.5])