Skip to content

Commit 3cad03f

Browse files
Backport PR #39235: Revert "Inconsistent indexes for tick label plotting (#28733)" (#39252)
Co-authored-by: Simon Hawkins <[email protected]>
1 parent 15eaddd commit 3cad03f

File tree

4 files changed

+8
-96
lines changed

4 files changed

+8
-96
lines changed

doc/source/whatsnew/v1.2.0.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ Plotting
751751

752752
- Bug in :meth:`DataFrame.plot` was rotating xticklabels when ``subplots=True``, even if the x-axis wasn't an irregular time series (:issue:`29460`)
753753
- Bug in :meth:`DataFrame.plot` where a marker letter in the ``style`` keyword sometimes caused a ``ValueError`` (:issue:`21003`)
754-
- Bug in :meth:`DataFrame.plot.bar` and :meth:`Series.plot.bar` where ticks positions were assigned by value order instead of using the actual value for numeric or a smart ordering for string (:issue:`26186`, :issue:`11465`)
754+
- Bug in :meth:`DataFrame.plot.bar` and :meth:`Series.plot.bar` where ticks positions were assigned by value order instead of using the actual value for numeric or a smart ordering for string (:issue:`26186`, :issue:`11465`). This fix has been reverted in pandas 1.2.1, see :doc:`v1.2.1`
755755
- Twinned axes were losing their tick labels which should only happen to all but the last row or column of 'externally' shared axes (:issue:`33819`)
756756
- Bug in :meth:`Series.plot` and :meth:`DataFrame.plot` was throwing a :exc:`ValueError` when the Series or DataFrame was
757757
indexed by a :class:`.TimedeltaIndex` with a fixed frequency and the x-axis lower limit was greater than the upper limit (:issue:`37454`)

doc/source/whatsnew/v1.2.1.rst

+3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ Fixed regressions
3434
- Fixed regression that raised ``AttributeError`` with PyArrow versions [0.16.0, 1.0.0) (:issue:`38801`)
3535
- Fixed regression in :func:`pandas.testing.assert_frame_equal` raising ``TypeError`` with ``check_like=True`` when :class:`Index` or columns have mixed dtype (:issue:`39168`)
3636

37+
We have reverted a commit that resulted in several plotting related regressions in pandas 1.2.0 (:issue:`38969`, :issue:`38736`, :issue:`38865`, :issue:`38947` and :issue:`39126`).
38+
As a result, bugs reported as fixed in pandas 1.2.0 related to inconsistent tick labeling in bar plots are again present (:issue:`26186` and :issue:`11465`)
39+
3740
.. ---------------------------------------------------------------------------
3841
3942
.. _whatsnew_121.bug_fixes:

pandas/plotting/_matplotlib/core.py

+4-21
Original file line numberDiff line numberDiff line change
@@ -1370,6 +1370,7 @@ def __init__(self, data, **kwargs):
13701370
self.bar_width = kwargs.pop("width", 0.5)
13711371
pos = kwargs.pop("position", 0.5)
13721372
kwargs.setdefault("align", "center")
1373+
self.tick_pos = np.arange(len(data))
13731374

13741375
self.bottom = kwargs.pop("bottom", 0)
13751376
self.left = kwargs.pop("left", 0)
@@ -1392,16 +1393,7 @@ def __init__(self, data, **kwargs):
13921393
self.tickoffset = self.bar_width * pos
13931394
self.lim_offset = 0
13941395

1395-
if isinstance(self.data.index, ABCMultiIndex):
1396-
if kwargs["ax"] is not None and kwargs["ax"].has_data():
1397-
warnings.warn(
1398-
"Redrawing a bar plot with a MultiIndex is not supported "
1399-
+ "and may lead to inconsistent label positions.",
1400-
UserWarning,
1401-
)
1402-
self.ax_index = np.arange(len(data))
1403-
else:
1404-
self.ax_index = self.data.index
1396+
self.ax_pos = self.tick_pos - self.tickoffset
14051397

14061398
def _args_adjust(self):
14071399
if is_list_like(self.bottom):
@@ -1428,15 +1420,6 @@ def _make_plot(self):
14281420

14291421
for i, (label, y) in enumerate(self._iter_data(fillna=0)):
14301422
ax = self._get_ax(i)
1431-
1432-
if self.orientation == "vertical":
1433-
ax.xaxis.update_units(self.ax_index)
1434-
self.tick_pos = ax.convert_xunits(self.ax_index).astype(np.int)
1435-
elif self.orientation == "horizontal":
1436-
ax.yaxis.update_units(self.ax_index)
1437-
self.tick_pos = ax.convert_yunits(self.ax_index).astype(np.int)
1438-
self.ax_pos = self.tick_pos - self.tickoffset
1439-
14401423
kwds = self.kwds.copy()
14411424
if self._is_series:
14421425
kwds["color"] = colors
@@ -1508,8 +1491,8 @@ def _post_plot_logic(self, ax: "Axes", data):
15081491
str_index = [pprint_thing(key) for key in range(data.shape[0])]
15091492
name = self._get_index_name()
15101493

