是否可以将参数数据传递给bokeh应用程序?

问题描述

所以我有各种各样的熊猫数据框,我想重用bokeh应用程序来查看它们,而不是将数据硬编码到应用程序中。我改编了交叉过滤器示例以显示我的方法存在的问题。

这应该称为

dframe = some Pandas dataframe
invokeh(bk_crossfilter,dframe)

,并在下面的代码块中定义。

似乎bokeh不喜欢在下面的应用程序定义中使用functools.partial,并在浏览器中给我500服务器错误。今天早些时候,在bokeh应用程序中的打印语句显示了数据框,但是现在似乎在函数输入过程中陷入了bokeh.Document中。现在,控制台输出为:

Preparing a bokeh application.
opening bokeh application on http://localhost:5006/
CROSSFILTER:  <bokeh.document.document.Document object at 0x0000029BAB2783C8>
ERROR:tornado.application:Uncaught exception GET / (::1)
HTTPServerRequest(protocol='http',host='localhost:5006',method='GET',uri='/',version='HTTP/1.1',remote_ip='::1')
Traceback (most recent call last):
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\tornado\web.py",line 1703,in _execute
    result = await result
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\bokeh\server\views\doc_handler.py",line 52,in get
    session = await self.get_session()
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\bokeh\server\views\session_handler.py",line 120,in get_session
    session = await self.application_context.create_session_if_needed(session_id,self.request,token)
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\bokeh\server\contexts.py",line 218,in create_session_if_needed
    self._application.initialize_document(doc)
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\bokeh\application\application.py",line 171,in initialize_document
    h.modify_document(doc)
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\bokeh\application\handlers\function.py",line 132,in modify_document
    self._func(doc)
  File "c:\users\jdorsey\code\utils\dorsey\visualisation.py",line 36,in bk_crossfilter
    columns = sorted(df.columns)
AttributeError: 'Document' object has no attribute 'columns'
ERROR:tornado.access:500 GET / (::1) 7.98ms
WARNING:tornado.access:404 GET /favicon.ico (::1) 0.99ms
Traceback (most recent call last):
  File "<stdin>",line 1,in <module>
  File "c:\users\jdorsey\code\utils\dorsey\visualisation.py",line 27,in invokeh
    io_loop.start()
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\site-packages\tornado\platform\asyncio.py",line 149,in start
    self.asyncio_loop.run_forever()
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\asyncio\base_events.py",line 422,in run_forever
    self._run_once()
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\asyncio\base_events.py",line 1396,in _run_once
    event_list = self._selector.select(timeout)
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\selectors.py",line 323,in select
    r,w,_ = self._select(self._readers,self._writers,[],timeout)
  File "C:\Users\jdorsey\code\conda\environment\REDACTED\lib\selectors.py",line 314,in _select
    r,x = select.select(r,timeout)

在invokeh函数添加打印语句,以确认数据集在那里是有效的熊猫框架。

[1379 rows x 82 columns]

代码

from tornado.ioloop import IOLoop
from bokeh.application.handlers import FunctionHandler
from bokeh.application import Application
from bokeh.server.server import Server
from bokeh.layouts import column,row
from bokeh.models import Select
from bokeh.palettes import Spectral5
from bokeh.plotting import curdoc,figure
from functools import partial

def invokeh(visual,dataset):
    """
    Launch a bokeh server and connect to it.
    
    ARGUMENTS:
    visual: A bokeh visualisation
    dataset: A dataset to populate the visualisation
    """
    print("Preparing a bokeh application.")
    io_loop = IOLoop.current()
    bokeh_app = Application(FunctionHandler(partial(visual,dataset)))
    server = Server({"/": bokeh_app})#,io_loop=io_loop)
    server.start()
    print("opening bokeh application on http://localhost:5006/")
    
    io_loop.add_callback(server.show,"/")
    io_loop.start()

