From afb6aaa05539872776c9b590638d4795535d010f Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Fri, 20 Sep 2019 08:43:04 -0500 Subject: [PATCH 1/9] DEPR: Remove matplotlib implicit warning --- ci/code_checks.sh | 2 +- doc/source/whatsnew/v1.0.0.rst | 24 +++++++- pandas/core/config_init.py | 6 +- pandas/plotting/_core.py | 6 -- pandas/plotting/_matplotlib/boxplot.py | 3 - pandas/plotting/_matplotlib/converter.py | 70 ++++++++++++----------- pandas/plotting/_matplotlib/core.py | 9 +-- pandas/plotting/_matplotlib/hist.py | 3 - pandas/plotting/_matplotlib/timeseries.py | 4 +- pandas/tests/plotting/test_converter.py | 44 +++----------- 10 files changed, 79 insertions(+), 92 deletions(-) diff --git a/ci/code_checks.sh b/ci/code_checks.sh index b03c4f2238445..97a09fa8c50f5 100755 --- a/ci/code_checks.sh +++ b/ci/code_checks.sh @@ -204,7 +204,7 @@ import sys import pandas blacklist = {'bs4', 'gcsfs', 'html5lib', 'http', 'ipython', 'jinja2', 'hypothesis', - 'lxml', 'numexpr', 'openpyxl', 'py', 'pytest', 's3fs', 'scipy', + 'lxml', 'matplotlib', 'numexpr', 'openpyxl', 'py', 'pytest', 's3fs', 'scipy', 'tables', 'urllib.request', 'xlrd', 'xlsxwriter', 'xlwt'} # GH#28227 for some of these check for top-level modules, while others are diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 173cc6b6b483c..f7ab633ca8781 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -101,6 +101,10 @@ Backwards incompatible API changes pd.arrays.IntervalArray.from_tuples([(0, 1), (2, 3)]) +- Changed the default configuration value for ``options.matplotlib.register_converters`` from ``True`` to ``"auto"`` (:issue:``). + Now, pandas custom formatters will only be applied to plots created by pandas, through :meth:`~DataFrame.plot`. + Previously, pandas' formatters would be applied to all plots created *after* a :meth:`~DataFrame.plot`. + .. _whatsnew_1000.api.other: @@ -109,7 +113,6 @@ Other API changes - :meth:`pandas.api.types.infer_dtype` will now return "integer-na" for integer and ``np.nan`` mix (:issue:`27283`) - :meth:`MultiIndex.from_arrays` will no longer infer names from arrays if ``names=None`` is explicitly provided (:issue:`27292`) -- .. _whatsnew_1000.deprecations: @@ -132,6 +135,25 @@ See :ref:`sparse.migration` for help with migrating existing code. Removal of prior version deprecations/changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +**Matplotlib unit registration** + +Previously, pandas would register converters with matplotlib as a side effect of importing pandas (:issue:`18720`). +This changed the output of plots made via matplotlib plots after pandas was imported, even if you were using +matplotlib directly rather than rather than :meth:`~DataFrame.plot`. + +To use pandas formatters with a matplotlib plot, specify + +.. code-block:: python + + >>> import pandas as pd + >>> pd.options.plotting.matplotlib.register_converters = True + +Note that plots created by :meth:`DataFrame.plot` and :meth:`Series.plot` *do* register the converters +automatically. The only behavior change is when plotting a date-like object via ``matplotlib.pyplot.plot`` +or ``matplotlib.Axes.plot``. + +**Other removals** + - Removed the previously deprecated :meth:`Series.get_value`, :meth:`Series.set_value`, :meth:`DataFrame.get_value`, :meth:`DataFrame.set_value` (:issue:`17739`) - Changed the the default value of `inplace` in :meth:`DataFrame.set_index` and :meth:`Series.set_axis`. It now defaults to False (:issue:`27600`) - :meth:`pandas.Series.str.cat` now defaults to aligning ``others``, using ``join='left'`` (:issue:`27611`) diff --git a/pandas/core/config_init.py b/pandas/core/config_init.py index bc2eb3511629d..ba0a4d81a88d3 100644 --- a/pandas/core/config_init.py +++ b/pandas/core/config_init.py @@ -599,7 +599,7 @@ def register_plotting_backend_cb(key): register_converter_doc = """ -: bool +: bool or 'auto'. Whether to register converters with matplotlib's units registry for dates, times, datetimes, and Periods. Toggling to False will remove the converters, restoring any converters that pandas overwrote. @@ -619,8 +619,8 @@ def register_converter_cb(key): with cf.config_prefix("plotting.matplotlib"): cf.register_option( "register_converters", - True, + "auto", register_converter_doc, - validator=bool, + validator=is_one_of_factory(["auto", True, False]), cb=register_converter_cb, ) diff --git a/pandas/plotting/_core.py b/pandas/plotting/_core.py index fe6b339c2f4c8..eab763c81ff88 100644 --- a/pandas/plotting/_core.py +++ b/pandas/plotting/_core.py @@ -3,7 +3,6 @@ from pandas._config import get_option -from pandas.compat._optional import import_optional_dependency from pandas.util._decorators import Appender from pandas.core.dtypes.common import is_integer, is_list_like @@ -11,11 +10,6 @@ from pandas.core.base import PandasObject -# Trigger matplotlib import, which implicitly registers our -# converts. Implicit registration is deprecated, and when enforced -# we can lazily import matplotlib. -import_optional_dependency("pandas.plotting._matplotlib", raise_on_missing=False) - def hist_series( self, diff --git a/pandas/plotting/_matplotlib/boxplot.py b/pandas/plotting/_matplotlib/boxplot.py index 99035013092cc..9787f7fcb0544 100644 --- a/pandas/plotting/_matplotlib/boxplot.py +++ b/pandas/plotting/_matplotlib/boxplot.py @@ -11,7 +11,6 @@ import pandas as pd from pandas.io.formats.printing import pprint_thing -from pandas.plotting._matplotlib import converter from pandas.plotting._matplotlib.core import LinePlot, MPLPlot from pandas.plotting._matplotlib.style import _get_standard_colors from pandas.plotting._matplotlib.tools import _flatten, _subplots @@ -366,7 +365,6 @@ def boxplot_frame( ): import matplotlib.pyplot as plt - converter._WARN = False # no warning for pandas plots ax = boxplot( self, column=column, @@ -398,7 +396,6 @@ def boxplot_frame_groupby( sharey=True, **kwds ): - converter._WARN = False # no warning for pandas plots if subplots is True: naxes = len(grouped) fig, axes = _subplots( diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 446350cb5d915..bde230108ea0f 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -1,6 +1,7 @@ +import contextlib import datetime as pydt from datetime import datetime, timedelta -import warnings +import functools from dateutil.relativedelta import relativedelta import matplotlib.dates as dates @@ -23,6 +24,7 @@ ) from pandas.core.dtypes.generic import ABCSeries +from pandas import get_option import pandas.core.common as com from pandas.core.index import Index from pandas.core.indexes.datetimes import date_range @@ -39,7 +41,6 @@ MUSEC_PER_DAY = 1e6 * SEC_PER_DAY -_WARN = True # Global for whether pandas has registered the units explicitly _mpl_units = {} # Cache for units overwritten by us @@ -55,13 +56,43 @@ def get_pairs(): return pairs -def register(explicit=True): - # Renamed in pandas.plotting.__init__ - global _WARN +def pandas_converters_deco(func): + """ + Decorator applying pandas_converters. + """ + + @functools.wraps(func) + def wrapper(*args, **kwargs): + with pandas_converters(): + return func(*args, **kwargs) - if explicit: - _WARN = False + return wrapper + +@contextlib.contextmanager +def pandas_converters(): + """ + Context manager registering pandas' converters for a plot. + + When + See Also + -------- + pandas_converters_deco : Decorator that applies this. + """ + value = get_option("plotting.matplotlib.register_converters") + + if value: + # register for True or "auto" + register() + try: + yield + finally: + if value == "auto": + # only deregister for "auto" + deregister() + + +def register(): pairs = get_pairs() for type_, cls in pairs: # Cache previous converter if present @@ -86,24 +117,6 @@ def deregister(): units.registry[unit] = formatter -def _check_implicitly_registered(): - global _WARN - - if _WARN: - msg = ( - "Using an implicitly registered datetime converter for a " - "matplotlib plotting method. The converter was registered " - "by pandas on import. Future versions of pandas will require " - "you to explicitly register matplotlib converters.\n\n" - "To register the converters:\n\t" - ">>> from pandas.plotting import register_matplotlib_converters" - "\n\t" - ">>> register_matplotlib_converters()" - ) - warnings.warn(msg, FutureWarning) - _WARN = False - - def _to_ordinalf(tm): tot_sec = tm.hour * 3600 + tm.minute * 60 + tm.second + float(tm.microsecond / 1e6) return tot_sec @@ -253,7 +266,6 @@ class DatetimeConverter(dates.DateConverter): @staticmethod def convert(values, unit, axis): # values might be a 1-d array, or a list-like of arrays. - _check_implicitly_registered() if is_nested_list_like(values): values = [DatetimeConverter._convert_1d(v, unit, axis) for v in values] else: @@ -330,7 +342,6 @@ def __init__(self, locator, tz=None, defaultfmt="%Y-%m-%d"): class PandasAutoDateLocator(dates.AutoDateLocator): def get_locator(self, dmin, dmax): """Pick the best locator based on a distance.""" - _check_implicitly_registered() delta = relativedelta(dmax, dmin) num_days = (delta.years * 12.0 + delta.months) * 31.0 + delta.days @@ -372,7 +383,6 @@ def get_unit_generic(freq): def __call__(self): # if no data have been set, this will tank with a ValueError - _check_implicitly_registered() try: dmin, dmax = self.viewlim_to_dt() except ValueError: @@ -990,7 +1000,6 @@ def _get_default_locs(self, vmin, vmax): def __call__(self): "Return the locations of the ticks." # axis calls Locator.set_axis inside set_m_formatter - _check_implicitly_registered() vi = tuple(self.axis.get_view_interval()) if vi != self.plot_obj.view_interval: @@ -1075,7 +1084,6 @@ def set_locs(self, locs): "Sets the locations of the ticks" # don't actually use the locs. This is just needed to work with # matplotlib. Force to use vmin, vmax - _check_implicitly_registered() self.locs = locs @@ -1088,7 +1096,6 @@ def set_locs(self, locs): self._set_default_format(vmin, vmax) def __call__(self, x, pos=0): - _check_implicitly_registered() if self.formatdict is None: return "" @@ -1120,7 +1127,6 @@ def format_timedelta_ticks(x, pos, n_decimals): return s def __call__(self, x, pos=0): - _check_implicitly_registered() (vmin, vmax) = tuple(self.axis.get_view_interval()) n_decimals = int(np.ceil(np.log10(100 * 1e9 / (vmax - vmin)))) if n_decimals > 9: diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 3c9256e629740..84cdf294eb547 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -4,8 +4,6 @@ import numpy as np -from pandas._config import get_option - from pandas.errors import AbstractMethodError from pandas.util._decorators import cache_readonly @@ -28,8 +26,8 @@ import pandas.core.common as com from pandas.io.formats.printing import pprint_thing -from pandas.plotting._matplotlib import converter from pandas.plotting._matplotlib.compat import _mpl_ge_3_0_0 +from pandas.plotting._matplotlib.converter import pandas_converters_deco from pandas.plotting._matplotlib.style import _get_standard_colors from pandas.plotting._matplotlib.tools import ( _flatten, @@ -41,9 +39,6 @@ table, ) -if get_option("plotting.matplotlib.register_converters"): - converter.register(explicit=False) - class MPLPlot: """ @@ -112,7 +107,6 @@ def __init__( import matplotlib.pyplot as plt - converter._WARN = False # no warning for pandas plots self.data = data self.by = by @@ -648,6 +642,7 @@ def _get_xticks(self, convert_period=False): return x @classmethod + @pandas_converters_deco def _plot(cls, ax, x, y, style=None, is_errorbar=False, **kwds): mask = isna(y) if mask.any(): diff --git a/pandas/plotting/_matplotlib/hist.py b/pandas/plotting/_matplotlib/hist.py index 5213e09f14067..590e573733471 100644 --- a/pandas/plotting/_matplotlib/hist.py +++ b/pandas/plotting/_matplotlib/hist.py @@ -9,7 +9,6 @@ import pandas.core.common as com from pandas.io.formats.printing import pprint_thing -from pandas.plotting._matplotlib import converter from pandas.plotting._matplotlib.core import LinePlot, MPLPlot from pandas.plotting._matplotlib.tools import _flatten, _set_ticks_props, _subplots @@ -255,7 +254,6 @@ def _grouped_hist( def plot_group(group, ax): ax.hist(group.dropna().values, bins=bins, **kwargs) - converter._WARN = False # no warning for pandas plots xrot = xrot or rot fig, axes = _grouped_plot( @@ -365,7 +363,6 @@ def hist_frame( bins=10, **kwds ): - converter._WARN = False # no warning for pandas plots if by is not None: axes = _grouped_hist( data, diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index f160e50d8d99b..62518da4d67ff 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -25,6 +25,7 @@ TimeSeries_DateFormatter, TimeSeries_DateLocator, TimeSeries_TimedeltaFormatter, + pandas_converters_deco, ) import pandas.tseries.frequencies as frequencies from pandas.tseries.offsets import DateOffset @@ -33,6 +34,7 @@ # Plotting functions and monkey patches +@pandas_converters_deco def tsplot(series, plotf, ax=None, **kwargs): """ Plots a Series on the given Matplotlib axes or the current axes @@ -56,7 +58,7 @@ def tsplot(series, plotf, ax=None, **kwargs): "'tsplot' is deprecated and will be removed in a " "future version. Please use Series.plot() instead.", FutureWarning, - stacklevel=2, + stacklevel=3, ) # Used inferred freq is possible, need a test case for inferred diff --git a/pandas/tests/plotting/test_converter.py b/pandas/tests/plotting/test_converter.py index aabe16d5050f9..41b70d3d74736 100644 --- a/pandas/tests/plotting/test_converter.py +++ b/pandas/tests/plotting/test_converter.py @@ -28,18 +28,6 @@ pytest.importorskip("matplotlib.pyplot") -def test_initial_warning(): - code = ( - "import pandas as pd; import matplotlib.pyplot as plt; " - "s = pd.Series(1, pd.date_range('2000', periods=12)); " - "fig, ax = plt.subplots(); " - "ax.plot(s.index, s.values)" - ) - call = [sys.executable, "-c", code] - out = subprocess.check_output(call, stderr=subprocess.STDOUT).decode() - assert "Using an implicitly" in out - - def test_registry_mpl_resets(): # Check that Matplotlib converters are properly reset (see issue #27481) code = ( @@ -71,27 +59,12 @@ def test_register_by_default(self): call = [sys.executable, "-c", code] assert subprocess.check_call(call) == 0 - def test_warns(self): - plt = pytest.importorskip("matplotlib.pyplot") - s = Series(range(12), index=date_range("2017", periods=12)) - _, ax = plt.subplots() - - # Set to the "warning" state, in case this isn't the first test run - converter._WARN = True - with tm.assert_produces_warning(FutureWarning, check_stacklevel=False) as w: - ax.plot(s.index, s.values) - plt.close() - - assert len(w) == 1 - assert "Using an implicitly registered datetime converter" in str(w[0]) - def test_registering_no_warning(self): plt = pytest.importorskip("matplotlib.pyplot") s = Series(range(12), index=date_range("2017", periods=12)) _, ax = plt.subplots() # Set to the "warn" state, in case this isn't the first test run - converter._WARN = True register_matplotlib_converters() with tm.assert_produces_warning(None) as w: ax.plot(s.index, s.values) @@ -102,7 +75,6 @@ def test_pandas_plots_register(self): pytest.importorskip("matplotlib.pyplot") s = Series(range(12), index=date_range("2017", periods=12)) # Set to the "warn" state, in case this isn't the first test run - converter._WARN = True with tm.assert_produces_warning(None) as w: s.plot() @@ -110,13 +82,15 @@ def test_pandas_plots_register(self): def test_matplotlib_formatters(self): units = pytest.importorskip("matplotlib.units") - assert Timestamp in units.registry - ctx = cf.option_context("plotting.matplotlib.register_converters", False) - with ctx: - assert Timestamp not in units.registry + # Can't make any assertion about the start state. + # We we check that toggling converters off remvoes it, and toggling it + # on restores it. - assert Timestamp in units.registry + with cf.option_context("plotting.matplotlib.register_converters", True): + with cf.option_context("plotting.matplotlib.register_converters", False): + assert Timestamp not in units.registry + assert Timestamp in units.registry def test_option_no_warning(self): pytest.importorskip("matplotlib.pyplot") @@ -125,7 +99,7 @@ def test_option_no_warning(self): s = Series(range(12), index=date_range("2017", periods=12)) _, ax = plt.subplots() - converter._WARN = True + # converter._WARN = True # Test without registering first, no warning with ctx: with tm.assert_produces_warning(None) as w: @@ -134,7 +108,7 @@ def test_option_no_warning(self): assert len(w) == 0 # Now test with registering - converter._WARN = True + # converter._WARN = True register_matplotlib_converters() with ctx: with tm.assert_produces_warning(None) as w: From b9346a8256a4b4f5cfd4f1e9dbaab45845a5dd99 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 23 Sep 2019 14:47:25 -0500 Subject: [PATCH 2/9] cleanup --- pandas/plotting/_matplotlib/__init__.py | 5 ----- pandas/plotting/_misc.py | 4 ++-- pandas/tests/plotting/test_converter.py | 2 -- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/pandas/plotting/_matplotlib/__init__.py b/pandas/plotting/_matplotlib/__init__.py index d3b7a34b6c923..206600ad37acc 100644 --- a/pandas/plotting/_matplotlib/__init__.py +++ b/pandas/plotting/_matplotlib/__init__.py @@ -1,5 +1,3 @@ -from pandas._config import get_option - from pandas.plotting._matplotlib.boxplot import ( BoxPlot, boxplot, @@ -42,9 +40,6 @@ "hexbin": HexBinPlot, } -if get_option("plotting.matplotlib.register_converters"): - register(explicit=False) - def plot(data, kind, **kwargs): # Importing pyplot at the top of the file (before the converters are diff --git a/pandas/plotting/_misc.py b/pandas/plotting/_misc.py index a8e86d9dfa997..3838797278d59 100644 --- a/pandas/plotting/_misc.py +++ b/pandas/plotting/_misc.py @@ -30,7 +30,7 @@ def table(ax, data, rowLabels=None, colLabels=None, **kwargs): ) -def register(explicit=True): +def register(): """ Register Pandas Formatters and Converters with matplotlib @@ -49,7 +49,7 @@ def register(explicit=True): deregister_matplotlib_converters """ plot_backend = _get_plot_backend("matplotlib") - plot_backend.register(explicit=explicit) + plot_backend.register() def deregister(): diff --git a/pandas/tests/plotting/test_converter.py b/pandas/tests/plotting/test_converter.py index 41b70d3d74736..ccc2afbb8b824 100644 --- a/pandas/tests/plotting/test_converter.py +++ b/pandas/tests/plotting/test_converter.py @@ -99,7 +99,6 @@ def test_option_no_warning(self): s = Series(range(12), index=date_range("2017", periods=12)) _, ax = plt.subplots() - # converter._WARN = True # Test without registering first, no warning with ctx: with tm.assert_produces_warning(None) as w: @@ -108,7 +107,6 @@ def test_option_no_warning(self): assert len(w) == 0 # Now test with registering - # converter._WARN = True register_matplotlib_converters() with ctx: with tm.assert_produces_warning(None) as w: From 2e5b2906f751a100abfaf2a463250718187ab3db Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 30 Sep 2019 16:06:04 -0500 Subject: [PATCH 3/9] fixup --- doc/source/whatsnew/v1.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 7392903768657..2ce081cdc554e 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -101,7 +101,7 @@ Backwards incompatible API changes pd.arrays.IntervalArray.from_tuples([(0, 1), (2, 3)]) -- Changed the default configuration value for ``options.matplotlib.register_converters`` from ``True`` to ``"auto"`` (:issue:``). +- Changed the default configuration value for ``options.matplotlib.register_converters`` from ``True`` to ``"auto"`` (:issue:`18720`). Now, pandas custom formatters will only be applied to plots created by pandas, through :meth:`~DataFrame.plot`. Previously, pandas' formatters would be applied to all plots created *after* a :meth:`~DataFrame.plot`. From 8e97c14941b4422a19144237ee919708d8273e24 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 10 Oct 2019 10:23:14 -0500 Subject: [PATCH 4/9] fixup --- pandas/plotting/_matplotlib/converter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index bde230108ea0f..286372ec81b90 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -74,7 +74,6 @@ def pandas_converters(): """ Context manager registering pandas' converters for a plot. - When See Also -------- pandas_converters_deco : Decorator that applies this. From 3f04c9c7274ff718b5c9773f5269c2eb290bd87b Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Oct 2019 10:25:54 -0500 Subject: [PATCH 5/9] doc note --- doc/source/user_guide/visualization.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index fa16b2f216610..6756145419e47 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1244,6 +1244,12 @@ in ``pandas.plotting.plot_params`` can be used in a `with statement`: plt.close('all') +.. versionchanged:: 1.0.0 + +The custom date formatters are applied only to plots created by pandas. +To have them apply to all plots, including those made by matplotlib, set +the option ``pd.options.matplotlib.register_converters = True``. + Automatic date tick adjustment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From b17757626d87862f0bbd45cfa9c877757081cd88 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Thu, 17 Oct 2019 10:27:39 -0500 Subject: [PATCH 6/9] doc note --- doc/source/user_guide/visualization.rst | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 6756145419e47..9a88b1c976641 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1190,6 +1190,18 @@ with "(right)" in the legend. To turn off the automatic marking, use the plt.close('all') +Custom formatters for timeseries plots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionchanged:: 1.0.0 + +Pandas provides custom formatters for timeseries plots. These change the +formatting of the axis labels for dates and times. By default, +the custom formatters are applied only to plots created by pandas with +:meth:`DataFrame.plot` or :meth:`Series.plot`. To have them apply to all +plots, including those made by matplotlib, set the option +``pd.options.matplotlib.register_converters = True``. + Suppressing tick resolution adjustment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1244,12 +1256,6 @@ in ``pandas.plotting.plot_params`` can be used in a `with statement`: plt.close('all') -.. versionchanged:: 1.0.0 - -The custom date formatters are applied only to plots created by pandas. -To have them apply to all plots, including those made by matplotlib, set -the option ``pd.options.matplotlib.register_converters = True``. - Automatic date tick adjustment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ From d7d0dbadd9a9a101c25f74efdb3a006459d23b34 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 21 Oct 2019 09:15:57 -0500 Subject: [PATCH 7/9] fixups --- doc/source/user_guide/visualization.rst | 5 ++++- doc/source/whatsnew/v1.0.0.rst | 2 +- pandas/plotting/_matplotlib/converter.py | 4 ++-- pandas/plotting/_matplotlib/core.py | 4 ++-- pandas/plotting/_matplotlib/timeseries.py | 4 ++-- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/source/user_guide/visualization.rst b/doc/source/user_guide/visualization.rst index 9a88b1c976641..342e87289e993 100644 --- a/doc/source/user_guide/visualization.rst +++ b/doc/source/user_guide/visualization.rst @@ -1190,6 +1190,8 @@ with "(right)" in the legend. To turn off the automatic marking, use the plt.close('all') +.. _plotting.formatters: + Custom formatters for timeseries plots ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1200,7 +1202,8 @@ formatting of the axis labels for dates and times. By default, the custom formatters are applied only to plots created by pandas with :meth:`DataFrame.plot` or :meth:`Series.plot`. To have them apply to all plots, including those made by matplotlib, set the option -``pd.options.matplotlib.register_converters = True``. +``pd.options.plotting.matplotlib.register_converters = True`` or use +:meth:`pandas.plotting.register_matplotlib_converters`. Suppressing tick resolution adjustment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 1f0620a8f6fac..000ac1bf60da3 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -177,7 +177,7 @@ Backwards incompatible API changes - Changed the default configuration value for ``options.matplotlib.register_converters`` from ``True`` to ``"auto"`` (:issue:`18720`). Now, pandas custom formatters will only be applied to plots created by pandas, through :meth:`~DataFrame.plot`. Previously, pandas' formatters would be applied to all plots created *after* a :meth:`~DataFrame.plot`. - + See :ref:`plotting.formatters` for more. .. _whatsnew_1000.api.other: diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 286372ec81b90..946ce8bcec97f 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -56,7 +56,7 @@ def get_pairs(): return pairs -def pandas_converters_deco(func): +def register_pandas_matplotlib_converters(func): """ Decorator applying pandas_converters. """ @@ -76,7 +76,7 @@ def pandas_converters(): See Also -------- - pandas_converters_deco : Decorator that applies this. + register_pandas_matplotlib_converters : Decorator that applies this. """ value = get_option("plotting.matplotlib.register_converters") diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 7693c4d7fbd09..541dca715e814 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -27,7 +27,7 @@ from pandas.io.formats.printing import pprint_thing from pandas.plotting._matplotlib.compat import _mpl_ge_3_0_0 -from pandas.plotting._matplotlib.converter import pandas_converters_deco +from pandas.plotting._matplotlib.converter import register_pandas_matplotlib_converters from pandas.plotting._matplotlib.style import _get_standard_colors from pandas.plotting._matplotlib.tools import ( _flatten, @@ -642,7 +642,7 @@ def _get_xticks(self, convert_period=False): return x @classmethod - @pandas_converters_deco + @register_pandas_matplotlib_converters def _plot(cls, ax, x, y, style=None, is_errorbar=False, **kwds): mask = isna(y) if mask.any(): diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index 62518da4d67ff..931c699d9b9fd 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -25,7 +25,7 @@ TimeSeries_DateFormatter, TimeSeries_DateLocator, TimeSeries_TimedeltaFormatter, - pandas_converters_deco, + register_pandas_matplotlib_converters, ) import pandas.tseries.frequencies as frequencies from pandas.tseries.offsets import DateOffset @@ -34,7 +34,7 @@ # Plotting functions and monkey patches -@pandas_converters_deco +@register_pandas_matplotlib_converters def tsplot(series, plotf, ax=None, **kwargs): """ Plots a Series on the given Matplotlib axes or the current axes From ea61e6ffe2dab14343c996dd1c01b704784a290c Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 21 Oct 2019 10:35:27 -0500 Subject: [PATCH 8/9] link --- doc/source/whatsnew/v1.0.0.rst | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 000ac1bf60da3..d6942325f59ab 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -174,11 +174,6 @@ Backwards incompatible API changes pd.arrays.IntervalArray.from_tuples([(0, 1), (2, 3)]) -- Changed the default configuration value for ``options.matplotlib.register_converters`` from ``True`` to ``"auto"`` (:issue:`18720`). - Now, pandas custom formatters will only be applied to plots created by pandas, through :meth:`~DataFrame.plot`. - Previously, pandas' formatters would be applied to all plots created *after* a :meth:`~DataFrame.plot`. - See :ref:`plotting.formatters` for more. - .. _whatsnew_1000.api.other: Other API changes @@ -190,7 +185,12 @@ Other API changes - In order to improve tab-completion, Pandas does not include most deprecated attributes when introspecting a pandas object using ``dir`` (e.g. ``dir(df)``). To see which attributes are excluded, see an object's ``_deprecations`` attribute, for example ``pd.DataFrame._deprecations`` (:issue:`28805`). - The returned dtype of ::func:`pd.unique` now matches the input dtype. (:issue:`27874`) -- +- Changed the default configuration value for ``options.matplotlib.register_converters`` from ``True`` to ``"auto"`` (:issue:`18720`). + Now, pandas custom formatters will only be applied to plots created by pandas, through :meth:`~DataFrame.plot`. + Previously, pandas' formatters would be applied to all plots created *after* a :meth:`~DataFrame.plot`. + See :ref:`units registration ` for more. +- + .. _whatsnew_1000.api.documentation: @@ -224,6 +224,8 @@ with migrating existing code. Removal of prior version deprecations/changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. _whatsnew_1000.matplotlib_units: + **Matplotlib unit registration** Previously, pandas would register converters with matplotlib as a side effect of importing pandas (:issue:`18720`). @@ -239,7 +241,7 @@ To use pandas formatters with a matplotlib plot, specify Note that plots created by :meth:`DataFrame.plot` and :meth:`Series.plot` *do* register the converters automatically. The only behavior change is when plotting a date-like object via ``matplotlib.pyplot.plot`` -or ``matplotlib.Axes.plot``. +or ``matplotlib.Axes.plot``. See :ref:`plotting.formatters` for more. **Other removals** From db648dacd96e8501727893cdd2cca090b1d65c62 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 21 Oct 2019 16:54:11 -0500 Subject: [PATCH 9/9] whitespace --- doc/source/whatsnew/v1.0.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index d6942325f59ab..9262e8c325be3 100644 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -189,7 +189,7 @@ Other API changes Now, pandas custom formatters will only be applied to plots created by pandas, through :meth:`~DataFrame.plot`. Previously, pandas' formatters would be applied to all plots created *after* a :meth:`~DataFrame.plot`. See :ref:`units registration ` for more. -- +- .. _whatsnew_1000.api.documentation: