0

I want to plot a series of values against a date range in matplotlib. I changed the tick base parameter to 7, to get one tick at the beginning of every week (plticker.IndexLocator, base = 7). The problem is that the set_xticklabels function does not accept a base parameter. As a result, the second tick (representing day 8 on the beginning of week 2) is labelled with day 2 from my date range list, and not with day 8 as it should be (see picture).

How to give set_xticklabelsa base parameter?

Here is the code:

my_data = pd.read_csv("%r_filename_%s_%s_%d_%d.csv" % (num1, num2, num3, num4, num5), dayfirst=True)
my_data.plot(ax=ax1, color='r', lw=2.)
loc = plticker.IndexLocator(base=7, offset = 0) # this locator puts ticks at regular intervals
ax1.set_xticklabels(my_data.Date, rotation=45, rotation_mode='anchor', ha='right') # this defines the tick labels
ax1.xaxis.set_major_locator(loc)

Here is the plot:

Plot

sudonym
  • 3,788
  • 4
  • 36
  • 61

2 Answers2

2

Many thanks - your solution perfectly works. For the case that other people run into the same issue in the future: i have implemented the above-mentioned solution but also added some code so that the tick labels keep the desired rotation and also align (with their left end) to the respective tick. May not be pythonic, may not be best-practice, but it works

 x_fmt = mpl.ticker.IndexFormatter(x)
 ax.set_xticklabels(my_data.Date, rotation=-45)
 ax.tick_params(axis='x', pad=10)
 ax.xaxis.set_major_formatter(x_fmt)
 labels = my_data.Date
 for tick in ax.xaxis.get_majorticklabels():
    tick.set_horizontalalignment("left")
sudonym
  • 3,788
  • 4
  • 36
  • 61
1

The reason your ticklabels went bad is that setting manual ticklabels decouples the labels from your data. The proper approach is to use a Formatter according to your needs. Since you have a list of ticklabels for each data point, you can use an IndexFormatter. It seems to be undocumented online, but it has a help:

class IndexFormatter(Formatter)
 |  format the position x to the nearest i-th label where i=int(x+0.5)
 |  ...
 |  __init__(self, labels)
 |  ...

So you just have to pass your list of dates to IndexFormatter. With a minimal, pandas-independent example (with numpy only for generating dummy data):

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


# create dummy data    
x = ['str{}'.format(k) for k in range(20)]
y = np.random.rand(len(x))

# create an IndexFormatter with labels x
x_fmt = mpl.ticker.IndexFormatter(x)

fig,ax = plt.subplots()
ax.plot(y)
# set our IndexFormatter to be responsible for major ticks
ax.xaxis.set_major_formatter(x_fmt)

This should keep your data and labels paired even when tick positions change:

result

I noticed you also set the rotation of the ticklabels in the call to set_xticklabels, you would lose this now. I suggest using fig.autofmt_xdate to do this instead, it seems to be designed exactly for this purpose, without messing with your ticklabel data.

Community
  • 1
  • 1