Simple way of adding hatches to only one bar of interest

301 Views Asked by At

I'm searching for an easy way of adding hatches to my plots in matplotlib. I only want the hatches in specific bars and not for all my bars in the plot. I don't want to manually put settings for each bar.

0) This is a part of my df:

target  withCR_RF   withCR_ET   withCR_LG   withCR_Ridge
0   partA   0.102   0.100   -0.3    -0.3
1   partB   0.081   0.085   -0.3    -0.3
2   part    -0.063  -0.050  -0.3    -0.3

enter image description here

1) This is the code I'm using for the plot:

from matplotlib.colors import ListedColormap

cmap = ListedColormap(['#96C3EB', '#299438', '#B8B8B8', '#CCAC93'])
ax = df.plot.bar(x='target', colormap=cmap)

ax.set_xlabel(None)
ax.set_ylabel('prediction performance R²')
ax.set_title('comparing pipelines of prediction of executive function variables')
plt.xticks(rotation=45, ha='right')
plt.show()

2) Now, I'd like to implement the hatches in the same way as the colors. I don't want all of the bars hatched, but just the first one, so I try this, which doesn't work.

cmap = ListedColormap(['#96C3EB', '#299438', '#B8B8B8', '#CCAC93'])
hatches = ['++', '', '', '']
ax = df.plot.bar(x='target', colormap=cmap, hatch=hatches)

ax.set_xlabel(None)
ax.set_ylabel('prediction performance R²')
ax.set_title('comparing pipelines of prediction of executive function variables')
plt.xticks(rotation=45, ha='right')
plt.show()

I either get all bars hatched or none of them hatched. I don't want hatches for all the bars and I don't want to adapt every bar manually.

3) @Tranbi, thanks for your suggestion. This is now working but not for all light blue bars. There are six light blue bars with the condition withCR_RF (because of 6 targets) but only one bar of them has changed. How can I change all six of them?

cmap = ListedColormap(['#96C3EB', '#299438', '#B8B8B8', '#CCAC93'])
#hatches = ['++', '', '', '']
#hatches = ['', '++', '', '', '', '', 'xx', '', '', '']
ax = df.plot.bar(x='target', colormap=cmap, hatch=hatches)

ax.set_xlabel(None)
ax.set_ylabel('prediction performance R²')
ax.set_title('comparing pipelines of prediction of executive function variables')
plt.xticks(rotation=45, ha='right')


for lbl, patch in zip(ax.get_xticklabels() , ax.patches):
        if lbl.get_text() == 'withCR_RF':
            patch.set_hatch('*')
            patch.set_edgecolor(patch.get_facecolor())
            patch.set_facecolor('none')

plt.show()

plot

4) @Mozway, thanks for your answer. Your last option is perfect for my needs, but is it possible to index more than one bar? This doesn't work, unfortunately. I'd like to have all light blue bars hatched.

cmap = ListedColormap(['#96C3EB', '#299438', '#B8B8B8', '#CCAC93'])
hatches = ['++', '', '', '']
hatches = ['', '++', '', '', '', '', 'xx', '', '', '']
ax = df.plot.bar(x='target', colormap=cmap)
ax.patches[0,1,2,3].set_hatch('+') #see here please
ax.set_xlabel(None)
ax.set_ylabel('prediction performance R²')
ax.set_title('comparing pipelines of prediction of executive function variables')
plt.xticks(rotation=45, ha='right')
plt.show()
2

There are 2 best solutions below

1
mozway On

What you want is unclear.

Given your data, you can either use:

hatches = ['++', '', '', '']
ax = df.plot.bar(x='target', colormap=cmap, hatch=hatches)

enter image description here

Or maybe:

hatches = ['++', '', '', '']
df.set_index('target').T.plot.bar(colormap=cmap, hatch=hatches)

enter image description here

Last option, if you want to manually change one patch:

cmap = ListedColormap(['#96C3EB', '#299438', '#B8B8B8', '#CCAC93'])
ax = df.plot.bar(x='target', colormap=cmap)
ax.patches[0].set_hatch('+')

enter image description here

0
beginner On

For me, the following code works best as I don't have to define each axes but can easily change and edit every bar I want to change. In my case, I can specify the conditions of the targets perfectly by setting the order. This code is still simple and I can adapt it easily to create a lot of similar plots.

fig, ax = plt.subplots()
ax = df.plot.bar(rot=0,ax=ax)
# get all bars in the plot
bars = ax.patches
patterns = ['/', 'o', '', '',]  # set hatch patterns in the correct order
hatches = []  # list for hatches in the order of the bars
for h in patterns:  # loop over patterns to create bar-ordered hatches
    for i in range(int(len(bars) / len(patterns))):
        hatches.append(h)
for bar, hatch in zip(bars, hatches):  # loop over bars and hatches to set hatches in correct order
    bar.set_hatch(hatch)
# generate legend. this is important to set explicitly, otherwise no hatches will be shown!
ax.legend()
plt.show()