2017-10-08 4 views
0

私はプロットの特定の領域で(x、y)領域を陰影にしようとしています。単純化した例として、confidence intervalsの正規分布を考えてみましょう。 1標準偏差(または1シグマ)内の領域が最も暗い、2標準偏差(または2シグマ)以内の領域が少し軽いなどの信頼区間を陰にしたいと思います。これを行う方法があります。私はスクリプトをより柔軟にしようとしています。コードは以下のとおりです。このplt.fill_between()アプローチをループで変更できますか?

## imports 
import numpy as np 
import matplotlib.pyplot as plt 
from math import pi 

## y = f(x) 
def get_f(x, mu, sigma): 
    """ Normal Distribution Probability Density Function """ 
    norm_constant = (sigma* (2*pi)**(1/2)) 
    return [norm_constant * np.exp((-1) * (x[idx] - mu)**2/(2* sigma**2)) for idx in range(len(x))] 

x = np.linspace(0, 100, 5000) 

xと関数f(x)があるので、プロットすることができます。私は、動作するコードの部分に残して、私の解決策を解説しました。私は希望の間隔の数に基づいて陰影を付けるほうが便利でコードが繰り返しではないので、うまくいけば自分の解決方法が好きです。

## generate plot 
def get_plot(x, num_intervals=None, line_color='g', shade_color='b', mu=48, sigma=7): 
    """ Returns (x,y) plot; confidence intervals shading is optional """ 
    y = get_f(x, mu, sigma) 
    plt.plot(x, y, line_color) 
    if num_intervals is not None: 

     ## THIS CODE SEGMENT BELOW WORKS BUT I WOULD LIKE TO MAKE IT BETTER 

     plt.fill_between(x, y, where=(mu - sigma <= x), alpha=0.18, color=shade_color) 
     plt.fill_between(x, y, where=(x <= mu + sigma), alpha=0.18, color=shade_color) 
     plt.fill_between(x, y, where=(mu - 2*sigma <= x), alpha=0.11, color=shade_color) 
     plt.fill_between(x, y, where=(x <= mu + 2*sigma), alpha=0.11, color=shade_color) 
     plt.fill_between(x, y, where=(mu - 3*sigma <= x), alpha=0.02, color=shade_color) 
     plt.fill_between(x, y, where=(x <= mu + 3*sigma), alpha=0.02, color=shade_color) 

     ## THIS CODE SEGMENT BELOW DOES NOT WORK AS I WOULD LIKE 
     ## IT WILL SHADE THE REGIONS IN THE WRONG SHADE/DARKNESS 

     ## choose shading level via dictionary 
     # alpha_keys = [idx+1 for idx in range(num_intervals)] 
     # alpha_vals = [0.18, 0.11, 0.02] 
     # alpha_dict = dict(zip(alpha_keys, alpha_vals)) 
     # for idx in range(num_intervals): 
      # print("\nidx & stdev = %d & %d, \nmu - (stdev * sigma) = %.2f, \nmu + (stdev * sigma) = %.2f, alpha = %.2f" %(idx, stdev, mu - stdev*sigma, mu + stdev*sigma, alpha_dict[stdev]), "\n") 
      # stdev = idx + 1 ## number of standard deviations away from mu 
      # plt.fill_between(x, y, where=(mu - stdev * sigma <= x), alpha=alpha_dict[stdev], color=shade_color) 
      # plt.fill_between(x, y, where=(x >= mu + stdev * sigma), alpha=alpha_dict[stdev], color=shade_color) 


    plt.show() 

正しいコードを実行すると、this plotが生成されます。より便利な解決策を試してみるとthis plotが生成され、下の出力が(printステートメントを介して)出力されますが、間違いの原因を見つけることはできません。

idx & stdev = 0 & 1, 
mu - (stdev * sigma) = 41.00, 
mu + (stdev * sigma) = 55.00, alpha = 0.18 


idx & stdev = 1 & 2, 
mu - (stdev * sigma) = 34.00, 
mu + (stdev * sigma) = 62.00, alpha = 0.11 


idx & stdev = 2 & 3, 
mu - (stdev * sigma) = 27.00, 
mu + (stdev * sigma) = 69.00, alpha = 0.02 

私のアプローチは、より便利なソリューションに適していますか?

答えて

2

ここでは、あなたよりもコンパクトな正規分布図を提供しています。私は車輪を再構築するのではなく、Scipyパッケージの正規分布関数を使用します。

from scipy.stats import norm # import normal dist. 
import matplotlib.pyplot as plt 
import numpy as np 

# mean and standard deviation 
mu,sigma = 48,7 

# normal_dist(mu,sigma) 
anorm = norm(loc=mu, scale=sigma) 
factors = [1,2,3]   # multiple of sigma 
alphas = [0.18, 0.11, 0.08] # level of alpha 

fig, ax = plt.subplots(1, 1) 
fig.set_size_inches(10,8) 

# plot full normal curve 
segs = 100 
x = np.linspace(anorm.ppf(0.0005), anorm.ppf(0.9995), segs) 
ax.plot(x, anorm.pdf(x), 'b-', lw=0.5, alpha=0.6) 

# plot color-filled portions 
for fac, alp in zip(factors, alphas): 
    # print(mu-fac*sigma, mu+fac*sigma, alp) 
    lo = mu-fac*sigma 
    hi = mu+fac*sigma 
    xs = np.linspace(lo, hi, fac*segs/4) # prep array of x's 
    plt.fill_between(xs, anorm.pdf(xs), y2=0, where= xs >= lo , \ 
        interpolate=False, \ 
        color='blue', alpha=alp) 

plt.ylim(0, 0.06) 

plt.show() 

結果のプロット:

enter image description here

関連する問題