Handling Plot Axis Spines in Python | by Elena Kosourova | Towards Data Science

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.
In many cases, we just need to remove spines. Let’s suppose that we have the following plot:
import numpy as npimport matplotlib.pyplot as pltx = np.arange(0, 5, 1)y = 2 * xplt.plot(x, y)plt.show()
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()
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 snsplt.plot(x, y)sns.despine()plt.show()
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()
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()
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()
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()
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:
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()
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()
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()
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()
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()
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: