Share experience: bokeh is embedded in HTML server and supports Ajax requests the server_document

1、【Requirement】: front and back end separation
2、【Unresolved issues】:Websocket will be created every time HTML request
3、【Tank】:Thank @Bryan, a member of the bokeh team, for the whole process
Support given

python code

from os.path import join
from pathlib import Path
from typing import Any
import bokeh.plotting as bp
from bokeh.embed import server_document, server_session
from bokeh.layouts import column
from bokeh.models import HoverTool, CustomJS, ColumnDataSource, Button, TextInput
from bokeh.themes import Theme
from bokeh.document import Document
from django.http import HttpRequest, HttpResponse, request
import datashader as ds
import pandas as pd
import numpy as np
import datashader.transfer_functions as tf
from django.shortcuts import render
from datashader.bokeh_ext import InteractiveImage
from utils import matUtil, jsonUtil
from web.CustomModelBackends import token_required_url, token_required
from ykkj_ai import settings

def with_request(f):
    def wrapper(doc):
        return f(doc, doc.session_context.request)
    return wrapper

def signal_chart_handler(doc: Document,reqeust: Any) -> None:
    # Search signal storage file by request parameter
    args = doc.session_context.request.arguments
    theme = Theme(filename=join(settings.THEMES_DIR, "theme.yaml"))
    data = matUtil.loadmat(Path(join(settings.BASE_DIR, "featrue_bokeh", args.get("wriId") + ".mat")))["data"]
    # 悬停工具
    hover = HoverTool(
            ("(x值,y值)", "($x, $y)"),
    # Process and package signal data
    p = bp.figure(x_axis_type="datetime", x_range=(0, 5), title=args.get("wriId")+"信号数据",
                  tools=[hover, 'wheel_zoom', 'box_zoom', 'save', 'reset'],
                  y_range=(np.min(data), np.max(data)))
    dists = {cat: pd.DataFrame(dict(x=np.arange(0, len(data), 1) / float(44100),
                                    val=val, cat=cat))
             for x, y, s, val, cat in
             [(2, 2, 0.01, 10, "d1")]}
    df = pd.concat(dists, ignore_index=True)
    df["cat"] = df["cat"].astype("category")
    source = ColumnDataSource(data=dict(image=[], x=[],
                                        y=[], dw=[], dh=[]))
    def update(attr,old,new):
        width, height = p.plot_width, p.plot_height
        xmin, xmax = p.x_range.start, p.x_range.end
        ymin, ymax = p.y_range.start, p.y_range.end
        x_range = (xmin, xmax)
        y_range = (ymin, ymax)
        dw, dh = xmax - xmin, ymax - ymin
        cvs = ds.Canvas(plot_width=width, plot_height=height, x_range=x_range, y_range=y_range)
        agg = cvs.line(df, 'x', 'y')  # , ds.count())
        img_agg = tf.shade(agg, min_alpha=255)
        image = tf.dynspread(img_agg, threshold=0.25, max_px=1)[], x=[xmin],
                                            y=[ymin], dw=[dw], dh=[dh])
    p.image_rgba(source=source, image='image', x='x', y='y',
                 dw='dw', dh='dh', dilate=False)
    # 处理各种回调
    p.y_range.on_change('end', update)
    # 准备推送到客户端
    doc.theme = theme
    doc.title = args.get("wriId")+"信号数据"
    doc.add_root(column(p, sizing_mode='stretch_both'))

#Request parameter wriId: primary key when collecting signals
def signal_chart_main(request: HttpRequest) -> HttpResponse:
    script = server_document(
        url=request.build_absolute_uri("/bokeh_apps/signal_chart_handler"),# 此处配置与bokeh_apps.autoload中请求地址保持一致
        arguments=dict(request.GET.dict(), **request.POST.dict())# bokeh只接受不带参数的url因此处理django参数,处理django参数数据

    return HttpResponse(jsonUtil.http_response_success(script))

html code

When Ajax requests the server_document to get the returned script every time it carries the parameter

<iframe id="iframeref" frameborder="no" style="width: 100%;height: 100%;padding: 0;border: 0" scrolling="no"></iframe>
    var iframe = document.getElementById('iframeref');
    var doc = document.all ? iframe.contentWindow.document : iframe.contentDocument;;
    doc.write("<div style='height:100%;width:100%;'>" + Get script tag from server_document + "</div>");
1 Like

Thanks for the contribution @416970882!