【问题标题】:Plotting time data with different frequencies (matplotlib, pandas)绘制不同频率的时间数据(matplotlib、pandas)
【发布时间】:2018-10-16 18:47:00
【问题描述】:

我正在尝试将 Pandas 时间序列和多个垂直段(标记)组合在同一个图中。该系列的频率为“Q-DEC”(季度),在此示例中是从日期推断的,但实际问题是数据集的一部分。标记通常不与系列对齐,可能出现在任何地方,不一定在季度末。

我的问题是,如果我先绘制系列然后绘制标记,则标记的位置会四舍五入到该季度的下一个结尾(上图)。如果我先绘制标记,然后绘制系列,则标记位于正确的位置,但 x 刻度标签不合适(下图)。

:如何在时间序列图的正确位置绘制标记?

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()

【问题讨论】:

    标签: python python-3.x pandas matplotlib time-series


    【解决方案1】:

    如果您将日期作为PeriodIndex 移动到索引中,请以freq="M" 开头以确保正确绘制线条。
    然后将刻度替换为设置为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')
    

    现在重置刻度:

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

    输出:

    注意:如果您不删除带有 minorticks_off() 的次要刻度,您将获得与原始每月刻度和新季度刻度的一些重叠。

    更新
    如果您确实需要像示例中那样完全获得格式,则需要对主要和次要刻度位置和格式进行一些操作:

    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)
    

    【讨论】:

      【解决方案2】:

      以下代码可以像第一个子图一样更改您的第二个子图轴。如果您希望将四分之一作为 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")
      

      输出

      【讨论】:

      • 谢谢,但您的解决方案非常具体。如果我改变原始数据的频率,我将不得不重写绘图(或者实际上是标记)过程。
      猜你喜欢
      • 2018-03-13
      • 1970-01-01
      • 1970-01-01
      • 2019-05-14
      • 2014-10-11
      • 2016-02-22
      • 2020-07-18
      • 1970-01-01
      • 2014-03-24
      相关资源
      最近更新 更多