简体   繁体   English

绘制具有不同频率的时间数据(matplotlib,pandas)

[英]Plotting time data with different frequencies (matplotlib, pandas)

I am trying to combine a Pandas time series and a number of vertical segments (markers) in the same plot. 我正在尝试在同一图中将熊猫时间序列和许多垂直线段(标记)结合起来。 The series has the frequency of 'Q-DEC' (quarter), which in this example is inferred from the dates, but in the real problem is a part of the dataset. 该序列的频率为“ Q-DEC”(四分之一),在本示例中是从日期推断的,但实际上,问题是数据集的一部分。 The markers in general are not aligned with the series and may appear anywhere, not necessarily at the end of a quarter. 标记通常与系列不符,可能会出现在任何位置,而不一定出现在四分之一结束时。

My problem is that if I first plot the series and then the markers, the markers' positions are rounded up to the next end of the quarter (the upper plot). 我的问题是,如果我先绘制序列,然后绘制标记,则标记的位置将四舍五入到该季度的下一个端点(上方的图)。 If I plot the markers first, followed by the series, the markers are in the right positions but the x ticks labels are inappropriate (the lower plot). 如果我先绘制标记,然后再绘制系列,则标记位于正确的位置,但x刻度标签不合适(下图)。

Q : How can I plot the markers at the right positions over a time series plot? :如何在时间序列图上的正确位置绘制标记?

import datetime
import pandas as pd
from pandas import Timestamp
import matplotlib.pyplot as plt

data = pd.DataFrame({0: {Timestamp('2017-03-31'): 1, 
                         Timestamp('2017-06-30'): 2, 
                         Timestamp('2017-09-30'): 3, 
                         Timestamp('2017-12-31'): 3, 
                         Timestamp('2018-03-31'): 2, 
                         Timestamp('2018-06-30'): 1}})

ax = plt.subplot(2,1,1)
data[0].plot(ax=ax,style="-mo")
ax.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
ax.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
ax.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
ax.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')
ax = plt.subplot(2,1,2)
ax.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
ax.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
ax.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
ax.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')
data[0].plot(ax=ax,style="-mo")
plt.show()

例

If you move the dates into the index as a PeriodIndex , start with freq="M" to ensure the lines get drawn correctly. 如果将日期作为PeriodIndex移入索引,则以freq="M"开头以确保正确绘制线条。
Then replace the ticks with the index values set to freq="Q-DEC" . 然后将刻度线替换为设置为freq="Q-DEC"的索引值。

data.set_index(pd.PeriodIndex(data.index, freq="M"), inplace=True)
ax = data[0].plot(style="-mo")

ax.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
ax.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
ax.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
ax.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')

Now reset the ticks: 现在重置刻度线:

q_ticks = data.index.asfreq("Q-DEC")
ax.minorticks_off()
ax.set_xticks(q_ticks)
ax.set_xticklabels(q_ticks)

Output: 输出:

在此处输入图片说明

Note: If you don't remove the minor ticks with minorticks_off() , you'll get some overlap with the original monthly ticks and the new quarterly ticks. 注意:如果不使用minorticks_off()删除次要minorticks_off() ,则会与原始的每月价格变动和新的季度价格变动重叠。

Update 更新
If you really need to get the format exactly as it is in your example, you'll need to do a bit of maneuvering with major and minor tick locations and formats: 如果确实需要完全按照示例中的方式获取格式,则需要对主要和次要刻度位置和格式进行一些调整:

ax.get_xaxis().set_tick_params(which='major', pad=15)

q_ticks = data.index.asfreq("Q-DEC")

# extract only the year, and only the year's first listing
major_ticklabels = pd.Series(q_ticks.strftime("%Y"))
major_ticklabels[major_ticklabels.duplicated()] = ""
ax.set_xticks(q_ticks)
ax.set_xticklabels(major_ticklabels)

# format as Q[quarter number]
minor_ticklabels = q_ticks.strftime("Q%q")
ax.xaxis.set_ticks(q_ticks, minor=True)
ax.xaxis.set_ticklabels(minor_ticklabels, minor=True)

在此处输入图片说明

The following code can change your second subplot axis like the first subplot. 以下代码可以像第一个子图一样更改第二个子图轴。 Try it if you want the quarter as x-axis. 如果要将四分之一作为x轴,请尝试一下。

data = pd.DataFrame({0: {Timestamp('2017-03-31'): 1, 
                         Timestamp('2017-06-30'): 2, 
                         Timestamp('2017-09-30'): 3, 
                         Timestamp('2017-12-31'): 3, 
                         Timestamp('2018-03-31'): 2, 
                         Timestamp('2018-06-30'): 1}})

xaxis = ['Q{}'.format((pd.to_datetime(date).month-1)//3+1) for date in data.index.values]
plt.xticks(data.index.values,xaxis)

plt.axvline(pd.Timestamp(datetime.date(2017, 7, 1)), c='r')
plt.axvline(pd.Timestamp(datetime.date(2017, 8, 10)), c='g')
plt.axvline(pd.Timestamp(datetime.date(2017, 9, 20)), c='b')
plt.axvline(pd.Timestamp(datetime.date(2017, 11, 30)), c='k')
data[0].plot(style="-mo")

output 产量 在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM