简体   繁体   English

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

[英]Matplotlib: How can I add an alternating background color when I have dates on the x-axis?

I've recently started using the dark chesterish theme from dunovank , and I love how good a simple pandas.DataFrame.plot( ) looks like out of the box: 我最近开始使用dark chesterish主题从dunovank ,我喜欢简单的多么好pandas.DataFrame.plot( )看起来开箱:

Snippet 1 : 片段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()

Output 1: 输出1:

在此处输入图片说明

But I'd like to add an alternating background color (seems to be all the rage with big news agencies). 但是我想添加一种交替的背景色(似乎是大型新闻社大肆宣传的色彩)。 The post How can I set the background color on specific areas of a pyplot figure? 帖子如何在pyplot图形的特定区域设置背景颜色? gives a good description of how you can do it. 很好地描述了如何做到这一点。 And it's really easy for numeric x-values : 对于数字x值 ,这真的很容易:

Snippet 2 : 片段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)

Output 2: 输出2:

在此处输入图片说明

But it gets a lot messier (for me at least) when the x-axis is of a time or date format. 但是当x轴为时间或日期格式时,它将变得更加混乱(至少对我而言)。 And that's because the axis in my two examples goes from this 那是因为我的两个示例中的轴都来自于此

# 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)

To this (abbreviated): 为此(缩写):

# 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() returns the data on the x-axis. ts.plot().lines[0].get_data()返回x轴上的数据。 But is there a way to find out where matplotlib renders the vertical lines for each 'Jan' observation , so I can more easily find decent intervals for the alternating black and grey background color? 但是,是否有一种方法可以找出matplotlib 哪里为每个“ Jan”观察结果绘制垂直线 ,以便我可以更轻松地找到交替的黑色和灰色背景色的合适间隔?

在此处输入图片说明

Thank you for any suggestions! 感谢您的任何建议!


Edit - Or is there a theme? 编辑-还是有主题?

Or does anyone know if there exists a theme somewhere that is free to use? 还是有人知道某个地方是否存在免费使用的主题? I've checked all matplotlib themes import matplotlib.pyplot as plt; print(plt.style.available) 我已经检查了所有matplotlib主题, import matplotlib.pyplot as plt; print(plt.style.available) import matplotlib.pyplot as plt; print(plt.style.available) and Seaborn , but with no success. import matplotlib.pyplot as plt; print(plt.style.available)Seaborn ,但是没有成功。


Edit 2 - Suggested solution from ImportanceOfBeingErnest with the chesterish theme activated: 编辑2-从ImportanceOfBeingErnest建议的解决方案,激活了切斯特风格的主题:

在此处输入图片说明

In my humble opinion, this is a perfect setup for a time series chart (could maybe drop the splines though) 以我的拙见,这是时间序列图的理想设置(尽管可能会降低样条曲线)

Use an axis vertical span with datetime values for the x-values: 将带有日期时间值的轴垂直跨度用于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)

带有阴影垂直区域的时间序列图

Gridlines are by default shown at the positions of the major ticks. 默认情况下,网格线显示在主要刻度线的位置。 You can get those ticks via ax.get_xticks() . 您可以通过ax.get_xticks()获得这些ax.get_xticks() The problem will be that it is not guaranteed that the edges of the plot coincide with those ticks, in fact they are most often dissimilar. 问题将是,不能保证曲线图的边缘与那些刻度线一致,实际上,它们通常是不同的。 So in order to have a consistent shading over the range of the axes, the first shade should start at the edge of the plot and end at the first gridline, then the following shades can go in between gridlines, up to the last, which will again be between the last gridline and the edge of the axes. 因此,为了在轴的范围上具有一致的阴影,第一个阴影应从绘图的边缘开始,并在第一个网格线处结束,然后,以下阴影可以在网格线之间进入,直到最后一个网格为止。再次位于最后一个网格线和轴的边缘之间。

Another problem is that the limits of the plot and hence the automatically generated gridlines may change over the lifetime of the plot, eg because you decide to have different limits or zoom or pan the plot. 另一个问题是,图的限制以及因此自动生成的网格线可能会在图的生存期内发生变化,例如,因为您决定使用不同的限制或缩放或平移图。 So ideally one would recreate the shading each time the axis limits change. 因此,理想情况下,每次轴限制发生变化时,都会重新创建阴影。 This is what the following does: 这是以下内容:

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()

在此处输入图片说明

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 x 轴上添加一系列带日期的箱线图? - How do I add a series of boxplots on x-axis with dates? Matplotlib:如何重新排列图表的 x 轴? - Matplotlib: How can I reorder the graphs' x-axis? matplotlib当x轴相隔1周时,如何减少堆积条形图中条形之间的空间量? - matplotlib how do I reduce the amount of space between bars in a stacked bar chart when x-axis are dates 1-week apart? 如何在 matplotlib 中格式化 x 轴上的日期? - how to format dates on x-axis in matplotlib? 如何使用分类 x 轴绘制 matplotlib 散点图,允许我根据第三个变量指定标记和颜色? - How can I do a matplotlib scatter plot with a categorical x-axis, that allows me to specify the marker and color based on a third variable? 如何在 matplotlib 的 x 轴上显示日期? - How can I display dates on the x axis in matplotlib? 如何使plot的x轴原点和y轴原点在matplotlib中重叠? - How can I make the origin of the x-axis and the origin of the y-axis of a plot overlap in matplotlib? 我可以将 label 的 x 轴设为 \rho,即 matplotlib 中的希腊字母吗? - Can I label the x-axis as \rho, the Greek letter in matplotlib? Matplotlib:如何在x轴的另一侧出现xtick标签? - Matplotlib: How do I have the xtick labels apear on the other side of the x-axis? 如何在 matplotlib 中添加第二个 x 轴 - How to add a second x-axis in matplotlib
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM