How to Get Ticks Every Hour

How to get ticks every hour

The problem is that while pandas in general directly wraps the matplotlib plotting methods, this is not the case for plots with dates. As soon as dates are involved, pandas uses a totally different numerical representation of dates and hence also uses its own locators for the ticks.

In case you want to use matplotlib.dates formatters or locators on plots created with pandas you may use the x_compat=True option in pandas plots.

df.plot(ax = ax, color = 'black', linewidth = 0.4, x_compat=True)

This allows to use the matplotlib.dates formatters or locators as shown below.
Else you may replace df.plot(ax = ax, color = 'black', linewidth = 0.4) by

ax.plot(df.index, df.values, color = 'black', linewidth = 0.4)

Complete example:

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 = 'min')
df = pd.Series(np.random.randn(len(idx)), index = idx)

fig, ax = plt.subplots()
hours = mdates.HourLocator(interval = 1)
h_fmt = mdates.DateFormatter('%H:%M:%S')

ax.plot(df.index, df.values, color = 'black', linewidth = 0.4)
#or use
df.plot(ax = ax, color = 'black', linewidth = 0.4, x_compat=True)
#Then tick and format with matplotlib:
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(h_fmt)

fig.autofmt_xdate()
plt.show()

Sample Image


If the motivation to use pandas here is (as stated in the comments below) to be able to use secondary_y, the equivalent for matplotlib plots would be a twin axes twinx.

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 = 'min')

df = pd.DataFrame(np.cumsum(np.random.randn(len(idx), 2),0),
index = idx, columns=list("AB"))

fig, ax = plt.subplots()
ax.plot(df.index, df["A"], color = 'black')
ax2 = ax.twinx()
ax2.plot(df.index, df["B"], color = 'indigo')

hours = mdates.HourLocator(interval = 1)
h_fmt = mdates.DateFormatter('%H:%M:%S')
ax.xaxis.set_major_locator(hours)
ax.xaxis.set_major_formatter(h_fmt)

fig.autofmt_xdate()
plt.show()

Sample Image

Major tick every month and minor tick every week in matplotlib

The month display is set by MonthLocator to one month with the month abbreviation. For weeks, we have 7-day interval data in DayLocator and set the original labels. It would have been easy to use ax.xaxis.set_minor_formatter('%U'), but

import pandas as pd
import numpy as np
import random

random.seed(202012)

date_rng = pd.date_range('2019/01/01', '2019/12/31', freq='1H')
temp = np.random.randint(-10,35, size=8737)
df = pd.DataFrame({'date':pd.to_datetime(date_rng),'Temp':temp})

df['Time'] = df['date'].dt.hour
df['Date'] = df['date'].dt.date
df['Week'] = df['date'].dt.week
df = df[['Date','Week','Time','Temp']]
pivot = pd.pivot_table(df, values='Temp',columns='Date',index='Time')

# week num create
weeks = df[['Date','Week']]
ww = weeks.groupby('Week').first().reset_index()

import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import matplotlib.ticker as ticker
import seaborn as sns

fig, ax = plt.subplots(figsize = (24,6))

clr = sns.color_palette("coolwarm", as_cmap=True)
fig = sns.heatmap(pivot, center = 0,cmap = clr )

months = mdates.MonthLocator(interval=1)
months_fmt = mdates.DateFormatter('%b')
ax.xaxis.set_major_locator(months)
ax.xaxis.set_major_formatter(months_fmt)

days = mdates.DayLocator(interval=7)
ax.xaxis.set_minor_locator(days)
ax.xaxis.set_minor_formatter(ticker.FixedFormatter(ww.Week))
# ax.xaxis.set_minor_formatter('%U') # Not displayed correctly

plt.show()

Sample Image

Highcharts tickInterval every hour

You have irregular interval between points, so Highcharts can't really calculate proper distance between points. That causes problem with interval on xAxis - workaround is to set pointRange for example to 1/10 of hour: jsfiddle.net/qn6romsf/7 - if you can't set pointRange, then try to use tickPositioner.

