-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
BUG: Handle overlapping line and scatter on the same plot #61244
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
Changes from 8 commits
4e1abd8
241c96c
7dc9cfd
593520d
b96cf2d
0d0375a
102f5a9
a4de7f8
3cdd854
5eba291
9cb7b99
71e60c3
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 |
---|---|---|
|
@@ -48,7 +48,6 @@ | |
from pandas._typing import NDFrameT | ||
|
||
from pandas import ( | ||
DataFrame, | ||
DatetimeIndex, | ||
Index, | ||
PeriodIndex, | ||
|
@@ -231,8 +230,8 @@ def _get_freq(ax: Axes, series: Series): | |
return freq, ax_freq | ||
|
||
|
||
def use_dynamic_x(ax: Axes, data: DataFrame | Series) -> bool: | ||
freq = _get_index_freq(data.index) | ||
def use_dynamic_x(ax: Axes, index: Index) -> bool: | ||
freq = _get_index_freq(index) | ||
ax_freq = _get_ax_freq(ax) | ||
|
||
if freq is None: # convert irregular if axes has freq info | ||
|
@@ -250,16 +249,15 @@ def use_dynamic_x(ax: Axes, data: DataFrame | Series) -> bool: | |
return False | ||
|
||
# FIXME: hack this for 0.10.1, creating more technical debt...sigh | ||
if isinstance(data.index, ABCDatetimeIndex): | ||
if isinstance(index, ABCDatetimeIndex): | ||
# error: "BaseOffset" has no attribute "_period_dtype_code" | ||
freq_str = OFFSET_TO_PERIOD_FREQSTR.get(freq_str, freq_str) | ||
base = to_offset(freq_str, is_period=True)._period_dtype_code # type: ignore[attr-defined] | ||
x = data.index | ||
if base <= FreqGroup.FR_DAY.value: | ||
return x[:1].is_normalized | ||
period = Period(x[0], freq_str) | ||
return index[:1].is_normalized | ||
period = Period(index[0], freq_str) | ||
assert isinstance(period, Period) | ||
return period.to_timestamp().tz_localize(x.tz) == x[0] | ||
return period.to_timestamp().tz_localize(index.tz) == index[0] | ||
return True | ||
|
||
|
||
|
@@ -366,3 +364,17 @@ def format_dateaxis( | |
raise TypeError("index type not supported") | ||
|
||
plt.draw_if_interactive() | ||
|
||
|
||
def prepare_ts_data(data, ax, kwds): | ||
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. Is it possible to type this function? 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. Done |
||
freq, data = maybe_resample(data, ax, kwds) | ||
|
||
# Set ax with freq info | ||
decorate_axes(ax, freq) | ||
# digging deeper | ||
if hasattr(ax, "left_ax"): | ||
decorate_axes(ax.left_ax, freq) | ||
if hasattr(ax, "right_ax"): | ||
decorate_axes(ax.right_ax, freq) | ||
|
||
return freq, data |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -840,14 +840,26 @@ def test_plot_scatter_shape(self): | |
axes = df.plot(x="x", y="y", kind="scatter", subplots=True) | ||
_check_axes_shape(axes, axes_num=1, layout=(1, 1)) | ||
|
||
def test_raise_error_on_datetime_time_data(self): | ||
# GH 8113, datetime.time type is not supported by matplotlib in scatter | ||
def test_scatter_on_datetime_time_data(self): | ||
# datetime.time type is now supported in scatter, since a converter | ||
# is implemented in ScatterPlot | ||
df = DataFrame(np.random.default_rng(2).standard_normal(10), columns=["a"]) | ||
df["dtime"] = date_range(start="2014-01-01", freq="h", periods=10).time | ||
msg = "must be a string or a (real )?number, not 'datetime.time'" | ||
|
||
with pytest.raises(TypeError, match=msg): | ||
df.plot(kind="scatter", x="dtime", y="a") | ||
df.plot(kind="scatter", x="dtime", y="a") | ||
|
||
def test_scatter_line_xticks(self): | ||
# GH#61005 | ||
datetime_list = [datetime(year=2025, month=1, day=1, hour=n) for n in range(3)] | ||
df = DataFrame(columns=["datetime", "y"]) | ||
for i, n in enumerate(datetime_list): | ||
df.loc[len(df)] = [n, i] | ||
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. Could you create this in 1 call? i.e. pass a 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. I created it by passing a list |
||
fig, ax = plt.subplots(2, sharex=True) | ||
df.plot.scatter(x="datetime", y="y", ax=ax[0]) | ||
scatter_xticks = ax[0].get_xticks() | ||
df.plot(x="datetime", y="y", ax=ax[1]) | ||
line_xticks = ax[1].get_xticks() | ||
assert scatter_xticks[0] == line_xticks[0] | ||
assert scatter_xticks[-1] == line_xticks[-1] | ||
|
||
@pytest.mark.parametrize("x, y", [("dates", "vals"), (0, 1)]) | ||
def test_scatterplot_datetime_data(self, x, y): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we conditionally import this where used?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done