Numerical & Scientific Computing with Python: Moving Spines and Changing Ticks


Matplotlib Tutorial: Spines and Ticks


Moving the Border Lines and Polishing up the Axes Notations

spines

The word spine is most commonly known as the backbone or spinal cord of the human skeleton. Another meaning stands for a book's jacket. Our picture on the right side shows the spines of a cactus, artistically changed into something which looks like a ribcage. You will hardly find the usage of matplotlib in a dictionary. Spines in matplotlib are the lines connecting the axis tick marks and noting the boundaries of the data area.

We will demonstrate in the following that the spines can be placed at arbitrary positions.

But before we can start with our first example, we need to introduce the gca function, which returns the current Axes instance on the current figure.

We can e.g. call plt.gca(projection='polar') to get the current polar axes on the current figure.

# the next "inline" statement is only needed,
# if you are working with "ipython notebook"
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)
F1 = np.sin(2* X)
F2 = (2*X**5 + 4*X**4 - 4.8*X**3 + 1.2*X**2 + X + 1)*np.exp(-X**2)
# get the current axes, creating them if necessary:
ax = plt.gca()
# making the top and right spine invisible:
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# moving bottom spine up to y=0 position:
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
# moving left spine to the right to position x == 0:
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
plt.plot(X, F1)
plt.plot(X, F2)
plt.show()


Customizing Ticks

Matplotlib has so far - in all our previous examples - automatically taken over the task of spacing points on the axis. We can see for example that the X axis in our previous example was numbered -8, -6. -4, -2, 0, 2, 4, 6, 8, whereas the Y axis was numbered -2.0, -1.5, -1.0, -0.5, 0, 0.5, 1.0, 1.5, 2.0

xticks is a method, which can be used to get or to set the current tick locations and the labels. The same is true for yticks:

# get the current axes, creating them if necessary:
ax = plt.gca()
locs, labels = plt.xticks()
print(locs, labels)
locs, labels = plt.yticks()
print(locs, labels)
[ 0.   0.2  0.4  0.6  0.8  1. ] <a list of 6 Text xticklabel objects>
[ 0.   0.2  0.4  0.6  0.8  1. ] <a list of 6 Text yticklabel objects>

As we said before, we can also use xticks to set the location of xticks:

plt.xticks( np.arange(10) )
locs, labels = plt.xticks()
print(locs, labels)
[0 1 2 3 4 5 6 7 8 9] <a list of 10 Text xticklabel objects>

Now, we will set both the locations and the labels of the xticks:

# set the locations and labels of the xticks
plt.xticks( np.arange(4), 
           ('Berlin', 'London', 'Hamburg', 'Toronto') )
After having executed the Python code above we received the following output:
([<matplotlib.axis.XTick at 0x7f3e1ac841d0>,
  <matplotlib.axis.XTick at 0x7f3e1aadf668>,
  <matplotlib.axis.XTick at 0x7f3e1aaac080>,
  <matplotlib.axis.XTick at 0x7f3e1a7d23c8>],
 <a list of 4 Text xticklabel objects>)

Let's get back to our previous example with the trigonometric functions. Most people might consider factors of Pi to be more appropriate for the X axis than the integer labels:

import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)
X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)
F1 = np.sin(X**2)
F2 = X * np.sin(X)
# get the current axes, creating them if necessary:
ax = plt.gca()
# making the top and right spine invisible:
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# moving bottom spine up to y=0 position:
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
# moving left spine to the right to position x == 0:
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
plt.xticks( [-6.28, -3.14, 3.14, 6.28])
plt.yticks([-3, -1, 0, +1, 3])
plt.plot(X, F1)
plt.plot(X, F2)
plt.show()


Setting Tick Labels

We want to rename the xticks now with custom markers. We will use the method xticks again for this purpose as we did in our previous examples. But this time we will call xticks with two parameters: The first one is the same list we used before, i.e. the positions on the x axis, where we want to have the ticks. The second parameter is a list of the same size with corresponding LaTeX tick marks, i.e. the text which we want to see instead of the values. The LaTeX notation has to be a raw string in most cases to suppress the escaping mechanism of Python, because the LaTeX notation heavily uses and relies on the backslash.

import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)
F1 = X * np.sin(X)
ax = plt.gca()
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
# labelling the X ticks:
plt.xticks( [-6.28, -3.14, 3.14, 6.28],
        [r'$-2\pi$', r'$-\pi$', r'$+\pi$', r'$+2\pi$'])
plt.yticks([-3, -1, 0, +1, 3])
plt.plot(X, F1)
plt.show()


Adjusting the ticklabels

We want to increase the legibility of the ticklabels. We will increase the font size, and we will render them on a semi transparant background.

print(ax.get_xticklabels())
<a list of 4 Text xticklabel objects>
for xtick in ax.get_xticklabels():
    print(xtick)
Text(-6.28,0,'$-2\\pi$')
Text(-3.14,0,'$-\\pi$')
Text(3.14,0,'$+\\pi$')
Text(6.28,0,'$+2\\pi$')
labels = [xtick.get_text() for xtick in ax.get_xticklabels()]
print(labels)
['$-2\\pi$', '$-\\pi$', '$+\\pi$', '$+2\\pi$']

Let's increase the fontsize and make the font semi transparant:

import numpy as np
import matplotlib.pyplot as plt
X = np.linspace(-2 * np.pi, 2 * np.pi, 170, endpoint=True)
F1 = np.sin(X**3 / 2)
ax = plt.gca()
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
plt.xticks( [-6.28, -3.14, 3.14, 6.28],
        [r'$-2\pi$', r'$-\pi$', r'$+\pi$', r'$+2\pi$'])
plt.yticks([-3, -1, 0, +1, 3])
for xtick in ax.get_xticklabels():
    xtick.set_fontsize(18)
    xtick.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.7 ))
for ytick in ax.get_yticklabels():
    ytick.set_fontsize(14)
    ytick.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.7 ))
    
plt.plot(X, F1, label="$sin(x)$")
plt.legend(loc='lower left')
plt.show()