Skip to content

some markers missing from legend #14958

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
nbecker opened this issue Dec 22, 2016 · 18 comments · Fixed by #30687
Closed

some markers missing from legend #14958

nbecker opened this issue Dec 22, 2016 · 18 comments · Fixed by #30687
Labels
Milestone

Comments

@nbecker
Copy link

nbecker commented Dec 22, 2016

Code Sample, a copy-pastable example if possible

# Your code here
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.randn(8, 3), 
                  columns=['A', 'B', 'C'])
ax = df.plot (y=['A'], marker='x', linestyle='solid')
df.plot (y=['B'], marker='o', linestyle='dotted', ax=ax)
df.plot (y=['C'], marker='<', linestyle='dotted', ax=ax)
plt.grid()
plt.show()

Problem description

The legend is missing some markers.
If I add
plt.legend()
then they show up.

See attached
figure1.pdf

[this should explain why the current behaviour is a problem and why the expected output is a better solution.]

Expected Output

Output of pd.show_versions()

# Paste the output here pd.show_versions() here INSTALLED VERSIONS ------------------ commit: None python: 3.5.2.final.0 python-bits: 64 OS: Linux OS-release: 4.8.14-300.fc25.x86_64 machine: x86_64 processor: x86_64 byteorder: little LC_ALL: None LANG: en_US.UTF-8 LOCALE: en_US.UTF-8

pandas: 0.19.1
nose: 1.3.7
pip: 9.0.1
setuptools: 31.0.0
Cython: 0.25.2
numpy: 1.12.0rc1
scipy: 0.18.1
statsmodels: None
xarray: None
IPython: 5.1.0
sphinx: 1.5
patsy: None
dateutil: 2.6.0
pytz: 2016.10
blosc: None
bottleneck: None
tables: 3.3.0
numexpr: 2.6.1
matplotlib: 2.0.0rc2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: 4.5.1
html5lib: 0.999
httplib2: None
apiclient: None
sqlalchemy: None
pymysql: None
psycopg2: None
jinja2: 2.8
boto: None
pandas_datareader: None

@jorisvandenbossche
Copy link
Member

@nbecker Thanks for the report. Can confirm this on master. The legend drawing should be retriggered somehow after adding the additional lines (although I am not sure why the lines get added automatically, but the markers not)

@Vutsuak16
Copy link
Contributor

Vutsuak16 commented Dec 29, 2016

The 'ax' object let us draw all the plots in the same figure. If we draw each plot separately like this

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.randn(8, 3), 
                  columns=['A', 'B', 'C'])
ax = df.plot (y=['A'], marker='x', linestyle='solid')
df.plot (y=['B'], marker='o', linestyle='dotted')
df.plot (y=['C'], marker='<', linestyle='dotted')
plt.show()

We get the desired result. We need not add plt.legend().
@nbecker @jorisvandenbossche

@jorisvandenbossche
Copy link
Member

@Vutsuak16 Yes, that is correct, but then you get separate figures. The point here is to have them on a single figure. And it is in that case that only the first one gets a correct legend.

@jorisvandenbossche jorisvandenbossche added this to the Next Major Release milestone Dec 29, 2016
@Vutsuak16
Copy link
Contributor

Well let me have a look on it.
Should I hack into the matplotlib or pandas codebase ? Maybe there is some kind of conflict ?
@jorisvandenbossche

@TomAugspurger
Copy link
Contributor

Should I hack into the matplotlib or pandas codebase ?

In pandas I think. We have some logic for when to redraw the legend. See pandas/tools/plotting.py.

@jorisvandenbossche
Copy link
Member

No, I think this is probably just a pandas issue. In matplotlib you need to call legend explicitly in any case. It is pandas that gives the convenience of trying to do this for you.

Eg in this pure matplotlib example, only after calling the first ax.legend(), the legend is drawn. When adding another line, you need to call it again to update the legend:

fig, ax = plt.subplots()
ax.plot(df.index, df.A, marker='x', linestyle='solid')
ax.legend()
ax.plot(df.index, df.B, marker='o', linestyle='dotted')
ax.legend()

