代码之家  ›  专栏  ›  技术社区  ›  vestland

Matplotlib:当X轴上有日期时,如何添加交替的背景色?

  •  0
  • vestland  · 技术社区  · 6 年前

    我最近开始使用 dark chesterish 主题从 dunovank 和我 爱多好一个简单的 pandas.DataFrame.plot( )看起来像开箱即用:

    Snippet 1 :

    # Theme from dunovank, exclude if not installed:
    from jupyterthemes import jtplot
    jtplot.style()
    
    # snippet from pandas docs:
    ts = pd.Series(np.random.randn(1000),index=pd.date_range('1/1/2000', periods=1000)).cumsum()
    ax = ts.plot()
    

    输出1:

    enter image description here

    但我想增加一个交替的背景色(似乎是所有与大新闻机构的愤怒)。岗位 How can I set the background color on specific areas of a pyplot figure? 很好地描述了如何做到这一点。而且很容易 数字x值 :

    片段2 :

    # imports
    import pandas as pd
    import numpy as np
    from jupyterthemes import jtplot
    
    # Sample data
    np.random.seed(123)
    rows = 50
    dfx = pd.DataFrame(np.random.randint(90,110,size=(rows, 1)), columns=['Variable Y'])
    dfy = pd.DataFrame(np.random.randint(25,68,size=(rows, 1)), columns=['Variable X'])
    df = pd.concat([dfx,dfy], axis = 1)
    jtplot.style()
    
    ax = df.plot()
    for i in range(0, 60, 20):       
                ax.axvspan(i, i+10, facecolor='lightgrey', alpha=0.025)
    

    输出2:

    enter image description here

    但当X轴是时间或日期格式时(至少对我来说)会变得更混乱。这是因为我的两个例子中的轴是从这个

    # in:
    ax.lines[0].get_data()
    
    # out:
    array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
            34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
           dtype=int64)
    

    对此(缩写):

    # in:
    ts.plot().lines[0].get_data()
    
    # out:
    .
    .
    Period('2002-09-15', 'D'), Period('2002-09-16', 'D'),
    Period('2002-09-17', 'D'), Period('2002-09-18', 'D'),
    Period('2002-09-19', 'D'), Period('2002-09-20', 'D'),
    Period('2002-09-21', 'D'), Period('2002-09-22', 'D'),
    Period('2002-09-23', 'D'), Period('2002-09-24', 'D'),
    Period('2002-09-25', 'D'), Period('2002-09-26', 'D')], dtype=object)  
    

    ts.plot().lines[0].get_data() 返回X轴上的数据。但是有没有办法知道Matplotlib在哪 呈现每个“jan”观测的垂直线 所以我可以更容易地找到黑色和灰色背景色交替的合适间隔?

    enter image description here

    谢谢你的建议!


    编辑-还是有主题?

    或者有人知道有没有一个主题可以自由使用? 我查过所有的主题 import matplotlib.pyplot as plt; print(plt.style.available) Seaborn 但是没有成功。


    编辑2-来自重要的Beingernest的建议解决方案,并激活切斯特里斯主题:

    enter image description here

    在我看来,这是一个完美的时间序列图设置(可能会删除样条曲线)

    2 回复  |  直到 6 年前
        1
  •  1
  •   ImportanceOfBeingErnest    6 年前

    默认情况下,网格线显示在主要刻度的位置。你可以通过 ax.get_xticks() . 问题是,不能保证绘图的边缘与这些记号重合,事实上,它们通常是不同的。因此,为了在轴的范围内具有一致的阴影,第一个阴影应该从绘图的边缘开始,并在第一个网格线结束,然后以下阴影可以在网格线之间进入,直到最后一个,这将再次在最后一个网格线和轴的边缘之间。

    另一个问题是,绘图的限制,因此自动生成的网格线可能会在绘图的整个生命周期内发生变化,例如,因为您决定使用不同的限制或缩放或平移绘图。因此,理想情况下,每次轴限制更改时都会重新创建着色。这是以下功能:

    import pandas as pd
    import matplotlib.pyplot as plt
    import numpy as np
    
    # time series
    ts = pd.Series(np.random.randn(1000),index=pd.date_range('1/1/2000', periods=1000)).cumsum()
    # numeric series
    #ts = pd.Series(np.random.randn(1000),index=np.linspace(25,800,1000)).cumsum()
    ax = ts.plot(x_compat=True)
    
    ax.grid()
    
    class GridShader():
        def __init__(self, ax, first=True, **kwargs):
            self.spans = []
            self.sf = first
            self.ax = ax
            self.kw = kwargs
            self.ax.autoscale(False, axis="x")
            self.cid = self.ax.callbacks.connect('xlim_changed', self.shade)
            self.shade()
        def clear(self):
            for span in self.spans:
                try:
                    span.remove()
                except:
                    pass
        def shade(self, evt=None):
            self.clear()
            xticks = self.ax.get_xticks()
            xlim = self.ax.get_xlim()
            xticks = xticks[(xticks > xlim[0]) & (xticks < xlim[-1])]
            locs = np.concatenate(([[xlim[0]], xticks, [xlim[-1]]]))
    
            start = locs[1-int(self.sf)::2]  
            end = locs[2-int(self.sf)::2]
    
            for s, e in zip(start, end):
                self.spans.append(self.ax.axvspan(s, e, zorder=0, **self.kw))
    
    gs = GridShader(ax, facecolor="lightgrey", first=False, alpha=0.7)
    
    plt.show()
    

    enter image description here

        2
  •  1
  •   9769953    6 年前

    使用带有日期时间值的垂直轴跨度作为x值:

    from jupyterthemes import jtplot
    import pandas as pd
    import numpy as np
    from datetime import datetime
    
    jtplot.style()
    ts = pd.Series(np.random.randn(1000),index=pd.date_range('1/1/2000', periods=1000)).cumsum()
    ax = ts.plot()
    
    # or an appropriate for-loop
    ax.axvspan(datetime(1999, 12, 15), datetime(2000, 1, 15), facecolor='red', alpha=0.25)
    ax.axvspan(datetime(2000, 12, 15), datetime(2001, 1, 15), facecolor='red', alpha=0.25)
    

    timeseries graph with shaded vertical areas