1

I am trying to do a simple bar chart for a dataframe, that has dates as index and several columns of data.

start_date = pd.to_datetime('20180101')
dates = pd.date_range(start_date, periods=365)
df = pd.DataFrame(np.random.randn(365,4), index = dates, columns = list('ABCD'))
df = df.resample('M').sum()

If I use

df.plot.bar()

Then dates on the x-axis are messed up. If I use

fig, ax = plt.subplots()
ax.bar(df.index, df['A'],width = 5, align = 'center')
ax.bar(df.index, df['B'], width = 5 , align = 'center')
ax.bar(df.index, df['C'],width = 5, align = 'center')
ax.bar(df.index, df['D'], width = 5 , align = 'center')
ax.xaxis_date()
ax.get_xaxis().set_major_locator(mdates.MonthLocator())
ax.get_xaxis().set_major_formatter(mdates.DateFormatter("%b %Y"))
fig.autofmt_xdate()
plt.show()

Then my bars overlap each other and dates are shown with a shift by one month.

Can someone please suggest an elegant solution how to plot a bar chart that will not have the above mentioned drawbacks?

1
  • Pandas bar charts are catgorical. But to me the result looks fine. The shift of one month in the matplotlib chart is in your data, due to the resampling you perform. This example shows how to make a grouped barchart in matplotlib. Commented Oct 6, 2018 at 14:51

1 Answer 1

3

I did a similar project with bars and used this example to get the formatting correct.

Since i don't have the mdates values I can't run it to check if it's correct in your case but try doing this:

...
fig, ax = plt.subplots()
width = 5
ax.bar(df.index, df['A'], width, align = 'center')
ax.bar(df.index + width , df['B'], width, align = 'center')
ax.bar(df.index + 2*width, df['C'], width, align = 'center')
ax.bar(df.index + 3*width, df['D'], width, align = 'center')
ax.set_xticks(df.index + width) # sets the x-ticks to the middle of the cluster of bars
ax.xaxis_date()
...
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you! I saw this solution as well, yet didnt manage to make it work with dates.
not sure if its only on my side, but I had to use df.index + datetime.timedelta(days=width) to obtain the desired output

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.