Skip to content

plotting in pandas is not picking the list of colors passed, it only gets the first value #16822

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
eyadsibai opened this issue Jul 4, 2017 · 17 comments · Fixed by #17360
Closed
Labels
Regression Functionality that used to work in a prior pandas version Visualization plotting
Milestone

Comments

@eyadsibai
Copy link

eyadsibai commented Jul 4, 2017

Code Sample, a copy-pastable example if possible

>>> df = pd.DataFrame({"A": range(4), "color": ['red', 'blue', 'blue', 'red']})
>>> ax = df.plot.bar(y='A', color=df['color'])
>>> [p.get_facecolor() for p in ax.patches]
[(1.0, 0.0, 0.0, 1.0),
 (1.0, 0.0, 0.0, 1.0),
 (1.0, 0.0, 0.0, 1.0),
 (1.0, 0.0, 0.0, 1.0)]

Problem description

It plots correctly but it does not pick the right color per bar. it only pick the color of the first value in the list.
it was working perfectly in pandas 0.19.2

Expected Output

the plot should contain a different color as the list is being passed. Similar to matplotlib behavior and the old pandas version

Output of pd.show_versions()

pandas: 0.20.2
pytest: None
pip: 9.0.1
setuptools: 36.0.1
Cython: None
numpy: 1.12.1
scipy: 0.19.1
xarray: None
IPython: 5.4.1
sphinx: None
patsy: None
dateutil: 2.6.0
pytz: 2017.2
blosc: None
bottleneck: None
tables: None
numexpr: None
feather: None
matplotlib: 2.0.2
openpyxl: None
xlrd: 1.0.0
xlwt: None
xlsxwriter: None
lxml: None
bs4: None
html5lib: 0.9999999
sqlalchemy: None
pymysql: None
psycopg2: 2.7.1 (dt dec pq3 ext lo64)
jinja2: 2.9.6
s3fs: None
pandas_gbq: None
pandas_datareader: None

@halflings
Copy link

I left a comment on #14757 which seems to be the culprit.

@eyadsibai eyadsibai changed the title plotting in pandas is not picking the list of colors passed only the first value plotting in pandas is not picking the list of colors passed, it only gets the first value Jul 4, 2017
@TomAugspurger
Copy link
Contributor

#14757 looks unrelated, that was for .style, not .plot. PRs welcome if you want to take a look.

@TomAugspurger TomAugspurger added this to the Next Major Release milestone Jul 4, 2017
@TomAugspurger TomAugspurger added Regression Functionality that used to work in a prior pandas version Visualization plotting labels Jul 4, 2017
@TomAugspurger
Copy link
Contributor

TomAugspurger commented Jul 4, 2017

The problem seems to be in _get_colors. I think that BarPlot should define a _get_colors that does something like

def _get_colors(self, num_colors=None, color_kwds='color'):
    color = self.kwds.get('color')
    if color is None:
        return super()._get_colors(self, num_colors=num_colors, color_kwds=color_kwds)
    else:
        num_colors = len(self.data)  # maybe? may not work for some cases
        return _get_standard_colors(color=kwds.get('color'), num_colors=num_colors)

will need tests and stuff too.

@bcolsen
Copy link

bcolsen commented Jul 6, 2017

@TomAugspurger This a regression bug that can crash matplotlib(see below). I think this might be a bigger deal than "next major release"

If you give a color as an RGB or RGBA tuple the dataframe plot command only forwards the first number and this(a single float) isn't a valid color so matplotlib crashes and plots a blank(broken really) graph.

user@user-comp:~$ ipython --pylab
Python 3.6.0 |Anaconda custom (64-bit)| (default, Dec 23 2016, 12:22:00) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
Using matplotlib backend: Qt5Agg

In [1]: import pandas as pd

In [2]: pd.__version__
Out[2]: '0.20.2'

In [3]: df = pd.DataFrame({"A": range(10)})

In [4]: df.plot(y='A', color=(0.3,0.4,0.4,1))
Out[4]: <matplotlib.axes._subplots.AxesSubplot at 0x7f90dbdea160>

In [5]: Traceback (most recent call last):
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/colors.pa
    rgba = _colors_full_map.cache[c, alpha]
KeyError: (0.3, None)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/backendsg
    FigureCanvasAgg.draw(self)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/backendsw
    self.figure.draw(self.renderer)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/artist.pr
    draw(artist, renderer, *args, **kwargs)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/figure.pw
    renderer, self, dsu, self.suppressComposite)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/image.pys
    a.draw(renderer)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/artist.pr
    draw(artist, renderer, *args, **kwargs)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/axes/_baw
    mimage._draw_list_compositing_images(renderer, self, dsu)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/image.pys
    a.draw(renderer)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/artist.pr
    draw(artist, renderer, *args, **kwargs)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/lines.pyw
    ln_color_rgba = self._get_rgba_ln_color()
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/lines.pyr
    return mcolors.to_rgba(self._color, self._alpha)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/colors.pa
    rgba = _to_rgba_no_colorcycle(c, alpha)
  File "/home/user/anaconda3/lib/python3.6/site-packages/matplotlib/colors.pe
    raise ValueError("Invalid RGBA argument: {!r}".format(orig_c))
