The world’s leading publication for data science, AI, and ML professionals.

Handling Plot Axis Spines in Python

Some useful methods and tricks in matplotlib and seaborn

From Unsplash
From Unsplash

Axis spines are the lines confining the plot area. Depending on the situation, we may want to remove some (or all) of them, change their color, make them less visible, regulate their width/style, or change their position. In this article, we’ll explore some handy approaches for dealing with axis spines.

Removing spines

In many cases, we just need to remove spines. Let’s suppose that we have the following plot:

import numpy as np
import Matplotlib.pyplot as plt
x = np.arange(0, 5, 1)
y = 2 * x
plt.plot(x, y)
plt.show()
Image by Author
Image by Author

and we want to remove the top spine from the axes. For this purpose, we can use the set_visible() method of the object-oriented API interface (i.e. when we use ax.plot instead of plt.plot). The syntax is the following: ax.spines['top'].set_visible(False). For removing several spines, it makes sense to use a for-loop:

fig, ax = plt.subplots()
ax.plot(x, y)
for spine in ['top', 'right']:
    ax.spines[spine].set_visible(False)
plt.show()
Image by Author
Image by Author

A more straightforward approach is to use a seaborn utility function sns.despine(). In this case, it doesn’t matter if we use the object-oriented API or pyplot interface. If no argument is passed in, by default, the top and right spines will be removed:

import seaborn as sns
plt.plot(x, y)
sns.despine()
plt.show()
Image by Author
Image by Author

It’s possible to remove any of the remaining spines (e.g., left=True) or to restore the spines removed by default (e.g., right=False).

To remove all the 4 spines at once, we can use either set_visible() or sns.despine(), but there is a shorter way: using the plt.box() method.

plt.plot(x, y)
plt.box(on=False)
plt.show()
Image by Author
Image by Author

Changing spine color and transparency

The set_color() and set_alpha() methods are related to the object-oriented API interface and have the syntax similar to the one for set_visible(). The set_alpha() method is convenient when we want to keep a spine but make it less evident:

fig, ax = plt.subplots()
ax.plot(x, y)
ax.spines['left'].set_color('red')
ax.spines['bottom'].set_alpha(0.2)
plt.show()
Image by Author
Image by Author

Adjusting spine width/style

Let’s now try changing the width and style for some spines of our plot with the methods set_linewidth() and set_linestyle(), where the latter can take in the following values: 'solid' (by default), 'dashed', 'dashdot', or 'dotted'.

fig, ax = plt.subplots()
ax.plot(x, y)
ax.spines['left'].set_linewidth(3)
ax.spines['bottom'].set_linestyle('dashed')
plt.show()
Image by Author
Image by Author

It seems that the set_linestyle() method didn’t work as expected. We can fix it changing the width of the same spine:

fig, ax = plt.subplots()
ax.plot(x, y)
ax.spines['bottom'].set_linewidth(4)
ax.spines['bottom'].set_linestyle('dashed')
plt.show()
Image by Author
Image by Author

Looks better now, but the dashes are too close to each other. To further fix it, we can adjust another property of axis spines: the capstyle, i.e the style of ending for each dash or dot. The capstyle can be projecting, butt, or round. To understand the difference between them, let’s look at the following scheme illustrating the dashes of the same length but with different capstyle:

Image by Author
Image by Author

We see that the butt capstyle is the least "space-consuming", while the default one for axis spines is projecting. Let’s adjust our plot applying the set_capstyle() method and passing in a new value:

fig, ax = plt.subplots()
ax.plot(x, y)
ax.spines['bottom'].set_capstyle('butt')
ax.spines['bottom'].set_linewidth(4)
ax.spines['bottom'].set_linestyle('dashed')
plt.show()
Image by Author
Image by Author

There is an alternative way of providing a spine style: passing in to set_linestyle() a tuple of the following form: (offset, onoffseq), where the offset is usually 0 and onoffseq is an even-length tuple of on and off ink in points. This approach is even more convenient since it doesn’t need to adjust any other parameters like width or capstyle. We can use it for making spines dashed, dotted, or having any other pattern:

fig, ax = plt.subplots()
ax.plot(x, y)
ax.spines['top'].set_linestyle((0, (10, 10)))
ax.spines['right'].set_linestyle((0, (10, 10, 1, 10)))
plt.show()
Image by Author
Image by Author

Changing position

We can put any spine at an arbitrary position using the set_position() method and passing in a tuple of the following form: (position type, amount). The possible position types are:

  • 'outward' – out from the plot area (or inside it, in the case of a negative value of the amount in points),
  • 'axes' – at the specified axes coordinate, can take values from 0 to 1,
  • 'data' – at the specified data coordinate.

The last option, for example, can be useful for putting a vertical spine at 0:

x1 = np.arange(-5, 5, 0.1)
y1 = np.sin(x1)
fig, ax = plt.subplots()
plt.plot(x1, y1)
ax.spines['left'].set_position(('data', 0))
sns.despine()
plt.show()
Image by Author
Image by Author

The 'outward' position type has an equivalent in the sns.despine() function where we can pass in the optional offset parameter. This parameter can take in a single integer as an offset to all visible spines or a dictionary to specify an offset for each visible spine separately. The following 2 plots are identical:

fig, ax = plt.subplots()
ax.plot(x, y)
ax.spines['left'].set_position(('outward', 20))
sns.despine()
plt.show()
fig, ax = plt.subplots()
ax.plot(x, y)
sns.despine(offset={'left': 20})
plt.show()
Image by Author
Image by Author

Finally, talking about positioning spines, there is one more method that, in some cases, can turn to be useful: set_zorder(). Passing in 0 to it, we can "hide" a spine behind the plot. Let’s compare the plots below:

fig, ax = plt.subplots()
plt.plot(x1, y1, color='red', linewidth=5)
ax.spines['left'].set_position(('data', 0))
ax.spines['left'].set_linewidth(5)
sns.despine()
plt.show()
fig, ax = plt.subplots()
plt.plot(x1, y1, color='red', linewidth=5)
ax.spines['left'].set_zorder(0)
ax.spines['left'].set_position(('data', 0))
ax.spines['left'].set_linewidth(5)
sns.despine()
plt.show()
Image by Author
Image by Author

Conclusion

In this article, we explored different methods and tricks for handling axis spines in matplotlib and seaborn libraries including removing them, changing their color and transparency, adjusting width/style, or changing position.

Thanks for reading!


You can find interesting also these articles:

How To Fill Plots With Patterns In Matplotlib

An Unconventional Yet Convenient Matplotlib Broken_Barh Function And When It Is Particularly…

How To Fetch The Exact Values From A Boxplot (Python)


Related Articles