diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 4a10311b1f9fa..69f46a333503d 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -17,16 +17,14 @@ ) from dateutil.relativedelta import relativedelta -from matplotlib import ( - dates, - units, -) +import matplotlib.dates as mdates from matplotlib.ticker import ( AutoLocator, Formatter, Locator, ) from matplotlib.transforms import nonsingular +import matplotlib.units as munits import numpy as np from pandas._libs import lib @@ -126,25 +124,25 @@ def register() -> None: pairs = get_pairs() for type_, cls in pairs: # Cache previous converter if present - if type_ in units.registry and not isinstance(units.registry[type_], cls): - previous = units.registry[type_] + if type_ in munits.registry and not isinstance(munits.registry[type_], cls): + previous = munits.registry[type_] _mpl_units[type_] = previous # Replace with pandas converter - units.registry[type_] = cls() + munits.registry[type_] = cls() def deregister() -> None: # Renamed in pandas.plotting.__init__ for type_, cls in get_pairs(): # We use type to catch our classes directly, no inheritance - if type(units.registry.get(type_)) is cls: - units.registry.pop(type_) + if type(munits.registry.get(type_)) is cls: + munits.registry.pop(type_) # restore the old keys for unit, formatter in _mpl_units.items(): if type(formatter) not in {DatetimeConverter, PeriodConverter, TimeConverter}: # make it idempotent by excluding ours. - units.registry[unit] = formatter + munits.registry[unit] = formatter def _to_ordinalf(tm: pydt.time) -> float: @@ -161,7 +159,7 @@ def time2num(d): return d -class TimeConverter(units.ConversionInterface): +class TimeConverter(munits.ConversionInterface): @staticmethod def convert(value, unit, axis): valid_types = (str, pydt.time) @@ -174,13 +172,13 @@ def convert(value, unit, axis): return value @staticmethod - def axisinfo(unit, axis) -> units.AxisInfo | None: + def axisinfo(unit, axis) -> munits.AxisInfo | None: if unit != "time": return None majloc = AutoLocator() majfmt = TimeFormatter(majloc) - return units.AxisInfo(majloc=majloc, majfmt=majfmt, label="time") + return munits.AxisInfo(majloc=majloc, majfmt=majfmt, label="time") @staticmethod def default_units(x, axis) -> str: @@ -231,7 +229,7 @@ def __call__(self, x, pos: int = 0) -> str: # Period Conversion -class PeriodConverter(dates.DateConverter): +class PeriodConverter(mdates.DateConverter): @staticmethod def convert(values, units, axis): if is_nested_list_like(values): @@ -277,7 +275,7 @@ def get_datevalue(date, freq): # Datetime Conversion -class DatetimeConverter(dates.DateConverter): +class DatetimeConverter(mdates.DateConverter): @staticmethod def convert(values, unit, axis): # values might be a 1-d array, or a list-like of arrays. @@ -291,12 +289,12 @@ def convert(values, unit, axis): def _convert_1d(values, unit, axis): def try_parse(values): try: - return dates.date2num(tools.to_datetime(values)) + return mdates.date2num(tools.to_datetime(values)) except Exception: return values if isinstance(values, (datetime, pydt.date, np.datetime64, pydt.time)): - return dates.date2num(values) + return mdates.date2num(values) elif is_integer(values) or is_float(values): return values elif isinstance(values, str): @@ -319,12 +317,12 @@ def try_parse(values): except Exception: pass - values = dates.date2num(values) + values = mdates.date2num(values) return values @staticmethod - def axisinfo(unit: tzinfo | None, axis) -> units.AxisInfo: + def axisinfo(unit: tzinfo | None, axis) -> munits.AxisInfo: """ Return the :class:`~matplotlib.units.AxisInfo` for *unit*. @@ -338,17 +336,17 @@ def axisinfo(unit: tzinfo | None, axis) -> units.AxisInfo: datemin = pydt.date(2000, 1, 1) datemax = pydt.date(2010, 1, 1) - return units.AxisInfo( + return munits.AxisInfo( majloc=majloc, majfmt=majfmt, label="", default_limits=(datemin, datemax) ) -class PandasAutoDateFormatter(dates.AutoDateFormatter): +class PandasAutoDateFormatter(mdates.AutoDateFormatter): def __init__(self, locator, tz=None, defaultfmt: str = "%Y-%m-%d") -> None: - dates.AutoDateFormatter.__init__(self, locator, tz, defaultfmt) + mdates.AutoDateFormatter.__init__(self, locator, tz, defaultfmt) -class PandasAutoDateLocator(dates.AutoDateLocator): +class PandasAutoDateLocator(mdates.AutoDateLocator): def get_locator(self, dmin, dmax): """Pick the best locator based on a distance.""" delta = relativedelta(dmax, dmin) @@ -366,18 +364,18 @@ def get_locator(self, dmin, dmax): locator.axis.set_data_interval(*self.axis.get_data_interval()) return locator - return dates.AutoDateLocator.get_locator(self, dmin, dmax) + return mdates.AutoDateLocator.get_locator(self, dmin, dmax) def _get_unit(self): return MilliSecondLocator.get_unit_generic(self._freq) -class MilliSecondLocator(dates.DateLocator): +class MilliSecondLocator(mdates.DateLocator): UNIT = 1.0 / (24 * 3600 * 1000) def __init__(self, tz) -> None: - dates.DateLocator.__init__(self, tz) + mdates.DateLocator.__init__(self, tz) self._interval = 1.0 def _get_unit(self): @@ -385,7 +383,7 @@ def _get_unit(self): @staticmethod def get_unit_generic(freq): - unit = dates.RRuleLocator.get_unit_generic(freq) + unit = mdates.RRuleLocator.get_unit_generic(freq) if unit < 0: return MilliSecondLocator.UNIT return unit @@ -398,7 +396,7 @@ def __call__(self): return [] # We need to cap at the endpoints of valid datetime - nmax, nmin = dates.date2num((dmax, dmin)) + nmax, nmin = mdates.date2num((dmax, dmin)) num = (nmax - nmin) * 86400 * 1000 max_millis_ticks = 6 @@ -427,12 +425,12 @@ def __call__(self): try: if len(all_dates) > 0: - locs = self.raise_if_exceeds(dates.date2num(all_dates)) + locs = self.raise_if_exceeds(mdates.date2num(all_dates)) return locs except Exception: # pragma: no cover pass - lims = dates.date2num([dmin, dmax]) + lims = mdates.date2num([dmin, dmax]) return lims def _get_interval(self): @@ -445,8 +443,8 @@ def autoscale(self): # We need to cap at the endpoints of valid datetime dmin, dmax = self.datalim_to_dt() - vmin = dates.date2num(dmin) - vmax = dates.date2num(dmax) + vmin = mdates.date2num(dmin) + vmax = mdates.date2num(dmax) return self.nonsingular(vmin, vmax) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 27603f7d987d2..664e8dfdb4d20 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -55,6 +55,7 @@ from pandas.core.frame import DataFrame from pandas.io.formats.printing import pprint_thing +from pandas.plotting._matplotlib import tools from pandas.plotting._matplotlib.converter import register_pandas_matplotlib_converters from pandas.plotting._matplotlib.groupby import reconstruct_data_with_by from pandas.plotting._matplotlib.misc import unpack_single_str_list @@ -73,7 +74,6 @@ get_all_lines, get_xlim, handle_shared_axes, - table, ) if TYPE_CHECKING: @@ -644,7 +644,7 @@ def _add_table(self) -> None: else: data = self.table ax = self._get_ax(0) - table(ax, data) + tools.table(ax, data) def _post_plot_logic_common(self, ax, data): """Common post process for each axes""" diff --git a/pandas/plotting/_matplotlib/tools.py b/pandas/plotting/_matplotlib/tools.py index eecfcbc72f489..7d3c857eea2dd 100644 --- a/pandas/plotting/_matplotlib/tools.py +++ b/pandas/plotting/_matplotlib/tools.py @@ -75,10 +75,9 @@ def table( cellText = data.values - table = matplotlib.table.table( + return matplotlib.table.table( ax, cellText=cellText, rowLabels=rowLabels, colLabels=colLabels, **kwargs ) - return table def _get_layout( diff --git a/pandas/tests/plotting/test_converter.py b/pandas/tests/plotting/test_converter.py index 9a6fed1afad1f..8da663b8e9977 100644 --- a/pandas/tests/plotting/test_converter.py +++ b/pandas/tests/plotting/test_converter.py @@ -215,7 +215,7 @@ def test_conversion_float(self, dtc): rtol = 0.5 * 10**-9 rs = dtc.convert(Timestamp("2012-1-1 01:02:03", tz="UTC"), None, None) - xp = converter.dates.date2num(Timestamp("2012-1-1 01:02:03", tz="UTC")) + xp = converter.mdates.date2num(Timestamp("2012-1-1 01:02:03", tz="UTC")) tm.assert_almost_equal(rs, xp, rtol=rtol) rs = dtc.convert( @@ -230,18 +230,18 @@ def test_conversion_outofbounds_datetime(self, dtc): # 2579 values = [date(1677, 1, 1), date(1677, 1, 2)] rs = dtc.convert(values, None, None) - xp = converter.dates.date2num(values) + xp = converter.mdates.date2num(values) tm.assert_numpy_array_equal(rs, xp) rs = dtc.convert(values[0], None, None) - xp = converter.dates.date2num(values[0]) + xp = converter.mdates.date2num(values[0]) assert rs == xp values = [datetime(1677, 1, 1, 12), datetime(1677, 1, 2, 12)] rs = dtc.convert(values, None, None) - xp = converter.dates.date2num(values) + xp = converter.mdates.date2num(values) tm.assert_numpy_array_equal(rs, xp) rs = dtc.convert(values[0], None, None) - xp = converter.dates.date2num(values[0]) + xp = converter.mdates.date2num(values[0]) assert rs == xp @pytest.mark.parametrize( @@ -264,7 +264,7 @@ def test_dateindex_conversion(self, freq, dtc): rtol = 10**-9 dateindex = tm.makeDateIndex(k=10, freq=freq) rs = dtc.convert(dateindex, None, None) - xp = converter.dates.date2num(dateindex._mpl_repr()) + xp = converter.mdates.date2num(dateindex._mpl_repr()) tm.assert_almost_equal(rs, xp, rtol=rtol) @pytest.mark.parametrize("offset", [Second(), Milli(), Micro(50)])