Pandas: DataFrame.plot(): changing position of legend with secondary_y removes legend entries

Created on 18 May 2017  路  5Comments  路  Source: pandas-dev/pandas

Code Sample

df = pd.DataFrame([[1, 1], [2, 4], [3, 7]], index=[1, 2, 3],
                  columns=['col a', 'col b'])
df.plot(kind='bar', secondary_y=['col b']).legend(bbox_to_anchor=(1.5, 1))

Problem description

The code above produces a barplot with secondary y axis for 'col b'.
The last command (.legend(...)) tells it to move the legend around, which works but produces a new legend that only includes 'col a'.

Expected Output

I believe it should include both columns in the legend, like it does when the .legend part is omitted.
I have also tried to move the legend around with other methods, but with no success.

Output of pd.show_versions()

INSTALLED VERSIONS

commit: None
python: 3.5.2.final.0
python-bits: 64
OS: Windows
OS-release: 7
machine: AMD64
processor: Intel64 Family 6 Model 42 Stepping 7, GenuineIntel
byteorder: little
LC_ALL: None
LANG: None
LOCALE: None.None

pandas: 0.19.2
nose: 1.3.7
pip: 8.1.2
setuptools: 35.0.2
Cython: 0.24.1
numpy: 1.12.1
scipy: 0.18.1
statsmodels: 0.6.1
xarray: None
IPython: 6.0.0
sphinx: 1.4.6
patsy: 0.4.1
dateutil: 2.6.0
pytz: 2017.2
blosc: None
bottleneck: 1.1.0
tables: 3.2.2
numexpr: 2.6.1
matplotlib: 1.5.3
openpyxl: 2.3.2
xlrd: 1.0.0
xlwt: 1.1.2
xlsxwriter: 0.9.3
lxml: 3.6.4
bs4: 4.5.1
html5lib: None
httplib2: None
apiclient: None
sqlalchemy: 1.0.13
pymysql: 0.7.9.None
psycopg2: None
jinja2: 2.8
boto: 2.42.0
pandas_datareader: None

Visualization

Most helpful comment

Hm... it seems to keep the labels this way, although the legend locations differ a bit.

Here's with

ax.get_legend().set_bbox_to_anchor((0.7, 1))

pandas_sec_y_bbox_output

Increasing it to more than 0.7 puts it out of the frame, although that is what I originally intended since I can still view it in IPython Notebook.

Edit: Here's the original, with

df = pd.DataFrame([[1, 1, 1], [2, 4, 3], [3, 7, 9]], index=[1, 2, 3],
                  columns=['col a', 'col b', 'col c'])
df.plot(kind='bar', secondary_y=['col b']).legend(bbox_to_anchor=(1.1, 1))

pandas_plot_bbox_orig

All 5 comments

df = pd.DataFrame([[1, 1, 1], [2, 4, 3], [3, 7, 9]], index=[1, 2, 3],
                  columns=['col a', 'col b', 'col c'])
df.plot(kind='bar', secondary_y=['col b']).legend(bbox_to_anchor=(1.5, 1))

it seems only the column in the secondary axis is left out

Not really sure what's going on. The bbox_to_anchor seems to produce a new legend.

In [58]: ax = df.plot(kind='bar', secondary_y=['col b'])

In [59]: ax.get_legend()
Out[59]: <matplotlib.legend.Legend at 0x11810d588>

In [60]: ax.legend(bbox_to_anchor=(1.5, 1))
Out[60]: <matplotlib.legend.Legend at 0x1181d1898>

In [61]: ax.get_legend()
Out[61]: <matplotlib.legend.Legend at 0x1181d1898>

It's possible that pandas isn't properly adding the legend labels / handles if you want to take a look in plotting/_core.py.

Actually, can you post an image of your output? Here's mine with ax.get_legend().set_bbox_to_anchor((1.1, 1))
fig

I think your 1.5 was plotting out of the frame for me. Does that work for you?

Hm... it seems to keep the labels this way, although the legend locations differ a bit.

Here's with

ax.get_legend().set_bbox_to_anchor((0.7, 1))

pandas_sec_y_bbox_output

Increasing it to more than 0.7 puts it out of the frame, although that is what I originally intended since I can still view it in IPython Notebook.

Edit: Here's the original, with

df = pd.DataFrame([[1, 1, 1], [2, 4, 3], [3, 7, 9]], index=[1, 2, 3],
                  columns=['col a', 'col b', 'col c'])
df.plot(kind='bar', secondary_y=['col b']).legend(bbox_to_anchor=(1.1, 1))

pandas_plot_bbox_orig

ax = plt.gca()
df = pd.DataFrame([[1, 1, 1], [2, 4, 3], [3, 7, 9]], index=[1, 2, 3], columns=['col a', 'col b', 'col c'])
df.plot(kind='bar', secondary_y=['col b'])
ax.legend(bbox_to_anchor=(1.5, 1))

Updating the values in anchor option will help to shift the location of the legend box. It's in X,Y order. Update first argument for moving along X axis and update second value for shifting along Y axis. Following code worked in my code.

ax.get_legend().set_bbox_to_anchor((.8532,.3))
plt.show()

github1

Was this page helpful?
0 / 5 - 0 ratings