This is a sort of unpleasant approach, but seems to be working. You can access the colors of the rectangles in the bar graph (ax.patches[x].get_facecolor()
), and use those to assign new colors to the error bars (ax.get_lines()[x].set_color()
). Here's an example using the seaborn
example:
import seaborn as sns
tips = sns.load_dataset("tips")
ax = sns.barplot(x="day", y="total_bill", data=tips,)
patches = ax.patches
lines_per_err = 3
for i, line in enumerate(ax.get_lines()):
newcolor = patches[i // lines_per_err].get_facecolor()
line.set_color(newcolor)
Resulting graph:
There are a couple issues with this solution:
- You have to use these less friendly
get
and set
commands from matplotlib
- There is an assumption that
ax.patches
and ax.get_lines()
are being returned in a consistent order, say left-to-right (more or less). Note that there are actually 12 line objects in my plot (4 * (error bar + bottom cap + top cap)), and only 4 graph bars. Just be aware of this since your graph has many more bars (i.e. I'm not sure if this assumption holds). You can try to be more explicit by applying a sort to the objects though (like sorted(ax.patches, key=lambda x: x.get_x()
and sorted(ax.get_lines(), key=lambda x:x.get_xdata()[0])
).
- If you have other line or rectangle geometry in the plot, you will likely not want to target those. So you may have to run this after the bars and errorbars are created, but before other things. This may not be possible with some
seaborn
plots which draw lots of things in one function call.
- clearly this is more troublesome than some sort of
errcolor
parameter, but I don't see an option to do so from the plot call. But the above may be sufficient in a pinch.
Edit: My original logic for linking the lines to the patches was incorrect. As shown above, you can use i // lines_per_error
to link the error bar line to the graph bar. The lines_per_error
is how many lines each error bar is drawn with. Since I believe it should be only 1 or 3 depending on if you use error bar caps, you can do something like:
capsize = None
ax = sns.barplot(..., capsize=capsize)
lines_per_err = 1 if capsize is None else 3
Also, here is an example working with a hue
:
import seaborn as sns
capsize = .1
tips = sns.load_dataset("tips")
ax = sns.barplot(x="day", y="total_bill", hue="sex", data=tips, capsize=capsize)
patches = ax.patches
lines_per_err = 1 if capsize is None else 3
for i, line in enumerate(ax.get_lines()):
newcolor = patches[i // lines_per_err].get_facecolor()
line.set_color(newcolor)
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…