【问题标题】:Annotate the quartiles with Matplotlib in a normal distribution plot在正态分布图中使用 Matplotlib 注释四分位数
【发布时间】:2017-04-12 04:38:39
【问题描述】:

我正在处理一个数据集,到目前为止,我已经制作了一个带有叠加正态分布曲线的直方图。 Histrogram with normal Distribution Curve

我想在image 中标出四分位数(箱线图供参考)。 这是我正在使用的代码:

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

depDelay.sort()
plt.hist(depDelay, bins=100, normed=True)
hmean = np.mean(depDelay)
hstd = np.std(depDelay)
pdf = stats.norm.pdf(depDelay, hmean, hstd)
markers = [np.percentile(depDelay,50)]
plt.plot(DepDelay, pdf,'-o',markevery=markers)
plt.title('Distribution of Departure Delay')
plt.xlabel('Departure Delay (in mins)')
plt.ylabel('Frequency')
plt.savefig('depDelayNormDist.png')
plt.show()

如何使用 matplotlib 绘制相同的图?

【问题讨论】:

  • 你看过plt.boxplotvert=False吗?此外,您的数据没有通过正态分布很好地建模。完全没有。
  • 是的@Paul,我也在使用盒须图,但我需要此图用于演示目的

标签: python numpy matplotlib plot


【解决方案1】:

我在类似帖子之后以函数的形式更新了答案,包括在具有分位数的 KDE 图上创建虚线:

import numpy as np
import scipy
import pandas as pd
from scipy.stats import norm
import matplotlib.pyplot as plt
#from matplotlib.mlab import normpdf  #check this: https://github.com/materialsproject/pymatgen/issues/1657

def KDE_hist_plot(df):
    for col in df.columns:
        n_bins = 50

        fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True, figsize=(10,5))

        #histogram
        n, bins, patches = axes[1].hist(df[col], n_bins, density=True, alpha=.1, edgecolor='black' )
        #data = pd.Series(s)
        mu = df[col].mean()
        sigma = df[col].std()
        pdf = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(bins-mu)**2/(2*sigma**2))
        median, q1, q3 = np.percentile(df[col], 50), np.percentile(df[col], 25), np.percentile(df[col], 75)

        #probability density function
        axes[1].plot(bins, pdf, color='orange', alpha=.6)

        #axes[1].figsize=(10,20)
        #fill from Q1-1.5*IQR to Q1 and Q3 to Q3+1.5*IQR
        iqr = 1.5 * (q3-q1)
        x1 = np.linspace(q1 - iqr, q1)
        x2 = np.linspace(q3, q3 + iqr)
        pdf1 = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(x1-mu)**2/(2*sigma**2))
        pdf2 = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(x2-mu)**2/(2*sigma**2))
        axes[1].fill_between(x1, pdf1, 0, alpha=.6, color='orange')
        axes[1].fill_between(x2, pdf2, 0, alpha=.6, color='orange')

        #add text to bottom graph.
        axes[1].annotate("{:.1f}%".format(100*(norm(mu, sigma).cdf(q1)    -norm(mu, sigma).cdf(q1-iqr))), xy=(q1-iqr/2, 0), ha='center')
        axes[1].annotate("{:.1f}%".format(100*(norm(mu, sigma).cdf(q3)    -norm(mu, sigma).cdf(q1)    )), xy=(median  , 0), ha='center')
        axes[1].annotate("{:.1f}%".format(100*(norm(mu, sigma).cdf(q3+iqr)-norm(mu, sigma).cdf(q3)    )), xy=(q3+iqr/2, 0), ha='center')
        axes[1].annotate('q1', xy=(q1, norm(mu, sigma).pdf(q1)), ha='center')
        axes[1].annotate('q3', xy=(q3, norm(mu, sigma).pdf(q3)), ha='center')

        #dashed lines
        plt.axvline(df[col].quantile(0),color='b', linestyle='-.')
        plt.axvline(df[col].quantile(0.25),color='g', linestyle='--')
        plt.axvline(df[col].quantile(0.50),color='g', linestyle='--')
        plt.axvline(df[col].quantile(0.75),color='b', linestyle='--')
        plt.axvline(df[col].quantile(1),color='r', linestyle='-.')

        axes[1].set_ylabel('Probability Density')

        #top boxplot
        axes[0].boxplot(df[col], 0, 'gD', vert=False)
        axes[0].axvline(median, color='orange', alpha=.6, linewidth=.5)
        axes[0].axis('off')

