Bokeh theme

This is a follow up to this discussion.
Is there, or perhaps should there be, a proper way to apply a bokeh theme to a plot in a pane? For the sake of clarity, I am working in a jupyterlab notebook.

I can get bokeh to show a themed object as follows:

from bokeh.io import curdoc, output_notebook, show
from bokeh.plotting import figure
from bokeh.themes import built_in_themes

output_notebook()

theme = built_in_themes["dark_minimal"]
doc = curdoc()
doc.theme = theme

fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
counts = [5, 3, 4, 2, 4, 6]

p = figure(x_range=fruits, plot_height=250, title="Fruit counts",
           toolbar_location=None, tools="", align="center")

p.vbar(x=fruits, top=counts, width=0.9)

p.xgrid.grid_line_color = None
p.y_range.start = 0

show(p)

Similarly for holoviews:

import holoviews as hv
from holoviews import opts

hv.extension("bokeh")
hv.renderer('bokeh').theme = theme

plot = hv.Bars((fruits, counts))
plot

But panel does not respect the bokeh theme:

import panel as pn

pn.extension()

pn.pane.Bokeh(p)

I also tried this unsuccessfully:

theme.apply_to_model(p)

pn.pane.Bokeh(p)

Although, the previously set holoviews theme is respected by panel:

pn.pane.HoloViews(plot)

A work around was provided in the same discussion mentioned above:

pn.viewable._Document.theme = theme

pn.pane.Bokeh(p)

However, to quote the concerns mentioned in the discussion:

It works, but is ugly and involves accessing “private” attribute and making module-wide change

Digging around, I also noticed that pn.io.save.file_html accepts a theme. And as a quick side note, while this renders fine:

from IPython.display import display, HTML
from bokeh.resources import CDN

html = pn.io.save.file_html(p, resources=CDN, theme=theme)
HTML(html)

It does not render well with panel unless the height is manually specified:

pn.pane.HTML(html)

In my imagination allowing pn.pane.Bokeh to accept a theme parameter would make sense.

In short, is there a better way to apply a bokeh theme to a bokeh object in a panel bokeh pane?


Update while still typing this post… I tried this, and it worked:

import param
from bokeh.themes import Theme
from panel.pane.plot import Bokeh

class ThemedBokeh(Bokeh):
    theme = param.ClassSelector(default=None, class_=(Theme, str),
                                allow_None=True, doc="""
        Bokeh theme to apply to the plot.""")

    def _get_model(self, doc, root=None, parent=None, comm=None):
        model = super()._get_model(doc, root=root, parent=parent, comm=comm)
        if self.theme:
            model._document.theme = self.theme
        return model

Then simply:

ThemedBokeh(p, theme=theme)

I think that really is a testament to how well structured this stack of technology is.
I don’t know if there are negative repercussions or potential side effects to this approach. If this is an appropriate approach, I’d be happy to submit a PR that either adds the theme parameter to the Bokeh pane class, or implements a ThemedBokeh class.

Any suggestions or feedback would be appreciated.

A PR for adding a theme parameter to the Bokeh pane has been merged into the master branch https://github.com/holoviz/panel/pull/2164

And PR to add this to the Reference Guide is on its way. Bokeh theme reference by brl0 · Pull Request #2166 · holoviz/panel (github.com)