1

I'm using pandas inbuilt .plot command to plot stuff some long-ish time series.

But my date ticks always are years ending in 9 by default.screenshot of plot

Why is that so, and how can I change it? Years ending in 0 would look much nicer.

Trying to set the window of the axis with plt.xlim('1966', '2013') or something like this also does not do anything about plots fetish for years ending in 9 (and 4, if you "zoom in", as shown above).

It also does not seem to have anything to do with the start and end of the dates in the source dataframe.

here is a minimal, empty, example:

dfdates = pd.date_range('01/01/1942', '01/01/2018', freq = 'MS')
dfzeros = np.zeros((len(dfdates)))
header_test = pd.MultiIndex.from_product([['zero'],['zero'], ['zero'], ['zero'], ['zero'], ['zero']], names = ['stuff1', 'stuff2', 'stuff3', 'stuff4', 'stuff5', 'stuff6'])
Big_df = pd.DataFrame(dfzeros, index = dfdates, columns = header_test)

Big_df.plot()
plt.show()

…And this results in this for me: empty test plot

And I cant change the 9's at the end, no matter if I set a window with plt.xlim or if I change the start and end years, months or days of dfdates, so it's not something easy as "start of the dataframe + 10 years" or similar, and my large header also does not affect those.

I probably could set more sensible ticks per hand, but I'd rather know why it is so hell bent on using years with 9 at the end.

EDIT So here is what happens when I plot, using @lanery's answer: plot with double ticks Note the double ticks in the area of the plot where I specified the custom ticks (starting at 1965). All my dataframes start at 1940, but many are empty, to a certain point where I start to get data, depending on the dataset in question. I can cut this off with plt.xlim('1965','2015'), but I left it in in this plot, to show whats happening.

JC_CL
  • 2,346
  • 6
  • 23
  • 36

1 Answers1

1

Since setting plt.xlim with datetime objects, something like

plt.xlim(pd.datetime(1966, 1, 1), pd.datetime(2013, 1, 1))

didn't do the trick, I think the best course of action is to set custom xticks and xticklabels. This can be done by like so

dates = pd.date_range('1990', '2015', freq=pd.DateOffset(years=5))
ax.xaxis.set_ticks(dates)
ax.xaxis.set_ticklabels(dates.strftime('%Y'))

A full example with some random data:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(17)
years = pd.date_range(pd.datetime(1990, 1, 1), pd.datetime(2015, 1, 1), freq='MS')
random_data = np.asarray(np.split(np.cumsum(np.random.randn(years.size*3)), 3)).T
df = pd.DataFrame(random_data, columns=['A', 'B', 'C'], index=years)

# all of the relevant plotting and xtick formatting
fig = plt.figure()
ax = fig.add_subplot(111)

df.plot(ax=ax)

# select range of years for the x-axis as well as major tick spacing
dates = pd.date_range('1990', '2015', freq=pd.DateOffset(years=5))
ax.xaxis.set_ticks(dates)
ax.xaxis.set_ticklabels(dates.strftime('%Y'))
# dates.strftime('%Y') = (['1990', '1995',...,'2010', '2015'])

ax.grid()

enter image description here

lanery
  • 5,222
  • 3
  • 29
  • 43
  • It does work with my example, but with the real data, it does not. (Or actually, it does, no errors, and the window moves, but the 9's stay). – JC_CL May 23 '16 at 16:26
  • `pandas` plotting puts more of an emphasis on auto-formatting plots, so I was hoping that setting the `xlim` would be a simple way of re-adjusting the automatically chosen major tickmarks (especially after it worked on your example). Since it did not, you'll likely need to override with some customizations, perhaps this example will help: http://stackoverflow.com/questions/3486121/how-to-plot-data-against-specific-dates-on-the-x-axis-using-matplotlib – lanery May 23 '16 at 18:15
  • @JC_CL I updated my answer to show how to set custom `xticks` and `xticklabels`. It basically comes down to just 3 lines, so hopefully applying this solution to your dataframe should be relatively painless (that is, if you haven't already found a workaround). – lanery May 24 '16 at 04:53
  • Thanks, that helps a lot! But it seems like the custom xticks only get added to pandas ticks, in the area I specified. so now I have major ticks (and labels) at yy10 and yyy5 inside the specified area, and minor ticks (with no labels) at yyy9 and yyy4. The next step is working with the SVG of the plot in inkscape anyways, so that is easily corrected, but I would still be very interested in knowing WTF pandas is "thinking". – JC_CL May 24 '16 at 09:14
  • Added a picture to my original question to illustrate whats happening. – JC_CL May 24 '16 at 09:21
  • I'm able to recreate that problem once the plot range >= 50 years. I believe this is the source code: https://github.com/pydata/pandas/blob/master/pandas/tseries/converter.py but I'm not able to pin down where it's making that decision. Anyway, to remove the 4 and 9 year ticks it's easiest to do `plt.tick_params(axis='x', which='minor', top='off', bottom='off')`. – lanery May 25 '16 at 02:59