【问题标题】:Bar plot with timedelta as bar width以 timedelta 作为条形宽度的条形图
【发布时间】:2014-12-17 09:10:06
【问题描述】:

我有一个 pandas 数据框,其中一列包含时间戳 (start),另一列包含 timedeltas (duration) 以指示持续时间。

我正在尝试绘制一个条形图,显示这些持续时间,其左边缘位于时间戳。我还没有在网上找到这样做的。有没有办法实现这一目标?

到目前为止,这是我所拥有的,但不起作用:

    height = np.ones(df.shape[0])
    width = [x for x in df['duration']]
    plt.bar(left=df['start'], height=height, width=width)

编辑: 我已将宽度更新如下,但这也不能解决这个问题:

width = [x.total_seconds()/(60*1200) for x in df['duration']]

我很想知道datetime.timedelta 对象是否可以在width 中使用,因为datetime 对象可以用作x 轴。如果没有,还有什么替代方案?

编辑#2:

这可能不是我问题的确切答案,但它解决了我的目的。对于有兴趣的人,这是我最终采用的方法(为此我使用startduration 制作end):

    for i in range(df.shape[0]):
        plt.axvspan(df.ix[i, 'start'], df.ix[i, 'end'], facecolor='g', alpha=0.3)
        plt.axvline(x=df.ix[i, 'start'], ymin=0.0, ymax=1.0, color='r', linewidth=1)
        plt.axvline(x=df.ix[i, 'end'], ymin=0.0, ymax=1.0, color='r', linewidth=1)

【问题讨论】:

    标签: python matplotlib pandas bar-chart dataframe


    【解决方案1】:

    如果您的 df.duration[0] 类型是 pandas.tslib.Timedelta 并且您的 timestamps 相隔几天,您可以使用:

    width = [x.days for x in df.duration]
    

    这将产生图表。

    否则请使用this answer 中所述的total_seconds 方法

    更新:

    如果数据是每小时一次,时间增量以分钟为单位,那么获得所需图表的一种方法是:

    import datetime as dt
    import numpy as np
    import pandas as pd
    import matplotlib.pyplot as plt
    
    dates = pd.date_range(start=dt.date(2014,10,22), periods=10, freq='H')
    df = pd.DataFrame({'start': dates, 'duration': np.random.randint(1, 10, len(dates))}, 
                      columns=['start', 'duration'])
    df['duration'] = df.duration.map(lambda x: pd.datetools.timedelta(0, 0, 0, 0, x))
    df.ix[1, 1] = pd.datetools.timedelta(0, 0, 0, 0, 30) # To clearly see the effect at 01:00:00
    width=[x.minutes/24.0/60.0 for x in df.duration] # mpl will treat x.minutes as days hense /24/60.
    plt.bar(left=df.start, width=width, height=[1]*df.start.shape[0])
    ax = plt.gca()
    _ = plt.setp(ax.get_xticklabels(), rotation=45)
    

    这会产生一个像这样的图表:

    【讨论】:

    • 谢谢。实际上,它们仅相隔数小时或数分钟,我已经看到了 total_seconds 的另一个答案,但它不起作用。原因是您必须将其缩放到小时和分钟,但由于这些时间的长度不同,因此这种缩放将不准确,并且每次都必须手动调整。所以现在,宽度是width = [x.total_seconds()/(60*1200) for x in df['duration']] Since Pyplot`为x轴处理datetime对象,我期待datetime.timedelta被识别和处理宽度,我很惊讶它不是。
    • @oxtay 是的,如果matplotlib 能够在barbroken_barh 图中本机理解TimeDeltas 或Offsets 会更好,但在此之前我只看到一些繁琐的方法来实现什么你要。我已经更新了我上面的帖子以显示小时/分钟的示例
    • @Primer 请注意,这不是开箱即用的,因为您缺少dates 声明的日期时间导入。也可能存在某种熊猫版本的技巧,因为我最终得到了numpy.timedelta64s,它没有与datetime.timedeltas 相同的方法......
    • @Ajean 谢谢,我添加了缺少的导入语句。而且,是的,我还注意到了熊猫关于pandas.tslib.Timedelta 的“技巧”(最初是在创建数据框时)。这就是为什么width 是通过列表理解生成的。 df.duration.apply(lambda x: x.minutes) 的“本机”方法不会“看到”pandas.tslib.Timedelta,因此会出现错误:'numpy.timedelta64' object has no attribute 'minutes'
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-05
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 2016-02-06
    相关资源
    最近更新 更多