I am adding patches in a plot inside matplotlib using from matplotlib.patches import Patch class. Please see the sample code below-
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
n = 5
hatch_1 = 'o'
hatch_2 = '.'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='Hatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='Hatch 2', hatch=hatch_2, alpha=opacity)
# add legends
plt.legend(handles=[patch_1, patch_2], loc='upper right')
plt.show()
Below is the generated plot-

The hatches used for legends aren't visisble properly. I guess if I make the patches bigger, it will be visible.
How to make patches bigger?
You can change the size of the legend patches in a couple of ways.
First, you can increase the width using the handlelength option to plt.legend.
However, there is no way to increase their height using kwargs. So we need to loop over the patches after creating the legend. If we keep a reference to the legend as we create it leg = plt.legend(...), then we can loop over the patches using for patch in leg.get_patches():.
Then you can change the height of the patch using patch.set_height().
However, all this tinkering means they won't be aligned quite right. So we also need to change their vertical position slightly (using patch.set_y()).
I also found it helped to increase the vertical spacing of the labels in the legend to fit things in nicely (use the labelspacing kwarg).
And finally, I added a new line at the beginning of the legend labels to make it all look nice (label='\nHatch 1').
A complete script is below. You may wish to play around with the values of labelspacing, handlelength, patch.set_height() and patch.set_y() to suit your needs.
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
n = 5
hatch_1 = 'o'
hatch_2 = '.'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='\nHatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='\nHatch 2', hatch=hatch_2, alpha=opacity)
# add legends
leg = plt.legend(handles=[patch_1, patch_2], loc='upper right', labelspacing=1.5, handlelength=4)
for patch in leg.get_patches():
patch.set_height(22)
patch.set_y(-6)
plt.show()

As of 3.5.0 (and maybe earlier), handleheight and handlelength are now options to plt.legend(). Using your code but replacing the call to plt.legend() with
plt.legend(handles=[patch_1, patch_2], loc='upper right', handleheight=3, handlelength=4)
gives the following:

n = 5
hatch_1 = 'O'
hatch_2 = '.'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='Hatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='Hatch 2', hatch=hatch_2, alpha=opacity)
plt.rcParams['figure.figsize'] = (25,15)
# add legends
plt.legend(handles=[patch_1, patch_2], loc='upper right')
plt.show()
Made your small o as O and increase the size of figure that will make sense i guess
While @tmdavison's solution works great, it is a bit involved.
Since the main issue here is that hatches are not easy to recognize in legends, a less ideal but much simpler workaround is to increase the hatch density, which is achieved simply by repeating the desired hatch character, ie, replacing o with ooo:
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
n = 5
hatch_1 = 'o'
hatch_2 = 'ooo'
opacity = 0.4
bar_width = 0.4
y = np.random.randint(low=0, high=10, size=n)
x = np.arange(n)
bars = plt.bar(x, y, bar_width, align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_1)
y = np.random.randint(low=0, high=10, size=n)
bars = plt.bar(x + bar_width, y, bar_width,
align='center', alpha=opacity, fill=False)
for bar in bars:
bar.set_hatch(hatch_2)
patch_1 = Patch(fill=False, label='Hatch 1', hatch=hatch_1, alpha=opacity)
patch_2 = Patch(fill=False, label='Hatch 2', hatch=hatch_2, alpha=opacity)
# add legends
plt.legend(handles=[patch_1, patch_2], loc='upper right')
plt.show()

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With