Matplotlib DateFormatter for axis label not working
pandas just doesn't work well with custom date-time formats.
You need to just use raw matplotlib in cases like this.
import numpyimport matplotlib.pyplot as pltimport matplotlib.dates as mdatesimport pandasN = 20numpy.random.seed(N)dates = pandas.date_range('1/1/2014', periods=N, freq='m')df = pandas.DataFrame( data=numpy.random.randn(N), index=dates, columns=['A'])fig, ax = plt.subplots(figsize=(10, 6))ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))ax.bar(df.index, df['A'], width=25, align='center')
And that gives me:
I stepped into the same problem and I used an workaround to transform the index from date time format into the desired string format:
import numpy as npimport matplotlib.dates as mdatesimport matplotlib.pyplot as pltimport pandas as pdrng = pd.date_range('1/1/2014', periods=20, freq='m')blah = pd.DataFrame(data = np.random.randn(len(rng)), index=rng)fig = plt.figure(figsize = (10,6))ax = fig.add_subplot(111)# transform index to stringsblah_test = blah.copy()str_index = []for s_year,s_month in zip(blah.index.year.values,blah.index.month.values): # build string accorind to format "%Y-%m" string_day = '{}-{:02d}'.format(s_year,s_month) str_index.append(string_day)blah_test.index = str_indexblah_test.plot(ax=ax, kind='bar', rot=45)plt.show()
which results in the following figure:
Solution with pandas only
You can create nicely formatted ticks by using the DatetimeIndex
and taking advantage of the datetime properties of the timestamps. Tick locators and formatters from matplotlib.dates
are not necessary for a case like this unless you would want dynamic ticks when using the interactive interface of matplotlib for zooming in and out (more relevant for time ranges longer than in this example).
import numpy as np # v 1.19.2import pandas as pd # v 1.1.3# Create sample time series with month start frequency, plot it with a pandas bar chartrng = np.random.default_rng(seed=1) # random number generatordti = pd.date_range('1/1/2014', periods=20, freq='m')df = pd.DataFrame(data=rng.normal(size=dti.size), index=dti)ax = df.plot.bar(figsize=(10,4), legend=None)# Set major ticks and tick labelsax.set_xticks(range(df.index.size))ax.set_xticklabels([ts.strftime('%b\n%Y') if ts.year != df.index[idx-1].year else ts.strftime('%b') for idx, ts in enumerate(df.index)])ax.figure.autofmt_xdate(rotation=0, ha='center');