113

Supposely, I have the bar chart as below:

BarPlot

Any ideas on how to set different colors for each carrier? As for example, AK would be Red, GA would be Green, etc?

I am using Pandas and matplotlib in Python

>>> f=plt.figure()
>>> ax=f.add_subplot(1,1,1)
>>> ax.bar([1,2,3,4], [1,2,3,4])
<Container object of 4 artists>
>>> ax.get_children()
[<matplotlib.axis.XAxis object at 0x6529850>, <matplotlib.axis.YAxis object at 0x78460d0>,  <matplotlib.patches.Rectangle object at 0x733cc50>, <matplotlib.patches.Rectangle object at 0x733cdd0>, <matplotlib.patches.Rectangle object at 0x777f290>, <matplotlib.patches.Rectangle object at 0x777f710>, <matplotlib.text.Text object at 0x7836450>, <matplotlib.patches.Rectangle object at 0x7836390>, <matplotlib.spines.Spine object at 0x6529950>, <matplotlib.spines.Spine object at 0x69aef50>, <matplotlib.spines.Spine object at 0x69ae310>, <matplotlib.spines.Spine object at 0x69aea50>]
>>> ax.get_children()[2].set_color('r') #You can also try to locate the first patches.Rectangle object instead of direct calling the index.

For the suggestions above, how do exactly we could enumerate ax.get_children() and check if the object type is rectangle? So if the object is rectangle, we would assign different random color?

Kromster
  • 7,181
  • 7
  • 63
  • 111
Santiago Munez
  • 1,965
  • 5
  • 18
  • 16
  • 1
    my_colors = ['brown','pink', 'red', 'green', 'blue', 'cyan','orange','purple'] plt.bar(yourX,yourY ,color=my_colors) – nofoobar Jan 14 '20 at 18:09

3 Answers3

186

Simple, just use .set_color

>>> barlist=plt.bar([1,2,3,4], [1,2,3,4])
>>> barlist[0].set_color('r')
>>> plt.show()

enter image description here

For your new question, not much harder either, just need to find the bar from your axis, an example:

>>> f=plt.figure()
>>> ax=f.add_subplot(1,1,1)
>>> ax.bar([1,2,3,4], [1,2,3,4])
<Container object of 4 artists>
>>> ax.get_children()
[<matplotlib.axis.XAxis object at 0x6529850>, 
 <matplotlib.axis.YAxis object at 0x78460d0>,  
 <matplotlib.patches.Rectangle object at 0x733cc50>, 
 <matplotlib.patches.Rectangle object at 0x733cdd0>, 
 <matplotlib.patches.Rectangle object at 0x777f290>, 
 <matplotlib.patches.Rectangle object at 0x777f710>, 
 <matplotlib.text.Text object at 0x7836450>, 
 <matplotlib.patches.Rectangle object at 0x7836390>, 
 <matplotlib.spines.Spine object at 0x6529950>, 
 <matplotlib.spines.Spine object at 0x69aef50>,
 <matplotlib.spines.Spine object at 0x69ae310>, 
 <matplotlib.spines.Spine object at 0x69aea50>]
>>> ax.get_children()[2].set_color('r') 
 #You can also try to locate the first patches.Rectangle object 
 #instead of direct calling the index.

If you have a complex plot and want to identify the bars first, add those:

>>> import matplotlib
>>> childrenLS=ax.get_children()
>>> barlist=filter(lambda x: isinstance(x, matplotlib.patches.Rectangle), childrenLS)
[<matplotlib.patches.Rectangle object at 0x3103650>, 
 <matplotlib.patches.Rectangle object at 0x3103810>, 
 <matplotlib.patches.Rectangle object at 0x3129850>, 
 <matplotlib.patches.Rectangle object at 0x3129cd0>, 
 <matplotlib.patches.Rectangle object at 0x3112ad0>]
