I have a pandas DataFrame
indexed by a DatetimeIndex
that holds a time series, i.e. some data as a function of time. Now I would like to plot the behavior over the day regardless of the date (cf. this question):
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
idx = pd.date_range('2017-01-01 05:03', '2017-01-05 18:03', freq = '30min')
df = pd.Series(np.random.randn(len(idx)), index = idx)
hours = mdates.HourLocator(interval = 1)
h_fmt = mdates.DateFormatter('%H:%M:%S')
for date, group in df.groupby(by = df.index.date):
group.index = group.index.timetz
group.name = date # for legend
ax = group.plot()
plt.ion()
plt.show()
This works but the labels on the x-axis have peculiar spacings:
I'd prefer, e.g., to have ticks every hour on the hour. Based on this SO answer I found a solution that works, setting x_compat
and using the HourLocator
:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
idx = pd.date_range('2017-01-01 05:03', '2017-01-01 18:03', freq = '30min')
df = pd.Series(np.random.randn(len(idx)), index = idx)
hours = mdates.HourLocator(interval = 1)
h_fmt = mdates.DateFormatter('%H:%M:%S')
with pd.plotting.plot_params.use('x_compat', True):
ax = df.plot()
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(h_fmt)
plt.ion()
plt.show()
This gives the following plot (note I have reduced the date_range
to one day here):
It still works when splitting with groupby
and plotting more data:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
idx = pd.date_range('2017-01-01 05:03', '2017-01-05 18:03', freq = '30min')
df = pd.Series(np.random.randn(len(idx)), index = idx)
hours = mdates.HourLocator(interval = 1)
h_fmt = mdates.DateFormatter('%H:%M:%S')
with pd.plotting.plot_params.use('x_compat', True):
for date, group in df.groupby(by = df.index.date):
ax = group.plot()
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(h_fmt)
plt.ion()
plt.show()
Of course, I still need to wrap around (drop) the date here. But once I do that, my solution no longer works:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
idx = pd.date_range('2017-01-01 05:03', '2017-01-05 18:03', freq = '30min')
df = pd.Series(np.random.randn(len(idx)), index = idx)
hours = mdates.HourLocator(interval = 1)
h_fmt = mdates.DateFormatter('%H:%M:%S')
with pd.plotting.plot_params.use('x_compat', True):
for date, group in df.groupby(by = df.index.date):
group.index = group.index.timetz
group.name = date # for legend
ax = group.plot()
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(h_fmt)
plt.ion()
plt.show()
After computing for a while, this throws an error, maybe it's trying to make ticks starting at pandas 0 for timestamps?
RuntimeError: Locator attempting to generate 2030401 ticks from 180.0 to 84780.0: exceeds Locator.MAXTICKS