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