1#----------------------------------------------------------------------------- 2# Copyright (c) 2012 - 2021, Anaconda, Inc., and Bokeh Contributors. 3# All rights reserved. 4# 5# The full license is in the file LICENSE.txt, distributed with this software. 6#----------------------------------------------------------------------------- 7''' Encapsulate implicit state that is useful for Bokeh plotting APIs. 8 9.. note:: 10 While ``State`` objects can also be manipulated explicitly, they are 11 automatically configured when the functions :func:`~bokeh.io.output_file`, 12 etc. from :ref:`bokeh.io` are used, so this is not necessary under 13 typical usage. 14 15Generating output for Bokeh plots requires coordinating several things: 16 17:class:`~bokeh.document.Document` 18 Groups together Bokeh models that may be shared between plots (e.g., 19 range or data source objects) into one common structure. 20 21:class:`~bokeh.resources.Resources` 22 Control how JavaScript and CSS for the client library BokehJS are 23 included and used in the generated output. 24 25It is possible to handle the configuration of these things manually, and some 26examples of doing this can be found in ``examples/models`` directory. When 27developing sophisticated applications, it may be necessary or desirable to work 28at this level. However, for general use this would quickly become burdensome. 29This module provides a ``State`` class that encapsulates these objects and 30ensures their proper configuration in many common usage scenarios. 31 32''' 33 34#----------------------------------------------------------------------------- 35# Boilerplate 36#----------------------------------------------------------------------------- 37import logging # isort:skip 38log = logging.getLogger(__name__) 39 40#----------------------------------------------------------------------------- 41# Imports 42#----------------------------------------------------------------------------- 43 44# Standard library imports 45import os 46 47# Bokeh imports 48from ..document import Document 49from ..resources import Resources 50 51#----------------------------------------------------------------------------- 52# Globals and constants 53#----------------------------------------------------------------------------- 54 55__all__ = ( 56 'curstate', 57 'State', 58) 59 60#----------------------------------------------------------------------------- 61# General API 62#----------------------------------------------------------------------------- 63 64class State: 65 ''' Manage state related to controlling Bokeh output. 66 67 ''' 68 def __init__(self): 69 self.last_comms_handle = None 70 self.uuid_to_server = {} # Mapping from uuid to server instance 71 self.reset() 72 73 # Properties -------------------------------------------------------------- 74 75 @property 76 def document(self): 77 ''' A default :class:`~bokeh.document.Document` to use for all 78 output operations. 79 80 ''' 81 return self._document 82 83 @document.setter 84 def document(self, doc): 85 self._document = doc 86 87 @property 88 def file(self): 89 ''' A dict with the default configuration for file output (READ ONLY) 90 91 The dictionary value has the following form: 92 93 .. code-block:: python 94 95 { 96 'filename' : # filename to use when saving 97 'resources' : # resources configuration 98 'title' : # a title for the HTML document 99 } 100 101 ''' 102 return self._file 103 104 @property 105 def notebook(self): 106 ''' Whether to generate notebook output on show operations. (READ ONLY) 107 108 ''' 109 return self._notebook 110 111 @property 112 def notebook_type(self): 113 ''' Notebook type 114 115 ''' 116 return self._notebook_type 117 118 @notebook_type.setter 119 def notebook_type(self, notebook_type): 120 ''' Notebook type, acceptable values are 'jupyter' as well as any names 121 defined by external notebook hooks that have been installed. 122 123 ''' 124 if notebook_type is None or not isinstance(notebook_type, str): 125 raise ValueError("Notebook type must be a string") 126 self._notebook_type = notebook_type.lower() 127 128 # Public methods ---------------------------------------------------------- 129 130 def output_file(self, filename, title="Bokeh Plot", mode=None, root_dir=None): 131 ''' Configure output to a standalone HTML file. 132 133 Calling ``output_file`` not clear the effects of any other calls to 134 ``output_notebook``, etc. It adds an additional output destination 135 (publishing to HTML files). Any other active output modes continue 136 to be active. 137 138 Args: 139 filename (str) : a filename for saving the HTML document 140 141 title (str, optional) : a title for the HTML document 142 143 mode (str, optional) : how to include BokehJS (default: ``'cdn'``) 144 145 One of: ``'inline'``, ``'cdn'``, ``'relative(-dev)'`` or 146 ``'absolute(-dev)'``. See :class:`~bokeh.resources.Resources` 147 for more details. 148 149 root_dir (str, optional) : root dir to use for absolute resources 150 (default: None) 151 152 This value is ignored for other resource types, e.g. ``INLINE`` or ``CDN``. 153 154 .. warning:: 155 The specified output file will be overwritten on every save, e.g., 156 every time ``show()`` or ``save()`` is called. 157 158 ''' 159 self._file = { 160 'filename' : filename, 161 'resources' : Resources(mode=mode, root_dir=root_dir), 162 'title' : title 163 } 164 165 if os.path.isfile(filename): 166 log.info("Session output file '%s' already exists, will be overwritten." % filename) 167 168 def output_notebook(self, notebook_type='jupyter'): 169 ''' Generate output in notebook cells. 170 171 Calling ``output_notebook`` not clear the effects of any other calls 172 to ``output_file``, etc. It adds an additional output destination 173 (publishing to notebook output cells). Any other active output modes 174 continue to be active. 175 176 Returns: 177 None 178 179 ''' 180 self._notebook = True 181 self.notebook_type = notebook_type 182 183 def reset(self): 184 ''' Deactivate all currently active output modes and set ``curdoc()`` 185 to a fresh empty ``Document``. 186 187 Subsequent calls to ``show()`` will not render until a new output mode 188 is activated. 189 190 Returns: 191 None 192 193 ''' 194 self._reset_with_doc(Document()) 195 196 # Private methods --------------------------------------------------------- 197 198 def _reset_keeping_doc(self): 199 ''' Reset output modes but DO NOT replace the default Document 200 201 ''' 202 self._file = None 203 self._notebook = False 204 self._notebook_type = None 205 206 def _reset_with_doc(self, doc): 207 ''' Reset output modes but DO replace the default Document 208 209 ''' 210 self._document = doc 211 self._reset_keeping_doc() 212 213def curstate(): 214 ''' Return the current State object 215 216 Returns: 217 State : the current default State object 218 219 ''' 220 global _STATE 221 if _STATE is None: 222 _STATE = State() 223 return _STATE 224 225#----------------------------------------------------------------------------- 226# Dev API 227#----------------------------------------------------------------------------- 228 229#----------------------------------------------------------------------------- 230# Private API 231#----------------------------------------------------------------------------- 232 233_STATE = None 234 235#----------------------------------------------------------------------------- 236# Code 237#----------------------------------------------------------------------------- 238