当前的项目是绘制一系列时间框架的图,这些时间框架在一年中的不同时间发生,每年都是相同的。
每个时间周期都有一个定义的开始和结束,这是根据周期内的事件来声明的。在这种情况下,公司在一年中的特定时间报告收益。每个报告周期的共同事项是公司通知将于何时向公众公布财务报告。
发行公告被视为"第0天",周期内的所有其他事件均与公告日期相关。它们发生在公告日期的前x天或后x天。
Matplotlib将使用正在绘制的数据中的最小/最大值自动设置范围。我试图将x报价器设置为5间隔,公告日期(0)作为基础
如果我使用:
ax.xaxis.set_major_locator(plt.IndexLocator(base=5, offset=0))
它在循环中不使用'Day 0',而是将x轴上的第一个(0)位置作为偏移量,然后将下一个股票在5处。
因此,如果我的数据集中周期的最小开始时间是在公告日期(我的"0")之前的53天,那么它将在-53处绘制第一个x轴,下一个在-48,-43处,等等。它不以0为中心。但是最小的x值。
然而,如果我在我的"0"处画一条垂直线,使用:
ax.vlines(0,-1,len(df))
将其绘制在正确的位置,但只有当第一个指针是5的倍数时,该线才匹配为'0'的指针。
(在我的示例数据集中,xmin = -53,在-3和2之间画了一条线。
我怎样才能强制定位器在我的"0"所在的图形中间偏移?
或者,我可以强制第一个自动粘附到最近的5的倍数上吗?
与其说是回答了我的问题,不如说是解决了我的问题。事实证明,使用IndexLocator作为设置x轴major_locator的基础并不是我想要的。
我应该用MultipleLocator代替。
下面是完成我想要的完整代码:
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.ticker import (MultipleLocator, AutoMinorLocator)
def round_to_five( n ): # function to round the number to the nearest 5
# Smaller multiple
a = (n // 5) * 5
# Larger multiple
b = a + 5
# Return of closest of two
return (b if n - a > b - n else a)
data = {'Period':['Q1','Q2','Q3','Q4'], 'Start':[-3,-18,-21,-29], 'End':[21,37,48,12]}
df = pd.DataFrame(data)
graph_start = round_to_five(df['Start'].min()) # set the left boundary to the nearest multiple of 5
graph_end = round_to_five(df['End'].max()) # set right boundary to the nearest multiple of 5
fig, ax = plt.subplots()
ax.vlines(0,-1,len(df['Period']),color='green', linewidth = 2, zorder = 0, label='Announcement' ) # show event reference line at Day 0.
ax.scatter(df['Start'],df['Period'],color = 'purple', label = 'Cycle Start', marker = '|', s = 100, zorder = 2) # plot cycle start in number of days before Announcement Date.
ax.scatter(df['End'],df['Period'],color = 'red', label = 'Cycle End', marker = '|', s = 100, zorder = 2) # plot cycle end in number of days after Announcement Date.
ax.hlines(df['Period'], xmin=df['Start'], xmax=df['End'], color='blue', linewidth = 1, zorder = 1) # show cycle
ax.legend(ncol=1, loc = 'upper right')
## Set min and max x values as left and right boundaries, and then makes ticks to be 5 apart.
ax.set_xlim([graph_start-5, graph_end+5])
ax.xaxis.set_major_locator(MultipleLocator(5))
ax.tick_params(axis = 'x', labelrotation = 60)
plt.show()