将样式表添加到Bokeh应用程序

时间:2018-06-12 19:52:11

标签: python bokeh

我做了一个很复杂的Bokeh仪表板。我没有为仪表板定义任何html模板。我只是使用下面的代码服务它。

我的问题是,当使用bokeh.plotting.output_notebook函数将其嵌入到Jupyter笔记本中时,仪表板看起来非常漂亮。现在,当尝试在Jupyter之外创建和提供仪表板时,它看起来更加丑陋,因为一些呈现漂亮表格的样式表并不存在。我的问题是,如何将外部样式表添加到我的bokeh webapp中。

仪表板代码:

def emb_bokehdash(self, doc, dash_width=1500, dash_height=800):
    # Get base data:
    df_orig = self._get_base_data_for_vis(unlabeled_name)
    unique_labels = list(df_orig.label.unique())

    ...

    # Sentence Selection Controls:
    index_text = AutocompleteInput(
        title="select sentence index", value=str(candidate_state),
        completions=list(df_orig.index.map(lambda idx: str(idx))),
        width=control_width
    )
    index_next = Button(label="next", button_type="primary", width=button_width)
    index_back = Button(label="back", button_type="primary", width=button_width)
    selection_checkboxes = CheckboxGroup(labels=['unseen', 'random'], active=[])

    index_input = row(
        widgetbox(index_text, width=control_width+200),
        widgetbox(index_next, index_back, width=button_width+40),
        selection_checkboxes,
        width=info_width
    )

    ... More code defining DOM and wrangling data

    layout_ = row(inputs_and_info, plot, height=dash_height)

    # initial load of the data
    update_selectioninfo_and_plot()
    update_selected_info()

    # Register title and dashboard with the document:
    doc.title = "Smart Feedback Labeler"
    doc.add_root(layout_)

仪表板服务器代码:

from bokeh.server.server import Server
from os import getpid

def emb_bokehdash_serve(self, **server_kwargs):
    # Route App:
    apps = {'/': Application(FunctionHandler(self.bokeh_dashboard))}

    # Extract Port (default = 5000):
    if "port" not in server_kwargs:
        server_kwargs["port"] = 5000

    # Find a suitable port to use:
    while True:
        try:
            server = Server(apps, **server_kwargs)
        except OSError:
            self.logger.info(
                f"Port {server_kwargs['port']} already in use, serving to port {server_kwargs['port']+1}"
            )
            server_kwargs["port"] += 1
        else:
            break

    # We have to defer opening in browser until we start up the server
    def show_callback():
        for route in apps.keys():
            server.show(route)
    server.io_loop.add_callback(show_callback)

    # Set server address (default is localhost):
    address_string = 'localhost'
    if server.address is not None and server.address != '':
        address_string = server.address

    for route in sorted(apps.keys()):
        url = "http://%s:%d%s%s" % (address_string, server.port, server.prefix, route)
        self.logger.info("Bokeh app running at: %s" % url)

    self.logger.info("Starting Bokeh server with process id: %d" % getpid())

    if not run_from_ipython():
        server.run_until_shutdown()  # Doesn't shutdown properly when run from Jupyter Notebook.
    else:
        server.start()

注意,我无法静态运行此仪表板。

1 个答案:

答案 0 :(得分:0)

我没有遇到您的问题,因为我跳过了Jupyter部分并从一开始就构建了一个独立的仪表板。但是,我使用样式表以下列方式自定义仪表板外观及其元素:

  • 在信息中心目录中,templates/index.html位于:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>{{ TITLE }}</title>
    {{ bokeh_css }}
    {{ bokeh_js }}
    <style>
      {% include 'styles.css' %}
    </style>
  </head>
  <body>
    <div>
    {{ plot_div|indent(8) }}
    {{ plot_script|indent(8) }}
  </body>
</html>
  • templates/styles.css内,我有自定义css。
  • 要将特定自定义应用于窗口小部件,仪表板代码需要包括:<widget object>.css_classes = ["<class from templates/styles.css>"]。它可以是这种分配中的字符串列表。

这有意义吗?我希望这会有所帮助。