如何在嵌入式Bokeh服务器上重用具有不同数据的Bokeh应用程序

时间:2017-06-02 22:04:57

标签: python bokeh

我已将用户指南flask_embed.html部分中从Embedding Bokeh Server as a Library获取的简单Bokeh应用示例集成到我的烧瓶应用程序中,以验证我是否可以正确设置集成所需的服务器基础结构进入我的烧瓶应用程序,我可以成功地路由到它,没有任何妨碍。

我没有清楚地看到如何摆脱散景应用程序与依赖modify_doc全局函数之间的硬关联,该函数使用预制数据并且其签名必须是单个参数是散景文件。我希望将数据从我的模型推送到一个函数,然后Bokeh将使用呈现文档。有一点需要注意,但是模型只有在用户加载由Flask应用程序和Flask会话维护的csv文件时才会在运行时填充。

作为一个最小的例子,我的烧瓶应用程序维护了一个模型实例,里面有一个pandas DataFrame,我希望创建一个Bokeh应用程序,我可以重用来做不同列对的散点图数据帧。这些对通过Flask创建的链接呈现给用户,该链接当前指向具有通过matplotlib生成的静态图像的页面。这些图像由一个函数创建,该函数将用于生成文件名的一对列名称和x和y坐标作为数据框的列。列名称作为参数传递给烧瓶路径,烧瓶路径逐渐下降到获取相应图像的模板。

基本上我想在Bokeh中以不同的数据重用相同的绘图逻辑,就像我使用Matplotlib一样。似乎FunctionHandler技术已修复在数据源上,因为我试图创建一个维护实现modify_doc方法的状态的类,但问题出现在self上类中需要的参数。

class BokehParamPlot() :
    def __init__( self , paramName , x , y ) :   
        # Initialize member data
        self.paramName = paramName
        self.x         = x
        self.y         = y

    def modify_doc( self , doc ) :
        x = self.x
        y = self.y

        source = ColumnDataSource(data=dict(x=x, y=y))

        plot = figure()
        plot.line('x', 'y', source=source)
        doc.add_root(column(slider, plot))

上述尝试的精神是尝试使用FunctionHandler技术进行参数化,因为应用程序将与不同的数据完全相同,并且我不想为每对应用程序制作应用程序我的数据框中的数据。然而,没有运气

  File "ParamPlot.py", line 362, in <module>
    bokeh_app = Application(FunctionHandler(BokehParamPlot.modify_doc))
  File "C:\Anaconda3\lib\site-packages\bokeh\application\handlers\function.py", line 11, in __init__
    _check_callback(func, ('doc',))
  File "C:\Anaconda3\lib\site-packages\bokeh\util\callback_manager.py", line 32, in _check_callback
    raise ValueError(error_msg % (", ".join(fargs), formatted_args))
ValueError: Callback functions must have signature func(doc), got func(self, doc)

查看Bokeh源代码另一个有希望的路线是CodeHandler,但我希望我尝试的不是一些远远不是用例,我只是错过了一些观点或者与Base Python的某些连接或者很快就会让我上路的东西。

1 个答案:

答案 0 :(得分:0)

这确实可以通过将查询字符串传递给散景应用程序来实现。在这个重用场景中发现了一个关键问题,那就是session_id的{​​{1}}参数的作用[编辑注意:此session_id功能仅适用于Bokeh 12.4,12.5打破了这种技术]。该会话ID必须在通过它传递的不同数据的各种文档呈现之间是不同的,因为如果您使用相同的ID,则在尝试呈现时将为其余数据缓存第一个数据。如果需要将更多参数信息传递到文档,您可以插入autoload_server返回的src标记的script属性,就像显示here一样}。

接下来是使模型数据对渲染散景文档的模块可见的方法。在我的情况下,我重新分层我的Flask应用程序,将我的用户会话模型存储在一个较低级别的模块中,该模块可供烧瓶应用程序主脚本和绘图模块访问,我在那里持有所有绘图逻辑。在我的Flask主页中,我执行以下逻辑来设置flask会话cookie中的会话信息,并将一个参数从flask传递到我的散景文档......

<强> MyFlaskApp.py

autoload_server

<强> SessionInfo.py

@flaskApp.route( '/' , methods=['GET', 'POST'] )
def index():
    # Create or load model instance for this user session based on model uuid cookie
    if sKeyModel in session :
        if session[ sKeyModel ] not in SessionInfo.userModels :
            logger.debug( "Loading Model instance for current user" )
            SessionInfo.userModels[ session[ sKeyModel ] ] = Model( ) # TODO create new for now, but latter must support loading from persisted JSON model file
    else :
        logger.debug( "Creating Model instance for current user" )
        session[ sKeyModel ] = str( uuid.uuid1() )
        SessionInfo.userModels[ session[ sKeyModel ] ] = Model( )

    model = SessionInfo.userModels[ session[ sKeyModel ] ]
...
@flaskApp.route( '/Plots/<param>' , methods=['GET'] )
def interactivePlotsPage( param ) :     
    script = autoload_server( model      = None ,
                              session_id = "%s.%s" % ( session[sKeyModel] , param ),
                              url        = 'http://localhost:5006/' )

    return render_template( "plotsPage.html" , script=script )

<强> Plots.py

bokehSession = "bokeh-session-id"
userModels = {} # GUID to user Model instances maintained in the Server

对于我的应用程序,Flask应用程序可以将所有模型数据保存在内存中,因为这只是一个内部数据分析仪表板工具,我们用它来分析一些机器学习异常值和性能。

使用查询字符串,我们可以向下传递参数以便在Bokeh中访问,然后您基本上需要访问需要在散景文档中呈现的数据。用户组中有一个条目(Bokeh Server + Flask : Passing data to plot from Flask to the Bokeh server app),可以讨论这种情况...

  

围绕不同的信息来源,我也发现了这一点   来自Bryan Van de Ven:

     
    

有很多方法可以做到这一点,而且还有很多方法可以解决这个问题。     别处。你只需要传达结果/数据/无论如何     应用程序需要为了进行绘图,应用程序。但那可能是     做了很多方法:

         
        
  • 应用可以访问HTML请求参数(新功能)
  •     
  • 应用可以访问Cookie
  •     
  • 应用可以访问外部数据库中的数据(redis,mongo等)
  •     
  • 应用程序可以对REST API进行AJAX调用
  •     
  • ...
  •     
  
     

基于此,我认为可能的解决方案可能是:生成数据   要绘制(在Flask一侧)使用pull_session()获取会话   使用session.id作为密钥临时将数据存储在redis中   使用散景应用程序中的session_id从redis中获取数据

我认为真正慢慢思考的问题是如何回答这个问题&#34;如何从全球范围内对这个功能显示数据?&#34;因此,数据库自然会降低全局用户会话数据 服务器的文件系统,文档应用程序所在的模块级状态信息等

我认为与flask_embed.py示例之间的差距是关于如何将参数信息传递给散景文档的那一点,这些拼图相互之间的距离太远,这让人有点难以想象这一切是怎么回事一起工作。值得庆幸的是,我的参数化文档正是我所需要的,我们在Bokeh的土地上飞得很高,并且到目前为止我们的仪表板总体上给人留下了深刻的印象。