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

2024-09-30 01:23:10 发布

您现在位置:Python中文网/ 问答频道 /正文

我最近开始使用来自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

^{pr2}$

输出2:

{a6}

但当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

谢谢你的建议!在


编辑-还是有主题?

或者有人知道某个地方是否有一个可以免费使用的主题? 我检查了所有matplotlib主题import matplotlib.pyplot as plt; print(plt.style.available)和{a8},但没有成功。在


编辑2-来自ImportanceOfBeingErnest并激活chesterish主题的建议解决方案:

enter image description here

在我的拙见中,这是一个完美的时间序列图表设置(可能会放弃样条线)


Tags: fromimportpandas主题datagetplotmatplotlib
2条回答

默认情况下,网格线显示在主刻度的位置。您可以通过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

对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

相关问题 更多 >

    热门问题