How can I embed a Bokeh plot on a Next.js application with a Bokeh server by using add_document_from_session from BokehJS?

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?

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.