How To Fill Plots With Patterns In Matplotlib
By: Elena Kosourova
Tags: Data Visualization, Data Science, Matplotlib, Python, Data Analysis

How To Fill Plots With Patterns In Matplotlib

Image by Author

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:

Image by Author

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:

Image by Author

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 hatch parameter ( '\\\\' , '\\\\\\' , 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:

Image by Author

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:

Image by Author

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:

Image by Author

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:

Image by Author

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:

Image by Author

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:

Image by Author

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:

Image by Author

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:

Image by Author

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.