[英]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( )看起来开箱:
# 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.