Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ Other enhancements
- :meth:`.DataFrameGroupBy.transform`, :meth:`.SeriesGroupBy.transform`, :meth:`.DataFrameGroupBy.agg`, :meth:`.SeriesGroupBy.agg`, :meth:`.SeriesGroupBy.apply`, :meth:`.DataFrameGroupBy.apply` now support ``kurt`` (:issue:`40139`)
- :meth:`DataFrame.apply` supports using third-party execution engines like the Bodo.ai JIT compiler (:issue:`60668`)
- :meth:`DataFrame.iloc` and :meth:`Series.iloc` now support boolean masks in ``__getitem__`` for more consistent indexing behavior (:issue:`60994`)
- :meth:`DataFrame.plot.bar` and :meth:`Series.plot.bar` now use ``TimeSeries_DateFormatter`` for datetime and period indices, matching the formatting behavior of line plots (:issue:`1918`)
- :meth:`DataFrame.to_csv` and :meth:`Series.to_csv` now support Python's new-style format strings (e.g., ``"{:.6f}"``) for the ``float_format`` parameter, in addition to old-style ``%`` format strings and callables. This allows for more flexible and modern formatting of floating point numbers when exporting to CSV. (:issue:`49580`)
- :meth:`DataFrameGroupBy.transform`, :meth:`SeriesGroupBy.transform`, :meth:`DataFrameGroupBy.agg`, :meth:`SeriesGroupBy.agg`, :meth:`RollingGroupby.apply`, :meth:`ExpandingGroupby.apply`, :meth:`Rolling.apply`, :meth:`Expanding.apply`, :meth:`DataFrame.apply` with ``engine="numba"`` now supports positional arguments passed as kwargs (:issue:`58995`)
- :meth:`Rolling.agg`, :meth:`Expanding.agg` and :meth:`ExponentialMovingWindow.agg` now accept :class:`NamedAgg` aggregations through ``**kwargs`` (:issue:`28333`)
Expand Down
35 changes: 29 additions & 6 deletions pandas/plotting/_matplotlib/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
from pandas.plotting._matplotlib.misc import unpack_single_str_list
from pandas.plotting._matplotlib.style import get_standard_colors
from pandas.plotting._matplotlib.timeseries import (
decorate_axes,
format_dateaxis,
maybe_convert_index,
prepare_ts_data,
Expand Down Expand Up @@ -2041,15 +2042,37 @@ def _make_plot(self, fig: Figure) -> None:
self._append_legend_handles_labels(rect, label)

def _post_plot_logic(self, ax: Axes, data) -> None:
if self.use_index:
str_index = [pprint_thing(key) for key in data.index]
else:
str_index = [pprint_thing(key) for key in range(data.shape[0])]

s_edge = self.ax_pos[0] - 0.25 + self.lim_offset
e_edge = self.ax_pos[-1] + 0.25 + self.bar_width + self.lim_offset

self._decorate_ticks(ax, self._get_index_name(), str_index, s_edge, e_edge)
# GH#1918: Apply date formatter for time series indices
if self._is_ts_plot():
decorate_axes(ax, data.index.freq)
freq = data.index.freq

index = data.index
if isinstance(index, ABCDatetimeIndex):
index = index.to_period(freq=freq)

if isinstance(index, ABCPeriodIndex):
format_dateaxis(ax, freq, index)

ax.set_xlim((s_edge, e_edge))
if self.xticks is not None:
ax.set_xticks(np.array(self.xticks))
else:
ax.set_xticks(self.tick_pos)

index_name = self._get_index_name()
if index_name is not None and self.use_index:
ax.set_xlabel(index_name)
else:
if self.use_index:
str_index = [pprint_thing(key) for key in data.index]
else:
str_index = [pprint_thing(key) for key in range(data.shape[0])]

self._decorate_ticks(ax, self._get_index_name(), str_index, s_edge, e_edge)

def _decorate_ticks(
self,
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/plotting/frame/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -2164,13 +2164,13 @@ def test_memory_leak(self, kind):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
).abs()
else:
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)

# Use a weakref so we can see if the object gets collected without
Expand Down
23 changes: 17 additions & 6 deletions pandas/tests/plotting/test_datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -1264,7 +1264,7 @@ def test_secondary_legend(self):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)
df.plot(secondary_y=["A", "B"], ax=ax)
leg = ax.get_legend()
Expand All @@ -1285,7 +1285,7 @@ def test_secondary_legend_right(self):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)
fig = mpl.pyplot.figure()
ax = fig.add_subplot(211)
Expand All @@ -1301,7 +1301,7 @@ def test_secondary_legend_bar(self):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)
fig, ax = mpl.pyplot.subplots()
df.plot(kind="bar", secondary_y=["A"], ax=ax)
Expand All @@ -1313,7 +1313,7 @@ def test_secondary_legend_bar_right(self):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)
fig, ax = mpl.pyplot.subplots()
df.plot(kind="bar", secondary_y=["A"], mark_right=False, ax=ax)
Expand All @@ -1325,14 +1325,14 @@ def test_secondary_legend_multi_col(self):
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)
fig = mpl.pyplot.figure()
ax = fig.add_subplot(211)
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 4)),
columns=Index(list("ABCD"), dtype=object),
index=date_range("2000-01-01", periods=10, freq="B"),
index=date_range("2000-01-01", periods=10, freq="D"),
)
ax = df.plot(secondary_y=["C", "D"], ax=ax)
leg = ax.get_legend()
Expand Down Expand Up @@ -1691,6 +1691,17 @@ def test_pickle_fig(self, temp_file, frame_or_series, idx):
with temp_file.open(mode="wb") as path:
pickle.dump(fig, path)

def test_bar_plot_with_datetime_index_uses_date_formatter(self):
# GH#1918 - bar plots should use DateFormatter for datetime indices
df = DataFrame(
np.random.default_rng(2).standard_normal((10, 2)),
index=date_range("2020-01-01", periods=10),
columns=["A", "B"],
)
ax_bar = df.plot(kind="bar")
bar_formatter = ax_bar.get_xaxis().get_major_formatter()
assert isinstance(bar_formatter, conv.TimeSeries_DateFormatter)


def _check_plot_works(f, freq=None, series=None, *args, **kwargs):
fig = plt.gcf()
Expand Down
Loading