class BokehBaseDisplay(with_metaclass(ABCMeta, BaseChartDisplay)): CellHandshake.addCallbackSniffer( lambda: "{'nostore_bokeh':!!window.Bokeh}") #get the bokeh version try: bokeh_version = pkg_resources.get_distribution("bokeh").parsed_version._version.release except: bokeh_version = None self.exception("Unable to get bokeh version") def __init__(self, options, entity, dataHandler=None): super(BokehBaseDisplay,self).__init__(options,entity,dataHandler) #no support for orientation self.no_orientation = True """ Default implementation for creating a chart object. """ def createBokehChart(self): return figure() def getPreferredOutputWidth(self): return super(BokehBaseDisplay,self).getPreferredOutputWidth() * 0.92 @cache(fieldName="_loadJS") def getLoadJS(self): html, loadJS = _load_notebook_html(hide_banner=True) return loadJS def doRenderChart(self): def genMarkup(chartFigure): return self.env.from_string(""" <script class="pd_save"> if ( !window.Bokeh && !window.autoload){{ window.autoload=true; {loadJS} }} </script> {chartFigure} {{%for message in messages%}} <div>{{{{message}}}}</div> {{%endfor%}} """.format(chartFigure=chartFigure, loadJS=self.getLoadJS()) ).render(messages=self.messages) if BokehBaseDisplay.bokeh_version < (0,12): raise Exception(""" <div>Incorrect version of Bokeh detected. Expected {0}, got {1}</div> <div>Please upgrade by using the following command: <b>!pip install --user --upgrade bokeh</b></div> """.format((0,12), BokehBaseDisplay.bokeh_version)) clientHasBokeh = self.options.get("nostore_bokeh", "false") == "true" if not clientHasBokeh: output_notebook(hide_banner=True) charts = self.createBokehChart() if not isinstance(charts, list): charts.add_tools(ResizeTool()) #bokeh 0.12.5 has a non backward compatible change on the title field. It is now of type Title #following line is making sure that we are still working with 0.12.4 and below if hasattr(charts, "title") and hasattr(charts.title, "text"): charts.title.text = self.options.get("title", "") else: charts.title = self.options.get("title", "") charts.plot_width = int(self.getPreferredOutputWidth() - 10 ) charts.plot_height = int(self.getPreferredOutputHeight() - 10 ) charts.grid.grid_line_alpha=0.3 return genMarkup(notebook_div(charts)) else: from bokeh.layouts import gridplot ncols = 2 nrows = len(charts)/2 + len(charts)%2 w = self.getPreferredOutputWidth()/ncols if len(charts) > 1 else self.getPreferredOutputWidth() h = w * self.getHeightWidthRatio() if len(charts) > 1 else self.getPreferredOutputHeight() for chart in charts: chart.plot_width = int(w - 5) chart.plot_height = int (h - 5) return genMarkup(notebook_div(gridplot(charts, ncols=ncols, nrows=nrows)))
class BokehBaseDisplay(with_metaclass(ABCMeta, BaseChartDisplay)): CellHandshake.addCallbackSniffer( lambda: "{'nostore_bokeh':!!window.Bokeh}") #get the bokeh version try: bokeh_version = pkg_resources.get_distribution( "bokeh").parsed_version._version.release except: bokeh_version = None self.exception("Unable to get bokeh version") def __init__(self, options, entity, dataHandler=None): super(BokehBaseDisplay, self).__init__(options, entity, dataHandler) #no support for orientation self.no_orientation = True """ Default implementation for creating a chart object. """ def createBokehChart(self): return figure() def getPreferredOutputWidth(self): return super(BokehBaseDisplay, self).getPreferredOutputWidth() * 0.92 def get_common_figure_options(self): options = {} x_fields = self.getKeyFields() if len(x_fields) == 1 and ( self.options.get("timeseries", 'false') == 'true' or self.dataHandler.isDateField(x_fields[0])): options["x_axis_type"] = "datetime" elif self.getBooleanOption("logx", False): options["x_axis_type"] = "log" if self.getBooleanOption("logy", False): options["y_axis_type"] = "log" return options @cache(fieldName="_loadJS") def getLoadJS(self): loadJS = self._load_notebook_html(hide_banner=True) return loadJS def colorPalette(self, size=None): # https://bokeh.pydata.org/en/latest/docs/reference/palettes.html # https://bokeh.pydata.org/en/latest/docs/reference/colors.html color = list( d3['Category10'][10]) # [ 'orangered', 'cornflowerblue', ] # color = list(Spectral9).reverse() if size is None: return color elif size <= len(color): return color[0:size] elif size <= 256: return linear_palette(plasma(256), size) else: return linear_palette( plasma(256) + viridis(256) + magma(256), size) def doRenderChart(self): def genMarkup(chartFigure): s = chartFigure[0] if isinstance(chartFigure, tuple) else chartFigure d = chartFigure[1] if isinstance(chartFigure, tuple) else '' return self.env.from_string(""" <script class="pd_save"> function setChartScript() {{ if (!window.Bokeh) {{ setTimeout(setChartScript, 250) }} else {{ var d = document.getElementById("pd-bkchartdiv-{p}") if (d){{ var el = document.createElement('div') el.innerHTML = `{chartScript}` var chartscript = el.childNodes[1] var s = document.createElement("script") s.innerHTML = chartscript.innerHTML d.parentNode.insertBefore(s, d) }} }} }} if (!window.Bokeh && !window.autoload){{ window.autoload=true; {loadJS} }} setChartScript() </script> <div style="padding:5px" id="pd-bkchartdiv-{p}">{chartDiv}</div> {{%for message in messages%}} <div>{{{{message}}}}</div> {{%endfor%}} """.format(chartScript=s.replace('</script>', '<\/script>'), chartDiv=d, loadJS=self.getLoadJS(), p=self.getPrefix())).render(messages=self.messages) minBkVer = (0, 12, 9) if BokehBaseDisplay.bokeh_version < minBkVer: raise Exception(""" <div>Incorrect version of Bokeh detected. Expected {0} or greater, got {1}</div> <div>Please upgrade by using the following command: <b>!pip install --user --upgrade bokeh</b></div> """.format(minBkVer, BokehBaseDisplay.bokeh_version)) clientHasBokeh = self.options.get("nostore_bokeh", "false") == "true" if not clientHasBokeh: output_notebook(hide_banner=True) charts = self.createBokehChart() if not isinstance(charts, list): # charts.add_tools(ResizeTool()) #bokeh 0.12.5 has a non backward compatible change on the title field. It is now of type Title #following line is making sure that we are still working with 0.12.4 and below if hasattr(charts, "title") and hasattr(charts.title, "text"): charts.title.text = self.options.get("title", "") else: charts.title = self.options.get("title", "") charts.plot_width = int(self.getPreferredOutputWidth() - 10) charts.plot_height = int(self.getPreferredOutputHeight() - 10) charts.grid.grid_line_alpha = 0.3 return genMarkup(notebook_div(charts)) else: from bokeh.layouts import gridplot ncols = 2 nrows = len(charts) / 2 + len(charts) % 2 w = self.getPreferredOutputWidth() / ncols if len( charts) > 1 else self.getPreferredOutputWidth() h = w * self.getHeightWidthRatio() if len( charts) > 1 else self.getPreferredOutputHeight() for chart in charts: chart.plot_width = int(w - 5) chart.plot_height = int(h - 5) return genMarkup( notebook_div(gridplot(charts, ncols=ncols, nrows=nrows))) # no longer part of bokeh # https://github.com/bokeh/bokeh/pull/6928#issuecomment-329040653 # https://www.bvbcode.com/code/9xhgwcsf-2674609 def _load_notebook_html(self, resources=None, hide_banner=False, load_timeout=5000): from bokeh.core.templates import AUTOLOAD_NB_JS from bokeh.util.serialization import make_id from bokeh.resources import CDN if resources is None: resources = CDN element_id = make_id() js = AUTOLOAD_NB_JS.render(elementid='' if hide_banner else element_id, js_urls=resources.js_files, css_urls=resources.css_files, js_raw=resources.js_raw, css_raw=resources.css_raw_str, force=1, timeout=load_timeout) return js
class BokehStreamingDisplay(StreamingDisplay): CellHandshake.addCallbackSniffer( lambda: "{'nostore_bokeh':!!window.Bokeh}") def __init__(self, options, entity, dataHandler=None): super(BokehStreamingDisplay, self).__init__(options, entity, dataHandler) self.handleId = None self.TOOLS = "crosshair,pan,wheel_zoom,box_zoom,reset,tap,box_select,lasso_select" self.figure = figure(tools=self.TOOLS) self.figure.axis.major_label_text_font_size = "18pt" self.hover = HoverTool(tooltips=None, mode="vline") self.figure.add_tools(self.hover) self.comms_handle = None self.glyphRenderer = None self.setup() def setup(self): pass def createGlyphRenderer(self, figure): return None def updateGlyphRenderer(self, figure, glyphRenderer): pass def _concatArrays(self, a, b): if type(a) != type(b): raise Exception("Can't concatenate objects of different types") if isinstance(a, list): return a + b elif isinstance(a, np.ndarray): return np.concatenate((a, b)) raise Exception("Can't concatenate: unsupported types") def _delWindowElements(self, array): if isinstance(array, list): del array[:len(array) - self.windowSize] return array elif isinstance(array, np.ndarray): array = np.delete(array, range(0, len(array) - self.windowSize)) return array raise Exception("Can't delete: unsupported type") def _toNPArray(self, a): if isinstance(a, list): return np.array(a) elif isinstance(a, np.ndarray): return a raise Exception("Can't cast to np array: unsupported type") def doRender(self, handlerId): clientHasBokeh = self.options.get("nostore_bokeh", "false") == "true" if not clientHasBokeh: output_notebook(hide_banner=True) data = self.entity.getNextData() if data is None: return x = None y = None if isinstance(data, (list, np.ndarray)): x = list( range(self.windowSize) ) if self.glyphRenderer is None else self.glyphRenderer.data_source.data[ 'x'] y = data if self.glyphRenderer is None else self._concatArrays( self.glyphRenderer.data_source.data['y'], data) if len(y) < self.windowSize: y = [0] * (self.windowSize - len(y)) + y elif len(y) > self.windowSize: y = self._delWindowElements(y) elif isinstance(data, pandas.core.frame.DataFrame): pd = pd.drop(pd.index[[0]]) #pd.index = list(range(len(pd.index))) pd['x'] = list(range(len(pd.index))) else: x = data[0] y = data[1] if self.glyphRenderer is None: self.glyphRenderer = self.createGlyphRenderer(self.figure, x, y) else: self.updateGlyphRenderer(self.figure, self.glyphRenderer) if self.glyphRenderer is None: print("Error: no glyphRenderer found") return self.glyphRenderer.data_source.data['x'] = x self.glyphRenderer.data_source.data['y'] = y if not self.handleId: self.handleId = make_id() if self.figure not in _state.document.roots: _state.document.add_root(self.figure) target = notebook_div(self.figure, self.handleId) from IPython.display import display as ipythonDisplay, HTML, Javascript ipythonDisplay(HTML(target)) self.comms_handle = _CommsHandle(get_comms(self.handleId), _state.document, _state.document.to_json()) else: push_notebook(handle=self.comms_handle)
class BokehBaseDisplay(with_metaclass(ABCMeta, BaseChartDisplay)): CellHandshake.addCallbackSniffer( lambda: "{'nostore_bokeh':!!window.Bokeh}") #get the bokeh version try: bokeh_version = pkg_resources.get_distribution("bokeh").parsed_version._version.release except: bokeh_version = None self.exception("Unable to get bokeh version") def __init__(self, options, entity, dataHandler=None): super(BokehBaseDisplay,self).__init__(options,entity,dataHandler) #no support for orientation self.no_orientation = True """ Default implementation for creating a chart object. """ def createBokehChart(self): return figure() def getPreferredOutputWidth(self): return super(BokehBaseDisplay,self).getPreferredOutputWidth() * 0.92 def doRenderChart(self): def genMarkup(chartFigure): return self.env.from_string(""" {0} {{%for message in messages%}} <div>{{{{message}}}}</div> {{%endfor%}} """.format(chartFigure) ).render(messages=self.messages) if BokehBaseDisplay.bokeh_version < (0,12): raise Exception(""" <div>Incorrect version of Bokeh detected. Expected {0}, got {1}</div> <div>Please upgrade by using the following command: <b>!pip install --user --upgrade bokeh</b></div> """.format((0,12), BokehBaseDisplay.bokeh_version)) clientHasBokeh = self.options.get("nostore_bokeh", "false") == "true" if not clientHasBokeh: output_notebook(hide_banner=True) charts = self.createBokehChart() if not isinstance(charts, list): charts.add_tools(ResizeTool()) charts.title = self.options.get("title", "") charts.plot_width = int(self.getPreferredOutputWidth() - 10 ) charts.plot_height = int(self.getPreferredOutputHeight() - 10 ) charts.grid.grid_line_alpha=0.3 return genMarkup(notebook_div(charts)) else: from bokeh.layouts import gridplot ncols = 1 nrows = 2 if(len(charts) > nrows): ncols = int(len(charts) / nrows) if(len(charts) % nrows != 0): ncols = ncols + 1 w = self.getPreferredOutputWidth()/ncols if len(charts) > 1 else self.getPreferredOutputWidth() h = self.getPreferredOutputWidth()/nrows if len(charts) > 1 else self.getPreferredOutputWidth() for chart in charts: chart.plot_width = int(w - 5) chart.plot_height = int (h - 5) return genMarkup(notebook_div(gridplot(charts, ncols=ncols, nrows=nrows)))