对曲线下的多个区域着色的有效方法

时间:2019-01-29 13:50:00

标签: python matplotlib normal-distribution

我想绘制正态分布曲线,并在曲线下方的三个区域分别画上阴影,分别定义为“平均值”(在负1和正1标准偏差之间),“高于或低于平均值”(在负2和负1分别为正1之间)和正两个标准偏差)和“远高于或低于平均值”(在负三个和负两个之间分别为正两个和正三个标准偏差)。

首先,我寻找了一个可以处理颜色的函数,并遇到了matplotlib的fill_between方法。然后,我使用np.linspace定义了三个x向量,并使用了for循环,使用fill_between来阴影区域。然后,我意识到fill_between将“连接”两个区域,即使我希望中间部分不加阴影(这适用于“高于和低于平均值”和“高于和低于平均值”)。因此,该方法不起作用。

然后,我在where中遇到了fill_between关键字参数,并提出了一个使用逻辑运算符定义三个区域的解决方案。此方法有效,但我对它并不满意,并强烈感到必须找到一种更有效的方法来解决此问题?

这是我的代码:

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

plotdata = {"mean": 50,"sd": 10}

# plot normal distribution
x_normdist = np.linspace(plotdata["mean"] - 3 * plotdata["sd"], plotdata["mean"] + 3 * plotdata["sd"],1000)
y = norm.pdf(x_normdist,plotdata["mean"],plotdata["sd"])
plt.plot(x_normdist,y)

# create logical lists
average = (x_normdist >= (plotdata["mean"] - 1 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] + 1 * plotdata["sd"]))

above_and_below_average = (x_normdist >= (plotdata["mean"] - 2 * plotdata["sd"])) & (x_normdist < (plotdata["mean"] - 1 * plotdata["sd"])) | (x_normdist > (plotdata["mean"] + 1 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] + 2 * plotdata["sd"]))

far_above_and_belowe_average = (x_normdist >= (plotdata["mean"] - 3 * plotdata["sd"])) & (x_normdist < (plotdata["mean"] - 2 * plotdata["sd"])) | (x_normdist > (plotdata["mean"] + 2 * plotdata["sd"])) & (x_normdist <= (plotdata["mean"] + 3 * plotdata["sd"]))

# bind lists
regions = [average,above_and_below_average,far_above_and_belowe_average]

# set alpha values
alpha_values = [0.75,0.5,0.25]

# plot regions with corresponding alpha values
for idx,region in enumerate(regions):
    y = norm.pdf(x_normdist, plotdata["mean"], plotdata["sd"])
    plt.fill_between(x_normdist, y,color="C0",alpha=alpha_values[idx],where=regions[idx])

plt.show()

1 个答案:

答案 0 :(得分:0)

我@Bazingaa同意你的解决方案可能不够好,易于阅读。如果您想树荫许多不同的时间间隔,它会得到麻烦,虽然。你可以优化该过程像下面,但是代码是可读的要少得多。

from scipy.stats import norm
m=50.
sd=10.

fig, ax = plt.subplots()
x = np.linspace(m-3*sd,m+3*sd,1000)
y = norm.pdf(x,m,sd)
ax.plot(x,y,c='C0')

cutoffs = [0,0.25,0.6,1.2,3]  # expressed in sd
colors = ['C0','C1','C2','C3']
alphas = [1.00,0.75,0.50,0.25]

where_x = np.zeros(len(x))
for cut in cutoffs:
    where_x+=np.where(np.abs(x-m)>cut*sd,1,0)
for cond,c,a in zip(range(1,len(cutoffs)),colors,alphas):
    ax.fill_between(x,y,color=c,alpha=a,where=(where_x==cond))

enter image description here