I have a Bokeh Server written on Python which also runs a Flask instance for testing. This server provides a plot that I want to embed on a Next.js application in order to correctly enforce the Bokeh Server architecture.
However, I am falling short.
Having used a Bokeh Server, I managed to embed it on the Flask instance (since the architecture is provided in the example), but I cannot understand how to utilize the functions provided in the BokehJS library to embed the returns.
The code for the server is similar as shown below. As per minimal example, I shall represent the code for the Flask Embed example.
from threading import Thread
from flask import Flask, render_template
from tornado.ioloop import IOLoop
from bokeh.embed import server_document
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
from bokeh.sampledata.sea_surface_temperature import sea_surface_temperature
from bokeh.server.server import Server
from bokeh.themes import Theme
app = Flask(__name__)
def bkapp(doc):
df = sea_surface_temperature.copy()
source = ColumnDataSource(data=df)
plot = figure(x_axis_type='datetime', y_range=(0, 25), y_axis_label='Temperature (Celsius)',
title="Sea Surface Temperature at 43.18, -70.43")
plot.line('time', 'temperature', source=source)
def callback(attr, old, new):
if new == 0:
data = df
else:
data = df.rolling(f"{new}D").mean()
source.data = ColumnDataSource.from_df(data)
slider = Slider(start=0, end=30, value=0, step=1, title="Smoothing by N Days")
slider.on_change('value', callback)
doc.add_root(column(slider, plot))
doc.theme = Theme(filename="theme.yaml")
@app.route('/', methods=['GET'])
def bkapp_page():
script = server_document('http://localhost:5006/bkapp')
return render_template("embed.html", script=script, template="Flask")
def bk_worker():
# Can't pass num_procs > 1 in this configuration. If you need to run multiple
# processes, see e.g. flask_gunicorn_embed.py
server = Server({'/bkapp': bkapp}, io_loop=IOLoop(), allow_websocket_origin=["localhost:8000"])
server.start()
server.io_loop.start()
Thread(target=bk_worker).start()
if __name__ == '__main__':
print('Opening single process Flask app with embedded Bokeh application on http://localhost:8000/')
print()
print('Multiple connections may block the Bokeh app in this configuration!')
print('See "flask_gunicorn_embed.py" for one way to run multi-process')
app.run(port=8000)
Afterwards, I have a Next.js component that shall be used as a way to embed the plot served by the Bokeh server (running on port 5006). I have found the function add_document_from_session inside the modules provided with BokehJS, but I can’t figure out a way to properly use it as I could not find accurate documentation for it (and for the fact that I am a JavaScript rookie).
Component code shown below (using Tailwind CSS).
"use client"
import React, { useEffect } from "react";
import * as Bokeh from '@bokeh/bokehjs';
export default function BokehPy(){
useEffect(() =>{
});
return(
<>
<div className="flex flex-col">
<h2 className="prose lg:prose-xl"> Plot goes here</h2>
<div id="graph"></div>
</div>
<button
className="bg-white hover:bg-gray-100 text-gray-800 font-semibold
py-2 px-4 border border-gray-400 rounded shadow">
Editar
</button>
</>
);
}
UseEffect is blank because I expect to be using it in the solution. How would I go about embedding the plot correctly? Making a GET request to the server returns an HTML document with the plot. I assume the add_document_from_session function is necessary, but I do not know how I would use it in this scenario.
I have tried making it work through workarounds (such as making the server return the script tag through server_document) but I also do not know enough JavaScript or BokehJS to make them work.
The StackOverflow question is linked here.
I should also add that I took a look at this previous discussion and came across a link which no longer exists and an open issue. So how would I go about this?