Bokeh is a nice visualization tool, enabling to create interactive .html
pages with data.
When making a website, you want the figures to be integrated in your page, not in a separeted one.
The post is divided in three parts:
.html
from BokehThis might be easy for you.
You should have included in your code:
from bokeh.plotting import output_file, show
[... my python code ...]
# p is your plot / figure
output_file(SAVE_PATH)
show(p)
output_file()
sets the path where the figure must be stored, and show()
creates the .html
and open the created file in your browser.
Here, nothing special.
To embed one Bokeh document, you need to store the .html
generated by Bokeh in the _includes/
repository.
So, if my document is named bokeh_toto.html
, it must be stored at _includes/bokeh_toto.html
.
To include it in a page of your website, you just need to write:
{% include bokeh_toto.html %}
in the markdown file.
Ok, it should work.
You may have the <!DOCTYPE html>
header printed that you can remove it (from the file bokeh_toto.html
).
Now, if you want to add a second bokeh document, it may not work.
There seems to be a conflict between div naming. I don’t know precisely the reason. I tried to change the IDs, sometimes it worked, sometimes it did not. It was confusing.
To include multiple document, we should not include the full .html
document, otherwise we may have conflict.
Instead, we must include only the <div>
and the <script>
which enable the stuff to run.
For Bokeh to run, there are two things:
<head>
partWe do not need them when we embedd a full document as these script are already present in the <head>
part.
Here, when we chose to include a specific Bokeh’s <div>
and <script>
, the script part is only for describing component interaction, the library is not in!!
Check the generated Bokeh .html
document and look at the header.
There might be some related scripts.
Please refer to your document (do not copy/paste the thing bellow), as the scripts needed depend on your Bokeh version.
You need to add this script in the .html
pages where you want to embed figures:
<head>
[... other scripts ...]
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.2.1.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.2.1.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.2.1.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.2.1.min.js"></script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-mathjax-3.2.1.min.js"></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
</head>
Replace 3.2.1
by your version number (NB: compatibility might be broken. Check if all your documents use the same version)
To avoid setting the header manually each time you use Bokeh with Jekyll, I suggest modifying your layout
with this:
In _layout/base.html
:
<head>
[... other scripts ...]
{% if page.bokeh == true %}
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-1.4.0.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-widgets-1.4.0.min.js"></script>
<script type="text/javascript" src="https://cdn.pydata.org/bokeh/release/bokeh-tables-1.4.0.min.js"></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
<script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-3.2.1.min.js"></script>
{% endif %}
</head>
And now, in your markdown page, in the yaml header set:
---
title: My title
bokeh: true
---
The liquid syntax:
{% if page.bokeh == true %}
enables loading only the script when necessary. If you have a good connection, it does not matter. However, when you have some limitation (or if you pay for each Mo downloaded), reducing the memory footprint is recommended.
If you are offline (in the train or in a plane for instance), or if you have a firewall installed, then Bokeh’s library scripts may be blocked and the figures would not load.
To prevent from this issue, save the bokeh
scripts locally in:
+ assets/
+ js/
- bokeh-3.2.1.min.js
- bokeh-gl-3.2.1.min.js
- bokeh-mathjax-3.2.1.min.js
- bokeh-tables-3.2.1.min.js
- bokeh-widgets-3.2.1.min.js
And in your _layout/base.html
, put:
<script src="/assets/js/bokeh-3.2.1.min.js"></script>
<script src="/assets/js/bokeh-gl-3.2.1.min.js"></script>
<script src="/assets/js/bokeh-mathjax-3.2.1.min.js"></script>
<script src="/assets/js/bokeh-tables-3.2.1.min.js"></script>
<script src="/assets/js/bokeh-widgets-3.2.1.min.js"></script>
<script type="text/javascript">
Bokeh.set_log_level("info");
</script>
If your website can load, then everything would load.
<div>
and <script>
When your website is ready to host Bokeh figures, we can generate the div
and script
parts.
Now that your page is ready to host Bokeh figures, we need to generate the corresponding <div>
and <script>
.
In your bokeh figure generator, you need to have these lines:
from bokeh.embed import components
[... my code ...]
# p is your plot / figure
script, div = components(p)
with open("tmp_div.txt", "w") as fp:
fp.write(div)
with open("tmp_script.txt", "w") as fp:
fp.write("<html>\n" + script + "</html>")
Here components()
will generate the minimal material needed.
You only need to save it in dedicated files.
For the <div>
, you must save it raw without changes.
For the <script>
, if you include it without any changes, all its content would be printed in your web page, and the <div>
would not show the Bokeh figure.
To prevent from this issue, adding <html>
before and </html>
after do the job (I am not an html expert. If you have a cleaner idea, please let me know).
Last, you need to store tmp_div.txt
and tmp_script.txt
in the _include/
folder.
Finally, invoke them with the include command:
{% include tmp_div.txt %}
{% include tmp_script.txt %}
Checklist:
components()
to get script and div_include/
folder{% include myfile.js %}
in your markdown pageAnd normally, everything should work.
>> You can subscribe to my mailing list here for a monthly update. <<