请查看下面df 的结果,colab notebook 中有 2 列/属性和工作函数:

KDE_hist_plot(df)

【讨论】:

    【解决方案2】:

    我尝试在某种程度上复制引用的图像。不确定您标记四分位数的确切含义,但我已经在 pdf 中添加了 Q1 和 Q3 的标签以及四分位数之间的百分比。

    import numpy as np
    import scipy
    import pandas as pd
    from scipy.stats import norm
    import matplotlib.pyplot as plt
    from matplotlib.mlab import normpdf
    
    # dummy data
    mu = 0
    sigma = 1
    n_bins = 50
    s = np.random.normal(mu, sigma, 1000)
    
    fig, axes = plt.subplots(nrows=2, ncols=1, sharex=True)
    
    #histogram
    n, bins, patches = axes[1].hist(s, n_bins, normed=True, alpha=.1, edgecolor='black' )
    pdf = 1/(sigma*np.sqrt(2*np.pi))*np.exp(-(bins-mu)**2/(2*sigma**2))
    
    median, q1, q3 = np.percentile(s, 50), np.percentile(s, 25), np.percentile(s, 75)
    print(q1, median, q3)
    
    #probability density function
    axes[1].plot(bins, pdf, color='orange', alpha=.6)
    
    #to ensure pdf and bins line up to use fill_between.
    bins_1 = bins[(bins >= q1-1.5*(q3-q1)) & (bins <= q1)] # to ensure fill starts from Q1-1.5*IQR
    bins_2 = bins[(bins <= q3+1.5*(q3-q1)) & (bins >= q3)]
    pdf_1 = pdf[:int(len(pdf)/2)]
    pdf_2 = pdf[int(len(pdf)/2):]
    pdf_1 = pdf_1[(pdf_1 >= norm(mu,sigma).pdf(q1-1.5*(q3-q1))) & (pdf_1 <= norm(mu,sigma).pdf(q1))]
    pdf_2 = pdf_2[(pdf_2 >= norm(mu,sigma).pdf(q3+1.5*(q3-q1))) & (pdf_2 <= norm(mu,sigma).pdf(q3))]
    
    #fill from Q1-1.5*IQR to Q1 and Q3 to Q3+1.5*IQR
    axes[1].fill_between(bins_1, pdf_1, 0, alpha=.6, color='orange')
    axes[1].fill_between(bins_2, pdf_2, 0, alpha=.6, color='orange')
    
    print(norm(mu, sigma).cdf(median))
    print(norm(mu, sigma).pdf(median))
    
    #add text to bottom graph.
    axes[1].annotate("{:.1f}%".format(100*norm(mu, sigma).cdf(q1)), xy=((q1-1.5*(q3-q1)+q1)/2, 0), ha='center')
    axes[1].annotate("{:.1f}%".format(100*(norm(mu, sigma).cdf(q3)-norm(mu, sigma).cdf(q1))), xy=(median, 0), ha='center')
    axes[1].annotate("{:.1f}%".format(100*(norm(mu, sigma).cdf(q3+1.5*(q3-q1)-q3)-norm(mu, sigma).cdf(q3))), xy=((q3+1.5*(q3-q1)+q3)/2, 0), ha='center')
    axes[1].annotate('q1', xy=(q1, norm(mu, sigma).pdf(q1)), ha='center')
    axes[1].annotate('q3', xy=(q3, norm(mu, sigma).pdf(q3)), ha='center')
    
    axes[1].set_ylabel('probability')
    
    #top boxplot
    axes[0].boxplot(s, 0, 'gD', vert=False)
    axes[0].axvline(median, color='orange', alpha=.6, linewidth=.5)
    axes[0].axis('off')
    
    plt.subplots_adjust(hspace=0)
    plt.show()
    

    仅供参考,我也回答了this 类似的问题。

    【讨论】:

    • 是的,这正是我想要的。谢谢。
    • 由于from matplotlib.mlab import normpdf 的问题,此答案需要更新。请参阅issue
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-20
    • 2021-07-12
    相关资源
    最近更新 更多