Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
483 views
in Technique[技术] by (71.8m points)

python - Errorbar colors in Seaborn barplot with hue

I plot seaborn.barplot with hue on several categories.

I want the errobar to have the same color line the bar itself - how can I do this?

I call it with a data frame like this, I have four huse categories:

sns.barplot(y = '$T_i$', x = 'algo', hue = 'pricing', data = df, alpha = 0.0, ci = 100, capsize = 0.1)

I found errcolor = 'black' in kwargs, but it changes it for all bars, regardless of hue.

enter image description here

question from:https://stackoverflow.com/questions/66064409/errorbar-colors-in-seaborn-barplot-with-hue

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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:

enter image description here

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)

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...