【问题标题】:Shade/Fill between Arbitrary Matplotlib Region Based On Axes, Not Data基于轴而不是数据的任意 Matplotlib 区域之间的阴影/填充
【发布时间】:2020-04-03 15:22:15
【问题描述】:

是否可以在图表的任意区域之间填充,而不是基于绘制的数据,而是基于 x 轴范围?

在下面的时间序列图中,我使用这个 fill_between 调用对晚上 8 点到早上 8 点之间的区域进行着色:

ax3.fill_between(d[0], 0, ax3.get_ylim()[1], where=fill, facecolor=face_color )

其中fill 是根据这些时间记录的数据确定的:

fill = [False if dt.time(8,0,0) < t.time() < dt.time(20,0,0) else True for t in d[0]]

这适用于前两个阴影区域。

问题在于,有时记录的数据不会在这些时间出现,因此阴影区域太小,不能代表适当的时间(请参阅图表中的第三个阴影区域)

我意识到我可以通过创建另一个具有适当 x 值范围的数据集然后将其设置为不可见来做到这一点,但我想知道是否有其他方法。

【问题讨论】:

    标签: python python-3.x matplotlib


    【解决方案1】:

    您可以构造一个datetime 对象数组,该数组与您的x 数据跨越相同的范围,并使用它来填充fill 数组,

    import numpy as np
    # ...
    fill = [False if dt.time(8, 0, 0) < t.time() < dt.time(20, 0, 0) else True for t in 
            np.arange(x[0], x[-1]+60, 60, dtype='datetime64').astype(dt.datetime)]
    

    完整示例:

    import matplotlib.pyplot as plt
    import datetime as dt
    import numpy as np
    
    plt.figure(figsize=(12,3))
    x = np.arange('2020-04-03T00:00Z', '2020-04-05T00:30Z', np.random.randint(50, 70), 
                  dtype='datetime64[m]')
    x = np.delete(x, np.s_[4:10])
    x = np.delete(x, np.s_[25:32])
    y = np.sin(np.linspace(0, np.pi*2, len(x))*2 + np.random.random(len(x)) - 0.5)
    plt.plot(x, y)
    
    dx = np.arange(x[0], x[-1]+60, 60, dtype='datetime64[m]').astype(dt.datetime)
    fill = [False if dt.time(8, 0, 0) < t.time() < dt.time(20, 0, 0) else True for t in dx]
    plt.fill_between(dx, plt.ylim()[0], plt.ylim()[1], where=fill, fc='grey', alpha=0.2)
    
    plt.tick_params(axis='x', rotation=90)
    plt.subplots_adjust(bottom=0.3)
    plt.show()
    
    

    【讨论】:

    • 好主意,但不幸的是,它不起作用:填充数组必须与要绘制的数据具有相同的维度。创建相同长度和范围的日期时间数组会导致数据 x 轴和填充 x 轴之间未对齐。我会使用更精细的填充数组创建机制,但收益递减定律会说它不值得付出努力。
    • @DaveB 我已经编辑了答案中的代码,以纠正您提出的问题。只要派生dx 的数组按最早到最新排序,代码现在应该可以正常工作。
    • 不幸的是,问题仍然存在,但在您的示例中不存在,因为 x 和 dx 完全相等。由于我的数据是时间序列的,因此它是非周期性间隔的。您可以通过执行类似x = np.arange('2020-04-03T00:00Z', '2020-04-05T00:30Z', np.random.randint(50, 70), dtype='datetime64[m]') 的操作来重现
    • @DaveB 很好,我已经更新了我的示例以使用非周期数据,并且在其中也放置了一些空白。如您所见,没有数据的区域已正确着色。希望对你有帮助
    • 谢谢威廉,但问题仍然存在。请比较 x、dx 和 Fill,您会发现在某些情况下,当 Fill 为真时,x 不在适当的小时之间。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-15
    • 2015-12-29
    • 2017-06-15
    • 2018-10-14
    相关资源
    最近更新 更多