From f03811297bc3a0ae682da21eaf4607d42ca92802 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Tue, 4 Feb 2020 19:50:20 +0100 Subject: [PATCH] Don't import rcParams but rather use mpl.rcParams. This helps letting modules be imported early in the init process, even before the rcParams object is constructed. I didn't change all cases, just those needed to make matplotlib.scale importable into matplotlib.colors. --- doc/devel/contributing.rst | 5 ++++ lib/matplotlib/path.py | 9 ++++--- lib/matplotlib/scale.py | 11 ++++---- lib/matplotlib/ticker.py | 53 ++++++++++++++++++++------------------ 4 files changed, 44 insertions(+), 34 deletions(-) diff --git a/doc/devel/contributing.rst b/doc/devel/contributing.rst index 434260dfd8f2..f9a115e47c1c 100644 --- a/doc/devel/contributing.rst +++ b/doc/devel/contributing.rst @@ -215,6 +215,11 @@ rules before submitting a pull request: import matplotlib.cbook as cbook import matplotlib.patches as mpatches + In general, Matplotlib modules should **not** import `.rcParams` using ``from + matplotlib import rcParams``, but rather access it as ``mpl.rcParams``. This + is because some modules are imported very early, before the `.rcParams` + singleton is constructed. + * If your change is a major new feature, add an entry to the ``What's new`` section by adding a new file in ``doc/users/next_whats_new`` (see :file:`doc/users/next_whats_new/README.rst` for more information). diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index 6068961a315f..49f9af911609 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -14,7 +14,8 @@ import numpy as np -from . import _path, cbook, rcParams +import matplotlib as mpl +from . import _path, cbook from .cbook import _to_unmasked_float_array, simple_linear_interpolation @@ -181,15 +182,15 @@ def _fast_from_codes_and_verts(cls, verts, codes, internals_from=None): pth._interpolation_steps = internals_from._interpolation_steps else: pth._should_simplify = True - pth._simplify_threshold = rcParams['path.simplify_threshold'] + pth._simplify_threshold = mpl.rcParams['path.simplify_threshold'] pth._interpolation_steps = 1 return pth def _update_values(self): - self._simplify_threshold = rcParams['path.simplify_threshold'] + self._simplify_threshold = mpl.rcParams['path.simplify_threshold'] self._should_simplify = ( self._simplify_threshold > 0 and - rcParams['path.simplify'] and + mpl.rcParams['path.simplify'] and len(self._vertices) >= 128 and (self._codes is None or np.all(self._codes <= Path.LINETO)) ) diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 7f3de75286ac..f61ca49993e7 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -13,7 +13,8 @@ import numpy as np from numpy import ma -from matplotlib import cbook, docstring, rcParams +import matplotlib as mpl +from matplotlib import cbook, docstring from matplotlib.ticker import ( NullFormatter, ScalarFormatter, LogFormatterSciNotation, LogitFormatter, NullLocator, LogLocator, AutoLocator, AutoMinorLocator, @@ -108,8 +109,8 @@ def set_default_locators_and_formatters(self, axis): axis.set_major_formatter(ScalarFormatter()) axis.set_minor_formatter(NullFormatter()) # update the minor locator for x and y axis based on rcParams - if (axis.axis_name == 'x' and rcParams['xtick.minor.visible'] - or axis.axis_name == 'y' and rcParams['ytick.minor.visible']): + if (axis.axis_name == 'x' and mpl.rcParams['xtick.minor.visible'] + or axis.axis_name == 'y' and mpl.rcParams['ytick.minor.visible']): axis.set_minor_locator(AutoMinorLocator()) else: axis.set_minor_locator(NullLocator()) @@ -193,8 +194,8 @@ def set_default_locators_and_formatters(self, axis): axis.set_major_formatter(ScalarFormatter()) axis.set_minor_formatter(NullFormatter()) # update the minor locator for x and y axis based on rcParams - if (axis.axis_name == 'x' and rcParams['xtick.minor.visible'] - or axis.axis_name == 'y' and rcParams['ytick.minor.visible']): + if (axis.axis_name == 'x' and mpl.rcParams['xtick.minor.visible'] + or axis.axis_name == 'y' and mpl.rcParams['ytick.minor.visible']): axis.set_minor_locator(AutoMinorLocator()) else: axis.set_minor_locator(NullLocator()) diff --git a/lib/matplotlib/ticker.py b/lib/matplotlib/ticker.py index f8764711dde9..f370a97dc77a 100644 --- a/lib/matplotlib/ticker.py +++ b/lib/matplotlib/ticker.py @@ -168,8 +168,10 @@ import logging import locale import math + import numpy as np -from matplotlib import rcParams + +import matplotlib as mpl from matplotlib import cbook from matplotlib import transforms as mtransforms @@ -291,7 +293,7 @@ def fix_minus(s): :rc:`axes.unicode_minus`. """ return (s.replace('-', '\N{MINUS SIGN}') - if rcParams['axes.unicode_minus'] + if mpl.rcParams['axes.unicode_minus'] else s) def _set_locator(self, locator): @@ -515,19 +517,20 @@ def __init__(self, useOffset=None, useMathText=None, useLocale=None): # and scientific notation in mathtext if useOffset is None: - useOffset = rcParams['axes.formatter.useoffset'] - self._offset_threshold = rcParams['axes.formatter.offset_threshold'] + useOffset = mpl.rcParams['axes.formatter.useoffset'] + self._offset_threshold = \ + mpl.rcParams['axes.formatter.offset_threshold'] self.set_useOffset(useOffset) - self._usetex = rcParams['text.usetex'] + self._usetex = mpl.rcParams['text.usetex'] if useMathText is None: - useMathText = rcParams['axes.formatter.use_mathtext'] + useMathText = mpl.rcParams['axes.formatter.use_mathtext'] self.set_useMathText(useMathText) self.orderOfMagnitude = 0 self.format = '' self._scientific = True - self._powerlimits = rcParams['axes.formatter.limits'] + self._powerlimits = mpl.rcParams['axes.formatter.limits'] if useLocale is None: - useLocale = rcParams['axes.formatter.use_locale'] + useLocale = mpl.rcParams['axes.formatter.use_locale'] self._useLocale = useLocale def get_useOffset(self): @@ -548,7 +551,7 @@ def get_useLocale(self): def set_useLocale(self, val): if val is None: - self._useLocale = rcParams['axes.formatter.use_locale'] + self._useLocale = mpl.rcParams['axes.formatter.use_locale'] else: self._useLocale = val @@ -559,7 +562,7 @@ def get_useMathText(self): def set_useMathText(self, val): if val is None: - self._useMathText = rcParams['axes.formatter.use_mathtext'] + self._useMathText = mpl.rcParams['axes.formatter.use_mathtext'] else: self._useMathText = val @@ -882,7 +885,7 @@ def __init__(self, base=10.0, labelOnlyBase=False, self._base = float(base) self.labelOnlyBase = labelOnlyBase if minor_thresholds is None: - if rcParams['_internal.classic_mode']: + if mpl.rcParams['_internal.classic_mode']: minor_thresholds = (0, 0) else: minor_thresholds = (1, 0.4) @@ -1075,8 +1078,8 @@ def __call__(self, x, pos=None): The position *pos* is ignored. """ - usetex = rcParams['text.usetex'] - min_exp = rcParams['axes.formatter.min_exponent'] + usetex = mpl.rcParams['text.usetex'] + min_exp = mpl.rcParams['axes.formatter.min_exponent'] if x == 0: # Symlog return r'$\mathdefault{0}$' @@ -1400,7 +1403,7 @@ def get_usetex(self): def set_usetex(self, val): if val is None: - self._usetex = rcParams['text.usetex'] + self._usetex = mpl.rcParams['text.usetex'] else: self._usetex = val @@ -1411,7 +1414,7 @@ def get_useMathText(self): def set_useMathText(self, val): if val is None: - self._useMathText = rcParams['axes.formatter.use_mathtext'] + self._useMathText = mpl.rcParams['axes.formatter.use_mathtext'] else: self._useMathText = val @@ -1580,7 +1583,7 @@ def symbol(self): symbol = self._symbol if not symbol: symbol = '' - elif rcParams['text.usetex'] and not self._is_latex: + elif mpl.rcParams['text.usetex'] and not self._is_latex: # Source: http://www.personal.ceu.hu/tex/specchar.htm # Backslash must be first for this to work correctly since # it keeps getting added in @@ -1876,7 +1879,7 @@ def view_limits(self, vmin, vmax): vmin -= 1 vmax += 1 - if rcParams['axes.autolimit_mode'] == 'round_numbers': + if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers': exponent, remainder = divmod( math.log10(vmax - vmin), math.log10(max(self.numticks - 1, 1))) exponent -= (remainder < .5) @@ -1919,7 +1922,7 @@ def view_limits(self, dmin, dmax): Set the view limits to the nearest multiples of base that contain the data. """ - if rcParams['axes.autolimit_mode'] == 'round_numbers': + if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers': vmin = self._edge.le(dmin) * self._edge.step vmax = self._edge.ge(dmax) * self._edge.step if vmin == vmax: @@ -2145,7 +2148,7 @@ def _raw_ticks(self, vmin, vmax): istep = np.nonzero(steps >= raw_step)[0][0] # Classic round_numbers mode may require a larger step. - if rcParams['axes.autolimit_mode'] == 'round_numbers': + if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers': for istep in range(istep, len(steps)): step = steps[istep] best_vmin = (_vmin // step) * step @@ -2205,7 +2208,7 @@ def view_limits(self, dmin, dmax): dmin, dmax = mtransforms.nonsingular( dmin, dmax, expander=1e-12, tiny=1e-13) - if rcParams['axes.autolimit_mode'] == 'round_numbers': + if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers': return self._raw_ticks(dmin, dmax)[[0, -1]] else: return dmin, dmax @@ -2317,7 +2320,7 @@ def __init__(self, base=10.0, subs=(1.0,), numdecs=4, numticks=None): """ if numticks is None: - if rcParams['_internal.classic_mode']: + if mpl.rcParams['_internal.classic_mode']: numticks = 15 else: numticks = 'auto' @@ -2420,7 +2423,7 @@ def tick_values(self, vmin, vmax): # Get decades between major ticks. stride = (max(math.ceil(numdec / (numticks - 1)), 1) - if rcParams['_internal.classic_mode'] else + if mpl.rcParams['_internal.classic_mode'] else (numdec + 1) // numticks + 1) # Does subs include anything other than 1? Essentially a hack to know @@ -2469,7 +2472,7 @@ def view_limits(self, vmin, vmax): vmax = math.ceil(math.log(vmax) / math.log(b)) vmin = b ** (vmax - self.numdecs) - if rcParams['axes.autolimit_mode'] == 'round_numbers': + if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers': vmin = _decade_less_equal(vmin, self._base) vmax = _decade_greater_equal(vmax, self._base) @@ -2627,7 +2630,7 @@ def view_limits(self, vmin, vmax): if vmax < vmin: vmin, vmax = vmax, vmin - if rcParams['axes.autolimit_mode'] == 'round_numbers': + if mpl.rcParams['axes.autolimit_mode'] == 'round_numbers': vmin = _decade_less_equal(vmin, b) vmax = _decade_greater_equal(vmax, b) if vmin == vmax: @@ -2797,7 +2800,7 @@ def __init__(self): To know the values of the non-public parameters, please have a look to the defaults of `~matplotlib.ticker.MaxNLocator`. """ - if rcParams['_internal.classic_mode']: + if mpl.rcParams['_internal.classic_mode']: nbins = 9 steps = [1, 2, 5, 10] else: