Repository: holoviz/holoviews
Pull request #6283 (2024-06-12 13:47:01)

Correctly handle y/xaxis=True/False/None
Handling of `{y|x}axis=True/False/None` wasn't correct due to a missing check for string types in the positioning logic.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/holoviz/holoviews/pull/6283?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) Report
All modified and coverable lines are covered by tests :white_check_mark:
> Project coverage is 88.54%. Comparing base [(`8c99659`)](https://app.codecov.io/gh/holoviz/holoviews/commit/8c99659d07d6b0d98ed6fc936b00d926fa6d51c9?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz) to head [(`4b1d881`)](https://app.codecov.io/gh/holoviz/holoviews/commit/4b1d88140f9ca7e55e1bbfcf3a8dc3c8701890b2?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz).


<details><summary>Additional details and impacted files</summary>


```diff
@@           Coverage Diff           @@
##             main    #6283   +/-   ##
=======================================
  Coverage   88.54%   88.54%           
=======================================
  Files         323      323           
  Lines       67977    67994   +17     
=======================================
+ Hits        60190    60207   +17     
  Misses       7787     7787           
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/holoviz/holoviews/pull/6283?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=holoviz).


Patch:
diff --git a/examples/gallery/demos/bokeh/multichannel_timeseries_viewer.ipynb b/examples/gallery/demos/bokeh/multichannel_timeseries_viewer.ipynb
index b06a8d4d0..c4888749f 100644
--- a/examples/gallery/demos/bokeh/multichannel_timeseries_viewer.ipynb
+++ b/examples/gallery/demos/bokeh/multichannel_timeseries_viewer.ipynb
@@ -17,19 +17,18 @@
   {
    "cell_type": "code",
    "execution_count": null,
-   "id": "8109537b-5fba-4f07-aba4-91a56f7e95c7",
+   "id": "4d81eadd-95c7-4474-9f59-deb2c0cf3297",
    "metadata": {},
    "outputs": [],
    "source": [
     "import numpy as np\n",
+    "import pandas as pd\n",
     "import holoviews as hv\n",
-    "from bokeh.models import HoverTool\n",
     "from holoviews.operation.normalization import subcoordinate_group_ranges\n",
     "from holoviews.operation.datashader import rasterize\n",
     "from holoviews.plotting.links import RangeToolLink\n",
-    "from scipy.stats import zscore\n",
     "import colorcet as cc\n",
-    "\n",
+    "from scipy.stats import zscore\n",
     "hv.extension('bokeh')"
    ]
   },
@@ -50,15 +49,6 @@
    "metadata": {},
    "outputs": [],
    "source": [
-    "import numpy as np\n",
-    "import pandas as pd\n",
-    "import holoviews as hv\n",
-    "from holoviews.operation.normalization import subcoordinate_group_ranges\n",
-    "from holoviews.plotting.links import RangeToolLink\n",
-    "from scipy.stats import zscore\n",
-    "\n",
-    "hv.extension('bokeh')\n",
-    "\n",
     "GROUP_EEG = 'EEG'\n",
     "GROUP_POS = 'Position'\n",
     "N_CHANNELS_EEG = 10\n",
@@ -113,7 +103,7 @@
    "outputs": [],
    "source": [
     "# Create a Curve per data series\n",
-    "def df_to_curves(df, kdim, vdim, color='black', group='EEG'):\n",
+    "def df_to_curves(df, kdim, vdim, color='black', group='EEG', ):\n",
     "    curves = []\n",
     "    for i, (channel, channel_data) in enumerate(df.items()):\n",
     "        ds = hv.Dataset((channel_data.index, channel_data), [kdim, vdim])\n",
@@ -135,8 +125,8 @@
     "pos_curves = df_to_curves(pos_df, time_dim, vdim_POS, color=cc.glasbey_cool, group='POS')\n",
     "\n",
     "# Combine EEG and POS curves into an Overlay\n",
-    "eeg_curves_overlay = hv.Overlay(eeg_curves, kdims=\"Channel\")\n",
-    "pos_curves_overlay = hv.Overlay(pos_curves, kdims=\"Channel\")\n",
+    "eeg_curves_overlay = hv.Overlay(eeg_curves, \"Channel\")\n",
+    "pos_curves_overlay = hv.Overlay(pos_curves, \"Channel\")\n",
     "curves_overlay = (eeg_curves_overlay * pos_curves_overlay).opts(\n",
     "    xlabel=time_dim.pprint_label, ylabel=\"Channel\", show_legend=False, aspect=3, responsive=True,\n",
     ")\n",
diff --git a/holoviews/plotting/bokeh/element.py b/holoviews/plotting/bokeh/element.py
index f5fea8f2b..0facacc48 100644
--- a/holoviews/plotting/bokeh/element.py
+++ b/holoviews/plotting/bokeh/element.py
@@ -943,11 +943,11 @@ class ElementPlot(BokehPlot, GenericElementPlot):
                     if axis_label and axis in self.labelled:
                         properties[f'{axis}_axis_label'] = axis_label
                     locs = {'left': 'left', 'right': 'right'} if axis == 'y' else {'bottom': 'below', 'top': 'above'}
-                    if axis_position is None:
+                    if axis_position in (None, False):
                         axis_props[axis]['visible'] = False
                     axis_props[axis].update(fontsize)
                     for loc, pos in locs.items():
-                        if axis_position and loc in axis_position:
+                        if isinstance(axis_position, str) and loc in axis_position:
                             properties[f'{axis}_axis_location'] = pos
 
         if not self.show_frame:


Test patch:
diff --git a/holoviews/tests/plotting/bokeh/test_elementplot.py b/holoviews/tests/plotting/bokeh/test_elementplot.py
index 7e3c02d9d..c465ac46b 100644
--- a/holoviews/tests/plotting/bokeh/test_elementplot.py
+++ b/holoviews/tests/plotting/bokeh/test_elementplot.py
@@ -111,6 +111,26 @@ class TestElementPlot(LoggingComparisonTestCase, TestBokehPlot):
         self.assertEqual(xaxis.major_tick_line_color, None)
         self.assertTrue(xaxis in plot.state.above)
 
+    def test_element_yaxis_true(self):
+        curve = Curve(range(10)).opts(yaxis=True)
+        plot = bokeh_renderer.get_plot(curve)
+        yaxis = plot.handles['yaxis']
+        assert yaxis in plot.state.left
+
+    def test_element_yaxis_false(self):
+        curve = Curve(range(10)).opts(yaxis=False)
+        plot = bokeh_renderer.get_plot(curve)
+        yaxis = plot.handles['yaxis']
+        assert yaxis in plot.state.left
+        assert not yaxis.visible
+
+    def test_element_yaxis_none(self):
+        curve = Curve(range(10)).opts(yaxis=None)
+        plot = bokeh_renderer.get_plot(curve)
+        yaxis = plot.handles['yaxis']
+        assert yaxis in plot.state.left
+        assert not yaxis.visible
+
     def test_element_yaxis_right(self):
         curve = Curve(range(10)).opts(yaxis='right')
         plot = bokeh_renderer.get_plot(curve)