Changing hatch color in matplotlib

Viewed 12613

Thanks for helping me get this graph right!

I have another issue now, that I wish to change the color of the hatch lines to grey.

I am working with matplotlib version 1.5.3'. I have tried mlp.rcParams['hatch.color'] = 'k'

But it doesn't seem to work...

Here is the code for the figure I already have, thanks to you:


import seaborn as sns
import matplotlib.pyplot as plt
mypallet = sns.color_palette([(190/256,7/256, 18/256),(127/256, 127/256, 127/256)])
import itertools
import numpy as np

plt.rcParams['figure.figsize'] = 7, 5
tips = sns.load_dataset("tips")
tips[(tips.day=='Thur') & (tips.sex=='Female') ] = np.nan
print(sns.__version__)
print(tips.head())
# Bigger than normal fonts
sns.set(font_scale=1.5)

ax = sns.swarmplot(x="day", y="total_bill", hue="sex",
                 data=tips, dodge=True, color='k')

#get first patchcollection
c0 = ax.get_children()[0]
x,y = np.array(c0.get_offsets()).T
#Add .2 to x values
xnew=x+.2
offsets = list(zip(xnew,y))
#set newoffsets
c0.set_offsets(offsets)

ax = sns.barplot(x="day", y="total_bill", hue="sex",
                 data=tips, capsize=0.1, alpha=0.8,
                 errwidth=1.25, ci=None, palette=mypallet)
xcentres = [0.2, 1, 2, 3]
delt = 0.2
xneg = [x-delt for x in xcentres]
xpos = [x+delt for x in xcentres]
xvals = xneg + xpos
xvals.sort()
yvals = tips.groupby(["day", "sex"]).mean().total_bill
yerr = tips.groupby(["day", "sex"]).std().total_bill

(_, caps, _)=ax.errorbar(x=xvals, y=yvals, yerr=yerr, capsize=4,
                         ecolor="red", elinewidth=1.25, fmt='none')
for cap in caps:
    cap.set_markeredgewidth(2)


handles, labels = ax.get_legend_handles_labels()
l = ax.legend(handles[0:2], labels[0:2]) # changed based on https://stackoverflow.com/a/42768387/8508004
#sns.ax.ylim([0,60]) #original
ax.set_ylim([0,60]) # adapted from https://stackoverflow.com/a/49049501/8508004 and change to legend
ax.set_ylabel("Out-of-sample R2") # based on https://stackoverflow.com/a/46235777/8508004
ax.set_xlabel("") # based on https://stackoverflow.com/a/46235777/8508004

for i, bar in enumerate(ax.patches):
    hatch = '///'
    bar.set_hatch(hatch)
    bar.set_x(bar.get_x() + bar.get_width()/2)
    break

I'd like to change the color of the hatch pattern from black to grey: (127/256, 127/256, 127/256)

4 Answers

Add, plt.rcParams['hatch.linewidth'] = 3 and use set_edgecolor, think the fact that `plt.rcParams['hatch.color'] = 'k' doesn't work is a bug.

import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib as mpl
mypallet = sns.color_palette([(190/256,7/256, 18/256),(127/256, 127/256, 127/256)])
import itertools
import numpy as np

plt.rcParams['figure.figsize'] = 7, 5
plt.rcParams['hatch.linewidth'] = 3
tips = sns.load_dataset("tips")
tips[(tips.day=='Thur') & (tips.sex=='Female') ] = np.nan
print(sns.__version__)
print(tips.head())
# Bigger than normal fonts
sns.set(font_scale=1.5)

ax = sns.swarmplot(x="day", y="total_bill", hue="sex",
                 data=tips, dodge=True, color='k')

#get first patchcollection
c0 = ax.get_children()[0]
x,y = np.array(c0.get_offsets()).T
#Add .2 to x values
xnew=x+.2
offsets = list(zip(xnew,y))
#set newoffsets
c0.set_offsets(offsets)

ax = sns.barplot(x="day", y="total_bill", hue="sex",
                 data=tips, capsize=0.1, alpha=0.8,
                 errwidth=1.25, ci=None, palette=mypallet)


xcentres = [0.2, 1, 2, 3]
delt = 0.2
xneg = [x-delt for x in xcentres]
xpos = [x+delt for x in xcentres]
xvals = xneg + xpos
xvals.sort()
yvals = tips.groupby(["day", "sex"]).mean().total_bill
yerr = tips.groupby(["day", "sex"]).std().total_bill

(_, caps, _)=ax.errorbar(x=xvals, y=yvals, yerr=yerr, capsize=4,
                         ecolor="red", elinewidth=1.25, fmt='none')
for cap in caps:
    cap.set_markeredgewidth(2)


handles, labels = ax.get_legend_handles_labels()
l = ax.legend(handles[0:2], labels[0:2]) # changed based on https://stackoverflow.com/a/42768387/8508004
#sns.ax.ylim([0,60]) #original
ax.set_ylim([0,60]) # adapted from https://stackoverflow.com/a/49049501/8508004 and change to legend
ax.set_ylabel("Out-of-sample R2") # based on https://stackoverflow.com/a/46235777/8508004
ax.set_xlabel("") # based on https://stackoverflow.com/a/46235777/8508004

for i, bar in enumerate(ax.patches):
    hatch = '///'
    bar.set_hatch(hatch)
    bar.set_edgecolor('k')
    bar.set_x(bar.get_x() + bar.get_width()/2)
    break

Output:

enter image description here

AFAIK, The hatch color is determined by the edgecolor property, but the problem with that is that it will also affect the border of your bars

BTW, I was confused with your loop at the end of your code, I rewrote it as:

(...)
ax.set_xlabel("") # based on https://stackoverflow.com/a/46235777/8508004

bar = ax.patches[0] #  modify properties of first bar (index 0)
hatch = '///'
bar.set_hatch(hatch)
bar.set_x(bar.get_x() + bar.get_width()/2)
bar.set_edgecolor([0.5,0.5,0.5])

for changing the linewidth of the hatches, it seems you have to modify the rcParams. You can add this somewhere close to the top of you script:

plt.rcParams['hatch.linewidth'] = 3

plt.rcParams.update({'hatch.color': 'k'})

Just two additional hints for someone who might also find that the hatch is not displayed or not with the proper color.

First, check if you set some edgecolor in another place. This seems to have precedence over a specified hatch color. Second, if you draw a Patch, use facecolor instead of color. With color, the hatch will not be visible:

So not this:

from matplotlib.patches import Polygon, Patch
fig, ax = plt.subplots()
ax.legend(handles=[Patch(color='red', hatch='///')])  # no hatch visible 
plt.show()

Instead:

from matplotlib.patches import Polygon, Patch
fig, ax = plt.subplots()
ax.legend(handles=[Patch(facecolor='red', hatch='///')])  # hatch is now visible 
plt.show()
Related