Source code for shyft.dashboard.apps.dtss_viewer.dtss_viewer_app

from typing import Optional, Dict, Any
from concurrent.futures import ThreadPoolExecutor
import bokeh
import bokeh.layouts
import bokeh.models

import shyft.time_series as sa

from shyft.dashboard.time_series.axes import YAxis, YAxisSide

from shyft.dashboard.time_series.ds_view_handle_registry import DsViewHandleRegistryApp
from shyft.dashboard.time_series.renderer import LineRenderer
from shyft.dashboard.time_series.state import State
from shyft.dashboard.time_series.tools.figure_tools import ResetYRange, WheelZoomDirection, \
    HoverToolToggleDropdown
from shyft.dashboard.time_series.tools.ts_viewer_tools import ResetTool
from shyft.dashboard.time_series.view_container.figure import Figure

from shyft.dashboard.time_series.ts_viewer import TsViewer

from shyft.dashboard.base.selector_presenter import SelectorPresenter
from shyft.dashboard.base.selector_views import FilterMultiSelect

from shyft.dashboard.base.app import AppBase
from shyft.dashboard.apps.dtss_viewer.widgets import (ContainerPathReceiver,
                                                      TsSelector, TsViewDemo)

from shyft.dashboard.base.ports import connect_ports
from shyft.dashboard.time_series.view_container.table import Table
from shyft.dashboard.widgets.logger_box import LoggerBox
from shyft.dashboard.widgets.message_viewer import MessageViewer

from shyft.dashboard.time_series.tools.figure_tools import HoverTool


[docs] class DtssViewerApp(AppBase):
[docs] def __init__(self, thread_pool: Optional[ThreadPoolExecutor] = None, app_kwargs: Optional[Dict[str, Any]] = None) -> None: super().__init__(thread_pool=thread_pool) a = app_kwargs or {} self.default_host: str = a.get('dtss_host', 'localhost') self.default_port: int = a.get('dtss_port', 20000) self.default_container: str = a.get('dtss_container', 'test')
@property def name(self) -> str: """ This property returns the name of the app """ return "DTSS Viewer App"
[docs] def get_layout(self, doc: 'bokeh.document.Document', logger: Optional[LoggerBox] = None) -> bokeh.models.LayoutDOM: """ This function returns the full page layout for the app """ std_width = 800 doc.title = self.name event_messenger = MessageViewer(title='Log:', rows=6, width=std_width, height=100, title_hight=15, show_time=True, time_zone='Europe/Oslo') container_path_input = ContainerPathReceiver(dtss_host=self.default_host, dtss_port=self.default_port,dtss_container=self.default_container) multi_select_view = FilterMultiSelect(title='Time Series in DTSS', height=200, width=std_width, size=40, padding=20) multi_select_presenter = SelectorPresenter(name='Ts', view=multi_select_view) ts_selector = TsSelector(multi_select_presenter) utc = sa.Calendar() time_range = sa.UtcPeriod(utc.time(2000, 1, 1), utc.time(2024, 1, 1)) time_step_restrictions = [sa.Calendar.HOUR, sa.Calendar.HOUR * 3, sa.Calendar.DAY, sa.Calendar.WEEK, sa.Calendar.MONTH, sa.Calendar.QUARTER, sa.Calendar.YEAR] reset_tool = ResetTool(logger=logger) reset_y_range_tool = ResetYRange(logger=logger) wheel_zoom = WheelZoomDirection(logger=logger) ts_viewer = TsViewer(bokeh_document=doc, title="Ts Viewer", padding=10, height=50, unit_registry=State.unit_registry, thread_pool_executor=self.thread_pool, tools=[reset_tool], init_view_range=time_range, time_step_restrictions=time_step_restrictions, reset_time_axis=False ) # TODO rather use auto axis when adding time-series ax_any = YAxis(label="any", unit='', side=YAxisSide.LEFT) ax_mmh = YAxis(label="precipitation", unit='mm/h', side=YAxisSide.RIGHT) ax_m3s = YAxis(label="flow", unit='m**3/s', side=YAxisSide.LEFT, color='green') ax_tmp = YAxis(label="temperature", unit='degC', side=YAxisSide.RIGHT, color='magenta') ax_swe = YAxis(label="swe", unit='mm', side=YAxisSide.RIGHT, color='blue') hover = HoverTool( point_policy='follow_mouse', tooltips=[("label", "@label"), ("value", "$y"), ("time", "$x{%d-%m-%Y %H:%M}")], formatters={'$x': 'datetime'} ) hover_tool_toggle = HoverToolToggleDropdown([hover]) fig = Figure(viewer=ts_viewer, width=std_width, height=600, init_renderers={LineRenderer: 6}, tools=[reset_y_range_tool, wheel_zoom, hover] , y_axes=[ax_any, ax_mmh, ax_m3s, ax_swe, ax_tmp] ) table1 = Table(viewer=ts_viewer, width=std_width, height=400) ts_view = TsViewDemo(figure=fig, table=table1) dsviewhandle_registry = DsViewHandleRegistryApp() connect_ports(container_path_input.send_event_message, event_messenger.receive_message) connect_ports(ts_selector.send_event_message, event_messenger.receive_message) connect_ports(ts_view.send_event_message, event_messenger.receive_message) connect_ports(container_path_input.send_dtss_url, ts_selector.receive_url) connect_ports(container_path_input.send_shyft_container, ts_selector.receive_container) connect_ports(container_path_input.send_pattern, ts_selector.receive_pattern) connect_ports(container_path_input.send_dtss_url, ts_view.receive_dtss_url) connect_ports(ts_selector.send_selected_time_series, ts_view.receive_time_series) connect_ports(ts_view.send_selected, dsviewhandle_registry.receive_ds_view_handles_to_register) connect_ports(dsviewhandle_registry.send_ds_view_handles_to_add, ts_viewer.receive_ds_view_handles_to_add) connect_ports(dsviewhandle_registry.send_ds_view_handles_to_remove, ts_viewer.receive_ds_view_handles_to_remove) # ensure we get a flying start sending suitable start values to the container container_path_input.send_dtss_url(f'{self.default_host}:{self.default_port}') container_path_input.send_shyft_container(self.default_container) sizing_mode="stretch_width" return bokeh.layouts.column(bokeh.layouts.row(event_messenger.layout, sizing_mode=sizing_mode), bokeh.layouts.row( bokeh.layouts.column( bokeh.layouts.row(container_path_input.layout_components["widgets"][0], container_path_input.layout_components["widgets"][1], container_path_input.layout_components["widgets"][2] ), multi_select_view.layout_components['widgets'][1], bokeh.layouts.row(dsviewhandle_registry.layout_components['widgets'][1], dsviewhandle_registry.layout_components['widgets'][0] ) ), sizing_mode=sizing_mode ), bokeh.layouts.row( bokeh.layouts.column( bokeh.layouts.row( ts_viewer.layout_components['widgets'], reset_y_range_tool.layout, wheel_zoom.layout, reset_tool.layout, hover_tool_toggle.layout , sizing_mode=sizing_mode ), fig.layout, table1.layout) , sizing_mode=sizing_mode ) )