neuralib.dashboard.base

Bokeh Base module

author:

Ta-Shun Su

[Bokeh](https://docs.bokeh.org/en/latest/) base module for building bokeh application which is web-based, interactive and python communicate-able.

Simple Example

>>> from neuralib.dashboard import BokehServer, View
>>> class Top(View):
...     def setup(self):
...         from bokeh.models import Div
...         from bokeh.layouts import column
...         return column(Div(text="Hello World!"))
>>> SERVER = BokehServer('Example')
>>> SERVER.start(Top())

General Application Structure

This structure proposol was following MVC common structure. For this module. M (Model) is defined as a group of functions that handle the data IO and processing. V (View) is defined as a group of classes that hold the bokeh UI components. C (Controller) is defined as a group of functions that bride the Model and View. They are UI event listeners, application controler and other kinds of function that nothing relate to the data.

>>> # data IO functions
... def list_data() -> list[str]: ...
>>> # Custom ViewComponent
... class DataView(ViewComponent): ...
>>> # Top View
... class Top(View):
...     view_data: DataView
...     def setup(self):
...         # init view_data
...     def update(self):
...         # update view_data
...     # controller functions
...     def on_data_update(self, attr, old, value): ... # property change/update event
...     def on_data_select(self, e): ... # action event
>>> # create cli parser (optional)
>>> # main function (optional)
>>> # create server
neuralib.dashboard.base.Figure(**kwargs)[source]
class neuralib.dashboard.base.View[source]

Top View of bokeh application.

Example

>>> class Top(View):
...     # custom viewer, it often follows a Figure
...     view_a: ViewA # class ViewA(ViewComponent)
...     figure_a: Figure
...
...     # exported UI components, put here if it needs to be access by controller functions
...     select_a: Select
...
...     def setup(self):
...         # initialize custom viewer
...         self.figure_a = Figure(...)
...         self.view_a = ViewA()
...         self.view_a.plot(self.figure_a)
...
...         # initialize exported UI components
...         self.select_a = Select(...)
...         self.select_a.on_change('value', on_select_a) # bind 'value' change event listener
...
...         # local UI components
...         # for those simple UIs without complex interaction, such as Button
...         button_a = Button('A')
...         button_a.on_click(on_btn_a) # bind pressed event listener
...
...         # layout UI components
...         from bokeh.layouts import row, column
...         return column(
...             self.figure_a,
...             row(self.select_a, button_a)
...         )

Implement Note

View instance should be singleton, which means there is no second instance existed in the same application/python runtime. It is a soft rule (which means you can break this rule without and error happen), and this class don’t have any mechanism to ensure this rule.

This class don’t force the __init__() function signature, which means you can define your own __init__ function with custom parameters, such as arguments from the CLI.

Beside top level updating function update(), you can define your own updating functions for only smaller group of UI components.

You can declare all the UI components inside the View class, but you probably will get a mess code. Hence, ViewComponent is used to group related functions together, included some controller functions and data processing functions. By this way, such as variable view_a in the example, it also provides a namespace that make the code more readable.

document: Document
property title: str
get_arg(key)[source]
Parameters:

key (str)

Return type:

list[str]

abstract setup()[source]

setup application top view. This function is called by BokehServer only once when the server created and opened the web browser.

In this function, you need to initialize the UI components and return the layout.

Return type:

Model

update()[source]

Top level UI components updating function. This function is called by BokehServer when setup() has done.

In this function, you need to initialize the data and update the UI components’ state.

run_later(callback, *args, **kwargs)[source]
Parameters:

callback (Callable)

run_timeout(delay, callback, *args, **kwargs)[source]
Parameters:
  • delay (int)

  • callback (Callable)

run_periodic(cycle, callback, *args, **kwargs)[source]
Parameters:
  • cycle (int)

  • callback (Callable)

on_message(message, reset)[source]

for logging purpose. i.e., TextAreaInput bokeh widget

Parameters:
  • message (str)

  • reset (bool)

class neuralib.dashboard.base.ViewComponent[source]

A UI component that provides certain graph on specific data type.

General Structure

>>> class MyView(ViewComponent):
...     # for ColumnDataSource attribute's name, there is no hard rule
...     data_a: ColumnDataSource
...     # for GlyphRenderer attribute's name, it should be named with prefix 'render_'
...     render_a: GlyphRenderer
...     def __init__(self):
...         # initialize an empty data
...         self.data_a = ColumnDataSource(data=dict(...))
...     def plot(self, figure):
...         # plotting data
...         self.render_a = figure.plot(self.data_a)
...     # function to update the render, data
...     def update(self, data):
...         # update data
...         self.data_a.activity = dict(...)

Implement Note

I suggest make plotting related properties as @property, because they usually need to update/invalid other attributes/properties when it is updated. In order to improve the performance, you don’t need to update the graph/render for each property update in an event loop. Because most render update functions have to process data and set value into ColumnDataSource, and ColumnDataSource need to sync the content with the web browser, it will take many times for every property update. You can mention (in document) the caller have to call the render update function after several properties update function.

abstract plot(figure, **kwargs)[source]

plot data in figure.

Parameters:
  • figure (Figure) – Figure.

  • kwargs – plotting parameters.

abstract update()[source]

update the plot

set_visible(visible, pattern=None)[source]

Set the visible state of renders for those name contain pattern. It is a recursive function that it also update the renders inside the ViewComponent attributes.

Parameters:
  • visible (bool)

  • pattern (str | None) – str in attribute name

list_renders(pattern=None, recursive=False)[source]

list all renders for those name contain pattern.

Parameters:
  • pattern (str | None) – str in attribute name

  • recursive (bool) – recursive find all renders from ViewComponent attributes.

Returns:

Return type:

list[GlyphRenderer]

class neuralib.dashboard.base.BokehServer[source]

Bokeh application server. It is a singleton class, that only one instance can hold the OS port.

Implement Note

For now, it is a single web-page application, that don’t provide any methods to route to other paths.

INSTANCE: ClassVar[BokehServer] = None
server: Server
__init__(theme='dark_minimal')[source]
Parameters:

theme (str)

start(viewer, open_url='/', **kwargs)[source]

start serving.

Parameters:
  • viewer (View | Application | dict[str, View | Application]) – top view

  • open_url (str | None)

:param open_url

page(viewer)[source]
Parameters:

viewer (View | Application)