问题描述
当前的项目是绘制一系列时间框架的图表,这些时间框架都标准化为相同的时间框架,即使发生在一年中的不同时间,每年也是如此。
每个时间周期都有一个定义的开始和结束时间,这些开始和结束时间是根据周期内的一个事件来说明的。在这种情况下,公司在一年中的某些时间报告收益。每个报告周期的共同事件是公司通知何时向公众公布财务报告。
分发公告已被视为“第 0 天”,并且该周期内的所有其他事件均按公告日期绘制。它们发生在公告日期之前或之后的“x”天。
Matplotlib 将使用正在绘制的数据中的最小值/最大值自动设置范围。我试图将 x 股票代码设置为 5,以公告日期 (0) 为基础
如果我使用:
ax.xaxis.set_major_locator(plt.IndexLocator(base=5,offset=0))
它在循环中不使用“第 0 天”,而是使用 x 轴上的第一个 (0) 位置作为偏移量,然后将下一个代码从该位置设置为 5。
因此,如果我的数据集中周期的最小开始时间是宣布日期前 53 天(我的“0”),那么它会在 -53 处绘制第一个 x-ticker,在 -48 处绘制下一个,- 43 等。它不以我的“0”为中心。但是最小的 x 值。
但是,如果我使用以下方法在“0”处绘制一条垂直线:
ax.vlines(0,-1,len(df))
它在正确的位置绘制它,但该行与代码“0”匹配的唯一方式是第一个代码是 5 的倍数。
(在我的示例数据集中,其中 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'],color = 'red',label = 'Cycle End',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()