使用fill_between python

时间:2016-04-21 16:06:52

标签: python matplotlib histogram fill percentile

目前,我试图用python中的fill_between函数填充直方图,直到原始数字中的10和90百分位数。 然而,问题是直方图曲线不是一个“函数”,而是一系列离散数与bin大小的间隔。我无法填充到10或90百分位。我尝试了几次尝试,但我失败了。 下面的代码是我试过的:

S1 = [0.34804491  0.18036933  0.41111951  0.31947523 .........

0.46212255  0.39229157  0.28937502  0.22095423  0.52415083]
N, bins = np.histogram(S1, bins=np.linspace(0.1,0.7,20), normed=False)
bincenters   = 0.5*(bins[1:]+bins[:-1])    
ax.fill_between(bincenters,N,0,where=bincenters<=np.percentile(S1,10),interpolate=True,facecolor='r', alpha=0.5)
ax.fill_between(bincenters,N,0,where=bincenters>=np.percentile(S1,90),interpolate=True, facecolor='r', alpha=0.5,label = "Summer 10 P")

它似乎只在给定百分位数之前或之后填充直到bincenter,直到达到那些。

任何想法或帮助都会非常感激。 艾萨克

2 个答案:

答案 0 :(得分:2)

尝试将最后两行更改为:

ax.fill_between(bincenters, 0, N, interpolate=True,
                where=((bincenters>=np.percentile(bincenters, 10)) &
                       (bincenters<=np.percentile(bincenters, 90))))

我相信你想在np.percentile上致电bincenters,因为这是你有效的x轴。

另一个区别是,您希望填充10<x<90区域之间的填充,这需要在&参数中使用where

根据OP的评论进行编辑:

我认为要实现你想要的,你必须做一些你自己的最小插值。请使用随机正态分布查看下面的示例,其中我使用interp1d scipy.interpolatebincenters进行插值。

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d

# create normally distributed random data
n = 10000
data = np.random.normal(0, 1, n)
bins = np.linspace(-data.max(), data.max(), 20)
hist = np.histogram(data, bins=bins)[0]
bincenters = 0.5 * (bins[1:] + bins[:-1])

# create interpolation function and dense x-axis to interpolate over
f = interp1d(bincenters, hist, kind='cubic')
x = np.linspace(bincenters.min(), bincenters.max(), n)

plt.plot(bincenters, hist, '-o')
# calculate greatest bincenter < 10th percentile
bincenter_under10thPerc = bincenters[bincenters < np.percentile(bincenters, 10)].max()
bincenter_10thPerc = np.percentile(bincenters, 10)

bincenter_90thPerc = np.percentile(bincenters, 90)
# calculate smallest bincenter > 90th percentile
bincenter_above90thPerc = bincenters[bincenters > np.percentile(bincenters, 90)].min()

# fill between 10th percentile region using dense x-axis array, x
plt.fill_between(x, 0, f(x), interpolate=True,
                 where=((x>=bincenter_under10thPerc) &
                        (x<=bincenter_10thPerc)))

# fill between 90th percentile region using dense x-axis array, x
plt.fill_between(x, 0, f(x), interpolate=True,
                 where=((x>=bincenter_90thPerc) &
                        (x<=bincenter_above90thPerc)))

我得出的数字如下。请注意,我将百分位数从10/90%更改为30/70%,以便它们在情节中显示得更好。再次,我希望这就是你要做的事情

plt.fill_between within percentiles

答案 1 :(得分:0)

我有一个版本,使用axvspan制作一个Rectangle,然后将hist用作clip_path:

def hist(sample, low=None, high=None):
    # draw the histogram
    options = dict(alpha=0.5, color='C0')
    xs, ys, patches = plt.hist(sample,
                               density=True,
                               histtype='step', 
                               linewidth=3,
                               **options)

    # fill in the histogram, if desired
    if low is not None:
        x1 = low
        if high is not None:
            x2 = high
        else:
            x2 = np.max(sample)

        fill = plt.axvspan(x1, x2, 
                           clip_path=patches[0],
                           **options)

这样的事情对你有用吗?