Skip to content

Commit f15f238

Browse files
committed
BUG: Inconsistent index for bar plot
Generate the tick position in BarPlot using convert tools from matlab. Add test for issue pandas-dev#26186 Add test for issue pandas-dev#11465
1 parent d2beaf3 commit f15f238

File tree

2 files changed

+55
-7
lines changed

2 files changed

+55
-7
lines changed

pandas/plotting/_core.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,6 @@ def __init__(self, data, **kwargs):
11991199
self.bar_width = kwargs.pop('width', 0.5)
12001200
pos = kwargs.pop('position', 0.5)
12011201
kwargs.setdefault('align', 'center')
1202-
self.tick_pos = np.arange(len(data))
12031202

12041203
self.bottom = kwargs.pop('bottom', 0)
12051204
self.left = kwargs.pop('left', 0)
@@ -1222,7 +1221,7 @@ def __init__(self, data, **kwargs):
12221221
self.tickoffset = self.bar_width * pos
12231222
self.lim_offset = 0
12241223

1225-
self.ax_pos = self.tick_pos - self.tickoffset
1224+
self.ax_index = self.data.index
12261225

12271226
def _args_adjust(self):
12281227
if is_list_like(self.bottom):
@@ -1249,6 +1248,16 @@ def _make_plot(self):
12491248

12501249
for i, (label, y) in enumerate(self._iter_data(fillna=0)):
12511250
ax = self._get_ax(i)
1251+
1252+
if self.orientation == 'vertical':
1253+
ax.xaxis.update_units(self.ax_index)
1254+
self.tick_pos = ax.convert_xunits(self.ax_index)
1255+
self.ax_pos = self.tick_pos - self.tickoffset
1256+
elif self.orientation == 'horizontal':
1257+
ax.yaxis.update_units(self.ax_index)
1258+
self.tick_pos = ax.convert_yunits(self.ax_index)
1259+
self.ax_pos = self.tick_pos - self.tickoffset
1260+
12521261
kwds = self.kwds.copy()
12531262
if self._is_series:
12541263
kwds['color'] = colors
@@ -1297,9 +1306,8 @@ def _post_plot_logic(self, ax, data):
12971306
else:
12981307
str_index = [pprint_thing(key) for key in range(data.shape[0])]
12991308
name = self._get_index_name()
1300-
1301-
s_edge = self.ax_pos[0] - 0.25 + self.lim_offset
1302-
e_edge = self.ax_pos[-1] + 0.25 + self.bar_width + self.lim_offset
1309+
s_edge = self.ax_pos.min() - 0.25 + self.lim_offset
1310+
e_edge = self.ax_pos.max() + 0.25 + self.bar_width + self.lim_offset
13031311

13041312
self._decorate_ticks(ax, name, str_index, s_edge, e_edge)
13051313

pandas/tests/plotting/test_frame.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -1084,14 +1084,17 @@ def test_bar_categorical(self):
10841084
for df in [df1, df2]:
10851085
ax = df.plot.bar()
10861086
ticks = ax.xaxis.get_ticklocs()
1087-
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5]))
1087+
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5],
1088+
dtype=np.float))
10881089
assert ax.get_xlim() == (-0.5, 5.5)
10891090
# check left-edge of bars
10901091
assert ax.patches[0].get_x() == -0.25
10911092
assert ax.patches[-1].get_x() == 5.15
10921093

10931094
ax = df.plot.bar(stacked=True)
1094-
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5]))
1095+
ticks = ax.xaxis.get_ticklocs()
1096+
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5],
1097+
dtype=np.float))
10951098
assert ax.get_xlim() == (-0.5, 5.5)
10961099
assert ax.patches[0].get_x() == -0.25
10971100
assert ax.patches[-1].get_x() == 4.75
@@ -3028,6 +3031,43 @@ def test_x_multiindex_values_ticks(self):
30283031
assert labels_position['(2013, 1)'] == 2.0
30293032
assert labels_position['(2013, 2)'] == 3.0
30303033

3034+
@pytest.mark.slow
3035+
@pytest.mark.parametrize('method', ['bar', 'barh'])
3036+
def test_bar_ticklabel_consistence(self, method):
3037+
# Draw two consecutiv bar plot with consistent ticklabels
3038+
# GH: 26186
3039+
def get_main_axis(ax):
3040+
if method == 'barh':
3041+
return ax.yaxis
3042+
elif method == 'bar':
3043+
return ax.xaxis
3044+
data = {"A": 0, "B": 3, "C": -4}
3045+
df = pd.DataFrame.from_dict(data, orient="index", columns=["Value"])
3046+
ax = getattr(df.plot, method)()
3047+
ax.get_figure().canvas.draw()
3048+
xticklabels = [t.get_text()
3049+
for t in get_main_axis(ax).get_ticklabels()]
3050+
label_positions_1 = dict(zip(xticklabels,
3051+
get_main_axis(ax).get_ticklocs()))
3052+
df = df.sort_values("Value") * - 2
3053+
ax = getattr(df.plot, method)(ax=ax, color="red")
3054+
ax.get_figure().canvas.draw()
3055+
xticklabels = [t.get_text()
3056+
for t in get_main_axis(ax).get_ticklabels()]
3057+
label_positions_2 = dict(zip(xticklabels,
3058+
get_main_axis(ax).get_ticklocs()))
3059+
assert label_positions_1 == label_positions_2
3060+
3061+
def test_bar_numeric(self):
3062+
# Bar plot with numeric index have tick location values equal to index
3063+
# values
3064+
# GH: 11465
3065+
index = np.arange(10, 20)
3066+
df = pd.DataFrame(np.random.rand(10), index=np.arange(10, 20))
3067+
ax = df.plot.bar()
3068+
ticklocs = ax.xaxis.get_ticklocs()
3069+
tm.assert_numpy_array_equal(ticklocs, index)
3070+
30313071

30323072
def _generate_4_axes_via_gridspec():
30333073
import matplotlib.pyplot as plt

0 commit comments

Comments
 (0)