除了从头开始创建刻度外,我不知道有什么方法可以做到这一点。
在以下示例中,从第一个日期(1 月 25 日)的月份开始,从 pandas 数据帧的 DatetimeIndex 创建了所有 first-DatetimeIndex-timestamp-of-the-month 的列表到最后一个持续月份的开始。 step 变量会自动选择适当数量的刻度,并添加上个月,然后在重复时使用 np.unique 将其删除。标签是根据刻度时间戳格式化的。
此解决方案适用于小于每年的任何频率:
import numpy as np # v 1.19.2
import pandas as pd # v 1.1.3
import matplotlib.pyplot as plt # v 3.3.2
# Create sample dataset
start_date = '2019-01-25'
end_date = '2021-02-12'
rng = np.random.default_rng(seed=123) # random number generator
dti = pd.date_range(start_date, end_date, freq='D')
variable = 100 + rng.normal(size=dti.size).cumsum()
df = pd.DataFrame(dict(variable=variable), index=dti)
# Create matplotlib plot
fig, ax = plt.subplots(figsize=(10, 2))
ax.plot(df.index, df.variable)
# Create list of monthly ticks made of timestamp objects
monthly_ticks = [timestamp for idx, timestamp in enumerate(df.index)
if (timestamp.month != df.index[idx-1].month) | (idx == 0)]
# Select appropriate number of ticks and include last month
step = 1
while len(monthly_ticks[::step]) > 10:
step += 1
ticks = np.unique(np.append(monthly_ticks[::step], monthly_ticks[-1]))
# Create tick labels from tick timestamps
labels = [timestamp.strftime('%b\n%Y') if timestamp.year != ticks[idx-1].year
else timestamp.strftime('%b') for idx, timestamp in enumerate(ticks)]
plt.xticks(ticks, labels, rotation=0, ha='center');
如您所见,第一个月和最后几个月与相邻刻度的距离不规则。
如果您正在绘制具有不连续日期范围的时间序列(例如不包括周末和节假日)并且您没有使用 DatetimeIndex 作为 x 轴(例如例如:ax.plot(range(df.index.size), df.variable)) 以避免在短时间序列和/或非常宽的图中出现直线的间隙,然后将最后一行代码替换为:
plt.xticks([df.index.get_loc(tick) for tick in ticks], labels, rotation=0, ha='center');