def bk_crossfilter(doc,df):
    print('CROSSFILTER: ',df)
    SIZES = list(range(6,22,3))
    COLORS = Spectral5
    N_SIZES = len(SIZES)
    N_COLORS = len(COLORS)
    
    columns = sorted(df.columns)
    discrete = [x for x in columns if df[x].dtype == object]
    continuous = [x for x in columns if x not in discrete]
    
    def create_figure():
        xs = df[x.value].values
        ys = df[y.value].values
        x_title = x.value.title()
        y_title = y.value.title()
        
        kw = dict()
        
        if x.value in discrete:
            kw['x_range'] = sorted(set(xs))
        if y.value in discrete:
            kw['y_range'] = sorted(set(ys))
        kw['title'] = "%s vs %s" % (x_title,y_title)
        
        p = figure(plot_height=600,plot_width=800,tools='pan,Box_zoom,hover,reset',**kw)
        p.xaxis.axis_label = x_title
        p.yaxis.axis_label = y_title
        
        if x.value in discrete:
            p.xaxis.major_label_orientation = pd.np.pi / 4
        sz = 9
        
        if size.value != 'None':
            if len(set(df[size.value])) > N_SIZES:
                groups = pd.qcut(df[size.value].values,N_SIZES,duplicates='drop')
            else:
                groups = pd.Categorical(df[size.value])
            sz = [SIZES[xx] for xx in groups.codes]
        
        c = "#31AADE"
        
        if color.value != 'None':
            if len(set(df[color.value])) > N_COLORS:
                groups = pd.qcut(df[color.value].values,N_COLORS,duplicates='drop')
            else:
                groups = pd.Categorical(df[color.value])
            c = [COLORS[xx] for xx in groups.codes]
        
        p.circle(x=xs,y=ys,color=c,size=sz,line_color="white",alpha=0.6,hover_color='white',hover_alpha=0.5)
        
        return p
    
    def update(attr,old,new):
        layout.children[1] = create_figure()
    
    print("COLUMNS: ",columns[0],columns[1])
    print("disCRETE: ",discrete," CONTINUOUS: ",continuous)
    x = Select(title='X-Axis',value=columns[0],options=columns)
    x.on_change('value',update)
    
    y = Select(title='Y-Axis',value=columns[1],options=columns)
    y.on_change('value',update)
    
    size = Select(title='Size',value='None',options=['None'] + continuous)
    size.on_change('value',update)
    
    color = Select(title='Color',options=['None'] + continuous)
    color.on_change('value',update)
    
    controls = column(x,y,color,size,width=200)
    layout = row(controls,create_figure())
    
    curdoc().add_root(layout)
    curdoc().title = "Crossfilter"

提前感谢您的任何建议。

解决方法

通过更改:

bokeh_app = Application(FunctionHandler(partial(visual,dataset)))

收件人:

bokeh_app = Application(FunctionHandler(lambda dataset: visual))

我现在只能在控制台中获得它:

Opening Bokeh application on http://localhost:5006/
WARNING:tornado.access:404 GET /favicon.ico (::1) 1.00ms

浏览器中没有错误。但是浏览器呈现了一个空白页面,其中包含以下来源(还有更多来源,但告诉我的并不多):

root.Bokeh.embed.embed_items(docs_json,render_items);
            
              }
              if (root.Bokeh !== undefined) {
                embed_document(root);
              } else {
                var attempts = 0;
                var timer = setInterval(function(root) {
                  if (root.Bokeh !== undefined) {
                    clearInterval(timer);
                    embed_document(root);
                  } else {
                    attempts++;
                    if (attempts > 100) {
                      clearInterval(timer);
                      console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");
                    }
                  }
                },10,root)
              }

控制台日志实际上并未显示页面源中提到的错误消息...

,

非常确定您需要使用partial明确表示要绑定哪些参数:

partial(visual,df=dataset)

因为我几乎可以肯定您将dataset绑定到doc参数,所以当Bokeh调用您的应用程序函数时,Document会以df的身份传入(剩下的唯一自由参数)。