Source code for shyft.dashboard.examples.range_tool

"""
Example of how to use Bokeh's range tool.

For this we need two figures showing the same data but with different
time periods - the main figure is zoomed in on the selected period and the second figure shows the full time
period.

This goes against the standard TsViewer usage and requires that 2 identical DataSources and TsViewers are created.

"""

from concurrent.futures import ThreadPoolExecutor
from typing import Optional, Dict, Any

import bokeh
from bokeh.layouts import row, column
from bokeh.models import RangeTool

from shyft.dashboard.base.app import AppBase
from shyft.dashboard.examples.test_data_generator import ExampleTsAdapterSine
from shyft.dashboard.time_series.axes import YAxis, YAxisSide
from shyft.dashboard.time_series.axes_handler import DsViewTimeAxisType
from shyft.dashboard.time_series.ds_view_handle import DsViewHandle
from shyft.dashboard.time_series.sources.source import DataSource
from shyft.dashboard.time_series.state import State
from shyft.dashboard.time_series.ts_viewer import TsViewer
from shyft.dashboard.time_series.view import Line
from shyft.dashboard.time_series.view_container.figure import Figure
from shyft.dashboard.widgets.logger_box import LoggerBox
from shyft.time_series import UtcPeriod, Calendar


[docs] class RangeToolExample(AppBase):
[docs] def __init__(self, thread_pool, app_kwargs: Optional[Dict[str, Any]] = None): super().__init__(thread_pool=thread_pool) self.logger = None
@property def name(self) -> str: """ This property returns the name of the app """ return "range_tool_example"
[docs] def get_layout(self, doc: bokeh.document.Document, logger: Optional[LoggerBox] = None) -> bokeh.layouts.LayoutDOM: """ This function returns the full page layout for the app """ # PRE RUNTIME doc.title = self.name figure_width = 800 # Set up async thread pool async_on = True thread_pool_executor = ThreadPoolExecutor(5) # self.thread_pool # Create our viewer1 app viewer1 = TsViewer(bokeh_document=doc, unit_registry=State.unit_registry, tools=[], time_step_restrictions=[Calendar.HOUR * 3, Calendar.DAY, Calendar.WEEK], thread_pool_executor=thread_pool_executor, logger=logger) # Create our viewer2 app viewer2 = TsViewer(bokeh_document=doc, unit_registry=State.unit_registry, tools=[], time_step_restrictions=[Calendar.HOUR * 3, Calendar.DAY, Calendar.WEEK], thread_pool_executor=thread_pool_executor, logger=logger) # Create view containers # set up additional y-axes ax1_fig1 = YAxis(label="left nonsens axes", unit='MW', side=YAxisSide.LEFT) # create first figure with all additional y-axes ''' Define the x range initially selected by the range tool ''' select_start = -2376000000.0 select_end = 2376000000.0 fig1 = Figure(viewer=viewer1, tools=[], width=figure_width, x_range=(select_start, select_end), y_axes=[ax1_fig1], init_renderers={Line: 20}.items(), logger=logger) # Initialise a data source time_range = UtcPeriod(-3600 * 24 * 100, 3600 * 24 * 100) example_data = ExampleTsAdapterSine(unit_to_decorate='MW', time_range=time_range, async_on=async_on) data_source = DataSource(ts_adapter=example_data, unit='MW', request_time_axis_type=DsViewTimeAxisType.padded_view_time_axis, time_range=time_range) data_source2 = DataSource(ts_adapter=example_data, unit='MW', request_time_axis_type=DsViewTimeAxisType.padded_view_time_axis, time_range=time_range) select = Figure(viewer=viewer2, tools=[], height=130, width=800, # y_range=p.y_range, # y_axes=[ax1_fig1], init_renderers={Line: 20}.items(), logger=logger) # Initialise views # create line view line_view_select = Line(color='blue', unit='MW', label='select line', visible=True, view_container=select, index=1) # create line view line_view = Line(color='blue', unit='MW', label='test adapter line', visible=True, view_container=fig1, index=1, y_axis=ax1_fig1) # Connecting the views and a data source through a DsViewHandle ds_view_handle = DsViewHandle(data_source=data_source, views=[line_view]) ds_view_handle2 = DsViewHandle(data_source=data_source2, views=[line_view_select]) # Adding the ds_view_handle to the app viewer1.add_ds_view_handles(ds_view_handles=[ds_view_handle]) viewer2.add_ds_view_handles(ds_view_handles=[ds_view_handle2]) # IN RUNTIME bokeh_fig1 = fig1.bokeh_figure range_tool = RangeTool(x_range=bokeh_fig1.x_range) range_tool.overlay.fill_color = "navy" range_tool.overlay.fill_alpha = 0.2 select.bokeh_figure.add_tools(range_tool) layout = column(fig1.layout, select.layout) return layout