Search code examples
pythonmatplotlibplot

Setting xtick labels in the middle using matplotlib


I have following piece of random code that just draws a scatter plot using some random numbers.

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np

x = np.random.rand(10)
y = np.random.rand(10)
fig, ax = plt.subplots()
ax.plot(y, x, '*')

plt.show()

And it generates a plot like this: enter image description here

All good. But what I want is to edit the x labels using some custom labels and I want them to be centered between two x-ticks. Here is how I modified the code to achieve it:

import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np

x = np.random.rand(10)
y = np.random.rand(10)
fig, ax = plt.subplots()
ax.plot(y, x, '*')

xlabels = ['potato','tomato','apple','cherry','pie']
# Remove the major tick labels
ax.xaxis.set_major_formatter(ticker.NullFormatter())

# Set the major ticks to match the number of labels
num_labels = len(xlabels)
mticks = np.arange(num_labels)
ax.set_xticks(mticks)
ax.set_xticklabels(xlabels)

# Rotate the x-axis labels
for label in ax.get_xticklabels():
    label.set_rotation(90)
    label.set_horizontalalignment('right')  # Adjust horizontal alignment

plt.show()

But it generates a plot like this: enter image description here (don't mind the scatter plot changing. I guess x and y are random distributed arrays)

How do I edit my code such that the xlabels are at the center in between the ticks.


Solution

  • Assuming you're looking to label the intervals between the automatically generated ticks, and you can rely on these being at 0.2, 0.4, etc., the following would get you what you want:

    import matplotlib.pyplot as plt
    import numpy as np
    
    x = np.random.rand(10)
    y = np.random.rand(10)
    fig, ax = plt.subplots()
    ax.plot(y, x, '*')
    
    sec_xa = ax.secondary_xaxis('bottom')
    sec_xa.set_xticks([0.1, 0.3, 0.5, 0.7, 0.9])
    sec_xa.tick_params(axis='x', length=0)
    sec_xa.set_xticklabels(['potato', 'tomato', 'apple', 'cherry', 'pie'])
    
    plt.show()
    

    This:

    • creates a secondary x-axis on the bottom.
    • sets the ticks for it to be centered between the ticks you now have.
    • sets the length of the ticks to 0, so they are effectively invisible.
    • assigns the labels, which will be centered on those positions.

    This is what it looks like: enter image description here