From 4c1fb744ec890d4e88802dae69c9923cf025e0ca Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Mon, 29 Sep 2025 04:30:20 -0700 Subject: [PATCH 1/3] Allow specifying grid --- doc/ref/plotting_options/styling.ipynb | 24 ++++++++++++++++++++++++ hvplot/converter.py | 18 +++++++++++++++--- hvplot/tests/testoptions.py | 25 +++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/doc/ref/plotting_options/styling.ipynb b/doc/ref/plotting_options/styling.ipynb index 1198124aa..d320c63ec 100644 --- a/doc/ref/plotting_options/styling.ipynb +++ b/doc/ref/plotting_options/styling.ipynb @@ -311,6 +311,30 @@ "plot2 = df.hvplot(group_label=\"Company\", grid=True, width=400, title=\"grid=True\")\n", "(plot1 + plot2).cols(1)" ] + }, + { + "cell_type": "markdown", + "id": "56cdf3e2", + "metadata": {}, + "source": [ + "To show grid only on the x-axis, use ``grid='x'``. To show grid only on the y-axis, use ``grid='y'``. To change the grid line style, suffix with ``'dashed'``, ``'dotted'``, ``'dotdash'``, or ``'dashdot'``, e.g. ``grid='x-dashed'``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e38dee4", + "metadata": {}, + "outputs": [], + "source": [ + "import hvplot.pandas # noqa\n", + "\n", + "df = hvplot.sampledata.stocks(\"pandas\", engine_kwargs={\"index_col\" : \"date\"})\n", + "\n", + "plot1 = df.hvplot(group_label=\"Company\", grid='x', width=400, title=\"grid='x'\")\n", + "plot2 = df.hvplot(group_label=\"Company\", grid='y-dashed', width=400, title=\"grid='y-dashed'\")\n", + "(plot1 + plot2).cols(1)" + ] } ], "metadata": { diff --git a/hvplot/converter.py b/hvplot/converter.py index 361b55da5..d628878f0 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -475,8 +475,11 @@ class HoloViewsConverter: fontsize : number or dict or None, default=None Set title, label and legend text to the same fontsize. Finer control by using a dict: ``{'title': '15pt', 'ylabel': '5px', 'ticks': 20}``. - grid : bool or None, default=None - Whether to show a grid. + grid : bool, str, or None, default=None + Whether to show a grid. If True, shows grid on both axes. + If ``'x'`` or ``'y'``, shows grid only on the specified axis. + Suffix with ``'dashed'``, ``'dotted'``, ``'dotdash'``, or ``'dashdot'`` + to change the grid line style, e.g. ``'x-dashed'``. Resampling Options ------------------ @@ -1059,7 +1062,16 @@ def __init__( plot_opts['logy'] = logy if grid is not None: - plot_opts['show_grid'] = grid + if isinstance(grid, str): + gridstyle = {} + axis = grid[0] + other_axis = 'x' if axis == 'y' else 'y' + if len(grid) > 0: + line_dash = grid[1:].lstrip('-').lstrip('.').lstrip('_') + gridstyle[f'{axis}grid_line_dash'] = line_dash + gridstyle[f'{other_axis}grid_line_alpha'] = 0 + plot_opts['gridstyle'] = gridstyle + plot_opts['show_grid'] = bool(grid) if legend is not None: plot_opts['show_legend'] = bool(legend) diff --git a/hvplot/tests/testoptions.py b/hvplot/tests/testoptions.py index b20676555..f402482f5 100644 --- a/hvplot/tests/testoptions.py +++ b/hvplot/tests/testoptions.py @@ -635,6 +635,31 @@ def test_legend_opts(self, df, backend): opts = Store.lookup_options(backend, plot, 'plot') assert opts.kwargs['legend_opts'] == lo + @pytest.mark.parametrize('grid_bool', [True, False]) + def test_grid_boolean(self, df, backend, grid_bool): + plot = df.hvplot('x', 'y', grid=grid_bool) + opts = Store.lookup_options(backend, plot, 'plot') + assert opts.kwargs['grid'] is grid_bool + + def test_grid_x(self, df, backend): + plot = df.hvplot('x', 'y', grid='x') + opts = Store.lookup_options(backend, plot, 'plot') + assert opts.kwargs['grid'] is True + assert opts.kwargs['gridstyle'] == {'ygrid_line_alpha': 0} + + def test_grid_y(self, df, backend): + plot = df.hvplot('x', 'y', grid='y') + opts = Store.lookup_options(backend, plot, 'plot') + assert opts.kwargs['grid'] is True + assert opts.kwargs['gridstyle'] == {'xgrid_line_alpha': 0} + + @pytest.mark.parameterize('grid_str', ['x-dashed', 'xdashed', 'x.dashed', 'x_dashed']) + def test_grid_line_dash(self, df, backend, grid_str): + plot = df.hvplot('x', 'y', grid=grid_str) + opts = Store.lookup_options(backend, plot, 'plot') + assert opts.kwargs['grid'] is True + assert opts.kwargs['gridstyle'] == {'ygrid_line_alpha': 0, 'xgrid_line_dash': 'dashed'} + @pytest.fixture(scope='module') def da(): From 6f17fd56dc95c6600c3eb992cb4dae85186e6d32 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Mon, 29 Sep 2025 04:33:03 -0700 Subject: [PATCH 2/3] fix spell --- hvplot/tests/testoptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hvplot/tests/testoptions.py b/hvplot/tests/testoptions.py index f402482f5..1c62f900a 100644 --- a/hvplot/tests/testoptions.py +++ b/hvplot/tests/testoptions.py @@ -653,7 +653,7 @@ def test_grid_y(self, df, backend): assert opts.kwargs['grid'] is True assert opts.kwargs['gridstyle'] == {'xgrid_line_alpha': 0} - @pytest.mark.parameterize('grid_str', ['x-dashed', 'xdashed', 'x.dashed', 'x_dashed']) + @pytest.mark.parametrize('grid_str', ['x-dashed', 'xdashed', 'x.dashed', 'x_dashed']) def test_grid_line_dash(self, df, backend, grid_str): plot = df.hvplot('x', 'y', grid=grid_str) opts = Store.lookup_options(backend, plot, 'plot') From 8484da3cc22899e27da9cacdf9039188f15ee60d Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Mon, 29 Sep 2025 07:28:00 -0700 Subject: [PATCH 3/3] Add dict & mpl support --- doc/ref/plotting_options/styling.ipynb | 26 +++++++++++++++++++++++++- hvplot/converter.py | 24 +++++++++++++++++++----- hvplot/tests/testoptions.py | 7 +++++++ 3 files changed, 51 insertions(+), 6 deletions(-) diff --git a/doc/ref/plotting_options/styling.ipynb b/doc/ref/plotting_options/styling.ipynb index d320c63ec..9d9550caf 100644 --- a/doc/ref/plotting_options/styling.ipynb +++ b/doc/ref/plotting_options/styling.ipynb @@ -317,7 +317,7 @@ "id": "56cdf3e2", "metadata": {}, "source": [ - "To show grid only on the x-axis, use ``grid='x'``. To show grid only on the y-axis, use ``grid='y'``. To change the grid line style, suffix with ``'dashed'``, ``'dotted'``, ``'dotdash'``, or ``'dashdot'``, e.g. ``grid='x-dashed'``." + "To show grid only on the x-axis, use ``grid='x'``. To show grid only on the y-axis, use ``grid='y'``. To change the grid line style, suffix with ``'dashed'``, ``'dotted'``, or ``'dashdot'``, e.g. ``grid='x-dashed'``." ] }, { @@ -335,6 +335,30 @@ "plot2 = df.hvplot(group_label=\"Company\", grid='y-dashed', width=400, title=\"grid='y-dashed'\")\n", "(plot1 + plot2).cols(1)" ] + }, + { + "cell_type": "markdown", + "id": "59315b89", + "metadata": {}, + "source": [ + " A dictionary of grid style options may also be supplied, e.g. for bokeh, ``{'grid_line_color': 'red', 'grid_line_alpha': 0.5}``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3b095ba", + "metadata": {}, + "outputs": [], + "source": [ + "import hvplot.pandas # noqa\n", + "\n", + "df = hvplot.sampledata.stocks(\"pandas\", engine_kwargs={\"index_col\" : \"date\"})\n", + "\n", + "plot1 = df.hvplot(group_label=\"Company\", grid={'grid_line_color': 'red', 'grid_line_alpha': 0.5}, width=400, title=\"grid=dict\")\n", + "plot2 = df.hvplot(group_label=\"Company\", grid={'xgrid_line_color': 'green', 'xgrid_line_alpha': 0.5}, width=400, title=\"grid=dict (x-axis only)\")\n", + "(plot1 + plot2).cols(1)" + ] } ], "metadata": { diff --git a/hvplot/converter.py b/hvplot/converter.py index d628878f0..33e9b6db9 100644 --- a/hvplot/converter.py +++ b/hvplot/converter.py @@ -475,11 +475,13 @@ class HoloViewsConverter: fontsize : number or dict or None, default=None Set title, label and legend text to the same fontsize. Finer control by using a dict: ``{'title': '15pt', 'ylabel': '5px', 'ticks': 20}``. - grid : bool, str, or None, default=None + grid : bool, str, dict, or None, default=None Whether to show a grid. If True, shows grid on both axes. If ``'x'`` or ``'y'``, shows grid only on the specified axis. - Suffix with ``'dashed'``, ``'dotted'``, ``'dotdash'``, or ``'dashdot'`` + Suffix with ``'dashed'``, ``'dotted'``, or ``'dashdot'`` to change the grid line style, e.g. ``'x-dashed'``. + A dictionary of grid style options may also be supplied, e.g. for bokeh, + ``{'grid_line_color': 'red', 'grid_line_alpha': 0.5}``. Resampling Options ------------------ @@ -1066,11 +1068,23 @@ def __init__( gridstyle = {} axis = grid[0] other_axis = 'x' if axis == 'y' else 'y' - if len(grid) > 0: + if len(grid) > 1: line_dash = grid[1:].lstrip('-').lstrip('.').lstrip('_') - gridstyle[f'{axis}grid_line_dash'] = line_dash - gridstyle[f'{other_axis}grid_line_alpha'] = 0 + line_dash_key = ( + f'{axis}grid_line_dash' + if self._backend_compat == 'bokeh' + else f'{axis}grid_linestyle' + ) + gridstyle[line_dash_key] = line_dash + line_alpha_key = ( + f'{other_axis}grid_line_alpha' + if self._backend_compat == 'bokeh' + else f'{other_axis}grid_alpha' + ) + gridstyle[line_alpha_key] = 0 plot_opts['gridstyle'] = gridstyle + elif isinstance(grid, dict): + plot_opts['gridstyle'] = grid plot_opts['show_grid'] = bool(grid) if legend is not None: diff --git a/hvplot/tests/testoptions.py b/hvplot/tests/testoptions.py index 1c62f900a..9cc22110d 100644 --- a/hvplot/tests/testoptions.py +++ b/hvplot/tests/testoptions.py @@ -660,6 +660,13 @@ def test_grid_line_dash(self, df, backend, grid_str): assert opts.kwargs['grid'] is True assert opts.kwargs['gridstyle'] == {'ygrid_line_alpha': 0, 'xgrid_line_dash': 'dashed'} + def test_grid_line_dict(self, df, backend): + grid_dict = {'ygrid_line_alpha': 0, 'xgrid_line_dash': 'dashed'} + plot = df.hvplot('x', 'y', grid=grid_dict) + opts = Store.lookup_options(backend, plot, 'plot') + assert opts.kwargs['grid'] is True + assert opts.kwargs['gridstyle'] == grid_dict + @pytest.fixture(scope='module') def da():