from datetime import datetime as dt from unittest import SkipTest from holoviews.core.options import Store from holoviews.core.spaces import DynamicMap from holoviews.element import Table from holoviews.element.comparison import ComparisonTestCase from holoviews.streams import CDSStream, Stream try: from bokeh.models.widgets import ( NumberEditor, NumberFormatter, DateFormatter, DateEditor, StringFormatter, StringEditor, IntEditor ) from holoviews.plotting.bokeh.callbacks import CDSCallback from holoviews.plotting.bokeh.renderer import BokehRenderer bokeh_renderer = BokehRenderer.instance(mode='server') except: bokeh_renderer = None class TestBokehTablePlot(ComparisonTestCase): def setUp(self): self.previous_backend = Store.current_backend if not bokeh_renderer: raise SkipTest("Bokeh required to test plot instantiation") Store.current_backend = 'bokeh' def tearDown(self): Store.current_backend = self.previous_backend bokeh_renderer.last_plot = None def test_table_plot(self): table = Table(([1, 2, 3], [1., 2., 3.], ['A', 'B', 'C']), ['x', 'y'], 'z') plot = bokeh_renderer.get_plot(table) dims = table.dimensions() formatters = (NumberFormatter, NumberFormatter, StringFormatter) editors = (IntEditor, NumberEditor, StringEditor) for dim, fmt, edit, column in zip(dims, formatters, editors, plot.state.columns): self.assertEqual(column.title, dim.pprint_label) self.assertIsInstance(column.formatter, fmt) self.assertIsInstance(column.editor, edit) def test_table_plot_escaped_dimension(self): table = Table([1, 2, 3], ['A Dimension']) plot = bokeh_renderer.get_plot(table) source = plot.handles['source'] renderer = plot.handles['glyph_renderer'] self.assertEqual(list(source.data.keys())[0], renderer.columns[0].field) def test_table_plot_datetimes(self): table = Table([dt.now(), dt.now()], 'Date') plot = bokeh_renderer.get_plot(table) column = plot.state.columns[0] self.assertEqual(column.title, 'Date') self.assertIsInstance(column.formatter, DateFormatter) self.assertIsInstance(column.editor, DateEditor) def test_table_plot_callback(self): table = Table(([1, 2, 3], [1., 2., 3.], ['A', 'B', 'C']), ['x', 'y'], 'z') CDSStream(source=table) plot = bokeh_renderer.get_plot(table) self.assertEqual(len(plot.callbacks), 1) self.assertIsInstance(plot.callbacks[0], CDSCallback) def test_table_change_columns(self): lengths = {'a': 1, 'b': 2, 'c': 3} table = DynamicMap(lambda a: Table(range(lengths[a]), a), kdims=['a']).redim.values(a=['a', 'b', 'c']) plot = bokeh_renderer.get_plot(table) self.assertEqual(sorted(plot.handles['source'].data.keys()), ['a']) self.assertEqual(plot.handles['table'].columns[0].title, 'a') plot.update(('b',)) self.assertEqual(sorted(plot.handles['source'].data.keys()), ['b']) self.assertEqual(plot.handles['table'].columns[0].title, 'b') def test_table_selected(self): table = Table([(0, 0), (1, 1), (2, 2)], ['x', 'y']).opts(selected=[0, 2]) plot = bokeh_renderer.get_plot(table) cds = plot.handles['cds'] self.assertEqual(cds.selected.indices, [0, 2]) def test_table_update_selected(self): stream = Stream.define('Selected', selected=[])() table = Table([(0, 0), (1, 1), (2, 2)], ['x', 'y']).apply.opts(selected=stream.param.selected) plot = bokeh_renderer.get_plot(table) cds = plot.handles['cds'] self.assertEqual(cds.selected.indices, []) stream.event(selected=[0, 2]) self.assertEqual(cds.selected.indices, [0, 2])