-
-
Notifications
You must be signed in to change notification settings - Fork 18.5k
TYP: plotting._matplotlib #47311
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TYP: plotting._matplotlib #47311
Changes from all commits
9c4b6ec
af687de
70bfbc3
4c84046
c963fa5
0166de0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -574,6 +574,8 @@ def _daily_finder(vmin, vmax, freq: BaseOffset): | |
Period(ordinal=int(vmin), freq=freq), | ||
Period(ordinal=int(vmax), freq=freq), | ||
) | ||
assert isinstance(vmin, Period) | ||
assert isinstance(vmax, Period) | ||
span = vmax.ordinal - vmin.ordinal + 1 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can safely assert as |
||
dates_ = period_range(start=vmin, end=vmax, freq=freq) | ||
# Initialize the output | ||
|
@@ -1073,7 +1075,9 @@ def __call__(self, x, pos=0) -> str: | |
fmt = self.formatdict.pop(x, "") | ||
if isinstance(fmt, np.bytes_): | ||
fmt = fmt.decode("utf-8") | ||
return Period(ordinal=int(x), freq=self.freq).strftime(fmt) | ||
period = Period(ordinal=int(x), freq=self.freq) | ||
assert isinstance(period, Period) | ||
return period.strftime(fmt) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here: |
||
|
||
|
||
class TimeSeries_TimedeltaFormatter(Formatter): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,25 @@ | ||
from __future__ import annotations | ||
|
||
from abc import ( | ||
ABC, | ||
abstractmethod, | ||
) | ||
from typing import ( | ||
TYPE_CHECKING, | ||
Hashable, | ||
Iterable, | ||
Literal, | ||
Sequence, | ||
) | ||
import warnings | ||
|
||
from matplotlib.artist import Artist | ||
import numpy as np | ||
|
||
from pandas._typing import IndexLabel | ||
from pandas._typing import ( | ||
IndexLabel, | ||
PlottingOrientation, | ||
) | ||
from pandas.errors import AbstractMethodError | ||
from pandas.util._decorators import cache_readonly | ||
|
||
|
@@ -78,7 +86,7 @@ def _color_in_style(style: str) -> bool: | |
return not set(BASE_COLORS).isdisjoint(style) | ||
|
||
|
||
class MPLPlot: | ||
class MPLPlot(ABC): | ||
""" | ||
Base class for assembling a pandas plot using matplotlib | ||
|
||
|
@@ -89,13 +97,17 @@ class MPLPlot: | |
""" | ||
|
||
@property | ||
def _kind(self): | ||
@abstractmethod | ||
def _kind(self) -> str: | ||
"""Specify kind str. Must be overridden in child class""" | ||
raise NotImplementedError | ||
|
||
_layout_type = "vertical" | ||
_default_rot = 0 | ||
orientation: str | None = None | ||
|
||
@property | ||
def orientation(self) -> str | None: | ||
return None | ||
|
||
axes: np.ndarray # of Axes objects | ||
|
||
|
@@ -843,7 +855,9 @@ def _get_xticks(self, convert_period: bool = False): | |
|
||
@classmethod | ||
@register_pandas_matplotlib_converters | ||
def _plot(cls, ax: Axes, x, y, style=None, is_errorbar: bool = False, **kwds): | ||
def _plot( | ||
cls, ax: Axes, x, y: np.ndarray, style=None, is_errorbar: bool = False, **kwds | ||
): | ||
mask = isna(y) | ||
if mask.any(): | ||
y = np.ma.array(y) | ||
|
@@ -1101,7 +1115,7 @@ def _get_axes_layout(self) -> tuple[int, int]: | |
return (len(y_set), len(x_set)) | ||
|
||
|
||
class PlanePlot(MPLPlot): | ||
class PlanePlot(MPLPlot, ABC): | ||
""" | ||
Abstract class for plotting on plane, currently scatter and hexbin. | ||
""" | ||
|
@@ -1159,7 +1173,9 @@ def _plot_colorbar(self, ax: Axes, **kwds): | |
|
||
|
||
class ScatterPlot(PlanePlot): | ||
_kind = "scatter" | ||
@property | ||
def _kind(self) -> Literal["scatter"]: | ||
return "scatter" | ||
|
||
def __init__(self, data, x, y, s=None, c=None, **kwargs) -> None: | ||
if s is None: | ||
|
@@ -1247,7 +1263,9 @@ def _make_plot(self): | |
|
||
|
||
class HexBinPlot(PlanePlot): | ||
_kind = "hexbin" | ||
@property | ||
def _kind(self) -> Literal["hexbin"]: | ||
return "hexbin" | ||
|
||
def __init__(self, data, x, y, C=None, **kwargs) -> None: | ||
super().__init__(data, x, y, **kwargs) | ||
|
@@ -1277,9 +1295,15 @@ def _make_legend(self): | |
|
||
|
||
class LinePlot(MPLPlot): | ||
_kind = "line" | ||
_default_rot = 0 | ||
orientation = "vertical" | ||
|
||
@property | ||
def orientation(self) -> PlottingOrientation: | ||
return "vertical" | ||
|
||
@property | ||
def _kind(self) -> Literal["line", "area", "hist", "kde", "box"]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needed so that the sub-classes are compatible with |
||
return "line" | ||
|
||
def __init__(self, data, **kwargs) -> None: | ||
from pandas.plotting import plot_params | ||
|
@@ -1363,8 +1387,7 @@ def _plot( # type: ignore[override] | |
cls._update_stacker(ax, stacking_id, y) | ||
return lines | ||
|
||
@classmethod | ||
def _ts_plot(cls, ax: Axes, x, data, style=None, **kwds): | ||
def _ts_plot(self, ax: Axes, x, data, style=None, **kwds): | ||
# accept x to be consistent with normal plot func, | ||
# x is not passed to tsplot as it uses data.index as x coordinate | ||
# column_num must be in kwds for stacking purpose | ||
|
@@ -1377,9 +1400,9 @@ def _ts_plot(cls, 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, cls._kind, kwds)) | ||
ax._plot_data.append((data, self._kind, kwds)) | ||
|
||
lines = cls._plot(ax, data.index, data.values, style=style, **kwds) | ||
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) | ||
return lines | ||
|
@@ -1471,7 +1494,9 @@ def get_label(i): | |
|
||
|
||
class AreaPlot(LinePlot): | ||
_kind = "area" | ||
@property | ||
def _kind(self) -> Literal["area"]: | ||
return "area" | ||
|
||
def __init__(self, data, **kwargs) -> None: | ||
kwargs.setdefault("stacked", True) | ||
|
@@ -1544,9 +1569,15 @@ def _post_plot_logic(self, ax: Axes, data): | |
|
||
|
||
class BarPlot(MPLPlot): | ||
_kind = "bar" | ||
@property | ||
def _kind(self) -> Literal["bar", "barh"]: | ||
return "bar" | ||
|
||
_default_rot = 90 | ||
orientation = "vertical" | ||
|
||
@property | ||
def orientation(self) -> PlottingOrientation: | ||
return "vertical" | ||
|
||
def __init__(self, data, **kwargs) -> None: | ||
# we have to treat a series differently than a | ||
|
@@ -1698,9 +1729,15 @@ def _decorate_ticks(self, ax: Axes, name, ticklabels, start_edge, end_edge): | |
|
||
|
||
class BarhPlot(BarPlot): | ||
_kind = "barh" | ||
@property | ||
def _kind(self) -> Literal["barh"]: | ||
return "barh" | ||
|
||
_default_rot = 0 | ||
orientation = "horizontal" | ||
|
||
@property | ||
def orientation(self) -> Literal["horizontal"]: | ||
return "horizontal" | ||
|
||
@property | ||
def _start_base(self): | ||
|
@@ -1727,7 +1764,10 @@ def _decorate_ticks(self, ax: Axes, name, ticklabels, start_edge, end_edge): | |
|
||
|
||
class PiePlot(MPLPlot): | ||
_kind = "pie" | ||
@property | ||
def _kind(self) -> Literal["pie"]: | ||
return "pie" | ||
|
||
_layout_type = "horizontal" | ||
|
||
def __init__(self, data, kind=None, **kwargs) -> None: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
|
||
from __future__ import annotations | ||
|
||
from datetime import timedelta | ||
import functools | ||
from typing import ( | ||
TYPE_CHECKING, | ||
|
@@ -185,11 +186,10 @@ def _get_ax_freq(ax: Axes): | |
return ax_freq | ||
|
||
|
||
def _get_period_alias(freq) -> str | None: | ||
def _get_period_alias(freq: timedelta | BaseOffset | str) -> str | None: | ||
freqstr = to_offset(freq).rule_code | ||
|
||
freq = get_period_alias(freqstr) | ||
return freq | ||
return get_period_alias(freqstr) | ||
|
||
|
||
def _get_freq(ax: Axes, series: Series): | ||
|
@@ -235,7 +235,9 @@ def use_dynamic_x(ax: Axes, data: DataFrame | Series) -> bool: | |
x = data.index | ||
if base <= FreqGroup.FR_DAY.value: | ||
return x[:1].is_normalized | ||
return Period(x[0], freq_str).to_timestamp().tz_localize(x.tz) == x[0] | ||
period = Period(x[0], freq_str) | ||
assert isinstance(period, Period) | ||
return period.to_timestamp().tz_localize(x.tz) == x[0] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
return True | ||
|
||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.