1511-
s_edge = self.ax_pos.min() - 0.25 + self.lim_offset
1512-
e_edge = self.ax_pos.max() + 0.25 + self.bar_width + self.lim_offset
1494+
s_edge = self.ax_pos[0] - 0.25 + self.lim_offset
1495+
e_edge = self.ax_pos[-1] + 0.25 + self.bar_width + self.lim_offset
15131496

15141497
self._decorate_ticks(ax, name, str_index, s_edge, e_edge)
15151498

pandas/tests/plotting/frame/test_frame.py

-74
Original file line numberDiff line numberDiff line change
@@ -2176,80 +2176,6 @@ def test_xlabel_ylabel_dataframe_plane_plot(self, kind, xlabel, ylabel):
21762176
assert ax.get_xlabel() == (xcol if xlabel is None else xlabel)
21772177
assert ax.get_ylabel() == (ycol if ylabel is None else ylabel)
21782178

2179-
@pytest.mark.parametrize("method", ["bar", "barh"])
2180-
def test_bar_ticklabel_consistence(self, method):
2181-
# Draw two consecutiv bar plot with consistent ticklabels
2182-
# The labels positions should not move between two drawing on the same axis
2183-
# GH: 26186
2184-
def get_main_axis(ax):
2185-
if method == "barh":
2186-
return ax.yaxis
2187-
elif method == "bar":
2188-
return ax.xaxis
2189-
2190-
# Plot the first bar plot
2191-
data = {"A": 0, "B": 3, "C": -4}
2192-
df = DataFrame.from_dict(data, orient="index", columns=["Value"])
2193-
ax = getattr(df.plot, method)()
2194-
ax.get_figure().canvas.draw()
2195-
2196-
# Retrieve the label positions for the first drawing
2197-
xticklabels = [t.get_text() for t in get_main_axis(ax).get_ticklabels()]
2198-
label_positions_1 = dict(zip(xticklabels, get_main_axis(ax).get_ticklocs()))
2199-
2200-
# Modify the dataframe order and values and plot on same axis
2201-
df = df.sort_values("Value") * -2
2202-
ax = getattr(df.plot, method)(ax=ax, color="red")
2203-
ax.get_figure().canvas.draw()
2204-
2205-
# Retrieve the label positions for the second drawing
2206-
xticklabels = [t.get_text() for t in get_main_axis(ax).get_ticklabels()]
2207-
label_positions_2 = dict(zip(xticklabels, get_main_axis(ax).get_ticklocs()))
2208-
2209-
# Assert that the label positions did not change between the plotting
2210-
assert label_positions_1 == label_positions_2
2211-
2212-
def test_bar_numeric(self):
2213-
# Bar plot with numeric index have tick location values equal to index
2214-
# values
2215-
# GH: 11465
2216-
df = DataFrame(np.random.rand(10), index=np.arange(10, 20))
2217-
ax = df.plot.bar()
2218-
ticklocs = ax.xaxis.get_ticklocs()
2219-
expected = np.arange(10, 20, dtype=np.int64)
2220-
tm.assert_numpy_array_equal(ticklocs, expected)
2221-
2222-
def test_bar_multiindex(self):
2223-
# Test from pandas/doc/source/user_guide/visualization.rst
2224-
# at section Plotting With Error Bars
2225-
# Related to issue GH: 26186
2226-
2227-
ix3 = pd.MultiIndex.from_arrays(
2228-
[
2229-
["a", "a", "a", "a", "b", "b", "b", "b"],
2230-
["foo", "foo", "bar", "bar", "foo", "foo", "bar", "bar"],
2231-
],
2232-
names=["letter", "word"],
2233-
)
2234-
2235-
df3 = DataFrame(
2236-
{"data1": [3, 2, 4, 3, 2, 4, 3, 2], "data2": [6, 5, 7, 5, 4, 5, 6, 5]},
2237-
index=ix3,
2238-
)
2239-
2240-
# Group by index labels and take the means and standard deviations
2241-
# for each group
2242-
gp3 = df3.groupby(level=("letter", "word"))
2243-
means = gp3.mean()
2244-
errors = gp3.std()
2245-
2246-
# No assertion we just ensure that we can plot a MultiIndex bar plot
2247-
# and are getting a UserWarning if redrawing
2248-
with tm.assert_produces_warning(None):
2249-
ax = means.plot.bar(yerr=errors, capsize=4)
2250-
with tm.assert_produces_warning(UserWarning):
2251-
means.plot.bar(yerr=errors, capsize=4, ax=ax)
2252-
22532179

22542180
def _generate_4_axes_via_gridspec():
22552181
import matplotlib as mpl

0 commit comments

Comments
 (0)