|
17 | 17 | import matplotlib.font_manager as mfonts
|
18 | 18 | import matplotlib.colors as mcolors
|
19 | 19 | import matplotlib.style.core as mstyle
|
| 20 | +import matplotlib.cbook as cbook |
20 | 21 | import numbers
|
21 | 22 | import cycler
|
22 | 23 | from collections import namedtuple
|
@@ -903,7 +904,7 @@ def reset(self, local=True, user=True, default=True):
|
903 | 904 | # "style", and do not use rc_quick to apply any default settings -- this
|
904 | 905 | # should be for user convenience only and shold not be used internally.
|
905 | 906 | if default:
|
906 |
| - mstyle.use('default') |
| 907 | + rc_params.update(_get_style_dicts('original', infer=False)) |
907 | 908 | rc_params.update(defaults._rc_params_default) # proplot changes
|
908 | 909 | rc_added.update(defaults._rc_added_default) # proplot custom params
|
909 | 910 | rc_quick.update(defaults._rc_quick_default) # proplot quick params
|
@@ -1021,9 +1022,145 @@ def config_inline_backend(fmt=None):
|
1021 | 1022 | ipython.magic('config InlineBackend.rc = {}')
|
1022 | 1023 | ipython.magic('config InlineBackend.close_figures = True')
|
1023 | 1024 | ipython.magic("config InlineBackend.print_figure_kwargs = {'bbox_inches': None}")
|
1024 |
| - ipython.magic( # use ProPlot tight layout instead |
1025 |
| - 'config InlineBackend.print_figure_kwargs = {"bbox_inches": None}' |
1026 |
| - ) |
| 1025 | + |
| 1026 | + |
| 1027 | +def _get_default_dict(): |
| 1028 | + """ |
| 1029 | + Get the default rc parameters dictionary with deprecated parameters filtered. |
| 1030 | + """ |
| 1031 | + # NOTE: Use RcParams update to filter and translate deprecated settings |
| 1032 | + # before actually applying them to rcParams down pipeline. This way we can |
| 1033 | + # suppress warnings for deprecated default params but still issue warnings |
| 1034 | + # when user-supplied stylesheets have deprecated params. |
| 1035 | + # WARNING: Some deprecated rc params remain in dictionary as None so we |
| 1036 | + # filter them out. Beware if hidden attribute changes. |
| 1037 | + rcdict = _get_filtered_dict(mpl.rcParamsDefault, warn=False) |
| 1038 | + with cbook._suppress_matplotlib_deprecation_warning(): |
| 1039 | + rcdict = dict(mpl.RcParams(rcdict)) |
| 1040 | + for attr in ('_deprecated_remain_as_none', '_deprecated_set'): |
| 1041 | + if hasattr(mpl, attr): # _deprecated_set is in matplotlib before v3 |
| 1042 | + for deprecated in getattr(mpl, attr): |
| 1043 | + rcdict.pop(deprecated, None) |
| 1044 | + return rcdict |
| 1045 | + |
| 1046 | + |
| 1047 | +def _get_filtered_dict(rcdict, warn=True): |
| 1048 | + """ |
| 1049 | + Filter out blacklisted style parameters. |
| 1050 | + """ |
| 1051 | + # NOTE: This implements bugfix: https://github.com/matplotlib/matplotlib/pull/17252 |
| 1052 | + # This fix is *critical* for proplot because we always run style.use() |
| 1053 | + # when the configurator is made. Without fix backend is reset every time |
| 1054 | + # you import proplot in jupyter notebooks. So apply retroactively. |
| 1055 | + rcdict_filtered = {} |
| 1056 | + for key in rcdict: |
| 1057 | + if key in mstyle.STYLE_BLACKLIST: |
| 1058 | + if warn: |
| 1059 | + warnings._warn_proplot( |
| 1060 | + f'Dictionary includes a parameter, {key!r}, that is not related ' |
| 1061 | + 'to style. Ignoring.' |
| 1062 | + ) |
| 1063 | + else: |
| 1064 | + rcdict_filtered[key] = rcdict[key] |
| 1065 | + return rcdict_filtered |
| 1066 | + |
| 1067 | + |
| 1068 | +def _get_style_dicts(style, infer=False): |
| 1069 | + """ |
| 1070 | + Return a dictionary of settings belonging to the requested style(s). If `infer` |
| 1071 | + is ``True``, two dictionaries are returned, where the second contains custom |
| 1072 | + ProPlot settings "inferred" from the matplotlib settings. |
| 1073 | + """ |
| 1074 | + # NOTE: This is adapted from matplotlib source for the following changes: |
| 1075 | + # 1. Add 'original' option. Like rcParamsOrig except we also *reload* |
| 1076 | + # from user matplotlibrc file. |
| 1077 | + # 2. When the style is changed we reset to the *default* state ignoring |
| 1078 | + # matplotlibrc. Matplotlib applies styles on top of current state |
| 1079 | + # (including matplotlibrc changes and runtime rcParams changes) but |
| 1080 | + # IMO the word 'style' implies a *rigid* static format. |
| 1081 | + # 3. Add a separate function that returns lists of style dictionaries so |
| 1082 | + # that we can modify the active style in a context block. ProPlot context |
| 1083 | + # is more conservative than matplotlib's rc_context because it gets |
| 1084 | + # called a lot (e.g. every time you make an axes and every format() call). |
| 1085 | + # Instead of copying the entire rcParams dict we just track the keys |
| 1086 | + # that were changed. |
| 1087 | + style_aliases = { |
| 1088 | + '538': 'fivethirtyeight', |
| 1089 | + 'mpl20': 'default', |
| 1090 | + 'mpl15': 'classic', |
| 1091 | + 'original': mpl.matplotlib_fname(), |
| 1092 | + } |
| 1093 | + if isinstance(style, str) or isinstance(style, dict): |
| 1094 | + styles = [style] |
| 1095 | + else: |
| 1096 | + styles = style |
| 1097 | + |
| 1098 | + # Always apply the default style *first* so styles are rigid |
| 1099 | + kw_params = _get_default_dict() |
| 1100 | + if style == 'default' or style is mpl.rcParamsDefault: |
| 1101 | + return kw_params |
| 1102 | + |
| 1103 | + # Apply "pseudo" default properties. Pretend some proplot settings are part of |
| 1104 | + # the matplotlib specification so they propagate to other styles. |
| 1105 | + kw_params['font.family'] = 'sans-serif' |
| 1106 | + kw_params['font.sans-serif'] = defaults._rc_params_default['font.sans-serif'] |
| 1107 | + |
| 1108 | + # Apply user input style(s) one by one |
| 1109 | + # NOTE: Always use proplot fonts if style does not explicitly set them. |
| 1110 | + for style in styles: |
| 1111 | + if isinstance(style, dict): |
| 1112 | + kw = style |
| 1113 | + elif isinstance(style, str): |
| 1114 | + style = style_aliases.get(style, style) |
| 1115 | + if style in mstyle.library: |
| 1116 | + kw = mstyle.library[style] |
| 1117 | + else: |
| 1118 | + try: |
| 1119 | + kw = mpl.rc_params_from_file(style, use_default_template=False) |
| 1120 | + except IOError: |
| 1121 | + raise IOError( |
| 1122 | + f'Style {style!r} not found in the style library and input is ' |
| 1123 | + 'not a valid URL or path. Available styles are: ' |
| 1124 | + + ', '.join(map(repr, mstyle.available)) + '.' |
| 1125 | + ) |
| 1126 | + else: |
| 1127 | + raise ValueError(f'Invalid style {style!r}. Must be string or dictionary.') |
| 1128 | + kw = _get_filtered_dict(kw, warn=True) |
| 1129 | + kw_params.update(kw) |
| 1130 | + |
| 1131 | + # Infer proplot params from stylesheet params |
| 1132 | + if infer: |
| 1133 | + kw_added = _infer_added_params(kw_params) |
| 1134 | + return kw_params, kw_added |
| 1135 | + else: |
| 1136 | + return kw_params |
| 1137 | + |
| 1138 | + |
| 1139 | +def _infer_added_params(kw_params): |
| 1140 | + """ |
| 1141 | + Infer values for proplot's "added" parameters from stylesheets. |
| 1142 | + """ |
| 1143 | + kw_added = {} |
| 1144 | + mpl_to_proplot = { |
| 1145 | + 'font.size': ('tick.labelsize',), |
| 1146 | + 'axes.titlesize': ( |
| 1147 | + 'abc.size', 'suptitle.size', 'title.size', |
| 1148 | + 'leftlabel.size', 'rightlabel.size', |
| 1149 | + 'toplabel.size', 'bottomlabel.size', |
| 1150 | + ), |
| 1151 | + 'axes.facecolor': ('geoaxes.facecolor',), |
| 1152 | + 'text.color': ( |
| 1153 | + 'abc.color', 'suptitle.color', 'tick.labelcolor', 'title.color', |
| 1154 | + 'leftlabel.color', 'rightlabel.color', |
| 1155 | + 'toplabel.color', 'bottomlabel.color', |
| 1156 | + ), |
| 1157 | + } |
| 1158 | + for key, params in mpl_to_proplot.items(): |
| 1159 | + if key in kw_params: |
| 1160 | + value = kw_params[key] |
| 1161 | + for param in params: |
| 1162 | + kw_added[param] = value |
| 1163 | + return kw_added |
1027 | 1164 |
|
1028 | 1165 |
|
1029 | 1166 | @docstring.add_snippets
|
|
0 commit comments