
Using filling patterns when creating plots is a good alternative to using colors. It can be particularly helpful in the following cases:
- the plot is going to be included in a black-and-white publication,
- if we want to reduce the number of colors used per plot (e.g. for pie plots),
- if we want to emphasize some of the elements of a plot (e.g. some bars of a bar plot).
For now, unfortunately, Matplotlib has rather limited functionality for this purpose. Moreover, there is no unique approach for different types of plots.
In this article, we’re going to explore how to add patterns to bar plots, histograms, box plots, and pie charts. To maximize the data-ink ratio, we’ll create only black-and-white plots by adding fill=False
everywhere.
Bar Plot
To fill a bar plot with a pattern, we just have to assign to the optional parameter hatch
one of the following values as a string: /
, ,
|
, -
, +
, x
, o
, O
, .
, *
:
import matplotlib.pyplot as plt
import numpy as np
x = range(1,5)
y = range(1,5)
plt.bar(x, y, fill=False, hatch='/')
plt.show()
Output:

To obtain a denser filling, we should add more symbols of the same kind to the string. So, let’s substitute '/'
with '///'
:
plt.bar(x, y, fill=False, hatch='///')
plt.show()
Output:

Attention: since the backslash (`) is a special character in Python, if we want to fill our bar plot with this pattern, we have to use a **double backslash** (
”). In this case, to obtain a denser pattern, it's necessary to assign an even numbers of backslashes to the
hatchparameter (
”,
‘\’`, etc.).
It’s also possible to combine two or more patterns on the same bars, adding the corresponding characters to the string:
plt.bar(x, y, fill=False, hatch='.O')
plt.show()
Output:

The filling becomes even more useful when plotting stacked or grouped bar plots:
y1 = range(1,5)
y2 = range(5,9)
plt.bar(x, y1, fill=False, hatch='xx')
plt.bar(x, y2, fill=False, hatch='..', bottom=y1)
plt.show()
Output:

Furthermore, as with colors, we can use the filling to emphasize only the most important bars. The algorithm here is the following. The plt.bar()
method returns a container of n bars that can be assigned to a variable:
bars = plt.bar(x, y)
print(bars)
Output:
<BarContainer object of 4 artists>
In our case, there are 4 bars in the container. Let’s set a condition for the bar patterns. For example, we want to emphasize only the bars where 1 < y < 3
. We can iterate through the list of y-values and for those satisfying the condition above, assign the star symbol ('*'
), otherwise assign nothing (an empty string). As a result, we’ll have a list of values of the hatch
parameter corresponding to each value of y:
hatches = ['*' if y>1 and y<3 else '' for y in y]
print(hatches)
Output:
['', '*', '', '']
Now, we can iterate through the bars of the container and set to each bar the corresponding hatch
value:
bars = plt.bar(x, y)
for i in range(len(bars)):
bars[i].set(hatch = hatches[i], fill=False)
plt.show()
Output:

Histogram
To fill a histogram, we have the same optional parameter hatch
as for a bar plot, with the same choice of possible values:
data = np.random.normal(loc=10, scale=10, size=500)
plt.hist(data, histtype='step', edgecolor='black', fill=False, hatch='.')
plt.show()
Output:

It becomes even more useful when plotting multiple histograms, either stacked or overlapped:
data1 = np.random.normal(30, 20, 5000)
data2 = np.random.normal(80, 15, 5000)
plt.hist(data1, bins=30, histtype='step', edgecolor='black', fill=False, hatch='.')
plt.hist(data2, bins=30, histtype='step', edgecolor='black', fill=False, hatch='o')
plt.show()
Output:

