class_docstr: Provide new default values for Bokeh models.
  
  Bokeh Model properties all have some built-in default value. If a property
  has not been explicitly set (e.g. ``m.foo = 10``), accessing the
  property will return the default value. It may be useful for users to be
  able to specify a different set of default values than the built-in
  default. The ``Theme`` class allows collections of custom default values
  to be easily applied to Bokeh documents.
  
  The ``Theme`` class can be constructed either from a YAML file or from a
  JSON dict (but not both). Examples of both formats are shown below.
  
  The plotting API's defaults override some theme properties. Namely:
  `fill_alpha`, `fill_color`, `line_alpha`, `line_color`, `text_alpha` and
  `text_color`. Those properties should therefore be set explicitly when
  using the plotting API.
  
  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.
  
  Examples:
  
      Themes are specified by providing a top-level key ``attrs`` which
      has blocks for Model types to be themed. Each block has keys and
      values that specify the new property defaults for that type.
  
      Take note of the fact that YAML interprets the value `None` as
      a string, which is not usually what you want. To give `None` as a
      value in YAML, use `!!null`. To give 'None' as a value in json,
      use `null`.
  
      Here is an example theme in YAML format that sets various visual
      properties for all figures, grids, and titles:
  
      .. code-block:: yaml
  
          attrs:
              Plot:
                  background_fill_color: '#2F2F2F'
                  border_fill_color: '#2F2F2F'
                  outline_line_color: '#444444'
              Axis:
                  axis_line_color: !!null
              Grid:
                  grid_line_dash: [6, 4]
                  grid_line_alpha: .3
              Title:
                  text_color: "white"
  
      Here is the same theme, in JSON format:
  
      .. code-block:: python
  
          {
              'attrs' : {
                  'Plot': {
                      'background_fill_color': '#2F2F2F',
                      'border_fill_color': '#2F2F2F',
                      'outline_line_color': '#444444',
                  },
                  'Axis': {
                      'axis_line_color': None,
                  },
                  'Grid': {
                      'grid_line_dash': [6, 4],
                      'grid_line_alpha': .3,
                  },
                  'Title': {
                      'text_color': 'white'
                  }
              }
          }
code: def __init__(
      self,
      filename: PathLike | None = None,
      json: dict[str, Any] | None = None,
  ) -> 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:
          with open(filename, "rb") as f:
              json = yaml.safe_load(f)
              # empty docs result in None rather than {}, fix it.
              if json is None:
                  json = {}
  
      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(
              f"theme problem: attrs field should be a dictionary of class names, not {self._json['attrs']!r}"
          )
  
      for key, value in self._json["attrs"].items():
          if not isinstance(value, dict):
              raise ValueError(
                  f"theme problem: attrs.{key} should be a dictionary of properties, not {value!r}"
              )
  
      # Special-case to allow Figure to continue working with a deprecation
      if "Figure" in self._json["attrs"]:
          self._json["attrs"]["figure"] = self._json["attrs"]["Figure"]
          del self._json["attrs"]["Figure"]
          deprecated(
              (3, 0, 0),
              "Use of 'Figure' as a key in Theme attributes",
              "'figure' (lower-case) as a key",
          )
  
      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 = {}
  
file_path: bokeh/src/bokeh/themes/theme.py
imports: from __future__ import annotations
  import logging
  from typing import TYPE_CHECKING, Any, overload
  import yaml
  from ..core.has_props import HasProps
  from ..core.types import PathLike
  from ..util.deprecation import deprecated
label_desc: Use image node_id 3 to create a new Theme object  with example: obj = Theme(filename, json)