Repository: pandas-dev/pandas

Issue:
Bar plots are misaligned by default
There has been a recent change in bar plot default behavior that is causing misalignment of the bars on the y-axis. I'm not sure when this change occurred, but I will estimate 3-4 months ago. 

Previously, bar plots looked like this:

![good bar plot](http://d.pr/i/c2mO+)

However, the same code under '0.14.0-205-gbbde837' yields the following (ignore the theme differences):

![bad bar plot](http://d.pr/i/uoOf+)

So, the bars are bizarrely pushed to the right. Is matplotlib to blame for this (running 1.4.x)? 

Running Python 2.7.6 (homebrew) on OS X 10.9.3.



Discussion:
possibly related: #6691

I'll look into this. The problem seems to occur when plotting single column without stacking. Workaround is specify `stacked=True`.

```
fig, axes = plt.subplots(2, 2)
df1 = pd.DataFrame(np.random.randn(5))
df2 = pd.DataFrame(np.random.randn(5, 2))
df1.plot(kind='bar', ax=axes[0][0], title='NG', legend=False)
df1.plot(kind='bar', stacked=True, ax=axes[0][1], title='stacked=True', legend=False)
df2.plot(kind='bar', ax=axes[1][0], title='OK', legend=False)
df2.plot(kind='bar', stacked=True, ax=axes[1][1], title='stacked=True', legend=False)
```

![figure_1](https://cloud.githubusercontent.com/assets/1696302/3328173/4e4213c0-f7b9-11e3-93c8-25e9f0692708.png)


Resolving patch:
diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py
--- a/pandas/tools/plotting.py
+++ b/pandas/tools/plotting.py
@@ -1784,9 +1784,10 @@ def __init__(self, data, **kwargs):
         self.stacked = kwargs.pop('stacked', False)
 
         self.bar_width = kwargs.pop('width', 0.5)
+
         pos = kwargs.pop('position', 0.5)
 
-        kwargs['align'] = kwargs.pop('align', 'center')
+        kwargs.setdefault('align', 'center')
         self.tick_pos = np.arange(len(data))
 
         self.bottom = kwargs.pop('bottom', None)
@@ -1797,14 +1798,19 @@ def __init__(self, data, **kwargs):
 
         if self.stacked or self.subplots:
             self.tickoffset = self.bar_width * pos
-        elif kwargs['align'] == 'edge':
-            K = self.nseries
-            w = self.bar_width / K
-            self.tickoffset = self.bar_width * (pos - 0.5) + w * 1.5
+            if kwargs['align'] == 'edge':
+                self.lim_offset = self.bar_width / 2
+            else:
+                self.lim_offset = 0
         else:
-            K = self.nseries
-            w = self.bar_width / K
-            self.tickoffset = self.bar_width * pos + w
+            if kwargs['align'] == 'edge':
+                w = self.bar_width / self.nseries
+                self.tickoffset = self.bar_width * (pos - 0.5) + w * 0.5
+                self.lim_offset = w * 0.5
+            else:
+                self.tickoffset = self.bar_width * pos
+                self.lim_offset = 0
+
         self.ax_pos = self.tick_pos - self.tickoffset
 
     def _args_adjust(self):
@@ -1881,9 +1887,8 @@ def _make_plot(self):
                 neg_prior = neg_prior + np.where(mask, 0, y)
             else:
                 w = self.bar_width / K
-                rect = bar_f(ax, self.ax_pos + (i + 1.5) * w, y, w,
+                rect = bar_f(ax, self.ax_pos + (i + 0.5) * w, y, w,
                              start=start, label=label, **kwds)
-
             self._add_legend_handle(rect, label, index=i)
 
     def _post_plot_logic(self):
@@ -1894,8 +1899,12 @@ def _post_plot_logic(self):
                 str_index = [com.pprint_thing(key) for key in
                              range(self.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
+
             if self.kind == 'bar':
-                ax.set_xlim([self.ax_pos[0] - 0.25, self.ax_pos[-1] + 1])
+                ax.set_xlim((s_edge, e_edge))
                 ax.set_xticks(self.tick_pos)
                 ax.set_xticklabels(str_index, rotation=self.rot,
                                    fontsize=self.fontsize)
@@ -1905,7 +1914,7 @@ def _post_plot_logic(self):
                     ax.set_xlabel(name)
             elif self.kind == 'barh':
                 # horizontal bars
-                ax.set_ylim([self.ax_pos[0] - 0.25, self.ax_pos[-1] + 1])
+                ax.set_ylim((s_edge, e_edge))
                 ax.set_yticks(self.tick_pos)
                 ax.set_yticklabels(str_index, rotation=self.rot,
                                    fontsize=self.fontsize)
@@ -1915,9 +1924,6 @@ def _post_plot_logic(self):
             else:
                 raise NotImplementedError(self.kind)
 
-        # if self.subplots and self.legend:
-        #    self.axes[0].legend(loc='best')
-
 
 class PiePlot(MPLPlot):
 


Test patch:
diff --git a/pandas/tests/test_graphics.py b/pandas/tests/test_graphics.py
--- a/pandas/tests/test_graphics.py
+++ b/pandas/tests/test_graphics.py
@@ -1255,43 +1255,40 @@ def _check_bar_alignment(self, df, kind='bar', stacked=False,
                        align=align, width=width, position=position,
                        grid=True)
 
-        tick_pos = np.arange(len(df))
-
         axes = self._flatten_visible(axes)
 
         for ax in axes:
             if kind == 'bar':
                 axis = ax.xaxis
                 ax_min, ax_max = ax.get_xlim()
+                min_edge = min([p.get_x() for p in ax.patches])
+                max_edge = max([p.get_x() + p.get_width() for p in ax.patches])
             elif kind == 'barh':
                 axis = ax.yaxis
                 ax_min, ax_max = ax.get_ylim()
+                min_edge = min([p.get_y() for p in ax.patches])
+                max_edge = max([p.get_y() + p.get_height() for p in ax.patches])
             else:
                 raise ValueError
 
+            # GH 7498
+            # compare margins between lim and bar edges
+            self.assertAlmostEqual(ax_min, min_edge - 0.25)
+            self.assertAlmostEqual(ax_max, max_edge + 0.25)
+
             p = ax.patches[0]
             if kind == 'bar' and (stacked is True or subplots is True):
                 edge = p.get_x()
                 center = edge + p.get_width() * position
-                tickoffset = width * position
             elif kind == 'bar' and stacked is False:
                 center = p.get_x() + p.get_width() * len(df.columns) * position
                 edge = p.get_x()
-                if align == 'edge':
-                    tickoffset = width * (position - 0.5) + p.get_width() * 1.5
-                else:
-                    tickoffset = width * position + p.get_width()
             elif kind == 'barh' and (stacked is True or subplots is True):
                 center = p.get_y() + p.get_height() * position
                 edge = p.get_y()
-                tickoffset = width * position
             elif kind == 'barh' and stacked is False:
                 center = p.get_y() + p.get_height() * len(df.columns) * position
                 edge = p.get_y()
-                if align == 'edge':
-                    tickoffset = width * (position - 0.5) + p.get_height() * 1.5
-                else:
-                    tickoffset = width * position + p.get_height()
             else:
                 raise ValueError
 
@@ -1307,59 +1304,43 @@ def _check_bar_alignment(self, df, kind='bar', stacked=False,
             else:
                 raise ValueError
 
-            # Check starting point and axes limit margin
-            self.assertEqual(ax_min, tick_pos[0] - tickoffset - 0.25)
-            self.assertEqual(ax_max, tick_pos[-1] - tickoffset + 1)
-            # Check tick locations and axes limit margin
-            t_min = axis.get_ticklocs()[0] - tickoffset
-            t_max = axis.get_ticklocs()[-1] - tickoffset
-            self.assertAlmostEqual(ax_min, t_min - 0.25)
-            self.assertAlmostEqual(ax_max, t_max + 1.0)
         return axes
 
     @slow
     def test_bar_stacked_center(self):
         # GH2157
         df = DataFrame({'A': [3] * 5, 'B': lrange(5)}, index=lrange(5))
-        axes = self._check_bar_alignment(df, kind='bar', stacked=True)
-        # Check the axes has the same drawing range before fixing # GH4525
-        self.assertEqual(axes[0].get_xlim(), (-0.5, 4.75))
-
+        self._check_bar_alignment(df, kind='bar', stacked=True)
         self._check_bar_alignment(df, kind='bar', stacked=True, width=0.9)
-
-        axes = self._check_bar_alignment(df, kind='barh', stacked=True)
-        self.assertEqual(axes[0].get_ylim(), (-0.5, 4.75))
-
+        self._check_bar_alignment(df, kind='barh', stacked=True)
         self._check_bar_alignment(df, kind='barh', stacked=True, width=0.9)
 
     @slow
     def test_bar_center(self):
         df = DataFrame({'A': [3] * 5, 'B': lrange(5)}, index=lrange(5))
-        axes = self._check_bar_alignment(df, kind='bar', stacked=False)
-        self.assertEqual(axes[0].get_xlim(), (-0.75, 4.5))
-
+        self._check_bar_alignment(df, kind='bar', stacked=False)
         self._check_bar_alignment(df, kind='bar', stacked=False, width=0.9)
-
-        axes = self._check_bar_alignment(df, kind='barh', stacked=False)
-        self.assertEqual(axes[0].get_ylim(), (-0.75, 4.5))
-
+        self._check_bar_alignment(df, kind='barh', stacked=False)
         self._check_bar_alignment(df, kind='barh', stacked=False, width=0.9)
 
     @slow
     def test_bar_subplots_center(self):
         df = DataFrame({'A': [3] * 5, 'B': lrange(5)}, index=lrange(5))
-        axes = self._check_bar_alignment(df, kind='bar', subplots=True)
-        for ax in axes:
-            self.assertEqual(ax.get_xlim(), (-0.5, 4.75))
-
+        self._check_bar_alignment(df, kind='bar', subplots=True)
         self._check_bar_alignment(df, kind='bar', subplots=True, width=0.9)
-
-        axes = self._check_bar_alignment(df, kind='barh', subplots=True)
-        for ax in axes:
-            self.assertEqual(ax.get_ylim(), (-0.5, 4.75))
-
+        self._check_bar_alignment(df, kind='barh', subplots=True)
         self._check_bar_alignment(df, kind='barh', subplots=True, width=0.9)
 
+    @slow
+    def test_bar_align_single_column(self):
+        df = DataFrame(randn(5))
+        self._check_bar_alignment(df, kind='bar', stacked=False)
+        self._check_bar_alignment(df, kind='bar', stacked=True)
+        self._check_bar_alignment(df, kind='barh', stacked=False)
+        self._check_bar_alignment(df, kind='barh', stacked=True)
+        self._check_bar_alignment(df, kind='bar', subplots=True)
+        self._check_bar_alignment(df, kind='barh', subplots=True)
+
     @slow
     def test_bar_edge(self):
         df = DataFrame({'A': [3] * 5, 'B': lrange(5)}, index=lrange(5))