[英]How to change pyplot background colour in region of interest?
I have a dataframe with a datetime index:我有一个带有日期时间索引的 dataframe:
A B
date
2020-05-04 0 0
2020-05-05 5 0
2020-05-07 2 0
2020-05-09 2 0
2020-05-18 -5 0
2020-05-19 -1 0
2020-05-20 0 0
2020-05-21 1 0
2020-05-22 0 0
2020-05-23 3 0
2020-05-24 1 1
2020-05-25 0 1
2020-05-26 4 1
2020-05-27 3 1
I want to make a lineplot to track A over time and colour the background of the plot red when the values of B are 1. I have implemented this code to make the graph:我想制作一个线图来跟踪 A 随着时间的推移,并在 B 的值为 1 时将 plot 的背景着色为红色。我已经实现了这段代码来制作图表:
from matplotlib import dates as mdates
from matplotlib.colors import ListedColormap
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
cmap = ListedColormap(['white','red'])
ax.plot(data['A'])
ax.set_xlabel('')
plt.xticks(rotation = 30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
ax.pcolorfast(ax.get_xlim(), ax.get_ylim(),
data['B'].values[np.newaxis],
cmap = cmap, alpha = 0.4)
plt.axhline(y = 0, color = 'black')
plt.tight_layout()
This gives me this graph:这给了我这个图表:
But the red region incorrectly starts from 2020-05-21 rather than 2020-05-24 and it doesn't end at the end date in the dataframe.但是红色区域错误地从 2020-05-21 而不是 2020-05-24 开始,并且它没有在 dataframe 中的结束日期结束。 How can I alter my code to fix this?
我怎样才能改变我的代码来解决这个问题?
If you change ax.pcolorfast(ax.get_xlim(), ...
by ax.pcolor(data.index, ...
you get what you want. The problem with the current code is that by using ax.get_xlim()
, it creates a uniform rectangular grid while your index is not uniform (dates are missing), so the coloredmeshed is not like expected. The whole thing is:如果你改变
ax.pcolorfast(ax.get_xlim(), ...
通过ax.pcolor(data.index, ...
你得到你想要的。当前代码的问题是使用ax.get_xlim()
,它创建了一个统一的矩形网格,而您的索引不统一(缺少日期),所以彩色网格不像预期的那样。整个事情是:
from matplotlib import dates as mdates
from matplotlib.colors import ListedColormap
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
cmap = ListedColormap(['white','red'])
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(data['A'])
ax.set_xlabel('')
plt.xticks(rotation = 30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
#here are the two changes use pcolor
ax.pcolor(data.index, #use data.index to create the proper grid
ax.get_ylim(),
data['B'].values[np.newaxis],
cmap = cmap, alpha = 0.4,
linewidth=0, antialiased=True)
plt.axhline(y = 0, color = 'black')
plt.tight_layout()
I prefer axvspan
in this case, see here for more information.在这种情况下,我更喜欢
axvspan
,请参阅此处了解更多信息。
This adaptation will color the areas where data.B==1
, including the potential where data.B
might not be a continuous block .这种适应将为
data.B==1
的区域着色,包括data.B
可能不是连续块的潜在区域。
With a modified dataframe data
from data1.csv
(added some more points that are 1):使用来自
data1.csv
的修改后的 dataframe data
(添加了更多为 1 的点):
date A B
5/4/2020 0 0
5/5/2020 5 0
5/7/2020 2 1
5/9/2020 2 1
5/18/2020 -5 0
5/19/2020 -1 0
5/20/2020 0 0
5/21/2020 1 0
5/22/2020 0 0
5/23/2020 3 0
5/24/2020 1 1
5/25/2020 0 1
5/26/2020 4 1
5/27/2020 3 1
from matplotlib import dates as mdates
import pandas as pd
import matplotlib.pyplot as plt
data = pd.read_csv('data1.csv',index_col='date')
data.index = pd.to_datetime(data.index)
fig = plt.figure()
ax = fig.add_subplot()
ax.plot(data['A'])
plt.xticks(rotation = 30)
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d'))
plt.axhline(y = 0, color = 'black')
# in this case I'm looking for a pair of ones to determine where to color
for i in range(1,len(data.B)):
if data.B[i]==True and data.B[i-1]==True:
plt.axvspan(data.index[i-1], data.index[i], color='r', alpha=0.4, lw=0)
plt.tight_layout()
If data.B==1
will always be "one block" you can do away with the for
loop and just use something like this in its place:如果
data.B==1
将始终是“一个块”,您可以取消for
循环,而只需使用类似的东西代替它:
first = min(idx for idx, val in enumerate(data.B) if val == 1)
last = max(idx for idx, val in enumerate(data.B) if val == 1)
plt.axvspan(data.index[first], data.index[last], color='r', alpha=0.4, lw=0)
Regarding "why" your data does not align, @Ben.T has this solution .关于“为什么”您的数据不对齐, @Ben.T 有这个解决方案。
UPDATE : as pointed out, the for
loop could be too crude for large datasets.更新:正如所指出的,
for
循环对于大型数据集来说可能过于粗糙。 The following uses numpy to find the falling and rising edges of data.B
and then loops on those results:下面使用 numpy 找到
data.B
的下降沿和上升沿,然后循环这些结果:
import numpy as np
diffB = np.append([0], np.diff(data.B))
up = np.where(diffB == 1)[0]
dn = np.where(diffB == -1)[0]
if diffB[np.argmax(diffB!=0)]==-1:
# we have a falling edge before rising edge, must have started 'up'
up = np.append([0], up)
if diffB[len(diffB) - np.argmax(diffB[::-1]) - 1]==1:
# we have a rising edge that never fell, force it 'dn'
dn = np.append(dn, [len(data.B)-1])
for i in range(len(up)):
plt.axvspan(data.index[up[i]], data.index[dn[i]], color='r', alpha=0.4, lw=0)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.