ValueError: Invalid RGBA argument: 0.3

works fine on 0.19

user@user-comp:~$ ipython --pylab
Python 3.6.0 |Anaconda custom (64-bit)| (default, Dec 23 2016, 12:22:00) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.
Using matplotlib backend: Qt5Agg

In [1]: import pandas as pd

In [2]: pd.__version__
Out[2]: '0.19.2'

In [3]: df = pd.DataFrame({"A": range(10)})

In [4]: df.plot(y='A', color=(0.3,0.4,0.4))
Out[4]: <matplotlib.axes._subplots.AxesSubplot at 0x7fa95e159710>

In [5]: 

@jreback
Copy link
Contributor

jreback commented Jul 6, 2017

@TomAugspurger This a regression bug that can crash matplotlib(see below). I think this might be a bigger deal than "next major release"

@bcolsen certainly a patch is welcome. We have 1900 issues, how does one prioritize?

@TomAugspurger
Copy link
Contributor

TomAugspurger commented Jul 6, 2017 via email

@bcolsen
Copy link

bcolsen commented Jul 6, 2017

@jreback Sorry for the bug triage suggestion...I clearly have no idea what your release scheduled is like.

I can't get a PR in by tomorrow, but will have a look at it. This is what i have so far.

Initially this line, seems to be the problem:

colors = list(color) if is_list_like(color) else color

colors = list(color) if is_list_like(color) else color

but this code is in plotting.py in 0.19 and it works fine.

The difference is in 0.19 _get_standard_colors gets the color tuple wrapped as a list already so line 100 does:

[(0.3, 0.4, 0.4)] ->  [(0.3, 0.4, 0.4)]

in 0.20 _get_standard_colors gets just the tuple. So it does this.

(0.3, 0.4, 0.4) ->  [0.3, 0.4, 0.4]

@ryanshrott
Copy link

Any update?

@bcolsen
Copy link

bcolsen commented Jul 18, 2017

I have a work around for people being affected by this:

Plot with color in an extra list:

df.plot(y='A', color=[(0.3,0.4,0.4,1)])

also fixes bar:

>>> df = pd.DataFrame({"A": range(4), "color": ['red', 'blue', 'blue', 'red']})
>>> ax = df.plot.bar(y='A', color=[df['color']])
>>> [p.get_facecolor() for p in ax.patches]
Out[35]: 
[(1.0, 0.0, 0.0, 1.0),
 (0.0, 0.0, 1.0, 1.0),
 (0.0, 0.0, 1.0, 1.0),
 (1.0, 0.0, 0.0, 1.0)]

@adesorme
Copy link

adesorme commented Feb 8, 2019

I'm still facing this issue...

@senjed
Copy link

senjed commented Aug 8, 2019

I am still facing the same issue. Why is this closed?

@TomAugspurger
Copy link
Contributor

#17360 fixed this. It's possible that there was a regression, or you're getting the same error message from a different case. Either way, @senjed / @adesorme can you open a new issue with an example demonstrating the problem?

@RT-Tap
Copy link

RT-Tap commented Mar 24, 2021

Is it possible this issue crawled its way back in? Im trying to use this on a bar plot and it only picks up the first color no matter what I do. Any ideas/suggestions?

@Zartexo
Copy link

Zartexo commented May 13, 2022

This problem still exists

@MarcoGorelli
Copy link
Member

MarcoGorelli commented May 13, 2022

The example from the original post looks fine in the latest pandas (1.4.2):

Screenshot 2022-05-13 at 12 55 34

If anyone's still facing the issue, could you please open a new issue with a minimal reproducible example? Thanks

@alexdanilowicz
Copy link

alexdanilowicz commented Sep 25, 2022

In case this helps anyone, I was having this issue with pandas==1.5.0 (and 1.4.2) because I was not passing the y argument.

For example:

No y=

        c = ['black', blue', 'green']
	ax = df.plot.barh(color=c)
	print([p.get_facecolor() for p in ax.patches])
       # [(0.0, 0.0, 0.0, 1.0), (0.0, 0.0, 0.0, 1.0), (0.0, 0.0, 0.0, 1.0)]

vs

With y=

        c = ['red', blue', 'green']
         # where A is a column name in your df
	ax = df.plot.barh(y="A", color=c)
	print([p.get_facecolor() for p in ax.patches])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Regression Functionality that used to work in a prior pandas version Visualization plotting
Projects
None yet
Development

Successfully merging a pull request may close this issue.