【问题标题】:Matplotlib and Pandas treatment of timeseries without weekendsMatplotlib 和 Pandas 处理没有周末的时间序列
【发布时间】:2020-08-20 14:57:10
【问题描述】:

我在将 Matplotlib 行添加到 Pandas 图中时遇到了一些问题。我正在尝试使用斜率绘制一条直线来确定起点和终点是什么。但是结果图看起来根本不像一条直线。

我已将案例简化为下面的 MVCE。初始部分用于设置复制我拥有的复杂数据框的关键功能。

import pandas as pd
import matplotlib.pyplot as plt

LEN_SER = 23
dates = pd.date_range('2015-07-03', periods=LEN_SER, freq='B')
df = pd.DataFrame(range(1,LEN_SER+1), index=dates)
ts = df.iloc[:,0]

# The above is the setup of the MVCE to replicate the issue.

fig = plt.figure()
ax1 = plt.subplot2grid((1, 1), (0, 0))
ax1.plot([ts.index[5], ts.index[20]],
        [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-')
ts.plot(ax=ax1)
plt.show()

这给出了一个由于周末而具有波浪线的图表。 Matplotlib 正在影响 Pandas 绘制系列的方式。如果我取出 ax1.plot() 线,那么它就变成了一条直线。

所以问题是:如何使用 Matplotlib 在我的 Pandas 图上绘制直线?换句话说,我希望绘图将轴标签视为类别,因此周末将被忽略。这样一来,我希望 Matplotlib 和 Pandas 都能给出一条直线。

【问题讨论】:

    标签: python pandas matplotlib


    【解决方案1】:

    正如您正确观察到的,如果您删除行 ax1.plot(),那么 matplotlib 会将您的日期视为类别,并且熊猫图是一条很好的直线。但是,在命令中

    ax1.plot([ts.index[5], ts.index[20]],
        [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-')
    

    您要求 matplotlib 在两点之间进行插值,在插值过程中 matplotlib 识别 x 轴上的日期。这就是为什么关于日期类别的直线熊猫图(每周 5 次)变成关于日期的波浪线(每周 7 次)。这也是正确的,因为就日期而言,您的数据根本不是用直线表示的。

    您可以强制类别解释通过字符串替换日期

    df.index = df.reset_index().apply(lambda x: x['index'].strftime('%Y-%m-%d'), axis=1)
    

    在定义 ts 之前。这导致了情节

    现在,matplotlib 图只是针对两个值的两个类别,matplotlib 并没有意识到这两个类别是 pandas 图中的类别。 (更改两个图的顺序至少可以保存您的 x 轴。)将 matplotlib 图修改为

    ax1.plot([5, 20], [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-')
    

    在类别 5 和 20 之间绘制一条线,最后给出关于类别 x 轴的两条直线。

    完整代码:

    import pandas as pd
    import matplotlib.pyplot as plt
    plt.style.use('seaborn') # (optional - style was set when I produced my graph)
    
    LEN_SER = 23
    dates = pd.date_range('2015-07-03', periods=LEN_SER, freq='B')
    df = pd.DataFrame(range(1,LEN_SER+1), index=dates)
    
    df.index = df.reset_index().apply(lambda x: \
        x['index'].strftime('%Y-%m-%d'), axis=1) # dates -> categories (string)
    ts = df.iloc[:,0]
    
    # The above is the setup of the MVCE to replicate the issue.
    
    fig = plt.figure()
    ax1 = plt.subplot2grid((1, 1), (0, 0))
    ax1.plot([5, 20], [ts[5], ts[5] + (1.0 * (20 - 5))], 'o-') 
    # x coordinates 'categories' 5 and 20
    ts.plot(ax=ax1)
    plt.show()
    

    【讨论】:

    • 您的解决方案似乎是我的想法。但我似乎无法重现它。我很欣赏这个解释,但你介意展示完整的代码来重现最终的图表吗?谢谢。
    • 我错过了“df.index =”,因为我认为 df.reset_index() 会就地发生。这就是为什么我无法重现您之前的内容。
    【解决方案2】:

    你已经回答了这个问题:“可能是因为周末”

    替换: 日期 = pd.date_range('2015-07-03', period=LEN_SER, freq='B')

    dates = pd.date_range('2015-07-03', periods=LEN_SER, freq='D')
    

    B - 工作日频率 D - 日历日频率

    你的线条被拉直了。

    【讨论】:

    • 我已经澄清了这个问题。它更复杂。 MVCE 是为了复制这个问题。更改问题的设置意味着它不再是我的问题的 MVCE。
    【解决方案3】:

    你是对的 - 这是由于周末。您可以从斜率看出 - 连续五天的倾斜度(每天+1)比连续三天(总共+1)更陡峭。那么,你究竟想要绘制什么?如果你想从字面上绘制蓝线,你可以像这样在两点之间插入点:

    ...
    # ts.plot(ax=ax1)
    ts.iloc[[5,20]].resample('1D').interpolate(how='mean').plot(ax=ax1)
    plt.show()
    

    【讨论】:

      【解决方案4】:

      为简单起见,我从 2015-07-04 开始。对你有用吗?

      import pandas as pd
      import numpy as np
      import matplotlib.pyplot as plt
      
      LEN_SER = 21
      dates = pd.date_range('2015-07-04', periods=LEN_SER, freq='B')
      the_axes = []
      # take the_axes like monday and friday for each week
      for monday, friday in zip(dates[dates.weekday==0], dates[dates.weekday==4]):
        the_axes.append([monday.date(), friday.date()])
      x = dates
      y = range(1,LEN_SER+1)
      n_Axes = len(the_axes)
      fig,(axes) = plt.subplots(1, n_Axes, sharey=True, figsize=(15,8))
      
      for i in range(n_Axes):
        ax = axes[i]
        ax.plot(x, y)
        ax.set_xlim(the_axes[i])
        fig.autofmt_xdate()
      print(dates)
      plt.show()
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-01-05
        • 2017-09-16
        • 2021-09-29
        • 1970-01-01
        • 2016-12-07
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多