Interactive plots and applications in the browser from Python
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Functions for embedding Bokeh plots in web pages, generating standalone HTML, and integrating with web frameworks and content management systems. These functions enable seamless integration of Bokeh visualizations into existing web applications and workflows.
Functions for generating HTML and JavaScript components that can be embedded in web pages.
def components(plot_objects, wrap_script=True, wrap_plot_info=True):
"""
Generate HTML components for embedding plots.
Returns separate script and div elements that can be embedded
in existing HTML pages. This is the most flexible embedding method.
Parameters:
- plot_objects: Single plot/layout or sequence of plot objects
- wrap_script: Whether to wrap JavaScript in <script> tags
- wrap_plot_info: Whether to wrap plot info in JSON
Returns:
Tuple[str, Union[str, List[str]]]: (script, div_elements)
- script: JavaScript code to render the plots
- div_elements: HTML div element(s) as placeholder(s)
For single plot: returns (script, div_string)
For multiple plots: returns (script, [div1, div2, ...])
"""
def file_html(models, resources, title=None, template=None, template_variables=None):
"""
Generate complete standalone HTML file content.
Creates a full HTML document containing plots with all necessary
resources. Ideal for saving self-contained HTML files.
Parameters:
- models: Plot objects or layouts to include
- resources: Resources object specifying how to include BokehJS
- title: HTML document title
- template: Custom Jinja2 template (optional)
- template_variables: Variables for template rendering
Returns:
str: Complete HTML document as string
"""Functions for generating JSON representations of plots for custom embedding scenarios.
def json_item(model, target=None):
"""
Generate JSON representation for embedding.
Creates a JSON object containing all plot data and configuration
that can be rendered by BokehJS. Useful for AJAX-based applications
and custom integration scenarios.
Parameters:
- model: Plot object or layout to serialize
- target: Target element ID for rendering (optional)
Returns:
str: JSON string containing plot specification
The JSON can be used with bokehjs.embed.embed_item() in JavaScript.
"""Functions for dynamic plot loading and autoloading scenarios.
def autoload_static(model, resources, script_path):
"""
Generate script for static autoloading.
Creates JavaScript that can be included via <script> tag to
automatically load and render a plot. The plot data is embedded
in the script itself.
Parameters:
- model: Plot object or layout to embed
- resources: Resources object for BokehJS inclusion
- script_path: Path where the script will be served
Returns:
str: JavaScript code for autoloading the plot
Usage: Save returned script to a .js file and include via:
<script src="path/to/generated/script.js"></script>
"""
def autoload_server(model, app_path, server_id=None,
server_url="http://localhost:5006", **kwargs):
"""
Generate script for server-based autoloading.
Creates JavaScript that loads plots from a running Bokeh server.
Enables embedding of server applications in external websites.
Parameters:
- model: Plot object or layout (unused, kept for compatibility)
- app_path: Path to server application
- server_id: Server session ID (optional)
- server_url: URL of Bokeh server
Returns:
str: JavaScript code for loading from server
"""Functions for embedding server-based applications.
def server_document(url, relative_urls=False, resources=None, **kwargs):
"""
Embed server document in existing page.
Generates HTML/JavaScript to embed a live server application
document in an existing webpage with bidirectional communication.
Parameters:
- url: URL to server application
- relative_urls: Whether to use relative URLs
- resources: Resources object (optional)
Returns:
str: HTML/JavaScript for embedding server document
"""
def server_session(model_or_server_id, session_id=None, url=None):
"""
Embed specific server session.
Embeds a specific server session, allowing multiple sessions
of the same application to be embedded independently.
Parameters:
- model_or_server_id: Model object or server session ID
- session_id: Specific session ID to embed
- url: Server URL
Returns:
str: HTML/JavaScript for embedding server session
"""Classes for controlling how BokehJS resources are included in embedded content.
class Resources:
"""
Controls how BokehJS resources are included.
Manages the inclusion of BokehJS JavaScript and CSS files
in generated HTML. Supports various deployment scenarios.
"""
def __init__(self, mode='inline', version=None, root_dir=None,
minified=True, log_level='info', root_url=None,
path_versioner=None):
"""
Parameters:
- mode: Resource inclusion mode
'inline' - Include resources directly in HTML
'cdn' - Link to CDN-hosted resources
'server' - Link to local server resources
'server-dev' - Link to development server resources
- version: Specific Bokeh version for CDN mode
- root_dir: Root directory for relative paths
- minified: Use minified JavaScript files
- log_level: JavaScript logging level ('trace', 'debug', 'info', 'warn', 'error', 'fatal')
- root_url: Base URL for server mode
- path_versioner: Function to add version info to paths
"""
mode: str
version: Optional[str]
minified: bool
# Resource URL generation
def js_files(self):
"""Get list of JavaScript file URLs."""
def css_files(self):
"""Get list of CSS file URLs."""
def js_raw(self):
"""Get raw JavaScript content (inline mode only)."""
def css_raw(self):
"""Get raw CSS content (inline mode only)."""
# Pre-configured resource instances
CDN: Resources # CDN-hosted resources (default)
INLINE: Resources # Inline resources (self-contained)Class for advanced embedding scenarios with custom rendering containers.
class RenderRoot:
"""
Root rendering container for embedding.
Provides fine-grained control over how plots are rendered
and embedded in custom containers.
"""
def __init__(self, elementid, child):
"""
Parameters:
- elementid: HTML element ID for rendering target
- child: Plot object or layout to render
"""
elementid: str
child: Modelfrom bokeh.plotting import figure
from bokeh.embed import components
from bokeh.resources import CDN
import numpy as np
# Create plot
p = figure(width=400, height=400, title="Embedded Plot")
x = np.linspace(0, 4*np.pi, 100)
p.line(x, np.sin(x), line_width=2)
# Generate components
script, div = components(p)
# Create HTML page
html_template = f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My Dashboard</title>
{CDN.render_css()}
{CDN.render_js()}
</head>
<body>
<h1>My Custom Dashboard</h1>
<div class="plot-container">
{div}
</div>
<p>This plot is embedded in custom HTML.</p>
{script}
</body>
</html>
"""
# Save HTML file
with open("embedded_plot.html", "w") as f:
f.write(html_template)from bokeh.plotting import figure
from bokeh.embed import components
from bokeh.resources import CDN
import numpy as np
# Create multiple plots
plots = []
functions = [np.sin, np.cos, np.tan]
colors = ['blue', 'red', 'green']
for i, (func, color) in enumerate(zip(functions, colors)):
p = figure(width=300, height=300, title=f"Plot {i+1}")
x = np.linspace(0, 4*np.pi, 100)
y = func(x)
if func == np.tan:
y = np.clip(y, -5, 5) # Limit tan values
p.line(x, y, color=color, line_width=2)
plots.append(p)
# Generate components for all plots
script, divs = components(plots)
# Create HTML with multiple plots
html = f"""
<!DOCTYPE html>
<html>
<head>
<title>Multiple Plots</title>
{CDN.render_css()}
{CDN.render_js()}
<style>
.plot-grid {{
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 20px;
padding: 20px;
}}
</style>
</head>
<body>
<h1>Function Comparison</h1>
<div class="plot-grid">
{divs[0]}
{divs[1]}
{divs[2]}
</div>
{script}
</body>
</html>
"""
with open("multiple_plots.html", "w") as f:
f.write(html)from bokeh.plotting import figure
from bokeh.embed import json_item
import json
import numpy as np
# Create plot
p = figure(width=500, height=400, title="AJAX Plot")
x = np.random.random(100)
y = np.random.random(100)
p.circle(x, y, size=10, alpha=0.6)
# Generate JSON
plot_json = json_item(p, "myplot")
# JavaScript for AJAX loading
js_code = f"""
// JavaScript code for embedding via AJAX
fetch('/api/plot-data')
.then(response => response.json())
.then(item => {{
Bokeh.embed.embed_item(item);
}});
// Or directly embed the JSON item:
const plotItem = {plot_json};
Bokeh.embed.embed_item(plotItem);
"""
# HTML template for AJAX embedding
html = """
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-3.0.0.min.js"></script>
</head>
<body>
<div id="myplot"></div>
<script>
// Plot will be loaded here via AJAX
</script>
</body>
</html>
"""from flask import Flask, render_template, jsonify
from bokeh.plotting import figure
from bokeh.embed import components, json_item
from bokeh.resources import CDN
import numpy as np
app = Flask(__name__)
def create_plot():
"""Create a sample plot."""
p = figure(width=500, height=400)
x = np.random.random(50)
y = np.random.random(50)
p.circle(x, y, size=12, alpha=0.6)
return p
@app.route('/')
def index():
"""Main page with embedded plot."""
plot = create_plot()
script, div = components(plot)
return render_template('index.html',
script=script,
div=div,
css_resources=CDN.render_css(),
js_resources=CDN.render_js())
@app.route('/api/plot')
def plot_api():
"""API endpoint returning plot as JSON."""
plot = create_plot()
return jsonify(json_item(plot, "api-plot"))
# templates/index.html:
"""
<!DOCTYPE html>
<html>
<head>
<title>Flask + Bokeh</title>
{{ css_resources|safe }}
{{ js_resources|safe }}
</head>
<body>
<h1>My Flask Dashboard</h1>
{{ div|safe }}
{{ script|safe }}
<!-- AJAX plot container -->
<div id="api-plot"></div>
<button onclick="loadPlot()">Load Plot via API</button>
<script>
function loadPlot() {
fetch('/api/plot')
.then(response => response.json())
.then(item => {
Bokeh.embed.embed_item(item);
});
}
</script>
</body>
</html>
"""
if __name__ == '__main__':
app.run(debug=True)# views.py
from django.shortcuts import render
from django.http import JsonResponse
from bokeh.plotting import figure
from bokeh.embed import components, json_item
from bokeh.resources import CDN
import numpy as np
def dashboard(request):
"""Django view with embedded Bokeh plot."""
# Create plot
p = figure(width=600, height=400, title="Django Dashboard")
x = np.linspace(0, 4*np.pi, 100)
p.line(x, np.sin(x), line_width=2, color='blue')
p.line(x, np.cos(x), line_width=2, color='red')
# Generate components
script, div = components(p)
context = {
'script': script,
'div': div,
'bokeh_css': CDN.render_css(),
'bokeh_js': CDN.render_js(),
}
return render(request, 'dashboard.html', context)
def plot_data(request):
"""API endpoint for dynamic plot data."""
# Generate new plot data
p = figure(width=400, height=300)
x = np.random.random(30)
y = np.random.random(30)
p.scatter(x, y, size=15, alpha=0.7)
return JsonResponse(json_item(p, "dynamic-plot"))
# templates/dashboard.html:
"""
<!DOCTYPE html>
<html>
<head>
<title>Django + Bokeh Dashboard</title>
{{ bokeh_css|safe }}
{{ bokeh_js|safe }}
</head>
<body>
<h1>Analytics Dashboard</h1>
<div class="main-plot">
{{ div|safe }}
</div>
<div id="dynamic-plot"></div>
<button onclick="updatePlot()">Update Data</button>
{{ script|safe }}
<script>
function updatePlot() {
fetch('{% url "plot_data" %}')
.then(response => response.json())
.then(item => {
Bokeh.embed.embed_item(item);
});
}
</script>
</body>
</html>
"""# server_embed.py - Bokeh server application
from bokeh.plotting import figure, curdoc
from bokeh.models import ColumnDataSource, Button, Column
import numpy as np
# Create interactive server application
source = ColumnDataSource(data=dict(x=[], y=[]))
p = figure(width=500, height=400, title="Server Application")
line = p.line('x', 'y', source=source, line_width=2)
button = Button(label="Update", button_type="success")
def update():
x = np.linspace(0, 4*np.pi, 100)
y = np.sin(x + np.random.random() * 2*np.pi)
source.data = dict(x=x, y=y)
button.on_click(update)
update() # Initial data
layout = Column(button, p)
curdoc().add_root(layout)
# External HTML page embedding the server app:
"""
<!DOCTYPE html>
<html>
<head>
<title>Embedded Server App</title>
</head>
<body>
<h1>My Website</h1>
<p>This is my regular website content.</p>
<!-- Embedded Bokeh server application -->
<div class="bokeh-app">
<script src="http://localhost:5006/server_embed/autoload.js" id="bokeh-server-app"></script>
</div>
<p>More website content below the app.</p>
</body>
</html>
"""
# Start server: bokeh serve server_embed.py --allow-websocket-origin=*from bokeh.plotting import figure
from bokeh.embed import file_html
from bokeh.resources import INLINE
from bokeh.layouts import column, row
import numpy as np
# Create multiple plots
p1 = figure(width=400, height=300, title="Sin Wave")
x = np.linspace(0, 4*np.pi, 100)
p1.line(x, np.sin(x), line_width=2)
p2 = figure(width=400, height=300, title="Scatter Plot")
x_scatter = np.random.random(50)
y_scatter = np.random.random(50)
p2.circle(x_scatter, y_scatter, size=10, alpha=0.6, color='red')
# Create layout
layout = column(
row(p1, p2),
sizing_mode='stretch_width'
)
# Generate complete HTML with inline resources
html = file_html(layout, INLINE, title="Standalone Dashboard")
# Save self-contained HTML file
with open("standalone_dashboard.html", "w") as f:
f.write(html)
print("Generated standalone HTML file with all resources embedded")