Coverage for matplotlib\style\core.py: 0%

# Coverage for matplotlib\style\core.py : 0%

## 98 statements 0 run 98 missing 0 excluded

Hot-keys on this page

r m x p toggle line displays

j k next/prev highlighted chunk

0 (zero) top of page

1 (one) first highlighted chunk

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 | from __future__ import absolute_import, division, print_function import six """ Core functions and attributes for the matplotlib style library: ``use`` Select style sheet to override the current matplotlib settings. ``context`` Context manager to use a style sheet temporarily. ``available`` List available style sheets. ``library`` A dictionary of style names and matplotlib settings. """ import os import re import contextlib import warnings import matplotlib as mpl from matplotlib import rc_params_from_file, rcParamsDefault __all__ = ['use', 'context', 'available', 'library', 'reload_library'] BASE_LIBRARY_PATH = os.path.join(mpl.get_data_path(), 'stylelib') # Users may want multiple library paths, so store a list of paths. USER_LIBRARY_PATHS = [os.path.join(mpl._get_configdir(), 'stylelib')] STYLE_EXTENSION = 'mplstyle' STYLE_FILE_PATTERN = re.compile(r'([\S]+).%s$' % STYLE_EXTENSION) # A list of rcParams that should not be applied from styles STYLE_BLACKLIST = { 'interactive', 'backend', 'backend.qt4', 'webagg.port', 'webagg.address', 'webagg.port_retries', 'webagg.open_in_browser', 'backend_fallback', 'toolbar', 'timezone', 'datapath', 'figure.max_open_warning', 'savefig.directory', 'tk.window_focus', 'docstring.hardcopy'} def _remove_blacklisted_style_params(d, warn=True): o = {} for key, val in d.items(): if key in STYLE_BLACKLIST: if warn: warnings.warn( "Style includes a parameter, '{0}', that is not related " "to style. Ignoring".format(key)) else: o[key] = val return o def is_style_file(filename): """Return True if the filename looks like a style file.""" return STYLE_FILE_PATTERN.match(filename) is not None def _apply_style(d, warn=True): mpl.rcParams.update(_remove_blacklisted_style_params(d, warn=warn)) def use(style): """Use matplotlib style settings from a style specification. The style name of 'default' is reserved for reverting back to the default style settings. Parameters ---------- style : str, dict, or list A style specification. Valid options are: +------+-------------------------------------------------------------+ | str | The name of a style or a path/URL to a style file. For a | | | list of available style names, see `style.available`. | +------+-------------------------------------------------------------+ | dict | Dictionary with valid key/value pairs for | | | `matplotlib.rcParams`. | +------+-------------------------------------------------------------+ | list | A list of style specifiers (str or dict) applied from first | | | to last in the list. | +------+-------------------------------------------------------------+ """ style_alias = {'mpl20': 'default', 'mpl15': 'classic'} if isinstance(style, six.string_types) or hasattr(style, 'keys'): # If name is a single str or dict, make it a single element list. styles = [style] else: styles = style styles = (style_alias.get(s, s) if isinstance(s, six.string_types) else s for s in styles) for style in styles: if not isinstance(style, six.string_types): _apply_style(style) elif style == 'default': _apply_style(rcParamsDefault, warn=False) elif style in library: _apply_style(library[style]) else: try: rc = rc_params_from_file(style, use_default_template=False) _apply_style(rc) except IOError: raise IOError( "{!r} not found in the style library and input is not a " "valid URL or path; see `style.available` for list of " "available styles".format(style)) @contextlib.contextmanager def context(style, after_reset=False): """Context manager for using style settings temporarily. Parameters ---------- style : str, dict, or list A style specification. Valid options are: +------+-------------------------------------------------------------+ | str | The name of a style or a path/URL to a style file. For a | | | list of available style names, see `style.available`. | +------+-------------------------------------------------------------+ | dict | Dictionary with valid key/value pairs for | | | `matplotlib.rcParams`. | +------+-------------------------------------------------------------+ | list | A list of style specifiers (str or dict) applied from first | | | to last in the list. | +------+-------------------------------------------------------------+ after_reset : bool If True, apply style after resetting settings to their defaults; otherwise, apply style on top of the current settings. """ initial_settings = mpl.rcParams.copy() if after_reset: mpl.rcdefaults() try: use(style) except: # Restore original settings before raising errors during the update. mpl.rcParams.update(initial_settings) raise else: yield finally: mpl.rcParams.update(initial_settings) def load_base_library(): """Load style library defined in this package.""" library = dict() library.update(read_style_directory(BASE_LIBRARY_PATH)) return library def iter_user_libraries(): for stylelib_path in USER_LIBRARY_PATHS: stylelib_path = os.path.expanduser(stylelib_path) if os.path.exists(stylelib_path) and os.path.isdir(stylelib_path): yield stylelib_path def update_user_library(library): """Update style library with user-defined rc files""" for stylelib_path in iter_user_libraries(): styles = read_style_directory(stylelib_path) update_nested_dict(library, styles) return library def iter_style_files(style_dir): """Yield file path and name of styles in the given directory.""" for path in os.listdir(style_dir): filename = os.path.basename(path) if is_style_file(filename): match = STYLE_FILE_PATTERN.match(filename) path = os.path.abspath(os.path.join(style_dir, path)) yield path, match.groups()[0] def read_style_directory(style_dir): """Return dictionary of styles defined in `style_dir`.""" styles = dict() for path, name in iter_style_files(style_dir): with warnings.catch_warnings(record=True) as warns: styles[name] = rc_params_from_file(path, use_default_template=False) for w in warns: message = 'In %s: %s' % (path, w.message) warnings.warn(message) return styles def update_nested_dict(main_dict, new_dict): """Update nested dict (only level of nesting) with new values. Unlike dict.update, this assumes that the values of the parent dict are dicts (or dict-like), so you shouldn't replace the nested dict if it already exists. Instead you should update the sub-dict. """ # update named styles specified by user for name, rc_dict in six.iteritems(new_dict): if name in main_dict: main_dict[name].update(rc_dict) else: main_dict[name] = rc_dict return main_dict # Load style library # ================== _base_library = load_base_library() library = None available = [] def reload_library(): """Reload style library.""" global library available[:] = library = update_user_library(_base_library) reload_library()