Box Plot
For a box plot, however, the approach is less straightforward since the plt.boxplot()
method doesn’t have the hatch
parameter. Hence, we have to use a workaround. The algorithm here is the following. The plt.boxplot()
method returns a dictionary with different elements of the box plot as its keys: whiskers, boxes, medians, fliers, etc. This dictionary can be assigned to a variable:
data = np.random.rand(100)
boxplots = plt.boxplot(data, patch_artist=True)
boxplots
Output:
{'whiskers': [<matplotlib.lines.Line2D at 0x195176862e0>,
<matplotlib.lines.Line2D at 0x19517686640>],
'caps': [<matplotlib.lines.Line2D at 0x195176869a0>,
<matplotlib.lines.Line2D at 0x19517686d00>],
'boxes': [<matplotlib.patches.PathPatch at 0x19517667f10>],
'medians': [<matplotlib.lines.Line2D at 0x195176900a0>],
'fliers': [<matplotlib.lines.Line2D at 0x195176903a0>],
'means': []}
Attention: to be able to use the hatch
property later, it’s necessary to set patch_artist=True
when calling plt.boxplot()
.
What we need from the dictionary above is the 'boxes'
key. We have to iterate through all the boxes (even though, in our case, we have only one box plot and hence only one box) and set to each box the corresponding hatch
value, just as we did for emphasizing only one bar in a bar plot:
boxplots = plt.boxplot(data, patch_artist=True)
for box in boxplots['boxes']:
box.set(hatch = 'x', fill=False)
plt.show()
Output:

The technique becomes more useful when creating two or more box plots: for emphasizing only some of them or just for assigning a different pattern to each. In this case, we have to create a list of values of the hatch
property (based on a condition, if necessary, or just random) and iterate also through it:
data1 = np.random.rand(10)
data2 = np.random.rand(20)
data3 = np.random.rand(500)
hatches = ['o', '++', 'x']
boxplots = plt.boxplot([data1, data2, data3], patch_artist=True)
for i in range(len(boxplots['boxes'])):
boxplots['boxes'][i].set(hatch = hatches[i], fill=False)
plt.show()
Output:

Pie Chart
As it was for a box plot, the plt.pie()
method doesn’t have the hatch
parameter, so filling a pie chart with patterns isn’t straightforward either. This time, the method plt.pie()
returns a tuple:
data = np.random.rand(5)
patches = plt.pie(data)
patches
Output:
([<matplotlib.patches.Wedge at 0x195177aa4c0>,
<matplotlib.patches.Wedge at 0x195177aa970>,
<matplotlib.patches.Wedge at 0x195177aadf0>,
<matplotlib.patches.Wedge at 0x195177b72b0>,
<matplotlib.patches.Wedge at 0x195177b7730>],
[Text(1.046742554077009, 0.3381272326866619, ''),
Text(-0.00440567017664189, 1.0999911772692974, ''),
Text(-1.0992106691773433, -0.0416641904601184, ''),
Text(-0.5217111246565277, -0.9684097802116732, ''),
Text(0.7338182292945598, -0.8194576293836047, '')])
The first element of this tuple (patches[0]
) contains all the wedges of our pie plot. In this case, there are 5 wedges. We can assign to each a specific pattern based on certain conditions or randomly. Let’s emphasize the smallest and the biggest wedges leaving all the others unfilled. For this purpose, we have to iterate through the data and for the values satisfying the conditions above (i.e., the minimum and maximum values), assign the 'o'
and 'O'
symbols to the corresponding hatch
values, otherwise assign nothing (an empty string):
hatches = ['o' if value==min(data) else 'O' if value==max(data) else '' for value in data]
Now, let’s iterate through both the wedges and the hatch
values and fill the smallest and the biggest wedges with the selected patterns:
patches = plt.pie(data)
for i in range(len(patches[0])):
patches[0][i].set(hatch = hatches[i], fill=False)
plt.show()
Output:

Conclusion
In this article, we explored the ways of filling contour plots, like bar plots, histograms, box plots, and pie charts, with different patterns in matplolib and considered the situations when this approach can be particularly helpful.
I hope you enjoyed reading and found this imformation useful for your future projects.
You may find interesting also these articles: