Skip to content

Commit 76d28c7

Browse files
authored
ENH: warn when silently ignoring log keywords in PiePlot (#55890)
* ENH: warn when silently ignoring log keywords in PiePlot * pyright fixup * mypy fixup * troubleshoot mypy
1 parent 70ce4eb commit 76d28c7

File tree

2 files changed

+57
-21
lines changed

2 files changed

+57
-21
lines changed

pandas/plotting/_matplotlib/core.py

Lines changed: 52 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,14 @@ def __init__(
159159
layout=None,
160160
include_bool: bool = False,
161161
column: IndexLabel | None = None,
162+
*,
163+
logx: bool | None | Literal["sym"] = False,
164+
logy: bool | None | Literal["sym"] = False,
165+
loglog: bool | None | Literal["sym"] = False,
166+
mark_right: bool = True,
167+
stacked: bool = False,
168+
label: Hashable | None = None,
169+
style=None,
162170
**kwds,
163171
) -> None:
164172
import matplotlib.pyplot as plt
@@ -230,13 +238,13 @@ def __init__(
230238
self.legend_handles: list[Artist] = []
231239
self.legend_labels: list[Hashable] = []
232240

233-
self.logx = kwds.pop("logx", False)
234-
self.logy = kwds.pop("logy", False)
235-
self.loglog = kwds.pop("loglog", False)
236-
self.label = kwds.pop("label", None)
237-
self.style = kwds.pop("style", None)
238-
self.mark_right = kwds.pop("mark_right", True)
239-
self.stacked = kwds.pop("stacked", False)
241+
self.logx = type(self)._validate_log_kwd("logx", logx)
242+
self.logy = type(self)._validate_log_kwd("logy", logy)
243+
self.loglog = type(self)._validate_log_kwd("loglog", loglog)
244+
self.label = label
245+
self.style = style
246+
self.mark_right = mark_right
247+
self.stacked = stacked
240248

241249
# ax may be an Axes object or (if self.subplots) an ndarray of
242250
# Axes objects
@@ -292,6 +300,22 @@ def _validate_sharex(sharex: bool | None, ax, by) -> bool:
292300
raise TypeError("sharex must be a bool or None")
293301
return bool(sharex)
294302

303+
@classmethod
304+
def _validate_log_kwd(
305+
cls,
306+
kwd: str,
307+
value: bool | None | Literal["sym"],
308+
) -> bool | None | Literal["sym"]:
309+
if (
310+
value is None
311+
or isinstance(value, bool)
312+
or (isinstance(value, str) and value == "sym")
313+
):
314+
return value
315+
raise ValueError(
316+
f"keyword '{kwd}' should be bool, None, or 'sym', not '{value}'"
317+
)
318+
295319
@final
296320
@staticmethod
297321
def _validate_subplots_kwarg(
@@ -556,14 +580,6 @@ def _axes_and_fig(self) -> tuple[Sequence[Axes], Figure]:
556580

557581
axes = flatten_axes(axes)
558582

559-
valid_log = {False, True, "sym", None}
560-
input_log = {self.logx, self.logy, self.loglog}
561-
if input_log - valid_log:
562-
invalid_log = next(iter(input_log - valid_log))
563-
raise ValueError(
564-
f"Boolean, None and 'sym' are valid options, '{invalid_log}' is given."
565-
)
566-
567583
if self.logx is True or self.loglog is True:
568584
[a.set_xscale("log") for a in axes]
569585
elif self.logx == "sym" or self.loglog == "sym":
@@ -1334,7 +1350,12 @@ def _make_plot(self, fig: Figure):
13341350
cbar.ax.set_yticklabels(self.data[c].cat.categories)
13351351

13361352
if label is not None:
1337-
self._append_legend_handles_labels(scatter, label)
1353+
self._append_legend_handles_labels(
1354+
# error: Argument 2 to "_append_legend_handles_labels" of
1355+
# "MPLPlot" has incompatible type "Hashable"; expected "str"
1356+
scatter,
1357+
label, # type: ignore[arg-type] # pyright: ignore[reportGeneralTypeIssues]
1358+
)
13381359

13391360
errors_x = self._get_errorbars(label=x, index=0, yerr=False)
13401361
errors_y = self._get_errorbars(label=y, index=0, xerr=False)
@@ -1999,10 +2020,21 @@ def __init__(self, data, kind=None, **kwargs) -> None:
19992020
if (data < 0).any().any():
20002021
raise ValueError(f"{self._kind} plot doesn't allow negative values")
20012022
MPLPlot.__init__(self, data, kind=kind, **kwargs)
2002-
self.grid = False
2003-
self.logy = False
2004-
self.logx = False
2005-
self.loglog = False
2023+
2024+
@classmethod
2025+
def _validate_log_kwd(
2026+
cls,
2027+
kwd: str,
2028+
value: bool | None | Literal["sym"],
2029+
) -> bool | None | Literal["sym"]:
2030+
super()._validate_log_kwd(kwd=kwd, value=value)
2031+
if value is not False:
2032+
warnings.warn(
2033+
f"PiePlot ignores the '{kwd}' keyword",
2034+
UserWarning,
2035+
stacklevel=find_stack_level(),
2036+
)
2037+
return False
20062038

20072039
def _validate_color_args(self, color, colormap) -> None:
20082040
# TODO: warn if color is passed and ignored?

pandas/tests/plotting/frame/test_frame.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,10 +333,14 @@ def test_invalid_logscale(self, input_param):
333333
# GH: 24867
334334
df = DataFrame({"a": np.arange(100)}, index=np.arange(100))
335335

336-
msg = "Boolean, None and 'sym' are valid options, 'sm' is given."
336+
msg = f"keyword '{input_param}' should be bool, None, or 'sym', not 'sm'"
337337
with pytest.raises(ValueError, match=msg):
338338
df.plot(**{input_param: "sm"})
339339

340+
msg = f"PiePlot ignores the '{input_param}' keyword"
341+
with tm.assert_produces_warning(UserWarning, match=msg):
342+
df.plot.pie(subplots=True, **{input_param: True})
343+
340344
def test_xcompat(self):
341345
df = tm.makeTimeDataFrame()
342346
ax = df.plot(x_compat=True)

0 commit comments

Comments
 (0)