fill_between不会为相邻间隔着色

时间:2018-07-28 10:12:11

标签: python pandas matplotlib

我正在尝试在两个相邻的时间间隔之间进行填充:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame({'Value': np.random.randint(10,size=10),
                   'Color': ['r','r','r','r','r','r','g','g','g','g']})

fig,ax = plt.subplots(1,1,figsize=(8,3))
ax.plot(df.Value)
ax.fill_between(df.index[df.Color == 'r'],
                df.Value[df.Color == 'r'], color='r')
ax.fill_between(df.index[df.Color == 'g'],
                df.Value[df.Color == 'g'], color='g')

哪个给我:

fill_between example

但是,我也想给索引5和6(红色)之间的间隔加上颜色。

我该怎么做?

1 个答案:

答案 0 :(得分:2)

您不仅要填充Colorr的位置,还要填充颜色从红色变为绿色的位置。您可以将其公式化为条件,并在where中使用fill_between参数。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

df = pd.DataFrame({'Value': np.random.randint(10,size=10),
                   'Color': ['r','r','r','r','r','r','g','g','g','g']})

fig,ax = plt.subplots(1,1,figsize=(8,3))
ax.plot(df.Value)

cond = df.Color == 'r'
cond2 = cond ^ np.concatenate(([0],np.diff(cond.astype(int)) == -1))

ax.fill_between(df.index, df.Value, where=cond2, color='r')
ax.fill_between(df.index, df.Value, where=~cond, color='g')

plt.show()

enter image description here

虽然在这种情况下可以正常工作,但是当涉及单个间隔时,它将失败。在这种情况下,您将无法使用fill_between

在点之后的间隔中使曲线下方的区域着色的最一般的解决方案如下。这会根据条件创建一个顶点多边形,并以相应的颜色绘制这些多边形的集合。

在此示例中,显示了一些测试用例:

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import PolyCollection

t1 = ['r','r','r','r','r','r','g','g','g','g']
t2 = ['r','g','r','r','g','r','g','g','r','g']
t3 = ['g','g','r','r','g','r','g','g','r','r']
t4 = ['g','r','g','g','r','g','g','g','g','r']

df = pd.DataFrame({'Value': np.random.randint(10,size=10),
                   'Color1': t1, "Color2": t2, 'Color3': t3, "Color4": t4})

def fill_intervals_post(x,y, color, cond, ax=None):
    ax = ax or plt.gca()
    cond1 = color == cond
    start = np.diff(cond1.astype(int)) == 1
    end = np.diff(cond1.astype(int)) == -1
    inxstart = np.arange(len(color)-1)[start]+1
    inxend = np.arange(len(color)-1)[end]+2
    inx  = np.concatenate(([0,0],np.sort(np.concatenate((inxstart,inxend)))))
    xs = np.split(x, inx)[(~cond1).astype(int)[0]::2]
    ys = np.split(y, inx)[(~cond1).astype(int)[0]::2]
    verts = []
    for xi,yi in zip(xs,ys):
        xsi = np.concatenate((xi, xi[::-1]))
        ysi = np.concatenate((yi, np.zeros_like(yi)))
        verts.append(np.c_[xsi,ysi])
    p = PolyCollection(verts, color=cond)
    ax.add_collection(p)


fig,axes = plt.subplots(4,1,figsize=(8,9))

for i,ax in enumerate(axes):
    ax.plot(df.index.values, df.Value.values, color="k")    

    ax.set_title(df["Color{}".format(i+1)].values)
    fill_intervals_post(df.index.values,df.Value.values, 
                        df["Color{}".format(i+1)].values, "r", ax=ax)
    fill_intervals_post(df.index.values,df.Value.values, 
                        df["Color{}".format(i+1)].values, "g", ax=ax)

fig.tight_layout()
plt.show()

enter image description here