Using BokehJS in an Angular app

Hello everyone,

I am trying to use BokehJS inside an angular app, and I am failing miserably. Please note that I am not familiar at all with Angular and front-end technologies in general, so I’m probably in way over my head. Any help would be greatly appreciated.

I have written a Python script that generates a JSON plot with bokeh.embed.json_item. I am now attempting to use BokehJS to display the plot where I want it to appear in the angular app.

To do so I have installed this node package.
Then I have added the following line to the .ts file of my Angular component :

import embed from "@bokeh/bokehjs";

But this prevents the application from compiling, with the following errors :

ERROR in node_modules/@bokeh/bokehjs/build/js/types/core/properties.d.ts(2,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/core/properties.d.ts(2,31): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/core/view.d.ts(1,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/core/view.d.ts(1,31): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(3,10): error TS1005: 'from' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(3,13): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(3,19): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(3,24): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(4,10): error TS1005: 'from' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(4,13): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(4,22): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(4,27): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(5,10): error TS1005: 'from' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(5,13): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(5,22): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/index.d.ts(5,27): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/ranges/data_range1d.d.ts(6,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/ranges/data_range1d.d.ts(6,27): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/button_tool.d.ts(6,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/button_tool.d.ts(6,38): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(10,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(10,30): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(11,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(11,35): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(12,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(12,36): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(13,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(13,33): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(14,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(14,34): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(15,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(15,30): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(16,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(16,36): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(17,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(17,36): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(18,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(18,37): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(19,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(19,38): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(20,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(20,34): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(21,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(21,32): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(22,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(22,31): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(23,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(23,31): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(24,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(24,31): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(25,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(25,32): error TS1005: ';' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(26,13): error TS1005: '=' expected.
node_modules/@bokeh/bokehjs/build/js/types/models/tools/tool.d.ts(26,31): error TS1005: ';' expected.

Could you please give me a few pointers to help me understand where I took a wrong turn ?

No idea ? If I can provide extra information, please tell me.
I have updated nodejs and npm to latest versions, but it did not help.

Thanks in advance

@JYannick

I suspect that the radio silence is that you’re working on a less common integration problem than the typical user.

I don’t personally have any experience with Angular so I cannot help with the topic directly, but in the interest of starting the discussion, I’ll ask whether Angular is a requirement for your specific application or it chosen because it seemed like a reasonable starting point.

If Angular is not a requirement, there are a number of examples embedding Bokeh in other servers like Flask, for example. https://github.com/bokeh/bokeh/tree/2.0.2/examples/

1 Like

Thank you @_jm !

I understand that my problem is very specific, and that most users here use Bokeh directly from Python. This is also usually my case, I have a more pythonic background so I was hoping some users of BokehJS might help me understand the issue when importing the library.

Unfortunately Angular is a requirement here. I am attempting to embed Bokeh plots into an existing Angular application, that is far too big to be rewritten using another technology. After some research I could not find anything as powerful as Bokeh in the JavaScript ecosystem, and since Bokeh provided many embedding features I decided to attempt an integration. Unfortunately, it seems more complicated than it looked like at first glance.

I think I have a solution ! Well, I have another problem afterwards, but at least now I can import BokehJS into my angular app.

Turns out my application was using an old version of Angular. I created a new prototype from scratch, using the latest version Angular 10, and this prototype can import Bokeh just fine with the following statement in a .ts component file : import * as Bokeh from "@bokeh/bokehjs"

However, when I’m attempting to actually make use of the library, I encounter the following issue :

My code snippet :

var item = JSON.parse('[...a JSON string exported from python via bokeh.embed.json_item()...]');
    Bokeh.embed.embed_item(item, "bokeh-plot");

And the error message:

Failed to compile.

./node_modules/@bokeh/bokehjs/build/js/lib/index.js 3:9
Module parse failed: Unexpected token (3:9)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| export { version } from "./version";
| export { index } from "./embed";
> export * as embed from "./embed";
| export * as protocol from "./protocol";
| export * as _testing from "./testing";

I have found a reference to this issue here (the first method described in the opening post). However I do not understand the proposed solution, and how to implement it with Angular. It seems that Babel is not an issue with Angular, according to this: angular5 - Is Babel being used as compiler (AOT or JIT) in angular 5 - Stack Overflow

I see that @mateusz was very helpful in this other topic: if you could give me a few pointers regarding this issue with angular, it would help me tremendously.

If it can help, here is a complete procedure to reproduce my issue from scratch:

  • install nodejs : Node.js
  • install angular-cli : npm install -g @angular/cli
  • initialize a new angular project in the current directory : ng new angular10BokehJSexample
  • enter the new project directory : cd angular10BokehJSexample
  • (optional) check that the example angular app works : npm start and open your browser on URL http://localhost:4200
  • install BokehJS : npm install @bokeh/bokehjs
  • open your favorite text editor and change the file src/app/app.module.ts. Add the following line with the other imports at the top : import * as Bokeh from '@bokeh/bokehjs'
  • if you start the server at this stage, it should still work fine, meaning that BokehJS can be imported successfully (that was not the case with an old version of Angular)
  • still in the file src/app/app.module.ts, change the class decalaration at the end of the file to make it look like this :
export class AppModule {

  private testBokeh(){
    var item = JSON.parse("just a test");
    Bokeh.embed.embed_item(item);
  }

}

(note: this is just a stub, the code does not work. I’ve put together a more complex code that is supposed to work, but this is sufficient to reproduce my issue)

  • run npm start again, it cannot compile :
ERROR in ./node_modules/@bokeh/bokehjs/build/js/lib/index.js 3:9
Module parse failed: Unexpected token (3:9)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| export { version } from "./version";
| export { index } from "./embed";
> export * as embed from "./embed";
| export * as protocol from "./protocol";
| export * as _testing from "./testing";

Okay, I did not give up, and finally got this to work. If anyone else is interested, here is what I did. The main trick was to import just the required file from the build subdirectory.

In the Python script

import json
from bokeh.embed import json_item
from bokeh.plotting import figure, output_file

p = figure()
p.circle([1], [1])
with(open("simple_plot.json", 'w')) as f:
    f.write(json.dumps(json_item(p)))
print("done")

In my angular component

In the TypeScript file :

import * as Bokeh from '@bokeh/bokehjs/build/js/lib/embed';

...

let bokehJson = ....retrieve the JSON file content generated by Python...
Bokeh.embed_item(JSON.parse(bokehJson), "bokeh-div-id");

In the HTML template file:

<div id="bokeh-div-id"></div>

This should be sufficient for most uses. However I wanted to use a more complex Bokeh plot with widgets and tables: those must be imported manually, and only once to prevent multiple declarations warnings. So:

In the angular application file main.ts

import * as Widgets from '@bokeh/bokehjs/build/js/lib/models/widgets/index';
import * as Tables from '@bokeh/bokehjs/build/js/lib/models/widgets/tables/index';
import { register_models } from "@bokeh/bokehjs/build/js/lib/base";

...

    register_models(Widgets);
    register_models(Tables);

And with this, you should be good to go !

1 Like

@JYannick I am looking for a similar solution you have provided above. Any chance you have the code on GitHub?

Hello @Chetan_Ambi

No, sorry. I did this for a closed source corporate project, I cannot post the code publicly.

I understand. Thank you!