This docs on this page refers to a PREVIOUS VERSION. For the latest stable release, go to https://docs.bokeh.org/

Archived docs for versions <= 1.0.4 have had to be modified from their original published configuration, and may be missing some features (e.g. source listing)

All users are encourage to update to version 1.1 or later, as soon as they are able.

bokeh.themes.theme — Bokeh 0.12.4 documentation

Source code for bokeh.themes.theme

''' Provide a ``Theme`` class for specify overrides for default values
for Bokeh :class:`~bokeh.model.Model` properties.

'''
from __future__ import absolute_import, print_function

import yaml

from ..core.has_props import HasProps

# whenever we cache that there's nothing themed for a class, we
# use this same dict instance, so we don't have a zillion empty
# dicts in our caches.
_empty_dict = dict()

# Note: in DirectoryHandler and in general we assume this is an
# immutable object, because we share it among sessions and we
# don't monitor it for changes. If you make this mutable by adding
# any kind of setter, you could have to refactor some other code.
[docs]class Theme(object): ''' Args: filename (str, optional) : path to a YAML theme file json (str, optional) : a JSON dictionary specifying theme values Raises: ValueError If neither ``filename`` or ``json`` is supplied. ''' def __init__(self, filename=None, json=None): if (filename is not None) and (json is not None): raise ValueError("Theme should be constructed from a file or from json not both") if filename is not None: f = open(filename) try: json = yaml.load(f) # empty docs result in None rather than {}, fix it. if json is None: json = {} finally: f.close() if json is None: raise ValueError("Theme requires json or a filename to construct") self._json = json if 'attrs' not in self._json: self._json['attrs'] = {} if not isinstance(self._json['attrs'], dict): raise ValueError("theme problem: attrs field should be a dictionary of class names, not %r" % (self._json['attrs'])) for key, value in self._json['attrs'].items(): if not isinstance(value, dict): raise ValueError("theme problem: attrs.%s should be a dictionary of properties, not %r" % (key, value)) self._line_defaults = self._json.get('line_defaults', _empty_dict) self._fill_defaults = self._json.get('fill_defaults', _empty_dict) self._text_defaults = self._json.get('text_defaults', _empty_dict) # mapping from class name to the full set of properties # (including those merged in from base classes) for that # class. self._by_class_cache = {} def _add_glyph_defaults(self, cls, props): from ..models.glyphs import Glyph if issubclass(cls, Glyph): if hasattr(cls, "line_alpha"): props.update(self._line_defaults) if hasattr(cls, "fill_alpha"): props.update(self._fill_defaults) if hasattr(cls, "text_alpha"): props.update(self._text_defaults) def _for_class(self, cls): if cls.__name__ not in self._by_class_cache: attrs = self._json['attrs'] combined = {} # we go in reverse order so that subclass props override base class for base in cls.__mro__[-2::-1]: if not issubclass(base, HasProps): continue self._add_glyph_defaults(base, combined) combined.update(attrs.get(base.__name__, _empty_dict)) if len(combined) == 0: combined = _empty_dict self._by_class_cache[cls.__name__] = combined return self._by_class_cache[cls.__name__]
[docs] def apply_to_model(self, model): ''' Apply this theme to a model. .. warning:: Typically, don't call this method directly. Instead, set the theme on the :class:`~bokeh.document.Document` the model is a part of. ''' model.apply_theme(self._for_class(model.__class__)) # a little paranoia because it would be Bad(tm) to mess # this up... would be nicer if python had a way to freeze # the dict. if len(_empty_dict) > 0: raise RuntimeError("Somebody put stuff in _empty_dict")