I am in the process of upgrading an application from Bokeh 0.12 (!) to 2.2.3.
I have defined a custom widget, which compiles correctly. On the backend, I generate a Bokeh document and export it in two parts: as JSON (using bokeh_embed.json_item) and JavaScript (for our custom models, using bundle_models). On the frontend, I then do the following:
Looking at the Panel source code, it looks like they use:
import * as Panel from "./models"
export {Panel}
import {register_models} from "@bokehjs/base"
register_models(Panel as any)
I don’t have my models defined externally, although that is a route I can investigate. It would be useful to be able to register models written in Python in __implementation__ clauses, though.
@bokeh/bokehjs is a non-module JS bundle (it has no exports), so Bokeh will be {} (give or take; assuming webpack is being used to package things, there may be some webpack’s cruft there). However, window.Bokeh (well, global Bokeh) should be set up properly nevertheless. So, this:
If bokeh generated modelJS and you are issuing Bokeh.embed.embed_item(), then you are doing the work twice, because bokeh’s generated JS boils down to calling embed_item().
I don’t see how to skip one of the above and how to only apply the other. If I try not to call modelJS, then it complains that my custom model (CheckboxWithLegendGroup) has not been registered.
Essentially you’re replacing a <script> tag with an import, but the rest of the code is the same in both cases. Not ideal, but I don’t think we can get anything better right now (at least not without improving bokeh and/or bokehjs).
Actually that’s not going to work because we define the scope of a model bundle as this, which will be bound to local module scope in this case, instead of the global scope. Try this instead:
For completeness, what I see on the import * as Bokeh from "@bokeh/bokehjs"; statement is everything from index.js:
export { version } from "./version";
export { index } from "./embed";
export * as embed from "./embed";
export * as protocol from "./protocol";
export * as _testing from "./testing";
export { logger, set_log_level } from "./core/logging";
export { settings } from "./core/settings";
export { Models } from "./base";
export { documents } from "./document";
export { safely } from "./safely";
Moved custom models into a separate file, BokehModels.js. Since I am not using TypeScript, I had to translate my custom model from TypeScript to JavaScript.
Inside my JavaScript plotting component, I do:
import * as Bokeh from "@bokeh/bokehjs";
import * as Models from "./BokehModels"; // my custom models
// `plotData` is shipped to the frontend by my Python backend
// which generates it with `bokeh_embed.json_item(layout)`
const { bokehJSON } = plotData;
Bokeh.Models.register_models(Models);
window.Bokeh = Bokeh;
Bokeh.embed.embed_item(bokehJSON, `bokeh-${bokehJSON.root_id}`);