Hello,
I have been happily using the very nice inline Bokeh extension mechanism, but I have gotten to the point where I want to have two classes derived from ColumnDataSource share a common third class derived from DataSource. So I’ve embarked on the path set out in pre-built extensions. I haven’t gotten there yet, but I am beginning to wonder if prebuilt extensions are only useful if the Bokeh server is used? If they can be used with just web-browser plotting, what hook is used to load the pre-built extension so that it can be referenced from the Python classes? In other words, once I have the extension, how do I use it?
Does anyone know if this is the case? In my case, the Bokeh Python functions are called from the user’s python session, so no Bokeh server is available.
Thanks for your help @Bryan Below is the solution I came up with (some time ago!). It seems to work well but does introduce some dependencies on BokehJS internals. The idea is that a call like:
initialize_bokeh( )
or if using the local development build of the library, like:
It would be nice if something similar (but generic) could be provided as part of the standard API.
version = "0.0.3"
...
@static_vars(initialized=False)
def initialize_bokeh( libs=None, dev=0 ):
"""Initialize `bokeh` for use with the ``mylibraryjs`` extensions.
The ``mylibraryjs`` extensions for Bokeh are built into a stand-alone
external JavaScript file constructed for the specific version of
Bokeh that is being used. The URL or the local path to a locally
built verion must be supplied as the ``libs`` parameter. If ``libs``
is ``None`` then the default is to use the published verison of
``mylibraryjs`` extensions built and installed for `HTTP` access.
Parameters
----------
libs: None or str or list of str
javascript library to load could be a local path, a URL or None.
None is the default in which case it loads the published library
for the current version of ``mylibraryjs`` and ``bokeh``
dev: int, optional
Chrome caches the javascript files. This parameter allows for
specifying `dev` allows for including a development version
for incremental updates to JavaScript from website.
"""
if initialize_bokeh.initialized:
### only initialize once...
return
library_hashes = {
### --------------------------------------------------------------------------------------------------
### Generate hashes with:
### echo `cat mylibraryjs-v0.0.2.0-b2.3.js | openssl dgst -sha384 -binary | openssl base64 -A`
### --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
### NOTE: with the conversion from Bokeh 2.3.3 to 2.4.1, it seems that the security hashes are no
### longer included in the generated HTML.
### --------------------------------------------------------------------------------------------------
'mylibraryjs-v0.0.2.0-b2.3.js': 'EtB9H3ooIK3inPGx9RsRXeUv/COHtArEjhZUr7P75GBUPl+lAoGH/tqoAc1sV5jD',
'mylibraryjs-v0.0.2.0-b2.3.min.js': 'jAFFXRC9B93jSanS1dmqo+l/3rkcBqM48uTMN+SFcY7GPC/IPeEoI+p+Za5ztkcm',
'mylibraryjs-v0.0.3.0-b2.4.min.js': '23DOS7ISXIG8BRyIsD7vINUllDbo8NDCozIGBy7jGC+M14Z+axfF7j4bruA2ZnzL',
'mylibraryjs-v0.0.3.0-b2.4.js': 'OmIWKy37YXZf973kemdoFd2L/h0I9AY/hsP5PMdk5/g5xlgj16yk6b0cgO01UMxM'
}
mylib = None
mylibraryjs_libs = None
mylibraryjs_url = None
if libs is None:
mylib = "mylibraryjs-v%s.%d-b%s.min.js" % (version,dev,'.'.join(bokeh_version.split('.')[0:2]))
mylibraryjs_url = "https://example.com/download/javascript/mylibraryjs/%s/%s" % (version,mylib)
mylibraryjs_libs = [ mylibraryjs_url ]
else:
mylibraryjs_libs = [ libs ] if type(libs) == str else libs
mylibraryjs_libs = list(map( path_to_url, mylibraryjs_libs ))
from bokeh import resources
resources.JSResources._old_hashes = resources.JSResources.hashes
def hashes( self ):
result = self._old_hashes
if mylib is not None and mylib in library_hashes:
result[mylibraryjs_url] = library_hashes[mylib]
return result
resources.JSResources._old_js_files = resources.JSResources.js_files
def js_files( self ):
result = self._old_js_files
result = result + mylibraryjs_libs
return result
resources.JSResources.hashes = property(hashes)
resources.JSResources.js_files = property(js_files)
initialize_bokeh.initialized = True