Skip to content

Commit

Permalink
BUG: Inconsistent index for bar plot
Browse files Browse the repository at this point in the history
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
  • Loading branch information
nrebena committed May 26, 2019
1 parent d2beaf3 commit f15f238
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 7 deletions.
18 changes: 13 additions & 5 deletions pandas/plotting/_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -1199,7 +1199,6 @@ def __init__(self, data, **kwargs):
self.bar_width = kwargs.pop('width', 0.5)
pos = kwargs.pop('position', 0.5)
kwargs.setdefault('align', 'center')
self.tick_pos = np.arange(len(data))

self.bottom = kwargs.pop('bottom', 0)
self.left = kwargs.pop('left', 0)
Expand All @@ -1222,7 +1221,7 @@ def __init__(self, data, **kwargs):
self.tickoffset = self.bar_width * pos
self.lim_offset = 0

self.ax_pos = self.tick_pos - self.tickoffset
self.ax_index = self.data.index

def _args_adjust(self):
if is_list_like(self.bottom):
Expand All @@ -1249,6 +1248,16 @@ def _make_plot(self):

for i, (label, y) in enumerate(self._iter_data(fillna=0)):
ax = self._get_ax(i)

if self.orientation == 'vertical':
ax.xaxis.update_units(self.ax_index)
self.tick_pos = ax.convert_xunits(self.ax_index)
self.ax_pos = self.tick_pos - self.tickoffset
elif self.orientation == 'horizontal':
ax.yaxis.update_units(self.ax_index)
self.tick_pos = ax.convert_yunits(self.ax_index)
self.ax_pos = self.tick_pos - self.tickoffset

kwds = self.kwds.copy()
if self._is_series:
kwds['color'] = colors
Expand Down Expand Up @@ -1297,9 +1306,8 @@ def _post_plot_logic(self, ax, data):
else:
str_index = [pprint_thing(key) for key in range(data.shape[0])]
name = self._get_index_name()

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
s_edge = self.ax_pos.min() - 0.25 + self.lim_offset
e_edge = self.ax_pos.max() + 0.25 + self.bar_width + self.lim_offset

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

Expand Down
44 changes: 42 additions & 2 deletions pandas/tests/plotting/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -1084,14 +1084,17 @@ def test_bar_categorical(self):
for df in [df1, df2]:
ax = df.plot.bar()
ticks = ax.xaxis.get_ticklocs()
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5]))
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5],
dtype=np.float))
assert ax.get_xlim() == (-0.5, 5.5)
# check left-edge of bars
assert ax.patches[0].get_x() == -0.25
assert ax.patches[-1].get_x() == 5.15

ax = df.plot.bar(stacked=True)
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5]))
ticks = ax.xaxis.get_ticklocs()
tm.assert_numpy_array_equal(ticks, np.array([0, 1, 2, 3, 4, 5],
dtype=np.float))
assert ax.get_xlim() == (-0.5, 5.5)
assert ax.patches[0].get_x() == -0.25
assert ax.patches[-1].get_x() == 4.75
Expand Down Expand Up @@ -3028,6 +3031,43 @@ def test_x_multiindex_values_ticks(self):
assert labels_position['(2013, 1)'] == 2.0
assert labels_position['(2013, 2)'] == 3.0

@pytest.mark.slow
@pytest.mark.parametrize('method', ['bar', 'barh'])
def test_bar_ticklabel_consistence(self, method):
# Draw two consecutiv bar plot with consistent ticklabels
# GH: 26186
def get_main_axis(ax):
if method == 'barh':
return ax.yaxis
elif method == 'bar':
return ax.xaxis
data = {"A": 0, "B": 3, "C": -4}
df = pd.DataFrame.from_dict(data, orient="index", columns=["Value"])
ax = getattr(df.plot, method)()
ax.get_figure().canvas.draw()
xticklabels = [t.get_text()
for t in get_main_axis(ax).get_ticklabels()]
label_positions_1 = dict(zip(xticklabels,
get_main_axis(ax).get_ticklocs()))
df = df.sort_values("Value") * - 2
ax = getattr(df.plot, method)(ax=ax, color="red")
ax.get_figure().canvas.draw()
xticklabels = [t.get_text()
for t in get_main_axis(ax).get_ticklabels()]
label_positions_2 = dict(zip(xticklabels,
get_main_axis(ax).get_ticklocs()))
assert label_positions_1 == label_positions_2

def test_bar_numeric(self):
# Bar plot with numeric index have tick location values equal to index
# values
# GH: 11465
index = np.arange(10, 20)
df = pd.DataFrame(np.random.rand(10), index=np.arange(10, 20))
ax = df.plot.bar()
ticklocs = ax.xaxis.get_ticklocs()
tm.assert_numpy_array_equal(ticklocs, index)


def _generate_4_axes_via_gridspec():
import matplotlib.pyplot as plt
Expand Down

0 comments on commit f15f238

Please sign in to comment.