pandas bar plot combined with line plot shows the time axis beginning at 1970

  • I do not advise plotting a bar plot with such a numerous amount of bars.
  • This answer explains why there is an issue with the xtick labels, and how to resolve the issue.
  • Plotting with pandas.DataFrame.plot works without issue with .set_major_locator
  • Tested in python 3.8.11, pandas 1.3.2, matplotlib 3.4.2
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas_datareader as web  # conda install -c anaconda pandas-datareader or pip install pandas-datareader

# download data
df = web.DataReader('amzn', data_source="yahoo", start="2015-02-21", end='2021-04-27')

# plot
ax = df.plot(y='Close', color="magenta", ls="-.", figsize=(10, 6), ylabel="Price ($)")

ax1 = df.plot(y='Volume', secondary_y=True, ax=ax, alpha=0.5, rot=0, lw=0.5)
ax1.set(ylabel="Volume")

# format
date_fmt="%d-%m-%y"
years = mdates.YearLocator()   # every year
yearsFmt = mdates.DateFormatter(date_fmt)

ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)

plt.setp(ax.get_xticklabels(), ha="center")
plt.show()

enter image description here


  • Why are the OP x-tick labels starting from 1970?
  • Bar plots locations are being 0 indexed (with pandas), and 0 corresponds to 1970
    • See Pandas bar plot changes date format
    • Most solutions with bar plots simply reformat the label to the appropriate datetime, however this is cosmetic and will not align the locations between the line plot and bar plot
    • Solution 2 of this answer shows how to change the tick locators, but is really not worth the extra code, when plt.bar can be used.
print(pd.to_datetime(ax1.get_xticks()))

DatetimeIndex([          '1970-01-01 00:00:00',
               '1970-01-01 00:00:00.000000001',
               '1970-01-01 00:00:00.000000002',
               '1970-01-01 00:00:00.000000003',
               ...
               '1970-01-01 00:00:00.000001552',
               '1970-01-01 00:00:00.000001553',
               '1970-01-01 00:00:00.000001554',
               '1970-01-01 00:00:00.000001555'],
              dtype="datetime64[ns]", length=1556, freq=None)
ax = df.plot(y='Close', color="magenta", ls="-.", figsize=(10, 6), ylabel="Price ($)")
print(ax.get_xticks())
ax1 = df.plot(y='Volume', secondary_y=True, ax=ax, kind='bar')
print(ax1.get_xticks())
ax1.set_xlim(0, 18628.)

date_fmt="%d-%m-%y"
years = mdates.YearLocator()   # every year
yearsFmt = mdates.DateFormatter(date_fmt)

ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)

[out]:
[16071. 16436. 16801. 17167. 17532. 17897. 18262. 18628.]  ← ax tick locations
[   0    1    2 ... 1553 1554 1555]  ← ax1 tick locations

enter image description here

  • With plt.bar the bar plot locations are indexed based on the datetime
ax = df.plot(y='Close', color="magenta", ls="-.", figsize=(10, 6), ylabel="Price ($)", rot=0)
plt.setp(ax.get_xticklabels(), ha="center")
print(ax.get_xticks())

ax1 = ax.twinx()
ax1.bar(df.index, df.Volume)
print(ax1.get_xticks())

date_fmt="%d-%m-%y"
years = mdates.YearLocator()   # every year
yearsFmt = mdates.DateFormatter(date_fmt)

ax.xaxis.set_major_locator(years)
ax.xaxis.set_major_formatter(yearsFmt)

[out]:
[16071. 16436. 16801. 17167. 17532. 17897. 18262. 18628.]
[16071. 16436. 16801. 17167. 17532. 17897. 18262. 18628.]

enter image description here

  • sns.barplot(x=df.index, y=df.Volume, ax=ax1) has xtick locations as [ 0 1 2 ... 1553 1554 1555], so the bar plot and line plot did not align.

Leave a Comment