How can I make xtick different from xlim in Python matplotlib?
That is not possible. xtick
is essentially a sub-domain within your xlim
(your x-range). "Ticks" are nothing more than discrete points within your limits which are produced by your chosen Locator
. Visually, the tick presents itself to you in two ways: First, the little orthogonal line, which I presume gives the "tick" its name, and second, the value which is shown close to it. However, how the value is presented to the user is, in turn, determined by the chosen Formatter
. Setting custom labels comes down to using a FixedFormatter
which simply returns arbitrary labels for local tick indices.
See https://matplotlib.org/api/ticker_api.html for further details.
What goes wrong in your code?
fig = plt.figure(figsize=(8,2))
ax = fig.add_subplot(1,1,1)
ax.axis([0, 12, 0, 1])
ax.get_xticks()
# returns array([ 0., 2., 4., 6., 8., 10., 12.])
Settings the limits how you do it produces exactly 6 ticks:

If you now assign more custom labels than the actual number of ticks, the excessive ones are simply ignored. This is the behavior you experienced.
Funny thing. What happens if you set the custom labels and increase the number of ticks (and by that also the range) afterwards?
fig = plt.figure(figsize=(8,2))
ax = fig.add_subplot(1,1,1)
ax.axis([0, 12, 0, 1])
ax.set_xticklabels(['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep','Oct', 'Nov', 'Dec'])
ax.set_xticks(range(24)) # [0, 1, ..., 22, 23]
ax.get_xlim()
# returns (0.0, 23.0)
It increases your x-range (!) and simply shows no labels for the exceeding 12 ticks:

Note that you also changed the x-range explicitly after setting the labels. But because the underlying Formatter does not really care about the concrete values but rather the local tick index AND the new x-range had the same amount of ticks you could not really see what is going on. After setting xlim(0, 100)
your ticks actually were [0, 20, 40, ... 100]
and not [0 ... 12]
anymore. This can easily cause bugs and that is why you should always try to operate consistently in one domain (months 0-12, percent 0-100/0-1).
Solving the problem: Choosing a domain!
For the sake of this example I choose the months as our domain which means we operate in the range 0 to 12. Note that 0, the lower bound, corresponds to January 1st and 12, the upper bound, corresponds to December 31st. We can now left-align our monthly ticks (equals ax.set_xticks(range(12))
) or center them under the respective month (equals import numpy as np; ax.set_xticks(np.arange(0, 12, 1) + 0.5)
). As we set the limits to be (0, 12)
modifying the ticks will not change the limits.
Using months as the domain also implies that your percent value (0, 1)
is relative to (0, 12)
and not (0, 100)
. Consequently, you have to multiply it by 12 to obtain the width you desire.
Putting it all together:
import random
import datetime
import matplotlib.pyplot as plt
def get_percent():
today = datetime.date.today()
start = datetime.date(today.year, 1, 1)
diff = today - start
percent = diff.days/365.0
return percent
fig = plt.figure(figsize=(8,2))
ax = fig.add_subplot(1,1,1)
percent = get_percent()
ax.axis([0, 12, 0, 1])
month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec']
ax.set_xticks(range(12)) # ticks placed on [0, 1, ..., 11]
ax.set_xticklabels(month)
ax.barh(bottom=0.5,width=int(percent*12),height=0.2)
plt.show()
plt.close()

When you also remove the typecast to int
when setting your bar width you receive the following result:

P.S. Forgive me for "Okt" instead of "Oct". That was my German soul at work.. :)