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
@with_request
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(
tooltips=[
("(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),
y=data,
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)
source.data=dict(image=[image.data], x=[xmin],
y=[ymin], dw=[dw], dh=[dh])
update(None,None,None)
p.image_rgba(source=source, image='image', x='x', y='y',
dw='dw', dh='dh', dilate=False)
# 处理各种回调
p.x_range.on_change('end',update)
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.open();
doc.write("<div style='height:100%;width:100%;'>" + Get script tag from server_document + "</div>");
doc.close();