@sinhrks
Copy link
Member

sinhrks commented Jan 4, 2017

related to #14563. Current legend-redrawing logic doesn't work well in specific condition.

@JoshuaC3
Copy link

This also seems to work nicely and would save time/code on multiple plots,

fig, ax = plt.subplots()
ax.plot(df.index, df.A, marker='x', linestyle='solid')
ax.plot(df.index, df.B, marker='o', linestyle='dotted')
ax.plot(df.index, df.C, marker='>', linestyle='solid')
# more plots here...

ax.legend()

@et2010
Copy link

et2010 commented Apr 2, 2018

Any updates on this?

@TomAugspurger
Copy link
Contributor

Still open. Are you interested in working on it @et2010?

@et2010
Copy link

et2010 commented Apr 2, 2018

I would like to but I don't know where to start @TomAugspurger

@TomAugspurger
Copy link
Contributor

Not entirely sure, but the issue is probably somewhere near

def _make_legend(self):
ax, leg = self._get_ax_legend(self.axes[0])
handles = []
labels = []
title = ''
if not self.subplots:
if leg is not None:
title = leg.get_title().get_text()
handles = leg.legendHandles
labels = [x.get_text() for x in leg.get_texts()]
if self.legend:
if self.legend == 'reverse':
self.legend_handles = reversed(self.legend_handles)
self.legend_labels = reversed(self.legend_labels)
handles += self.legend_handles
labels += self.legend_labels
if self.legend_title is not None:
title = self.legend_title
if len(handles) > 0:
ax.legend(handles, labels, loc='best', title=title)
elif self.subplots and self.legend:
for ax in self.axes:
if ax.get_visible():
ax.legend(loc='best')

@TomAugspurger
Copy link
Contributor

@et2010
Copy link

et2010 commented Apr 3, 2018

I didn't figure out how to fix this. But my friend @ashfinal gave me a work around for this:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

df = pd.DataFrame(np.random.randn(8, 3), 
                  columns=['A', 'B', 'C'])
ax = df.plot (y='A', marker='x', linestyle='solid')
df.plot (y='B', marker='o', linestyle='dotted', ax=ax, subplots=True)
df.plot (y='C', marker='<', linestyle='dotted', ax=ax, subplots=True)
plt.grid()
plt.show()

Add keyword argument subplots=True and the marker in legend will show as expected.

Also, one can modify the default rcParams to include marker styles using the cycler API from matplotlib. The benefit of doing so is that the legend (with name) could be formatted automatically without further tinkering.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from cycler import cycler

df = pd.DataFrame(np.random.randn(8, 3), columns=['A', 'B', 'C'])
df.columns.name = 'name'  # <=== legend description

marker_styles = cycler('marker',
                       ['o', 'x', 's', 'D', '*', '+', 'h', 'p', '^', 'P'])
color_styles = plt.rcParams['axes.prop_cycle']
plt.rcParams['axes.prop_cycle'] = marker_styles + color_styles

fig, ax = plt.subplots()
df.plot(ax=ax)

plt.grid()

image

@Ketki-Savle
Copy link

I ran into the same situation. When my plot style was seaborn-whitegrid, I could not view the indications displayed by plt.legend() but when I changed my plot style using plt.style.use('classic') then I could see the correct output. I hope that helps!

@charlesdong1991
Copy link
Member

i think this has been fixed, and i cannot reproduce it on master, seems to be fixed by #27808

Screen Shot 2020-01-04 at 6 03 19 PM

so i think this can be closed @TomAugspurger @jreback

@jreback
Copy link
Contributor

jreback commented Jan 4, 2020

do we have sufficient tests for this already; if not can u add one

@charlesdong1991
Copy link
Member

well, i have one in previous PR which fixed it,

@jreback how about I making tests for this issue and #14563 separately in one PR? and then close these two issues? they are very similar, def same type of issue.

@jreback jreback modified the milestones: Contributions Welcome, 1.0 Jan 4, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

10 participants