How to add hourly ticks in an axis from datetime formatted data

  • Convert the 'time' column to a datetime dtype with pd.to_datetime, and then extract the time component with the .dt accessor.
    • See python datetime format codes to specify the format=... string.
  • Plot with pandas.DataFrame.plot
  • Tested in python 3.8.12, pandas 1.3.3, matplotlib 3.4.3
import pandas as pd

# sample data
data = {'time': ['00:01:51.57', '00:01:52.54', '00:01:53.51', '00:01:54.49', '00:01:55.46', '00:01:56.43', '00:01:57.41', '00:01:58.38', '00:01:59.35', '00:02:00.33', '00:02:01.30', '00:02:02.27', '00:02:03.24', '00:02:04.22', '00:02:05.19', '00:02:06.17', '00:02:07.14', '00:02:08.11', '00:02:09.08', '00:02:10.06', '00:02:11.03', '00:02:12.00', '00:02:12.98', '00:02:13.95', '00:02:14.92', '00:02:15.90'],
'temp': [185.94, 187.48, 197.85, 195.71, 197.22, 187.33, 194.18, 199.9, 184.23, 201.34, 200.12, 199.13, 187.47, 187.65, 195.59, 188.7, 196.16, 191.17, 198.62, 190.79, 193.35, 199.36, 190.76, 205.16, 194.89, 185.3],
'temp_mean': [185.94, 186.71, 190.4233333, 191.745, 192.84, 191.9216667, 192.2442857, 193.20125, 192.2044444, 193.118, 193.7545455, 194.2025, 193.6846154, 193.2535714, 193.4093333, 193.115, 193.2941176, 193.1761111, 193.4626316, 193.329, 193.33, 193.6040909, 193.4804348, 193.9670833, 194.004, 193.6692308]}
df = pd.DataFrame(data)

# convert column to datetime and extract time component
df.time = pd.to_datetime(df.time, format='%H:%M:%S.%f').dt.time

# plot
ax = df.plot(x='time', color=['tab:blue', 'tab:red'])

Sample Image

How to change the datetime tick label frequency for matplotlib plots

First of all you have to convert pandas date objects to python date objects. This conversion is needed because of matplotlib internal date conversion functions. Then use functions from matplotlib.dates to set desired formatter and tick positions like here:

import pandas as pd
import numpy as np
import matplotlib.pylab as plt
import matplotlib.dates as mdates

# convert date objects from pandas format to python datetime
index = pd.date_range(start = "2015-07-01", end = "2017-01-01", freq = "D")
index = [pd.to_datetime(date, format='%Y-%m-%d').date() for date in index]
data = np.random.randint(1,100, size=len(index))
df = pd.DataFrame(data=data,index=index, columns=['data'])
print (df.head())

ax = df.plot()
# set monthly locator
ax.xaxis.set_major_locator(mdates.MonthLocator(interval=1))
# set formatter
ax.xaxis.set_major_formatter(mdates.DateFormatter('%d-%m-%Y'))
# set font and rotation for date tick labels
plt.gcf().autofmt_xdate()

plt.show()

For season labels you have to construct it by yourself and then set it with plt.setp function (for month 02 set label winter, 04 - spring etc.):
plt.setp(new_labels, rotation=90, fontsize=9).

Sample Image

head of df:

            data
2015-07-01 26
2015-07-02 33
2015-07-03 46
2015-07-04 69
2015-07-05 17

Using datetime as ticks in Matplotlib

This is an alternative plotting method plot_date, which you might want to use if your independent variable are datetime like, instead of using the more general plot method:

import datetime
data = np.random.rand(24)

#a list of time: 00:00:00 to 23:00:00
times = [datetime.datetime.strptime(str(i), '%H') for i in range(24)]

#'H' controls xticklabel format, 'H' means only the hours is shown
#day, year, week, month, etc are not shown
plt.plot_date(times, data, fmt='H')
plt.setp(plt.gca().xaxis.get_majorticklabels(),
'rotation', 90)

Sample Image

The benefit of it is that now you can easily control the density of xticks, if we want to have a tick every hour, we will insert these lines after plot_date:

##import it if not already imported
#import matplotlib.dates as mdates
plt.gca().xaxis.set_major_locator(mdates.HourLocator())

Sample Image



Related Topics



Leave a reply



Submit