From 7dee8e649de6ec2eeb7aa1a364bf89ebca66ac3a Mon Sep 17 00:00:00 2001 From: Dan Birken Date: Mon, 24 Jun 2013 20:52:04 -0700 Subject: [PATCH 1/2] BUG: Make secondary_y work properly for bar plots GH3598 --- pandas/tools/plotting.py | 43 ++++++++++++++++----------- pandas/tseries/tests/test_plotting.py | 22 ++++++++++++++ 2 files changed, 48 insertions(+), 17 deletions(-) diff --git a/pandas/tools/plotting.py b/pandas/tools/plotting.py index 4e85d742e352c..039e13f35c4d7 100644 --- a/pandas/tools/plotting.py +++ b/pandas/tools/plotting.py @@ -1084,6 +1084,11 @@ def _maybe_add_color(self, colors, kwds, style, i): if has_color and (style is None or re.match('[a-z]+', style) is None): kwds['color'] = colors[i % len(colors)] + def _get_marked_label(self, label, col_num): + if self.on_right(col_num): + return label + ' (right)' + else: + return label class KdePlot(MPLPlot): def __init__(self, data, **kwargs): @@ -1214,10 +1219,12 @@ def _make_plot(self): newline = plotf(*args, **kwds)[0] lines.append(newline) - leg_label = label - if self.mark_right and self.on_right(i): - leg_label += ' (right)' - labels.append(leg_label) + + if self.mark_right: + labels.append(self._get_marked_label(label, i)) + else: + labels.append(label) + ax.grid(self.grid) if self._is_datetype(): @@ -1235,18 +1242,16 @@ def _make_ts_plot(self, data, **kwargs): lines = [] labels = [] - def to_leg_label(label, i): - if self.mark_right and self.on_right(i): - return label + ' (right)' - return label - def _plot(data, col_num, ax, label, style, **kwds): newlines = tsplot(data, plotf, ax=ax, label=label, style=style, **kwds) ax.grid(self.grid) lines.append(newlines[0]) - leg_label = to_leg_label(label, col_num) - labels.append(leg_label) + + if self.mark_right: + labels.append(self._get_marked_label(label, col_num)) + else: + labels.append(label) if isinstance(data, Series): ax = self._get_ax(0) # self.axes[0] @@ -1356,6 +1361,7 @@ class BarPlot(MPLPlot): _default_rot = {'bar': 90, 'barh': 0} def __init__(self, data, **kwargs): + self.mark_right = kwargs.pop('mark_right', True) self.stacked = kwargs.pop('stacked', False) self.ax_pos = np.arange(len(data)) + 0.25 if self.stacked: @@ -1398,8 +1404,6 @@ def _make_plot(self): rects = [] labels = [] - ax = self._get_ax(0) # self.axes[0] - bar_f = self.bar_f pos_prior = neg_prior = np.zeros(len(self.data)) @@ -1407,6 +1411,7 @@ def _make_plot(self): K = self.nseries for i, (label, y) in enumerate(self._iter_data()): + ax = self._get_ax(i) label = com.pprint_thing(label) kwds = self.kwds.copy() kwds['color'] = colors[i % len(colors)] @@ -1419,8 +1424,6 @@ def _make_plot(self): start = 0 if mpl.__version__ == "1.2.1" else None if self.subplots: - ax = self._get_ax(i) # self.axes[i] - rect = bar_f(ax, self.ax_pos, y, self.bar_width, start = start, **kwds) @@ -1437,7 +1440,10 @@ def _make_plot(self): start = start, label=label, **kwds) rects.append(rect) - labels.append(label) + if self.mark_right: + labels.append(self._get_marked_label(label, i)) + else: + labels.append(label) if self.legend and not self.subplots: patches = [r[0] for r in rects] @@ -1537,7 +1543,10 @@ def plot_frame(frame=None, x=None, y=None, subplots=False, sharex=True, Rotation for ticks secondary_y : boolean or sequence, default False Whether to plot on the secondary y-axis - If dict then can select which columns to plot on secondary y-axis + If a list/tuple, which columns to plot on secondary y-axis + mark_right: boolean, default True + When using a secondary_y axis, should the legend label the axis of + the various columns automatically kwds : keywords Options to pass to matplotlib plotting method diff --git a/pandas/tseries/tests/test_plotting.py b/pandas/tseries/tests/test_plotting.py index eae04081e7479..f1602bbd3f020 100644 --- a/pandas/tseries/tests/test_plotting.py +++ b/pandas/tseries/tests/test_plotting.py @@ -615,6 +615,16 @@ def test_secondary_frame(self): self.assert_(axes[1].get_yaxis().get_ticks_position() == 'default') self.assert_(axes[2].get_yaxis().get_ticks_position() == 'right') + @slow + def test_secondary_bar_frame(self): + import matplotlib.pyplot as plt + plt.close('all') + df = DataFrame(np.random.randn(5, 3), columns=['a', 'b', 'c']) + axes = df.plot(kind='bar', secondary_y=['a', 'c'], subplots=True) + self.assert_(axes[0].get_yaxis().get_ticks_position() == 'right') + self.assert_(axes[1].get_yaxis().get_ticks_position() == 'default') + self.assert_(axes[2].get_yaxis().get_ticks_position() == 'right') + @slow def test_mixed_freq_regular_first(self): import matplotlib.pyplot as plt @@ -864,6 +874,18 @@ def test_secondary_legend(self): self.assert_(leg.get_texts()[2].get_text() == 'C') self.assert_(leg.get_texts()[3].get_text() == 'D') + plt.clf() + ax = df.plot(kind='bar', secondary_y=['A']) + leg = ax.get_legend() + self.assert_(leg.get_texts()[0].get_text() == 'A (right)') + self.assert_(leg.get_texts()[1].get_text() == 'B') + + plt.clf() + ax = df.plot(kind='bar', secondary_y=['A'], mark_right=False) + leg = ax.get_legend() + self.assert_(leg.get_texts()[0].get_text() == 'A') + self.assert_(leg.get_texts()[1].get_text() == 'B') + plt.clf() ax = fig.add_subplot(211) df = tm.makeTimeDataFrame() From 77ae62f863800b2843715ee7a5b8a3d516f06d96 Mon Sep 17 00:00:00 2001 From: Dan Birken Date: Mon, 24 Jun 2013 22:20:41 -0700 Subject: [PATCH 2/2] Add release notes for #3598 --- doc/source/release.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/release.rst b/doc/source/release.rst index b2c1e585fd90f..577d3a30c80f0 100644 --- a/doc/source/release.rst +++ b/doc/source/release.rst @@ -232,6 +232,7 @@ pandas 0.11.1 is a ``list`` or ``tuple``. - Fixed bug where a time-series was being selected in preference to an actual column name in a frame (:issue:`3594`) + - Make secondary_y work properly for bar plots (:issue:`3598`) - Fix modulo and integer division on Series,DataFrames to act similary to ``float`` dtypes to return ``np.nan`` or ``np.inf`` as appropriate (:issue:`3590`) - Fix incorrect dtype on groupby with ``as_index=False`` (:issue:`3610`)