如何在Data Spyre中使用小部件渲染Bokeh图?

时间:2016-04-06 16:40:18

标签: python cherrypy bokeh

我使用python的Data Spyre创建了一个简单的Web应用程序来公开一些数据和图表,我也希望利用其中的一些Bokeh小部件。我已经成功地包含了Bokeh图,但是一旦我添加了MultiSelect工具,我就会收到以下错误:

0x6afee4 0xe40e40 0xe41240
0x6afd54 0x6afd54 0x6afd54

我无法弄清楚是什么造成了这个错误。我以前能够在Jupyter笔记本中测试散景代码,并按预期渲染所有内容。当我将它移植到Spyre时,我不确定什么在破碎。

以下是我测试的代码:

(index):10137 Uncaught Error: Module `MultiSelect' does not exists. The problem may be two fold. Either a model was requested that's available in an extra bundle, e.g. a widget, or a custom model was requested, but it wasn't registered before first usage.

解: 感谢bigreddot确定了这一点。我也必须合并小部件js。我的自定义JS函数现在看起来像这样:

from spyre import server

import numpy as np
import pandas as pd
from bokeh.plotting import figure

from bokeh.resources import INLINE, CDN
from bokeh.embed import components
from bokeh.models.sources import ColumnDataSource
from bokeh.models import CustomJS, MultiSelect
import bokeh.models as bkm
from bokeh import palettes
from bokeh.io import vform

class SimpleApp(server.App):
    title = "Bokeh Test"
    inputs = [{ "type":"text",
                "key":"factor",
                "value":5,
                "label":"factor",
                "action_id":"line_plot"}]
    tabs=["Plot","Data"]
    outputs = [{"type":"html",
                "id":"bokeh_plot",
                "tab":"Plot",
                "control_id":"line_plot"},
                {"type":"table",
                "id":"bokeh_data",
                "tab":"Data",
                "control_id":"line_plot"}]
    controls = [{"type":"HIDDEN",
                 "id":"line_plot"}]
    def getHTML(self, params):
        df=self.getData(params)


        _tools_to_show = 'box_zoom,pan,save,resize,reset,tap,wheel_zoom'
        p=figure(plot_width=600, plot_height=600,x_axis_type='datetime',tools=_tools_to_show)

        colors=palettes.Spectral11
        colori=0

        #create source
        source_dict={}

        source_dict['Date']=df.index.format()
        for col in df.columns.tolist():
            source_dict['xaxis_'+col]=df.index.values
            source_dict['Date_'+col]=df.index.format()

            source_dict['yaxis_'+col]=df[col].values
            source_dict['yname_'+col]=np.tile(col, [len(df.index),1])

            source_dict['yaxisdup_'+col]=df[col].values

        source=ColumnDataSource(source_dict)

        #print source.data

        #source_dict={}
        for col in df.columns:
            #source= ColumnDataSource({'x': df.index.values, 'y': df[col].values, 'series_name': col, 'Date': df.index.format()})
            p.line('xaxis_'+col,'yaxis_'+col,source=source, legend=col,color=colors[colori],line_width=3)
            colori+=1



        colori=0
        scatlist=[]
        for col in df.columns.tolist():

            subdict = {'xaxis_'+col:source.data['xaxis_'+col], 'Date_'+col:source.data['Date_'+col], 'yname_'+col:source.data['yname_'+col],'yaxis_'+col:source.data['yaxis_'+col]}
            tempsource = ColumnDataSource(subdict)
            scat=p.scatter('xaxis_'+col, 'yaxis_'+col, source = source, fill_alpha=0, line_alpha=0.8, line_color=colors[colori],line_width=8)
            colori+=1
            scatlist.append(scat)
            g1_hover = bkm.HoverTool(renderers=[scat], tooltips=[("Series", "@yname_"+col), ("Date", "@Date_"+col),  ("Value", "@yaxis_"+col+"{0.00%}")])    
            g1_hover.mode='mouse'
            p.add_tools(g1_hover)



        p.background_fill_color='black'
        p.background_fill_alpha=0.9


        codestr="""
                var data = source.get('data');
                var f = cb_obj.get('value')

                cols="""+"['"+"','".join([col for col in df.columns.tolist()])+"']"+"""
                for (var i = 0; i < cols.length; i++) {
                    if (f.indexOf(cols[i])> -1) {
                        data['yaxis_'+cols[i]]=data['yaxisdup_'+cols[i]]   
                    }
                    else {
                        data['yaxis_'+cols[i]]='nan'
                    }

                }
                source.trigger('change');
            """
        callback = CustomJS(args=dict(source=source), code=codestr)

        multi_select = MultiSelect(title="Lines to plot:", \
        value=df.columns.tolist(), \
        options=df.columns.tolist(), callback=callback)
        layout = vform(multi_select, p)

        script,div=components(layout,CDN)
        html = "%s\n%s"%(div, script)


        html='<center>'+html+'</center>'
        return html

    def getData(self,params):
        f=int(params['factor'])
        dr=pd.date_range('1-1-2010','12-31-2010',freq='D')
        vals=[i*f for i in range(len(dr))]
        df=pd.DataFrame(vals,index=dr,columns=['data'])

        return df
    def getCustomJS(self):
        return INLINE.js_raw[0]

    def getCustomCSS(self):
        css=INLINE.css_raw[0]
        return css
if __name__ == '__main__':
    app = SimpleApp()
    app.launch()

1 个答案:

答案 0 :(得分:0)

解决方案:感谢bigreddot识别出这一点。我还必须合并小部件js,因为它位于js_raw中的单独脚本中。由于Data Spyre有自己内置的javascript函数需要覆盖,我最终在函数中返回了原始javascript元素的连接字符串。

我的自定义JS功能现在看起来像这样:

def getCustomJS(self):
    INLINE.js_raw[0]+INLINE.js_raw[1]