CT Zhu
  • 52,648
  • 17
  • 120
  • 133
  • 1
    Thanks for your reply. However, I get the barplot from: dfPlotSum.plot(kind="bar", title=titleStr, legend=False) This function would return ax object. Any idea on how to set the color on this way? Thanks! – Santiago Munez Sep 24 '13 at 05:17
  • See edit, this is a simple plot so I know the first bar has the index of 2. If you are dealing with a complex plot, you have to locate the bar you want to change first. Can't be more specific as I don't have your `dfPlotSum.plot()`, but the idea is the same. – CT Zhu Sep 24 '13 at 05:29
  • Thanks for your additional answers. How do I exactly find that the children object is refer to the rectangle of the barplot?Is there such enumerable function that could check the type of object? Like for example, for i in ax.get_children() is rectangle? Is there any is keyword in python like in C#? – Santiago Munez Sep 24 '13 at 05:32
  • No, simpler than what you thought, see additional edit. But if your plot is too complex, i.e., has a bar plot and a histogram which also has `patch.Rectangle` objects, this method will not be ideal. In that case, you may be better off modify your `dfPlotSum.plot()` such that it also returns the bars for later modification. – CT Zhu Sep 24 '13 at 05:39
  • 8
    Notice that this removes the black border (edge) of the bar. It can be brought back by using: `barlist[0].set_edgecolor("black")`. A better way might be to use `barlist[0].set_facecolor('r')` which does not change the edge of the bar. – m00am Apr 07 '16 at 14:39
  • 1
    @SantiagoMunez just put the plot in a variable and call .get_children() function, like this: `ax = dfPlotSum.plot(kind="bar", title=titleStr, legend=False)` and then `ax.get_children()[3].set_color('r')` – Marco Antonio Yamada May 23 '20 at 14:00
  • 1
    I tried to plot bar with `barlist=plt.bar(['a','b','c','d'], [1,2,3,4])` but failed with `barlist['a'].set_color('r')`. – Ynjxsjmh Jun 10 '20 at 08:19
  • Or if you prefer to use comprehensions instead of filter: `barlist = [bar for bar in ax.get_children() if isinstance(bar, matplotlib.patches.Rectangle)]` – Greg Cowell Feb 02 '23 at 00:37
50

I assume you are using Series.plot() to plot your data. If you look at the docs for Series.plot() here:

http://pandas.pydata.org/pandas-docs/dev/generated/pandas.Series.plot.html

there is no color parameter listed where you might be able to set the colors for your bar graph.

However, the Series.plot() docs state the following at the end of the parameter list:

kwds : keywords
Options to pass to matplotlib plotting method

What that means is that when you specify the kind argument for Series.plot() as bar, Series.plot() will actually call matplotlib.pyplot.bar(), and matplotlib.pyplot.bar() will be sent all the extra keyword arguments that you specify at the end of the argument list for Series.plot().

If you examine the docs for the matplotlib.pyplot.bar() method here:

http://matplotlib.org/api/pyplot_api.html#matplotlib.pyplot.bar

..it also accepts keyword arguments at the end of it's parameter list, and if you peruse the list of recognized parameter names, one of them is color, which can be a sequence specifying the different colors for your bar graph.

Putting it all together, if you specify the color keyword argument at the end of your Series.plot() argument list, the keyword argument will be relayed to the matplotlib.pyplot.bar() method. Here is the proof:

import pandas as pd
import matplotlib.pyplot as plt

s = pd.Series(
    [5, 4, 4, 1, 12],
    index = ["AK", "AX", "GA", "SQ", "WN"]
)

#Set descriptions:
plt.title("Total Delay Incident Caused by Carrier")
plt.ylabel('Delay Incident')
plt.xlabel('Carrier')

#Set tick colors:
ax = plt.gca()
ax.tick_params(axis='x', colors='blue')
ax.tick_params(axis='y', colors='red')

#Plot the data:
my_colors = 'rgbkymc'  #red, green, blue, black, etc.

pd.Series.plot(
    s, 
    kind='bar', 
    color=my_colors,
)

plt.show()

enter image description here

Note that if there are more bars than colors in your sequence, the colors will repeat.

Community
  • 1
  • 1
7stud
  • 46,922
  • 14
  • 101
  • 127
26

Update pandas 0.17.0

@7stud's answer for the newest pandas version would require to just call

s.plot( 
    kind='bar', 
    color=my_colors,
)

instead of

pd.Series.plot(
    s, 
    kind='bar', 
    color=my_colors,
)

The plotting functions have become members of the Series, DataFrame objects and in fact calling pd.Series.plot with a color argument gives an error

Yannis P.
  • 2,745
  • 1
  • 24
  • 39