From ea58ac6bea45e6e7bd3c0aa89bc928505e4af2d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Fri, 22 Sep 2023 19:43:34 -0400 Subject: [PATCH 01/11] TYP: towards matplotlib 3.8 --- pandas/plotting/_matplotlib/converter.py | 35 +++++++++++++++++------ pandas/plotting/_matplotlib/core.py | 20 ++++++++----- pandas/plotting/_matplotlib/hist.py | 26 +++++++++++++---- pandas/plotting/_matplotlib/style.py | 4 ++- pandas/plotting/_matplotlib/timeseries.py | 2 +- pandas/plotting/_matplotlib/tools.py | 18 ++++++++---- pandas/tests/plotting/common.py | 9 +++--- 7 files changed, 83 insertions(+), 31 deletions(-) diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index e6408a0eae841..02e05965b2c9c 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -63,6 +63,8 @@ if TYPE_CHECKING: from collections.abc import Generator + from matplotlib.axis import Axis + from pandas._libs.tslibs.offsets import BaseOffset @@ -186,7 +188,7 @@ class TimeFormatter(Formatter): def __init__(self, locs) -> None: self.locs = locs - def __call__(self, x, pos: int = 0) -> str: + def __call__(self, x, pos: int | None = 0) -> str: """ Return the time of day as a formatted string. @@ -350,10 +352,19 @@ def get_locator(self, dmin, dmax): if abs(tot_sec) < self.minticks: self._freq = -1 locator = MilliSecondLocator(self.tz) - locator.set_axis(self.axis) - - locator.axis.set_view_interval(*self.axis.get_view_interval()) - locator.axis.set_data_interval(*self.axis.get_data_interval()) + # error: Argument 1 to "set_axis" of "TickHelper" has incompatible type + # "Axis | _DummyAxis | _AxisWrapper | None"; expected "Axis | + # _DummyAxis | None" + locator.set_axis(self.axis) # type: ignore[arg-type] + + # error: Item "None" of "Axis | _DummyAxis | _AxisWrapper | None" + # has no attribute "get_data_interval" + locator.axis.set_view_interval( # type: ignore[union-attr] + *self.axis.get_view_interval() # type: ignore[union-attr] + ) + locator.axis.set_data_interval( # type: ignore[union-attr] + *self.axis.get_data_interval() # type: ignore[union-attr] + ) return locator return mdates.AutoDateLocator.get_locator(self, dmin, dmax) @@ -931,6 +942,8 @@ class TimeSeries_DateLocator(Locator): day : {int}, optional """ + axis: Axis + def __init__( self, freq: BaseOffset, @@ -980,7 +993,9 @@ def __call__(self): base = self.base (d, m) = divmod(vmin, base) vmin = (d + 1) * base - locs = list(range(vmin, vmax + 1, base)) + # error: No overload variant of "range" matches argument types "float", + # "float", "int" + locs = list(range(vmin, vmax + 1, base)) # type: ignore[call-overload] return locs def autoscale(self): @@ -1019,6 +1034,8 @@ class TimeSeries_DateFormatter(Formatter): Whether the formatter works in dynamic mode or not. """ + axis: Axis + def __init__( self, freq: BaseOffset, @@ -1065,7 +1082,7 @@ def set_locs(self, locs) -> None: (vmin, vmax) = (vmax, vmin) self._set_default_format(vmin, vmax) - def __call__(self, x, pos: int = 0) -> str: + def __call__(self, x, pos: int | None = 0) -> str: if self.formatdict is None: return "" else: @@ -1082,6 +1099,8 @@ class TimeSeries_TimedeltaFormatter(Formatter): Formats the ticks along an axis controlled by a :class:`TimedeltaIndex`. """ + axis: Axis + @staticmethod def format_timedelta_ticks(x, pos, n_decimals: int) -> str: """ @@ -1099,7 +1118,7 @@ def format_timedelta_ticks(x, pos, n_decimals: int) -> str: s = f"{int(d):d} days {s}" return s - def __call__(self, x, pos: int = 0) -> str: + def __call__(self, x, pos: int | None = 0) -> str: (vmin, vmax) = tuple(self.axis.get_view_interval()) n_decimals = min(int(np.ceil(np.log10(100 * 10**9 / abs(vmax - vmin)))), 9) return self.format_timedelta_ticks(x, pos, n_decimals) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index d88605db60720..11a80615a62f9 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1115,12 +1115,12 @@ def _get_errorbars( return errors def _get_subplots(self): - from matplotlib.axes import Subplot + from matplotlib.axes import Axes return [ ax for ax in self.fig.get_axes() - if (isinstance(ax, Subplot) and ax.get_subplotspec() is not None) + if (isinstance(ax, Axes) and ax.get_subplotspec() is not None) ] def _get_axes_layout(self) -> tuple[int, int]: @@ -1169,8 +1169,10 @@ def _post_plot_logic(self, ax: Axes, data) -> None: x, y = self.x, self.y xlabel = self.xlabel if self.xlabel is not None else pprint_thing(x) ylabel = self.ylabel if self.ylabel is not None else pprint_thing(y) - ax.set_xlabel(xlabel) - ax.set_ylabel(ylabel) + # error: Argument 1 to "set_xlabel" of "_AxesBase" has incompatible + # type "Hashable"; expected "str" + ax.set_xlabel(xlabel) # type: ignore[arg-type] + ax.set_ylabel(ylabel) # type: ignore[arg-type] def _plot_colorbar(self, ax: Axes, **kwds): # Addresses issues #10611 and #10678: @@ -1244,7 +1246,7 @@ def _make_plot(self): else: cmap = None - if color_by_categorical: + if color_by_categorical and cmap is not None: from matplotlib import colors n_cats = len(self.data[c].cat.categories) @@ -1504,7 +1506,9 @@ def get_label(i): if self._need_to_set_index: xticks = ax.get_xticks() xticklabels = [get_label(x) for x in xticks] - ax.xaxis.set_major_locator(FixedLocator(xticks)) + # error: Argument 1 to "FixedLocator" has incompatible type "ndarray[Any, + # Any]"; expected "Sequence[float]" + ax.xaxis.set_major_locator(FixedLocator(xticks)) # type: ignore[arg-type] ax.set_xticklabels(xticklabels) # If the index is an irregular time series, then by default @@ -1817,7 +1821,9 @@ def _decorate_ticks(self, ax: Axes, name, ticklabels, start_edge, end_edge) -> N ax.set_yticklabels(ticklabels) if name is not None and self.use_index: ax.set_ylabel(name) - ax.set_xlabel(self.xlabel) + # error: Argument 1 to "set_xlabel" of "_AxesBase" has incompatible type + # "Hashable | None"; expected "str" + ax.set_xlabel(self.xlabel) # type: ignore[arg-type] class PiePlot(MPLPlot): diff --git a/pandas/plotting/_matplotlib/hist.py b/pandas/plotting/_matplotlib/hist.py index 076b95a885d5e..c8ab3a20b18e6 100644 --- a/pandas/plotting/_matplotlib/hist.py +++ b/pandas/plotting/_matplotlib/hist.py @@ -181,11 +181,21 @@ def _make_plot_keywords(self, kwds, y): def _post_plot_logic(self, ax: Axes, data) -> None: if self.orientation == "horizontal": - ax.set_xlabel("Frequency" if self.xlabel is None else self.xlabel) - ax.set_ylabel(self.ylabel) + # error: Argument 1 to "set_xlabel" of "_AxesBase" has incompatible + # type "Hashable"; expected "str" + ax.set_xlabel( + "Frequency" + if self.xlabel is None + else self.xlabel # type: ignore[arg-type] + ) + ax.set_ylabel(self.ylabel) # type: ignore[arg-type] else: - ax.set_xlabel(self.xlabel) - ax.set_ylabel("Frequency" if self.ylabel is None else self.ylabel) + ax.set_xlabel(self.xlabel) # type: ignore[arg-type] + ax.set_ylabel( + "Frequency" + if self.ylabel is None + else self.ylabel # type: ignore[arg-type] + ) @property def orientation(self) -> PlottingOrientation: @@ -430,8 +440,14 @@ def hist_series( ax.grid(grid) axes = np.array([ax]) + # error: Argument 1 to "set_ticks_props" has incompatible type "ndarray[Any, + # dtype[Any]]"; expected "Axes | Sequence[Axes]" set_ticks_props( - axes, xlabelsize=xlabelsize, xrot=xrot, ylabelsize=ylabelsize, yrot=yrot + axes, # type: ignore[arg-type] + xlabelsize=xlabelsize, + xrot=xrot, + ylabelsize=ylabelsize, + yrot=yrot, ) else: diff --git a/pandas/plotting/_matplotlib/style.py b/pandas/plotting/_matplotlib/style.py index a5f34e9434cb7..bf4e4be3bfd82 100644 --- a/pandas/plotting/_matplotlib/style.py +++ b/pandas/plotting/_matplotlib/style.py @@ -269,7 +269,9 @@ def _is_single_string_color(color: Color) -> bool: """ conv = matplotlib.colors.ColorConverter() try: - conv.to_rgba(color) + # error: Argument 1 to "to_rgba" of "ColorConverter" has incompatible type + # "str | Sequence[float]"; expected "tuple[float, float, float] | ..." + conv.to_rgba(color) # type: ignore[arg-type] except ValueError: return False else: diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index 77de5c1ad7b42..d0e2f46656551 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -114,7 +114,7 @@ def _upsample_others(ax: Axes, freq, kwargs) -> None: labels.extend(rlabels) if legend is not None and kwargs.get("legend", True) and len(lines) > 0: - title = legend.get_title().get_text() + title: str | None = legend.get_title().get_text() if title == "None": title = None ax.legend(lines, labels, loc="best", title=title) diff --git a/pandas/plotting/_matplotlib/tools.py b/pandas/plotting/_matplotlib/tools.py index 8c0e401f991a6..898b5b25e7b01 100644 --- a/pandas/plotting/_matplotlib/tools.py +++ b/pandas/plotting/_matplotlib/tools.py @@ -52,10 +52,12 @@ def maybe_adjust_figure(fig: Figure, *args, **kwargs) -> None: def format_date_labels(ax: Axes, rot) -> None: # mini version of autofmt_xdate for label in ax.get_xticklabels(): - label.set_ha("right") + label.set_horizontalalignment("right") label.set_rotation(rot) fig = ax.get_figure() - maybe_adjust_figure(fig, bottom=0.2) + if fig is not None: + # should always be a Figure but can technically be None + maybe_adjust_figure(fig, bottom=0.2) def table( @@ -76,8 +78,14 @@ def table( cellText = data.values + # error: Argument "cellText" to "table" has incompatible type "ndarray[Any, + # Any]"; expected "Sequence[Sequence[str]] | None" return matplotlib.table.table( - ax, cellText=cellText, rowLabels=rowLabels, colLabels=colLabels, **kwargs + ax, + cellText=cellText, # type: ignore[arg-type] + rowLabels=rowLabels, + colLabels=colLabels, + **kwargs, ) @@ -369,12 +377,12 @@ def _has_externally_shared_axis(ax1: Axes, compare_axis: str) -> bool: "_has_externally_shared_axis() needs 'x' or 'y' as a second parameter" ) - axes = axes.get_siblings(ax1) + axes_siblings = axes.get_siblings(ax1) # Retain ax1 and any of its siblings which aren't in the same position as it ax1_points = ax1.get_position().get_points() - for ax2 in axes: + for ax2 in axes_siblings: if not np.array_equal(ax1_points, ax2.get_position().get_points()): return True diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index e51dd06881c4f..62421c1eddd0a 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -124,7 +124,8 @@ def _check_patches_all_filled(axes: Axes | Sequence[Axes], filled: bool = True) axes = _flatten_visible(axes) for ax in axes: for patch in ax.patches: - assert patch.fill == filled + # error: "Artist" has no attribute "fill" + assert patch.fill == filled # type: ignore[attr-defined] def _get_colors_mapped(series, colors): @@ -328,7 +329,7 @@ def _check_axes_shape(axes, axes_num=None, layout=None, figsize=None): ) -def _flatten_visible(axes): +def _flatten_visible(axes: Axes | Sequence[Axes]) -> Sequence[Axes]: """ Flatten axes, and filter only visible @@ -339,8 +340,8 @@ def _flatten_visible(axes): """ from pandas.plotting._matplotlib.tools import flatten_axes - axes = flatten_axes(axes) - axes = [ax for ax in axes if ax.get_visible()] + axes_ndarray = flatten_axes(axes) + axes = [ax for ax in axes_ndarray if ax.get_visible()] return axes From 4c24c9cce94524a3e0c5113288c4b83d6525b3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sat, 23 Sep 2023 12:51:48 -0400 Subject: [PATCH 02/11] test 3.8 --- ci/deps/actions-310.yaml | 2 +- ci/deps/actions-311-downstream_compat.yaml | 2 +- ci/deps/actions-311.yaml | 2 +- ci/deps/actions-39.yaml | 2 +- ci/deps/circle-310-arm64.yaml | 2 +- environment.yml | 2 +- pandas/plotting/_matplotlib/core.py | 62 ++++++++++++++++------ pandas/plotting/_matplotlib/timeseries.py | 24 ++++++--- pandas/tests/io/test_sql.py | 2 +- requirements-dev.txt | 2 +- 10 files changed, 70 insertions(+), 32 deletions(-) diff --git a/ci/deps/actions-310.yaml b/ci/deps/actions-310.yaml index 2522605cf5c38..682708d811878 100644 --- a/ci/deps/actions-310.yaml +++ b/ci/deps/actions-310.yaml @@ -34,7 +34,7 @@ dependencies: - gcsfs>=2022.05.0 - jinja2>=3.1.2 - lxml>=4.8.0 - - matplotlib>=3.6.1, <3.8 + - matplotlib>=3.6.1 - numba>=0.55.2 - numexpr>=2.8.0 - odfpy>=1.4.1 diff --git a/ci/deps/actions-311-downstream_compat.yaml b/ci/deps/actions-311-downstream_compat.yaml index dc67122c6e72e..d09d4e5dea648 100644 --- a/ci/deps/actions-311-downstream_compat.yaml +++ b/ci/deps/actions-311-downstream_compat.yaml @@ -35,7 +35,7 @@ dependencies: - gcsfs>=2022.05.0 - jinja2>=3.1.2 - lxml>=4.8.0 - - matplotlib>=3.6.1, <3.8 + - matplotlib>=3.6.1 - numba>=0.55.2 - numexpr>=2.8.0 - odfpy>=1.4.1 diff --git a/ci/deps/actions-311.yaml b/ci/deps/actions-311.yaml index c9faaa2146235..f458546fc3a1b 100644 --- a/ci/deps/actions-311.yaml +++ b/ci/deps/actions-311.yaml @@ -34,7 +34,7 @@ dependencies: - gcsfs>=2022.05.0 - jinja2>=3.1.2 - lxml>=4.8.0 - - matplotlib>=3.6.1, <3.8 + - matplotlib>=3.6.1 - numba>=0.55.2 - numexpr>=2.8.0 - odfpy>=1.4.1 diff --git a/ci/deps/actions-39.yaml b/ci/deps/actions-39.yaml index f51a8e04fbc7e..4ee8dc0c6d3fc 100644 --- a/ci/deps/actions-39.yaml +++ b/ci/deps/actions-39.yaml @@ -34,7 +34,7 @@ dependencies: - gcsfs>=2022.05.0 - jinja2>=3.1.2 - lxml>=4.8.0 - - matplotlib>=3.6.1, <3.8 + - matplotlib>=3.6.1 - numba>=0.55.2 - numexpr>=2.8.0 - odfpy>=1.4.1 diff --git a/ci/deps/circle-310-arm64.yaml b/ci/deps/circle-310-arm64.yaml index d1a9e336eaeac..c520fa17551e0 100644 --- a/ci/deps/circle-310-arm64.yaml +++ b/ci/deps/circle-310-arm64.yaml @@ -34,7 +34,7 @@ dependencies: - gcsfs>=2022.05.0 - jinja2>=3.1.2 - lxml>=4.8.0 - - matplotlib>=3.6.1, <3.8 + - matplotlib>=3.6.1 # test_numba_vs_cython segfaults with numba 0.57 - numba>=0.55.2, <0.57.0 - numexpr>=2.8.0 diff --git a/environment.yml b/environment.yml index db6138c34f37c..5caa57ef37ee8 100644 --- a/environment.yml +++ b/environment.yml @@ -36,7 +36,7 @@ dependencies: - ipython - jinja2>=3.1.2 - lxml>=4.8.0 - - matplotlib>=3.6.1, <3.8 + - matplotlib>=3.6.1 - numba>=0.55.2 - numexpr>=2.8.0 - openpyxl>=3.0.10 diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 11a80615a62f9..3159fd92ec3d3 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -465,7 +465,12 @@ def _args_adjust(self) -> None: def _has_plotted_object(self, ax: Axes) -> bool: """check whether ax has data""" - return len(ax.lines) != 0 or len(ax.artists) != 0 or len(ax.containers) != 0 + # error: "Axes" has no attribute "containers" + return ( + len(ax.lines) != 0 + or len(ax.artists) != 0 + or len(ax.containers) != 0 # type: ignore[attr-defined] + ) def _maybe_right_yaxis(self, ax: Axes, axes_num): if not self.on_right(axes_num): @@ -482,9 +487,16 @@ def _maybe_right_yaxis(self, ax: Axes, axes_num): # otherwise, create twin axes orig_ax, new_ax = ax, ax.twinx() # TODO: use Matplotlib public API when available - new_ax._get_lines = orig_ax._get_lines - new_ax._get_patches_for_fill = orig_ax._get_patches_for_fill - orig_ax.right_ax, new_ax.left_ax = new_ax, orig_ax + new_ax._get_lines = orig_ax._get_lines # type: ignore[attr-defined] + # TODO #54485 + new_ax._get_patches_for_fill = ( # type: ignore[attr-defined] + orig_ax._get_patches_for_fill # type: ignore[attr-defined] + ) + # TODO #54485 + orig_ax.right_ax, new_ax.left_ax = ( # type: ignore[attr-defined] + new_ax, + orig_ax, + ) if not self._has_plotted_object(orig_ax): # no data on left y orig_ax.get_yaxis().set_visible(False) @@ -1437,11 +1449,13 @@ def _ts_plot(self, ax: Axes, x, data, style=None, **kwds): decorate_axes(ax.left_ax, freq, kwds) if hasattr(ax, "right_ax"): decorate_axes(ax.right_ax, freq, kwds) - ax._plot_data.append((data, self._kind, kwds)) + # TODO #54485 + ax._plot_data.append((data, self._kind, kwds)) # type: ignore[attr-defined] lines = self._plot(ax, data.index, data.values, style=style, **kwds) # set date formatter, locators and rescale limits - format_dateaxis(ax, ax.freq, data.index) + # TODO #54485 + format_dateaxis(ax, ax.freq, data.index) # type: ignore[attr-defined] return lines def _get_stacking_id(self): @@ -1455,11 +1469,15 @@ def _initialize_stacker(cls, ax: Axes, stacking_id, n: int) -> None: if stacking_id is None: return if not hasattr(ax, "_stacker_pos_prior"): - ax._stacker_pos_prior = {} + # TODO #54485 + ax._stacker_pos_prior = {} # type: ignore[attr-defined] if not hasattr(ax, "_stacker_neg_prior"): - ax._stacker_neg_prior = {} - ax._stacker_pos_prior[stacking_id] = np.zeros(n) - ax._stacker_neg_prior[stacking_id] = np.zeros(n) + # TODO #54485 + ax._stacker_neg_prior = {} # type: ignore[attr-defined] + # TODO #54485 + ax._stacker_pos_prior[stacking_id] = np.zeros(n) # type: ignore[attr-defined] + # TODO #54485 + ax._stacker_neg_prior[stacking_id] = np.zeros(n) # type: ignore[attr-defined] @classmethod def _get_stacked_values(cls, ax: Axes, stacking_id, values, label): @@ -1470,9 +1488,17 @@ def _get_stacked_values(cls, ax: Axes, stacking_id, values, label): cls._initialize_stacker(ax, stacking_id, len(values)) if (values >= 0).all(): - return ax._stacker_pos_prior[stacking_id] + values + # TODO #54485 + return ( + ax._stacker_pos_prior[stacking_id] # type: ignore[attr-defined] + + values + ) elif (values <= 0).all(): - return ax._stacker_neg_prior[stacking_id] + values + # TODO #54485 + return ( + ax._stacker_neg_prior[stacking_id] # type: ignore[attr-defined] + + values + ) raise ValueError( "When stacked is True, each column must be either " @@ -1485,9 +1511,11 @@ def _update_stacker(cls, ax: Axes, stacking_id, values) -> None: if stacking_id is None: return if (values >= 0).all(): - ax._stacker_pos_prior[stacking_id] += values + # TODO #54485 + ax._stacker_pos_prior[stacking_id] += values # type: ignore[attr-defined] elif (values <= 0).all(): - ax._stacker_neg_prior[stacking_id] += values + # TODO #54485 + ax._stacker_neg_prior[stacking_id] += values # type: ignore[attr-defined] def _args_adjust(self) -> None: pass @@ -1587,9 +1615,11 @@ def _plot( # type: ignore[override] if stacking_id is None: start = np.zeros(len(y)) elif (y >= 0).all(): - start = ax._stacker_pos_prior[stacking_id] + # TODO #54485 + start = ax._stacker_pos_prior[stacking_id] # type: ignore[attr-defined] elif (y <= 0).all(): - start = ax._stacker_neg_prior[stacking_id] + # TODO #54485 + start = ax._stacker_neg_prior[stacking_id] # type: ignore[attr-defined] else: start = np.zeros(len(y)) diff --git a/pandas/plotting/_matplotlib/timeseries.py b/pandas/plotting/_matplotlib/timeseries.py index d0e2f46656551..7949ed6db26e3 100644 --- a/pandas/plotting/_matplotlib/timeseries.py +++ b/pandas/plotting/_matplotlib/timeseries.py @@ -124,7 +124,8 @@ def _replot_ax(ax: Axes, freq, kwargs): data = getattr(ax, "_plot_data", None) # clear current axes and data - ax._plot_data = [] + # TODO #54485 + ax._plot_data = [] # type: ignore[attr-defined] ax.clear() decorate_axes(ax, freq, kwargs) @@ -136,7 +137,8 @@ def _replot_ax(ax: Axes, freq, kwargs): series = series.copy() idx = series.index.asfreq(freq, how="S") series.index = idx - ax._plot_data.append((series, plotf, kwds)) + # TODO #54485 + ax._plot_data.append((series, plotf, kwds)) # type: ignore[attr-defined] # for tsplot if isinstance(plotf, str): @@ -153,17 +155,23 @@ def _replot_ax(ax: Axes, freq, kwargs): def decorate_axes(ax: Axes, freq, kwargs) -> None: """Initialize axes for time-series plotting""" if not hasattr(ax, "_plot_data"): - ax._plot_data = [] + # TODO #54485 + ax._plot_data = [] # type: ignore[attr-defined] - ax.freq = freq + # TODO #54485 + ax.freq = freq # type: ignore[attr-defined] xaxis = ax.get_xaxis() - xaxis.freq = freq + # TODO #54485 + xaxis.freq = freq # type: ignore[attr-defined] if not hasattr(ax, "legendlabels"): - ax.legendlabels = [kwargs.get("label", None)] + # TODO #54485 + ax.legendlabels = [kwargs.get("label", None)] # type: ignore[attr-defined] else: ax.legendlabels.append(kwargs.get("label", None)) - ax.view_interval = None - ax.date_axis_info = None + # TODO #54485 + ax.view_interval = None # type: ignore[attr-defined] + # TODO #54485 + ax.date_axis_info = None # type: ignore[attr-defined] def _get_ax_freq(ax: Axes): diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index f015c9efe7122..de44e609f1f7a 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -3160,7 +3160,7 @@ def dtype_backend_data() -> DataFrame: @pytest.fixture def dtype_backend_expected(): - def func(storage, dtype_backend, conn_name): + def func(storage, dtype_backend, conn_name) -> DataFrame: string_array: StringArray | ArrowStringArray string_array_na: StringArray | ArrowStringArray if storage == "python": diff --git a/requirements-dev.txt b/requirements-dev.txt index 98339f45a5052..b8e7e376378c6 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -25,7 +25,7 @@ gcsfs>=2022.05.0 ipython jinja2>=3.1.2 lxml>=4.8.0 -matplotlib>=3.6.1, <3.8 +matplotlib>=3.6.1 numba>=0.55.2 numexpr>=2.8.0 openpyxl>=3.0.10 From 5cc19e74611ea74720598902b720f9a77820a59e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20W=C3=B6rtwein?= Date: Sat, 23 Sep 2023 18:03:45 -0400 Subject: [PATCH 03/11] ignore pyright errors --- pyright_reportGeneralTypeIssues.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyright_reportGeneralTypeIssues.json b/pyright_reportGeneralTypeIssues.json index cad43632930ba..5f18fd091bf99 100644 --- a/pyright_reportGeneralTypeIssues.json +++ b/pyright_reportGeneralTypeIssues.json @@ -98,6 +98,9 @@ "pandas/io/sql.py", "pandas/io/stata.py", "pandas/plotting/_matplotlib/boxplot.py", + "pandas/plotting/_matplotlib/core.py", + "pandas/plotting/_matplotlib/timeseries.py", + "pandas/plotting/_matplotlib/tools.py", "pandas/tseries/frequencies.py", "pandas/tseries/holiday.py", ], From afc470c931f726a09bc1e7cd6b7430abd2a006a7 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:42:33 -0800 Subject: [PATCH 04/11] merging error --- pandas/plotting/_matplotlib/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index ae881200986e3..973156ab7f1f9 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1166,12 +1166,12 @@ def _get_errorbars( return errors @final - def _get_subplots(self): + def _get_subplots(self, fig: Figure): from matplotlib.axes import Axes return [ ax - for ax in self.fig.get_axes() + for ax in fig.get_axes() if (isinstance(ax, Axes) and ax.get_subplotspec() is not None) ] From ab129ca32fc5989a4baf88cbac4985a2cee3f5a2 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Thu, 9 Nov 2023 08:39:37 -0800 Subject: [PATCH 05/11] Conditional on import --- pandas/plotting/_matplotlib/core.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 29912bd12d6df..bd69aec8e20c9 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1179,12 +1179,15 @@ def _get_errorbars( @final def _get_subplots(self, fig: Figure): - from matplotlib.axes import Axes + if Version(mpl.__version__) < Version("3.8"): + from matplotlib.axes import Subplot as Klass + else: + from matplotlib.axes import Axes as Klass return [ ax for ax in fig.get_axes() - if (isinstance(ax, Axes) and ax.get_subplotspec() is not None) + if (isinstance(ax, Klass) and ax.get_subplotspec() is not None) ] @final From 048382080b192577f238b882599d15d1bbda04f8 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Thu, 9 Nov 2023 08:40:21 -0800 Subject: [PATCH 06/11] Disable parallel build to see docbuild error --- doc/make.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/make.py b/doc/make.py index dfa8ae6c1e34c..3987891445b5e 100755 --- a/doc/make.py +++ b/doc/make.py @@ -135,8 +135,8 @@ def _sphinx_build(self, kind: str): raise ValueError(f"kind must be html, latex or linkcheck, not {kind}") cmd = ["sphinx-build", "-b", kind] - if self.num_jobs: - cmd += ["-j", self.num_jobs] + # if self.num_jobs: + # cmd += ["-j", self.num_jobs] if self.warnings_are_errors: cmd += ["-W", "--keep-going"] if self.verbosity: From 00f30cd1ce7f616d9953b7e0d444e0aefe0132af Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Thu, 9 Nov 2023 08:44:43 -0800 Subject: [PATCH 07/11] Some unnecessary ignores --- pandas/plotting/_matplotlib/converter.py | 5 +---- pandas/plotting/_matplotlib/core.py | 7 +------ pandas/tests/plotting/common.py | 3 +-- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/pandas/plotting/_matplotlib/converter.py b/pandas/plotting/_matplotlib/converter.py index 6fef22434a97e..848fb77c942fb 100644 --- a/pandas/plotting/_matplotlib/converter.py +++ b/pandas/plotting/_matplotlib/converter.py @@ -364,10 +364,7 @@ def get_locator(self, dmin, dmax): if abs(tot_sec) < self.minticks: self._freq = -1 locator = MilliSecondLocator(self.tz) - # error: Argument 1 to "set_axis" of "TickHelper" has incompatible type - # "Axis | _DummyAxis | _AxisWrapper | None"; expected "Axis | - # _DummyAxis | None" - locator.set_axis(self.axis) # type: ignore[arg-type] + locator.set_axis(self.axis) # error: Item "None" of "Axis | _DummyAxis | _AxisWrapper | None" # has no attribute "get_data_interval" diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index bd69aec8e20c9..dd56cbabdba0e 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -476,12 +476,7 @@ def generate(self) -> None: @staticmethod def _has_plotted_object(ax: Axes) -> bool: """check whether ax has data""" - # error: "Axes" has no attribute "containers" - return ( - len(ax.lines) != 0 - or len(ax.artists) != 0 - or len(ax.containers) != 0 # type: ignore[attr-defined] - ) + return len(ax.lines) != 0 or len(ax.artists) != 0 or len(ax.containers) != 0 @final def _maybe_right_yaxis(self, ax: Axes, axes_num: int) -> Axes: diff --git a/pandas/tests/plotting/common.py b/pandas/tests/plotting/common.py index 57b9bedc10173..69120160699c2 100644 --- a/pandas/tests/plotting/common.py +++ b/pandas/tests/plotting/common.py @@ -124,8 +124,7 @@ def _check_patches_all_filled(axes: Axes | Sequence[Axes], filled: bool = True) axes = _flatten_visible(axes) for ax in axes: for patch in ax.patches: - # error: "Artist" has no attribute "fill" - assert patch.fill == filled # type: ignore[attr-defined] + assert patch.fill == filled def _get_colors_mapped(series, colors): From 68f20910365ed2d8bbfe1fe0a2c6304322d69509 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Tue, 14 Nov 2023 09:08:52 -0800 Subject: [PATCH 08/11] Add typing in test_sql --- pandas/tests/io/test_sql.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pandas/tests/io/test_sql.py b/pandas/tests/io/test_sql.py index d994f6bdc8a49..9ac20774b8c93 100644 --- a/pandas/tests/io/test_sql.py +++ b/pandas/tests/io/test_sql.py @@ -3180,6 +3180,8 @@ def dtype_backend_data() -> DataFrame: @pytest.fixture def dtype_backend_expected(): def func(storage, dtype_backend, conn_name) -> DataFrame: + string_array: StringArray | ArrowStringArray + string_array_na: StringArray | ArrowStringArray if storage == "python": string_array = StringArray(np.array(["a", "b", "c"], dtype=np.object_)) string_array_na = StringArray(np.array(["a", "b", pd.NA], dtype=np.object_)) From 5b94b75bed0136f97749f2305e76044adc5f9d13 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Wed, 15 Nov 2023 10:29:51 -0800 Subject: [PATCH 09/11] type ignores --- pandas/plotting/_matplotlib/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index 0e240e56de2c6..eaeba710db3f6 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -547,7 +547,7 @@ def _maybe_right_yaxis(self, ax: Axes, axes_num: int) -> Axes: new_ax.set_yscale("log") elif self.logy == "sym" or self.loglog == "sym": new_ax.set_yscale("symlog") - return new_ax + return new_ax # type: ignore[return-value] @final @cache_readonly @@ -1602,7 +1602,7 @@ def _ts_plot(self, ax: Axes, x, data: Series, style=None, **kwds): lines = self._plot(ax, data.index, np.asarray(data.values), style=style, **kwds) # set date formatter, locators and rescale limits # TODO #54485 - format_dateaxis(ax, ax.freq, data.index) # type: ignore[attr-defined] + format_dateaxis(ax, ax.freq, data.index) # type: ignore[arg-type] return lines @final From ad14df4615b9062b193d6c99db8da071f5709100 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Wed, 15 Nov 2023 11:09:55 -0800 Subject: [PATCH 10/11] Multiple ignores --- pandas/plotting/_matplotlib/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/plotting/_matplotlib/core.py b/pandas/plotting/_matplotlib/core.py index eaeba710db3f6..6be8284d2a0be 100644 --- a/pandas/plotting/_matplotlib/core.py +++ b/pandas/plotting/_matplotlib/core.py @@ -1602,7 +1602,7 @@ def _ts_plot(self, ax: Axes, x, data: Series, style=None, **kwds): lines = self._plot(ax, data.index, np.asarray(data.values), style=style, **kwds) # set date formatter, locators and rescale limits # TODO #54485 - format_dateaxis(ax, ax.freq, data.index) # type: ignore[arg-type] + format_dateaxis(ax, ax.freq, data.index) # type: ignore[arg-type, attr-defined] return lines @final From 9ceb8808bc2fb1997068d0c3363b1d059823a165 Mon Sep 17 00:00:00 2001 From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> Date: Wed, 15 Nov 2023 12:23:47 -0800 Subject: [PATCH 11/11] Uncomment --- doc/make.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/make.py b/doc/make.py index 3987891445b5e..dfa8ae6c1e34c 100755 --- a/doc/make.py +++ b/doc/make.py @@ -135,8 +135,8 @@ def _sphinx_build(self, kind: str): raise ValueError(f"kind must be html, latex or linkcheck, not {kind}") cmd = ["sphinx-build", "-b", kind] - # if self.num_jobs: - # cmd += ["-j", self.num_jobs] + if self.num_jobs: + cmd += ["-j", self.num_jobs] if self.warnings_are_errors: cmd += ["-W", "--keep-going"] if self.verbosity: