2

I have a dataFrame with datetimeIndex and two columns with int values. I would like to plot on the same graph Col1 as a bar plot, and Col2 as a line plot.

Important feature is to have correctly labeled x-axis as datetime, also when zooming in-out. I think solutions with DateFormatter would not work, since I want a dynamic xtick labeling.

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

startDate = dt.datetime(2018,1,1,0,0)
nrHours = 144
datetimeIndex = [startDate + dt.timedelta(hours=x) for x in  range(0,nrHours)]

dF = pd.DataFrame(index=datetimeIndex)
dF['Col1'] = np.random.randint(1,3,nrHours)
dF['Col2'] = np.random.randint(3,6,nrHours)

axes = dF[['Col1']].plot(kind='bar')
dF[['Col2']].plot(ax=axes)

What seemed to be a simple task turns out being very challenging. Actually, after extensive search on the net, I still haven't found any clean solutions.

I have tried to use both pandas plot and matplotlib. The main issue arises from the bar plot that seems to have difficulties handling datetime index (prefers integers, in some cases it plot dates but in Epoch 1970-1-1 style which is equivalent to 0).

Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • There are a whole bunch of similar questions, [here is a collection](https://stackoverflow.com/q/46503073/8881141). None of them provides a solution for your problem? – Mr. T Apr 11 '18 at 09:17
  • Thanks for your reply. I've already looked up these links and although some give very useful hints, none provide an entire solution. – Christopher H Apr 11 '18 at 11:26

1 Answers1

5

I finally found a way using mdates and date2num. The solution is not very clean but provides an efficient solution to:

  • Combine bar and line plot on same graph
  • Using datetime on x-axis
  • Correctly and dynamically displaying x-ticks time labels (also when zooming in and out)

Working example :

import matplotlib.pyplot as plt
import matplotlib.dates  as mdates
import pandas as pd
import datetime as dt
import numpy as np

startDate = dt.datetime(2018,1,1,0,0)
nrHours = 144
datetimeIndex = [startDate + dt.timedelta(hours=x) for x in range(0, nrHours)]

dF = pd.DataFrame(index=datetimeIndex)
dF['Col1'] = np.random.randint(1,3,nrHours)
dF['Col2'] = np.random.randint(3,6,nrHours)

fig,axes = plt.subplots()
axes.xaxis_date()
axes.plot(mdates.date2num(list(dF.index)),dF['Col2'])
axes.bar(mdates.date2num(list(dF.index)),dF['Col1'],align='center',width=0.02)
fig.autofmt_xdate()

Sample output:

enter image description here

Mr. T
  • 11,960
  • 10
  • 32
  • 54
  • I took the liberty to illustrate your script with a sample output. – Mr. T Apr 11 '18 at 20:38
  • Another method for processing and formatting dates that should work for a combined bar+line plot in matplotlib can be found in [this answer](https://stackoverflow.com/a/49573439/14148248). – Patrick FitzGerald Jan 10 '21 at 11:19