Bokeh is a visualization library for Python that makes it easy to plot data in Jupyter notebooks or web pages. Htmx allows you to develop dynamic, interactive web pages without complex JavaScript. The example below uses Htmx in a Flask app to display a Bokeh graph in a web page without updating the entire page.
The main Flask app is shown below. The Bokeh graph is created in Python then its HTML components are sent to the plot.html
template for display on the web page.
from flask import Flask
from flask import render_template
from flask import request
from bokeh.plotting import figure
from bokeh.embed import components
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/plot', methods=['POST'])
def plot():
# Get the form inputs
xdata = request.form['xdata']
ydata = request.form['ydata']
# Convert form input to a list of floats representing x and y values
x = list(map(float, xdata.split(', ')))
y = list(map(float, ydata.split(', ')))
# Create a Bokeh plot using the x and y values
p = figure(plot_width=400, plot_height=400)
p.circle(x, y, size=12, line_color='navy', fill_color='orange')
# Get HTML components to embed in a web page
script, div = components(p)
return render_template('plot.html', script=script, div=div)
The index.html
template is shown below. Notice how Htmx is used to post the form and target the #graph
div on page load as well as form submission. The Bokeh graph displays in the #graph
div.
<!-- templates/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.bokeh.org/bokeh/release/bokeh-2.4.2.min.js" crossorigin="anonymous"></script>
<title>Home Page</title>
<style type="text/css">
body { background-color: lightgray; }
input { max-width: 200px; }
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col">
<h1 class="mt-3">Submit data</h1>
<p>Input the x and y data points using comma separated values.</p>
<form hx-post="/plot" hx-target="#graph" hx-trigger="load, submit">
<div class="mb-3">
<label for="xdata" class="form-label">X data</label>
<input type="text" class="form-control" name="xdata" value="1, 2, 3, 4, 5, 4, 2">
</div>
<div class="mb-3">
<label for="ydata" class="form-label">Y data</label>
<input type="text" class="form-control" name="ydata" value="6, 7, 2, 4, 5, 3.2, 4">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
<div class="col">
<h1 class="mt-3">Plot data</h1>
<p>Below is a line plot using the X and Y data points.</p>
<div id="graph"></div>
</div>
</div>
</div>
<script src="https://unpkg.com/htmx.org@1.6.1" integrity="sha384-tvG/2mnCFmGQzYC1Oh3qxQ7CkQ9kMzYjWZSNtrRZygHPDDqottzEJsqS4oUVodhW" crossorigin="anonymous"></script>
</body>
</html>
The plot.html
template that displays the Bokeh components is given below.
<!-- templates/plot.html -->
{% raw %}{{ script | safe }}{% endraw %}
{% raw %}{{ div | safe }}{% endraw %}
Gavin Wiggins © 2024.
Made on a Mac with Genja. Hosted on GitHub Pages.